list.c
Go to the documentation of this file.
1 /*!**********************************************************************
2 *
3 * @copyright Copyright (C) 2016 Siemens Aktiengesellschaft.\n
4 * All rights reserved.
5 *
6 *************************************************************************
7 *
8 * @file list.c
9 * @date Jul 20, 2016
10 * @brief List module implementation file.
11 *
12 ************************************************************************/
13 
14 #include "list.h"
15 #include "memory.h"
16 #include "definitions.h"
17 #include "log_util.h"
18 
20 {
21  DEBUG_ENTRY("mcl_list_t **list = <%p>", list)
22 
23  E_MCL_ERROR_CODE code;
24  ASSERT_NOT_NULL(list);
25 
26  code = list_initialize(list);
27 
28  DEBUG_LEAVE("retVal = <%d>", code);
29  return code;
30 }
31 
33 {
34  DEBUG_ENTRY("mcl_list_t *list = <%p>, void *data = <%p>", list, data)
35 
36  E_MCL_ERROR_CODE code;
37  ASSERT_NOT_NULL(list);
38  ASSERT_NOT_NULL(data);
39 
40  code = list_add(list, data);
41 
42  DEBUG_LEAVE("retVal = <%d>", code);
43  return code;
44 }
45 
47 {
48  DEBUG_ENTRY("mcl_list_t *list = <%p>", list)
49 
50  ASSERT_NOT_NULL(list);
51  ASSERT_NOT_NULL(node);
52 
53  *node = list_next(list);
54 
55  if (MCL_NULL != *node)
56  {
57  DEBUG_LEAVE("retVal = <%d>", MCL_OK);
58  return MCL_OK;
59  }
60  else
61  {
62  DEBUG_LEAVE("retVal = <%d>", MCL_FAIL);
63  return MCL_FAIL;
64  }
65 }
66 
68 {
69  DEBUG_ENTRY("mcl_list_t *list = <%p>, mcl_list_node_t *node = <%p>", list, node)
70 
71  E_MCL_ERROR_CODE code;
72  ASSERT_NOT_NULL(list);
73  ASSERT_NOT_NULL(node);
74 
75  code = list_remove(list, node);
76 
77  DEBUG_LEAVE("retVal = <%d>", code);
78  return code;
79 }
80 
82 {
83  DEBUG_ENTRY("mcl_list_t *list = <%p>, mcl_list_node_t *node = <%p>, mcl_list_item_destroy_callback callback = <%p>", list, node, &callback)
84 
85  E_MCL_ERROR_CODE code;
86  ASSERT_NOT_NULL(list);
87  ASSERT_NOT_NULL(node);
88  ASSERT_NOT_NULL(callback);
89 
90  code = list_remove_with_content(list, node, callback);
91 
92  DEBUG_LEAVE("retVal = <%d>", code);
93  return code;
94 }
95 
96 E_MCL_ERROR_CODE mcl_list_exist(mcl_list_t *list, const void *item_to_find, mcl_list_compare_callback compare_function, void **item)
97 {
98  DEBUG_ENTRY("mcl_list_t *list = <%p>, const void *item_to_find = <%p>, mcl_list_compare_callback compare_function = <%p>, void **item = <%p>", list, item_to_find, &compare_function, item)
99 
100  E_MCL_ERROR_CODE code;
101  ASSERT_NOT_NULL(list);
102  ASSERT_NOT_NULL(item_to_find);
103  ASSERT_NOT_NULL(compare_function);
104  ASSERT_NOT_NULL(item);
105 
106  code = list_exist(list, item_to_find, compare_function, item);
107 
108  DEBUG_LEAVE("retVal = <%d>", code);
109  return code;
110 }
111 
113 {
114  DEBUG_ENTRY("mcl_list_t *list = <%p>", list)
115 
116  list_reset(list);
117 
118  DEBUG_LEAVE("retVal = void");
119 }
120 
122 {
123  DEBUG_ENTRY("mcl_list_t **list = <%p>", list)
124 
125  list_destroy(list);
126 
127  DEBUG_LEAVE("retVal = void");
128 }
129 
131 {
132  DEBUG_ENTRY("mcl_list_t **list = <%p>, mcl_list_item_destroy_callback callback = <%p>", list, &callback);
133 
134  list_destroy_with_content(list, callback);
135 
136  DEBUG_LEAVE("retVal = void");
137 }
138 
140 {
141  VERBOSE_ENTRY("list_t **list = <%p>", list)
142 
143  list_t *list_local;
144 
145  MCL_NEW(*list);
146  ASSERT_CODE_MESSAGE(MCL_NULL != *list, MCL_OUT_OF_MEMORY, "Not enough memory to allocate new list_t!");
147 
148  // initialize the list:
149  list_local = *list;
150  list_local->count = 0;
151  list_local->current = MCL_NULL;
152  list_local->head = MCL_NULL;
153  list_local->last = MCL_NULL;
154 
155  VERBOSE_LEAVE("retVal = <%d>", MCL_OK);
156  return MCL_OK;
157 }
158 
159 E_MCL_ERROR_CODE list_add(list_t *list, void *data)
160 {
161  VERBOSE_ENTRY("list_t *list = <%p>, void *data = <%p>", list, data)
162 
163  list_node_t *new_node;
164  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!");
165 
166  MCL_NEW(new_node);
167  ASSERT_CODE_MESSAGE(MCL_NULL != new_node, MCL_OUT_OF_MEMORY, "Not enough memory to allocate new mcl_node!");
168 
169  new_node->data = data;
170  new_node->prev = list->last;
171  new_node->next = MCL_NULL;
172  MCL_VERBOSE("new_node initialized and its data assigned to the received one. Node's data address = <%p>", (void *)new_node->data);
173 
174  if (0 == list->count)
175  {
176  MCL_VERBOSE("This is the first node in the list.");
177  list->head = new_node;
178  list->last = new_node;
179  list->current = new_node;
180  }
181  else
182  {
183  list->last->next = new_node;
184  list->last = new_node;
185  }
186 
187  // If we are here, it means adding is successful, we can increase the count:
188  ++list->count;
189  MCL_VERBOSE("new_node has been added to the list. Current list count = <%d>", list->count);
190 
191  VERBOSE_LEAVE("retVal = <%d>", MCL_OK);
192  return MCL_OK;
193 }
194 
196 {
197  DEBUG_ENTRY("list_t *list = <%p>, list_node_t *node = <%p>, list_item_destroy_callback callback = <%p>", list, node, callback)
198 
199  E_MCL_ERROR_CODE result;
200  void *data = node->data;
201 
202  if (MCL_OK == (result = list_remove(list, node)))
203  {
204  if (MCL_NULL != data)
205  {
206  callback(&data);
207  }
208  }
209 
210  DEBUG_LEAVE("retVal = <%d>", result);
211  return result;
212 }
213 
215 {
216  VERBOSE_ENTRY("list_t *list = <%p>, list_node_t *node = <%p>", list, node)
217 
218  ASSERT_CODE_MESSAGE(list->count > 0, MCL_ARRAY_IS_EMPTY, "The list count is 0. Not removing any element!");
219 
220  // Node connection handling:
221  MCL_VERBOSE("node connection handling begins");
222  if (MCL_NULL == node->prev)
223  {
224  // first node.
225  MCL_VERBOSE("node->prev is MCL_NULL.");
226  MCL_VERBOSE("This is the first node.");
227 
228  if (MCL_NULL == node->next)
229  {
230  // prev and next are MCL_NULL. This is the only node in list.
231  // no need to handle any node connection
232  MCL_VERBOSE("node->next is NULL.");
233  MCL_VERBOSE("This is the only node in list. No need for any connection handling.");
234  }
235  else
236  {
237  // prev is MCL_NULL but next is not. This should be the last node.
238  // set MCL_NULL to (node->next)->prev
239  node->next->prev = MCL_NULL;
240  MCL_VERBOSE("node->next is not MCL_NULL.");
241  MCL_VERBOSE("There is node's after this node. Next node's prev is set NULL.");
242  }
243  }
244  else
245  {
246  // not the first node.
247  MCL_VERBOSE("node->prev is not NULL.");
248  MCL_VERBOSE("This is NOT the first node.");
249 
250  if (MCL_NULL == node->next)
251  {
252  // prev is NOT MCL_NULL but next is MCL_NULL. This is the last node
253  // set node->prev->next to MCL_NULL
254  node->prev->next = MCL_NULL;
255 
256  MCL_VERBOSE("node->next is MCL_NULL.");
257  MCL_VERBOSE("This is the last node. Previous node's next is set NULL");
258  }
259  else
260  {
261  // prev is NOT MCL_NULL, next is NOT MCL_NULL. This is a middle node
262  // set node->prev->next to node->next and the other way :
263  node->prev->next = node->next;
264  node->next->prev = node->prev;
265  MCL_VERBOSE("node->next and node->prev are not MCL_NULL.");
266  MCL_VERBOSE("This is a middle node. prev's next is connected to current next. next's prev is connected to current prev.");
267  }
268  }
269  MCL_VERBOSE("node connection handling ends");
270 
271  MCL_VERBOSE("list handling begins");
272 
273  // List handling :
274  if (list->head == node)
275  {
276  // if this was the head node, take the head to the next one. If the next one is MCL_NULL then list->head will also be MCL_NULL. No need to check for MCL_NULL.
277  list->head = node->next;
278  MCL_VERBOSE("This is the head node. Head pointer updated to the next node");
279  }
280 
281  if (list->last == node)
282  {
283  // if this is the last node take the last node to the previous one. If the prev one is MCL_NULL then list->prev will also be MCL_NULL. No need to check for MCL_NULL.
284  list->last = node->prev;
285  MCL_VERBOSE("This is the last node. Last pointer updated to the previous node");
286  }
287 
288  if (list->current == node)
289  {
290  // if current currently points to this node, we slide it to the next
291  list->current = node->next;
292  MCL_VERBOSE("This is the list's current node. Current pointer updated to the next node");
293  }
294 
295  // decrease the list count :
296  --list->count;
297  MCL_VERBOSE("List counter decreased by one. Current count = <%d>", list->count);
298 
299  MCL_VERBOSE("list handling ends");
300 
301  // now node connection handling and list handling is completed. we can free the node:
302  MCL_FREE(node);
303  MCL_VERBOSE("node is freed");
304 
305  VERBOSE_LEAVE("retVal = <%d>", MCL_OK);
306  return MCL_OK;
307 }
308 
310 {
311  VERBOSE_ENTRY("list_t *list = <%p>", list)
312 
313  list_node_t *node = list->current;
314  ASSERT_MESSAGE(MCL_NULL != list, "Triggered list handle is NULL! Not performing any operations!");
315 
316  if (MCL_NULL == list->current)
317  {
318  list->current = list->head;
319  }
320  else
321  {
322  list->current = list->current->next;
323  }
324 
325  VERBOSE_LEAVE("retVal = <%p>", node);
326  return node;
327 }
328 
329 void list_reset(list_t *list)
330 {
331  VERBOSE_ENTRY("list_t *list = <%p>", list)
332 
333  if (MCL_NULL != list)
334  {
335  list->current = list->head;
336  MCL_VERBOSE("List is reset.");
337  }
338  else
339  {
340  MCL_VERBOSE("List is NULL.");
341  }
342 
343  VERBOSE_LEAVE("retVal = void");
344 }
345 
346 E_MCL_ERROR_CODE list_exist(list_t *list, const void *item_to_find, list_compare_callback compare_function, void **item)
347 {
348  DEBUG_ENTRY("list_t *list = <%p>, const void *item_to_find = <%p>, list_compare_callback compare_function = <%p>, void **item = <%p>", list, item_to_find,
349  &compare_function, item)
350 
351  // We don't call list_reset() not to change list's configuration of current node, next node etc.
352  list_node_t *current_node = list->head;
353  while (MCL_NULL != current_node)
354  {
355  E_MCL_ERROR_CODE item_exists_in_the_list = compare_function(current_node->data, item_to_find);
356 
357  if (MCL_OK == item_exists_in_the_list)
358  {
359  *item = current_node->data;
360  DEBUG_LEAVE("retVal = <%d>", MCL_OK);
361  return MCL_OK;
362  }
363 
364  // We don't call list_next() not to change list's configuration of current node, next node etc.
365  current_node = current_node->next;
366  }
367 
368  *item = MCL_NULL;
369  DEBUG_LEAVE("retVal = <%d>", MCL_FAIL);
370  return MCL_FAIL;
371 }
372 
374 {
375  DEBUG_ENTRY("list_t **list = <%p>, list_item_destroy_callback callback = <%p>", list, &callback)
376 
377  list_t *local_list = *list;
378 
379  if (MCL_NULL != local_list)
380  {
381  list_node_t *current_node = local_list->head;
382  mcl_size_t index = 0;
383 
384  MCL_DEBUG("List count = <%d>", local_list->count);
385 
386  while (MCL_NULL != current_node)
387  {
388  list_node_t *node_to_free;
389 
390  // we are not freeing the node->data if callback is NULL! It's users responsibility!
391  if ((MCL_NULL != callback) && (MCL_NULL != current_node->data))
392  {
393  callback(&(current_node->data));
394  }
395 
396  node_to_free = current_node;
397  current_node = node_to_free->next;
398  MCL_FREE(node_to_free);
399  MCL_DEBUG("%d. node has been freed..", index++);
400  }
401 
402  MCL_FREE(local_list);
403  *list = MCL_NULL;
404  }
405 
406  DEBUG_LEAVE("retVal = void");
407 }
408 
409 void list_destroy(list_t **list)
410 {
411  VERBOSE_ENTRY("list_t **list = <%p>", list)
412 
414 
415  VERBOSE_LEAVE("retVal = void");
416 }
Internal failure in MCL.
Definition: mcl_common.h:141
Memory module header file.
#define VERBOSE_LEAVE(...)
Definition: log_util.h:66
void list_reset(list_t *list)
Reset the current node to head node.
Definition: list.c:329
#define DEBUG_LEAVE(...)
Definition: log_util.h:81
#define DEBUG_ENTRY(...)
Definition: log_util.h:80
#define MCL_NEW(p)
Definition: memory.h:121
E_MCL_ERROR_CODE mcl_list_remove_with_content(mcl_list_t *list, mcl_list_node_t *node, mcl_list_item_destroy_callback callback)
Removes a node from the list and destroys the removed item with the provided callback function...
Definition: list.c:81
E_MCL_ERROR_CODE mcl_list_next(mcl_list_t *list, mcl_list_node_t **node)
Gets the next node from the list.
Definition: list.c:46
#define ASSERT_MESSAGE(condition,...)
Definition: definitions.h:82
void mcl_list_destroy_with_content(mcl_list_t **list, mcl_list_item_destroy_callback callback)
Destroys the list and its items with a given callback function.
Definition: list.c:130
void(* mcl_list_item_destroy_callback)(void **item)
Definition: mcl_list.h:66
E_MCL_ERROR_CODE list_exist(list_t *list, const void *item_to_find, list_compare_callback compare_function, void **item)
Searches item_to_find in the list.
Definition: list.c:346
#define MCL_DEBUG(...)
Definition: log_util.h:70
mcl_list_compare_callback list_compare_callback
Definition: list.h:23
#define ASSERT_NOT_NULL(argument)
Definition: definitions.h:129
Log utility module header file.
E_MCL_ERROR_CODE list_initialize(list_t **list)
Initializes the list.
Definition: list.c:139
E_MCL_ERROR_CODE mcl_list_exist(mcl_list_t *list, const void *item_to_find, mcl_list_compare_callback compare_function, void **item)
Searches item_to_find in the list.
Definition: list.c:96
E_MCL_ERROR_CODE
MCL Error code definitions. Every function returning an error code uses this enum values...
Definition: mcl_common.h:137
E_MCL_ERROR_CODE mcl_list_add(mcl_list_t *list, void *data)
Adds a new item to list.
Definition: list.c:32
void list_destroy(list_t **list)
To destroy the list.
Definition: list.c:409
#define MCL_FREE(p)
Definition: memory.h:125
#define VERBOSE_ENTRY(...)
Definition: log_util.h:65
struct mcl_list_node_t * next
Next node in the list.
Definition: mcl_list.h:34
mcl_list_node_t * head
Head node of the list.
Definition: mcl_list.h:42
void mcl_list_reset(mcl_list_t *list)
Reset the current node to head node.
Definition: list.c:112
E_MCL_ERROR_CODE list_remove(list_t *list, list_node_t *node)
Removes a node from the list.
Definition: list.c:214
There is no element in the array.
Definition: mcl_common.h:218
List module header file.
#define ASSERT_CODE_MESSAGE(condition, return_code,...)
Definition: definitions.h:105
Definitions module header file.
E_MCL_ERROR_CODE list_remove_with_content(list_t *list, list_node_t *node, list_item_destroy_callback callback)
Removes a node from the list and destroys the removed item with the provided callback function...
Definition: list.c:195
#define MCL_SIZE_MAX
Definition: definitions.h:21
list_node_t * list_next(list_t *list)
Get the next node from the list.
Definition: list.c:309
struct mcl_list_node_t * prev
Previous node in the list.
Definition: mcl_list.h:33
mcl_list_node_t * last
Last node of the list.
Definition: mcl_list.h:43
size_t mcl_size_t
Definition: mcl_common.h:38
No more space is left to add an additional object.
Definition: mcl_common.h:217
#define MCL_VERBOSE(...)
Definition: log_util.h:57
Success.
Definition: mcl_common.h:140
void mcl_list_destroy(mcl_list_t **list)
Destroys the list.
Definition: list.c:121
void list_destroy_with_content(list_t **list, list_item_destroy_callback callback)
To destroy the list and its items with a given callback function.
Definition: list.c:373
E_MCL_ERROR_CODE mcl_list_initialize(mcl_list_t **list)
Initializes a list with zero items in it.
Definition: list.c:19
mcl_list_node_t * current
Current node of the list.
Definition: mcl_list.h:44
E_MCL_ERROR_CODE(* mcl_list_compare_callback)(void *reference_item, const void *item_to_compare)
Definition: mcl_list.h:59
E_MCL_ERROR_CODE mcl_list_remove(mcl_list_t *list, mcl_list_node_t *node)
Removes a node from the list.
Definition: list.c:67
mcl_size_t count
Node count of the list.
Definition: mcl_list.h:45
E_MCL_ERROR_CODE list_add(list_t *list, void *data)
Adds a new list item.
Definition: list.c:159
Memory allocation fail.
Definition: mcl_common.h:143
#define MCL_NULL
Definition: definitions.h:24
mcl_list_item_destroy_callback list_item_destroy_callback
Definition: list.h:24
void * data
Data of the node.
Definition: mcl_list.h:32