Blame view

RIOT/core/include/clist.h 8.49 KB
a752c7ab   elopes   add first test an...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
  /*
   * Copyright (C) 2016 Kaspar Schleiser <kaspar@schleiser.de>
   *               2013 Freie Universitรคt Berlin
   *
   * This file is subject to the terms and conditions of the GNU Lesser
   * General Public License v2.1. See the file LICENSE in the top level
   * directory for more details.
   */
  
  /**
   * @addtogroup  core_util
   * @{
   *
   * @file
   * @brief       Circular linked list
   *
   * This file contains a circularly and singly linked list implementation.
   *
   * Its operations are:
   *
   * operation            | runtime | description
   * ---------------------|---------|---------------
   * clist_lpush()        | O(1)    | insert as head (leftmost node)
   * clist_lpop()         | O(1)    | remove and return head (leftmost node)
   * clist_rpush()        | O(1)    | append as tail (rightmost node)
   * clist_rpop()         | O(n)    | remove and return tail (rightmost node)
   * clist_find()         | O(n)    | find and return node
   * clist_find_before()  | O(n)    | find node return node pointing to node
   * clist_remove()       | O(n)    | remove and return node
   *
   * clist can be used as a traditional list, a queue (FIFO) and a stack (LIFO) using
   * fast O(1) operations.
   *
   * When used as traditional list, in order to traverse, make sure every element
   * is only visited once.
   *
   * Example:
   *
   *     void clist_traverse(clist_node_t *list) {
   *         clist_node_t *node = list->next;
   *         if (! node) {
   *             puts("list empty");
   *             return;
   *         }
   *
   *         do {
   *             node = node->next;
   *             // do something with node
   *         } while (node != list->next);
   *     }
   *
   * Or use the clist_foreach() helper function, e.g.,:
   *
   *    static int _print_node(clist_node_t *node)
   *    {
   *        printf("0x%08x ", (unsigned)node);
   *        return 0;
   *    }
   *
   *    [...]
   *    clist_foreach(&list, _print_node);
   *
   * To use clist as a queue, use clist_rpush() for adding elements and clist_lpop()
   * for removal. Using clist_lpush() and clist_rpop() is inefficient due to
   * clist_rpop()'s O(n) runtime.
   *
   * To use clist as stack, use clist_lpush()/clist_lpop().
   *
   * Implementation details:
   *
   * Each list is represented as a "clist_node_t". Its only member, the "next"
   * pointer, points to the last entry in the list, whose "next" pointer points to
   * the first entry.
   * Actual list objects should have a @c clist_node_t as member and then use
   * the container_of() macro in list operations.
   * See @ref thread_add_to_list() as example.
   *
   * @author      Kaspar Schleiser <kaspar@schleiser.de>
   */
  
  #ifndef CLIST_H
  #define CLIST_H
  
  #include <stddef.h>
  #include "list.h"
  
  #ifdef __cplusplus
   extern "C" {
  #endif
  
  /**
   * @brief List node structure
   *
   * Used as is as reference to a list.
   *
   */
  typedef list_node_t clist_node_t;
  
  /**
   * @brief Appends *new_node* at the end of *list
   *
   * @note Complexity: O(1)
   *
   * @param[in,out]   list        Pointer to clist
   * @param[in,out]   new_node    Node which gets inserted.
   *                              Must not be NULL.
   */
  static inline void clist_rpush(clist_node_t *list, clist_node_t *new_node)
  {
      if (list->next) {
          new_node->next = list->next->next;
          list->next->next = new_node;
      }
      else {
          new_node->next = new_node;
      }
      list->next = new_node;
  }
  
  
  /**
   * @brief Inserts *new_node* at the beginning of *list
   *
   * @note Complexity: O(1)
   *
   * @param[in,out]   list        Pointer to clist
   * @param[in,out]   new_node    Node which gets inserted.
   *                              Must not be NULL.
   */
  static inline void clist_lpush(clist_node_t *list, clist_node_t *new_node)
  {
      if (list->next) {
          new_node->next = list->next->next;
          list->next->next = new_node;
      }
      else {
          new_node->next = new_node;
          list->next = new_node;
      }
  }
  
  /**
   * @brief Removes and returns first element from list
   *
   * @note Complexity: O(1)
   *
   * @param[in,out]   list        Pointer to the *list* to remove first element
   *                              from.
   */
  static inline clist_node_t *clist_lpop(clist_node_t *list)
  {
      if (list->next) {
          clist_node_t *first = list->next->next;
          if (list->next == first) {
              list->next = NULL;
          }
          else {
              list->next->next = first->next;
          }
          return first;
      }
      else {
          return NULL;
      }
  }
  
  /**
   * @brief Advances the circle list.
   *
   * The result of this function is will be a list with
   * nodes shifted by one. So second list entry will be
   * first, first is last.
   *
   * [ A, B, C ] becomes [ B, C, A ]
   *
   * @note Complexity: O(1)
   *
   * @param[in,out]   list        The list to work upon.
   */
  static inline void clist_lpoprpush(clist_node_t *list)
  {
      if (list->next) {
          list->next = list->next->next;
      }
  }
  
  /**
   * @brief Returns first element in list
   *
   * @note: Complexity: O(1)
   *
   * @param[in]   list        The list to work upon.
   * @returns     first (leftmost) list element, or NULL if list is empty
   */
  static inline clist_node_t *clist_lpeek(const clist_node_t *list)
  {
      if (list->next) {
          return list->next->next;
      }
      return NULL;
  }
  
  /**
   * @brief Returns last element in list
   *
   * @note: Complexity: O(1)
   *
   * @param[in]   list        The list to work upon.
   * @returns     last (rightmost) list element, or NULL if list is empty
   */
  static inline clist_node_t *clist_rpeek(const clist_node_t *list)
  {
      return list->next;
  }
  
  /**
   * @brief Removes and returns last element from list
   *
   * @note Complexity: O(n) with n being the number of elements in the list.
   *
   * @param[in,out]   list        Pointer to the *list* to remove last element
   *                              from.
   */
  static inline clist_node_t *clist_rpop(clist_node_t *list)
  {
      if (list->next) {
          list_node_t *last = list->next;
          while (list->next->next != last) {
              clist_lpoprpush(list);
          }
          return clist_lpop(list);
      }
      else {
          return NULL;
      }
  }
  
  /**
   * @brief Finds node and returns its predecessor
   *
   * @note Complexity: O(n)
   *
   * @param[in]       list    pointer to clist
   * @param[in,out]   node    Node to look for
   *                          Must not be NULL.
   *
   * @returns         predecessor of node if found
   * @returns         NULL if node is not a list member
   */
  static inline clist_node_t *clist_find_before(const clist_node_t *list, const clist_node_t *node)
  {
      clist_node_t *pos = list->next;
      if (!pos) {
          return NULL;
      }
      do {
          pos = pos->next;
          if (pos->next == node) {
              return pos;
          }
      } while (pos != list->next);
  
      return NULL;
  }
  
  /**
   * @brief Finds and returns node
   *
   * @note Complexity: O(n)
   *
   * @param[in]       list    pointer to clist
   * @param[in,out]   node    Node to look for
   *                          Must not be NULL.
   *
   * @returns         node if found
   * @returns         NULL if node is not a list member
   */
  static inline clist_node_t *clist_find(const clist_node_t *list, const clist_node_t *node)
  {
      clist_node_t *tmp = clist_find_before(list, node);
      if (tmp) {
          return tmp->next;
      }
      else {
          return NULL;
      }
  }
  
  /**
   * @brief Finds and removes node
   *
   * @note Complexity: O(n)
   *
   * @param[in]       list    pointer to clist
   * @param[in,out]   node    Node to remove for
   *                          Must not be NULL.
   *
   * @returns         node if found and removed
   * @returns         NULL if node is not a list member
   */
  static inline clist_node_t *clist_remove(clist_node_t *list, clist_node_t *node)
  {
      if (list->next) {
          if (list->next->next == node) {
              return clist_lpop(list);
          }
          else {
              clist_node_t *tmp = clist_find_before(list, node);
              if (tmp) {
                  tmp->next = tmp->next->next;
                  if (node == list->next) {
                      list->next = tmp;
                  }
                  return node;
              }
          }
      }
  
      return NULL;
  }
  
  /**
   * @brief Traverse clist, call function for each member
   *
   * If @p func returns non-zero, traversal will be aborted like when calling
   * break within a for loop.
   *
   * @param[in]       list        List to traverse.
   * @param[in]       func        Function to call for each member.
   */
  static inline void clist_foreach(clist_node_t *list, int(*func)(clist_node_t *))
  {
      clist_node_t *node = list->next;
      if (! node) {
          return;
      }
      do {
          node = node->next;
          if (func(node)) {
              return;
          }
      } while (node != list->next);
  }
  
  #ifdef __cplusplus
  }
  #endif
  
  #endif /* CLIST_H */
  /** @} */