list.c
Go to the documentation of this file.
1 
9 #include "list.h"
10 #include "mcl_core/mcl_assert.h"
11 #include "mcl_core/mcl_memory.h"
12 
14 {
15  mcl_error_t code = MCL_OK;
16 
17  MCL_DEBUG_ENTRY("mcl_list_t **list = <%p>", list);
18 
19  MCL_ASSERT_NOT_NULL(list, code);
20  MCL_NEW(*list);
21  MCL_ASSERT_CODE_MESSAGE(MCL_NULL != *list, MCL_OUT_OF_MEMORY, "Not enough memory to allocate new list!");
22 
23  // Initialize the list.
24  (*list)->count = 0;
25  (*list)->current = MCL_NULL;
26  (*list)->head = MCL_NULL;
27  (*list)->last = MCL_NULL;
28 
30  MCL_DEBUG_LEAVE("retVal = <%d>", code);
31  return code;
32 }
33 
35 {
36  mcl_list_node_t *new_node;
37  mcl_error_t code = MCL_OK;
38 
39  MCL_DEBUG_ENTRY("mcl_list_t *list = <%p>, void *data = <%p>", list, data);
40 
41  MCL_ASSERT_NOT_NULL(list, code);
42  MCL_ASSERT_NOT_NULL(data, code);
43 
44  MCL_ASSERT_CODE_MESSAGE(list->count < MCL_SIZE_MAX, MCL_LIMIT_EXCEEDED, "Index of the list is already at the maximum value. Not adding the new data!");
45 
46  MCL_NEW(new_node);
47  MCL_ASSERT_CODE_MESSAGE(MCL_NULL != new_node, MCL_OUT_OF_MEMORY, "Not enough memory to allocate new mcl_node!");
48 
49  new_node->data = data;
50  new_node->prev = list->last;
51  new_node->next = MCL_NULL;
52  MCL_VERBOSE("new_node initialized and its data assigned to the received one. Node's data address = <%p>", (void *) new_node->data);
53 
54  if (0 == list->count)
55  {
56  MCL_VERBOSE("This is the first node in the list.");
57  list->head = new_node;
58  list->last = new_node;
59  list->current = new_node;
60  }
61  else
62  {
63  list->last->next = new_node;
64  list->last = new_node;
65  }
66 
67  // If we are here, it means adding is successful, we can increase the count.
68  ++list->count;
69  MCL_VERBOSE("new_node has been added to the list. Current list count = <%d>", list->count);
70 
72  MCL_DEBUG_LEAVE("retVal = <%d>", code);
73  return code;
74 }
75 
77 {
78  mcl_error_t code = MCL_OK;
79 
80  MCL_DEBUG_ENTRY("mcl_list_t *list = <%p>, mcl_list_node_t **node = <%p>", list, node);
81 
82  // Null check for node.
83  MCL_ASSERT_NOT_NULL(node, code);
84  *node = MCL_NULL;
85 
86  // Null check for list.
87  MCL_ASSERT_NOT_NULL(list, code);
88 
89  *node = list->current;
90 
91  if (MCL_NULL == list->current)
92  {
93  // If current node was last element, return head.
94  list->current = list->head;
95  }
96  else
97  {
98  // Set current node to next node for next call.
99  list->current = list->current->next;
100  }
101 
102  // Check if returned node is null.
103  if (MCL_NULL != *node)
104  {
105  code = MCL_OK;
106  }
107  else
108  {
109  code = MCL_FAIL;
110  }
111 
113  MCL_DEBUG_LEAVE("retVal = <%d>", code);
114  return code;
115 }
116 
118 {
119  mcl_error_t code = MCL_OK;
120 
121  MCL_DEBUG_ENTRY("mcl_list_t *list = <%p>, mcl_list_node_t *node = <%p>", list, node);
122 
123  MCL_ASSERT_NOT_NULL(list, code);
124  MCL_ASSERT_NOT_NULL(node, code);
125  MCL_ASSERT_CODE_MESSAGE(list->count > 0, MCL_LIST_IS_EMPTY, "The list count is 0. Not removing any item!");
126 
127  // Node connection handling.
128  MCL_VERBOSE("node connection handling begins");
129  if (MCL_NULL == node->prev)
130  {
131  // First node.
132  MCL_VERBOSE("node->prev is MCL_NULL.");
133  MCL_VERBOSE("This is the first node.");
134 
135  if (MCL_NULL == node->next)
136  {
137  // Prev and next are MCL_NULL. This is the only node in list.
138  // No need to handle any node connection.
139  MCL_VERBOSE("node->next is NULL.");
140  MCL_VERBOSE("This is the only node in list. No need for any connection handling.");
141  }
142  else
143  {
144  // Prev is MCL_NULL but next is not. This should be the last node.
145  // Set MCL_NULL to (node->next)->prev.
146  node->next->prev = MCL_NULL;
147  MCL_VERBOSE("node->next is not MCL_NULL.");
148  MCL_VERBOSE("There is node's after this node. Next node's prev is set NULL.");
149  }
150  }
151  else
152  {
153  // Not the first node.
154  MCL_VERBOSE("node->prev is not NULL.");
155  MCL_VERBOSE("This is NOT the first node.");
156 
157  if (MCL_NULL == node->next)
158  {
159  // Prev is NOT MCL_NULL but next is MCL_NULL. This is the last node.
160  // Set node->prev->next to MCL_NULL.
161  node->prev->next = MCL_NULL;
162 
163  MCL_VERBOSE("node->next is MCL_NULL.");
164  MCL_VERBOSE("This is the last node. Previous node's next is set NULL");
165  }
166  else
167  {
168  // Prev is NOT MCL_NULL, next is NOT MCL_NULL. This is a middle node.
169  // Set node->prev->next to node->next and the other way.
170  node->prev->next = node->next;
171  node->next->prev = node->prev;
172  MCL_VERBOSE("node->next and node->prev are not MCL_NULL.");
173  MCL_VERBOSE("This is a middle node. prev's next is connected to current next. next's prev is connected to current prev.");
174  }
175  }
176 
177  MCL_VERBOSE("node connection handling ends");
178  MCL_VERBOSE("list handling begins");
179 
180  // List handling.
181  if (list->head == node)
182  {
183  list->head = node->next;
184  MCL_VERBOSE("This is the head node. Head pointer updated to the next node");
185  }
186 
187  if (list->last == node)
188  {
189  list->last = node->prev;
190  MCL_VERBOSE("This is the last node. Last pointer updated to the previous node");
191  }
192 
193  if (list->current == node)
194  {
195  // If current currently points to this node, we slide it to the next.
196  list->current = node->next;
197  MCL_VERBOSE("This is the list's current node. Current pointer updated to the next node");
198  }
199 
200  // Decrease the list count.
201  --list->count;
202  MCL_VERBOSE("List counter decreased by one. Current count = <%d>", list->count);
203  MCL_VERBOSE("list handling ends");
204 
205  // Now node connection handling and list handling is completed. we can free the node.
206  MCL_FREE(node);
207  MCL_VERBOSE("node is freed");
208 
210  MCL_DEBUG_LEAVE("retVal = <%d>", code);
211  return code;
212 }
213 
215 {
216  mcl_error_t code;
217  void *data;
218 
219  MCL_DEBUG_ENTRY("mcl_list_t *list = <%p>, mcl_list_node_t *node = <%p>, mcl_list_item_destroy_callback callback = <%p>", list, node, callback);
220 
221  MCL_ASSERT_NOT_NULL(list, code);
222  MCL_ASSERT_NOT_NULL(node, code);
223  MCL_ASSERT_NOT_NULL(callback, code);
224 
225  data = node->data;
226 
227  code = mcl_list_remove(list, node);
228 
229  if ((MCL_OK == code) && (MCL_NULL != data))
230  {
231  callback(&data);
232  }
233 
235  MCL_DEBUG_LEAVE("retVal = <%d>", code);
236  return code;
237 }
238 
239 mcl_error_t mcl_list_exist(mcl_list_t *list, const void *item_to_find, mcl_list_compare_callback compare_function, void **item)
240 {
241  mcl_list_node_t *current_node;
242  mcl_error_t code = MCL_FAIL;
243 
244  MCL_DEBUG_ENTRY("mcl_list_t *list = <%p>, const void *item_to_find = <%p>, mcl_list_compare_callback compare_function = <%p>, void **item = <%p>",
245  list, item_to_find, compare_function, item);
246 
247  MCL_ASSERT_NOT_NULL(list, code);
248  MCL_ASSERT_NOT_NULL(item_to_find, code);
249  MCL_ASSERT_NOT_NULL(compare_function, code);
250  MCL_ASSERT_NOT_NULL(item, code);
251 
252  // We don't call list_reset() not to change list's configuration of current node, next node etc.
253  current_node = list->head;
254  while (MCL_NULL != current_node)
255  {
256  mcl_error_t item_exists_in_the_list = compare_function(current_node->data, item_to_find);
257 
258  if (MCL_OK == item_exists_in_the_list)
259  {
260  *item = current_node->data;
261  MCL_DEBUG_LEAVE("retVal = <%d>", MCL_OK);
262  return MCL_OK;
263  }
264 
265  // We don't call list_next() not to change list's configuration of current node, next node etc.
266  current_node = current_node->next;
267  }
268 
269  *item = MCL_NULL;
270 
272  MCL_DEBUG_LEAVE("retVal = <%d>", code);
273  return code;
274 }
275 
277 {
278  MCL_DEBUG_ENTRY("mcl_list_t *list = <%p>", list);
279 
280  if (MCL_NULL != list)
281  {
282  list->current = list->head;
283  MCL_VERBOSE("List is reset.");
284  }
285  else
286  {
287  MCL_VERBOSE("List is NULL.");
288  }
289 
290  MCL_DEBUG_LEAVE("retVal = void");
291 }
292 
294 {
295  MCL_DEBUG_ENTRY("mcl_list_t **list = <%p>", list);
296 
298 
299  MCL_DEBUG_LEAVE("retVal = void");
300 }
301 
303 {
304  MCL_DEBUG_ENTRY("mcl_list_t **list = <%p>, mcl_list_item_destroy_callback callback = <%p>", list, callback);
305 
306  if ((MCL_NULL != list) && (MCL_NULL != *list))
307  {
308  mcl_list_node_t *current_node = (*list)->head;
309 
310  MCL_VERBOSE("List count = <%d>", (*list)->count);
311 
312  while (MCL_NULL != current_node)
313  {
314  mcl_list_node_t *node_to_free;
315 
316  // We are not freeing the node->data if callback is NULL! It's users responsibility.
317  if ((MCL_NULL != callback) && (MCL_NULL != current_node->data))
318  {
319  callback(&(current_node->data));
320  }
321 
322  node_to_free = current_node;
323  current_node = node_to_free->next;
324  MCL_FREE(node_to_free);
325  }
326 
327  MCL_FREE(*list);
328  }
329 
330  MCL_DEBUG_LEAVE("retVal = void");
331 }
#define MCL_FUNCTION_LEAVE_LABEL
mcl_error_t(* mcl_list_compare_callback)(void *reference_item, const void *item_to_compare)
Definition: mcl_list.h:54
Assert module header file.
Success.
There is no element in the list.
mcl_int32_t mcl_error_t
#define MCL_DEBUG_ENTRY(...)
Definition: mcl_log_util.h:115
void mcl_list_destroy_with_content(mcl_list_t **list, mcl_list_item_destroy_callback callback)
Definition: list.c:302
void(* mcl_list_item_destroy_callback)(void **item)
Definition: mcl_list.h:61
#define MCL_VERBOSE(...)
Definition: mcl_log_util.h:102
mcl_error_t mcl_list_add(mcl_list_t *list, void *data)
Definition: list.c:34
mcl_error_t mcl_list_exist(mcl_list_t *list, const void *item_to_find, mcl_list_compare_callback compare_function, void **item)
Definition: list.c:239
#define MCL_ASSERT_CODE_MESSAGE(condition, return_code,...)
Definition: mcl_assert.h:77
#define MCL_NEW(p)
Definition: mcl_memory.h:55
#define MCL_NULL
mcl_error_t mcl_list_next(mcl_list_t *list, mcl_list_node_t **node)
Definition: list.c:76
struct mcl_list_node_t * next
Next node in the list.
Definition: mcl_list.h:29
mcl_list_node_t * head
Head node of the list.
Definition: mcl_list.h:37
void mcl_list_reset(mcl_list_t *list)
Definition: list.c:276
mcl_error_t mcl_list_remove_with_content(mcl_list_t *list, mcl_list_node_t *node, mcl_list_item_destroy_callback callback)
Definition: list.c:214
#define MCL_FREE(p)
Definition: mcl_memory.h:59
List module header file.
#define MCL_SIZE_MAX
#define MCL_ASSERT_NOT_NULL(argument, return_variable)
Definition: mcl_assert.h:38
mcl_error_t mcl_list_remove(mcl_list_t *list, mcl_list_node_t *node)
Definition: list.c:117
struct mcl_list_node_t * prev
Previous node in the list.
Definition: mcl_list.h:28
mcl_list_node_t * last
Last node of the list.
Definition: mcl_list.h:38
void mcl_list_destroy(mcl_list_t **list)
Definition: list.c:293
mcl_list_node_t * current
Current node of the list.
Definition: mcl_list.h:39
mcl_error_t mcl_list_initialize(mcl_list_t **list)
Definition: list.c:13
No more space is left to add an additional object.
Memory allocation fail.
mcl_size_t count
Node count of the list.
Definition: mcl_list.h:40
#define MCL_DEBUG_LEAVE(...)
Definition: mcl_log_util.h:116
Internal failure in MCL.
void * data
Data of the node.
Definition: mcl_list.h:27
Memory module interface header file.