rename a_list_shift to a_list_set
[liba.git] / include / a / list.h
blobd0b17578afd80d05fe04eedfd82d32ddfe98b3f7
1 /*!
2 @file list.h
3 @brief circular doubly linked list implementation
4 */
6 #ifndef LIBA_LIST_H
7 #define LIBA_LIST_H
9 #include "a.h"
11 /*!
12 @ingroup A
13 @addtogroup A_LIST circular doubly linked list
17 // clang-format off
18 #define A_LIST_INIT(node) {&(node), &(node)}
19 // clang-format on
21 /*!
22 @brief instance structure for circular doubly linked list
24 typedef struct a_list
26 struct a_list *next, *prev;
27 } a_list;
29 /*!
30 @brief cast a list pointer from another type pointer
31 @param[in] _ additional attributes of specified type
32 @param[in] x points to circular doubly linked list
33 @return a pointer to circular doubly linked list
35 #define a_list_(_, x) a_cast_s(a_list _, a_cast_s(void _, x))
37 /*!
38 @brief access the struct for this entry
39 @param ptr the &a_list pointer
40 @param type the type of the struct this is embedded in
41 @param member the name of the a_list within the struct
43 #define a_list_entry(ptr, type, member) a_container_of(ptr, type, member)
44 #define a_list_entry_next(ptr, type, member) a_list_entry((ptr)->next, type, member)
45 #define a_list_entry_prev(ptr, type, member) a_list_entry((ptr)->prev, type, member)
47 /*!
48 @brief iterate over a list
49 @param it the &a_list to use as a loop counter
50 @param ctx points to circular doubly linked list
51 @param next the direction of loop iteration
52 @arg next the backward iteration
53 @arg prev the forward iteration
55 #define a_list_foreach_(it, ctx, next) \
56 for (a_list *it = (ctx)->next; it != (ctx); it = it->next)
57 #define a_list_foreach_next(it, ctx) a_list_foreach_(it, ctx, next)
58 #define a_list_foreach_prev(it, ctx) a_list_foreach_(it, ctx, prev)
60 /*!
61 @brief iterate over a list safe against removal of list entry
62 @param it the &a_list to use as a loop counter
63 @param at another &a_list to use as temporary storage
64 @param ctx points to circular doubly linked list
65 @param next the direction of loop iteration
66 @arg next the backward iteration
67 @arg prev the forward iteration
69 #define a_list_forsafe_(it, at, ctx, next) \
70 for (a_list *it = (ctx)->next, *at = it->next; it != (ctx); it = at, at = it->next)
71 #define a_list_forsafe_next(it, at, ctx) a_list_forsafe_(it, at, ctx, next)
72 #define a_list_forsafe_prev(it, at, ctx) a_list_forsafe_(it, at, ctx, prev)
74 /*!
75 @brief constructor for circular doubly linked list
76 @param[in,out] ctx points to circular doubly linked list
78 A_INTERN void a_list_ctor(a_list *ctx) { ctx->prev = ctx->next = ctx; }
80 /*!
81 @brief initialize for circular doubly linked list
82 @param[in,out] ctx points to circular doubly linked list
84 A_INTERN void a_list_init(a_list *ctx) { ctx->prev = ctx->next = ctx; }
86 /*!
87 @brief destructor for circular doubly linked list
88 @param[in,out] ctx points to circular doubly linked list
90 A_INTERN void a_list_dtor(a_list *ctx) { ctx->prev = ctx->next = ctx; }
92 /*!
93 @brief link head node and tail node
94 @dot
95 digraph a_list_link {
96 node[shape="record"]
97 nodehead[label="{<prev>prev|<addr>head|<next>next}"]
98 nodetail[label="{<prev>prev|<addr>tail|<next>next}"]
99 nodehead:next -> nodetail:addr [color=green]
100 nodetail:prev -> nodehead:addr [color=green]
101 nodehead -> "..." -> nodetail
103 @enddot
104 @param[in,out] head the head node of a list
105 @param[in,out] tail the tail node of a list
107 A_INTERN void a_list_link(a_list *head, a_list *tail)
109 head->next = tail;
110 tail->prev = head;
114 @brief loop head node to tail node
115 @dot
116 digraph a_list_loop {
117 node[shape="record"]
118 nodehead[label="{<prev>prev|<addr>head|<next>next}"]
119 nodetail[label="{<prev>prev|<addr>tail|<next>next}"]
120 nodehead:prev -> nodetail:addr [color=green]
121 nodetail:next -> nodehead:addr [color=green]
122 nodehead -> "..." -> nodetail
124 @enddot
125 @param[in,out] head the head node of a list
126 @param[in,out] tail the tail node of a list
128 A_INTERN void a_list_loop(a_list *head, a_list *tail)
130 head->prev = tail;
131 tail->next = head;
135 @brief connect list1 and list2
136 @dot
137 digraph a_list_add_ {
138 node[shape="record"]
139 subgraph cluster0 {
140 head1[label="<prev>prev|<addr>head1|<next>next"]
141 tail1[label="<prev>prev|<addr>tail1|<next>next"]
143 subgraph cluster1 {
144 head2[label="<prev>prev|<addr>head2|<next>next"]
145 tail2[label="<prev>prev|<addr>tail2|<next>next"]
147 tail1:next -> head2:addr [color=green]
148 head2:prev -> tail1:addr [color=green]
149 tail2:next -> head1:addr [color=blue]
150 head1:prev -> tail2:addr [color=blue]
152 @enddot
153 @param[in,out] head1 the head node of the list1
154 @param[in,out] tail1 the tail node of the list1
155 @param[in,out] head2 the head node of the list2
156 @param[in,out] tail2 the tail node of the list2
158 A_INTERN void a_list_add_(a_list *head1, a_list *tail1, a_list *head2, a_list *tail2)
160 a_list_link(tail1, head2);
161 a_list_link(tail2, head1);
165 @brief insert a node to a list
166 @dot
167 digraph a_list_add_node {
168 node[shape="record"]
169 subgraph cluster0 {
170 0[label="<node>node"]
171 1[label="<head>head|<tail>tail"]
173 subgraph cluster1 {
174 2[label="<head>head|<tail>tail|<node>node"]
176 1 -> 2
178 @enddot
179 @param[in,out] head the head node of a list
180 @param[in,out] tail the tail node of a list
181 @param[in] node a circular doubly linked list node
183 A_INTERN void a_list_add_node(a_list *head, a_list *tail, a_list *node)
185 a_list_add_(head, tail, node, node);
189 @brief append a node to a list forward
190 @dot
191 digraph a_list_add_next {
192 node[shape="record"]
193 subgraph cluster0 {
194 0[label="<0>0"]
195 1[label="<prev>prev|<node>node|<next>next"]
197 subgraph cluster1 {
198 2[label="<prev>prev|<node>node|<next>next|<0>0"]
200 1 -> 2
202 @enddot
203 @param[in,out] ctx points to circular doubly linked list
204 @param[in] node a circular doubly linked list node
206 A_INTERN void a_list_add_next(a_list *ctx, a_list *node)
208 a_list_add_(ctx->next, ctx, node, node);
212 @brief append a node to a list backward
213 @dot
214 digraph a_list_add_prev {
215 node[shape="record"]
216 subgraph cluster0 {
217 1[label="<prev>prev|<node>node|<next>next"]
218 0[label="<0>0"]
220 subgraph cluster1 {
221 2[label="<0>0|<prev>prev|<node>node|<next>next"]
223 1 -> 2
225 @enddot
226 @param[in,out] ctx points to circular doubly linked list
227 @param[in] node a circular doubly linked list node
229 A_INTERN void a_list_add_prev(a_list *ctx, a_list *node)
231 a_list_add_(ctx, ctx->prev, node, node);
235 @brief delete a section of a list
236 @dot
237 digraph a_list_del_ {
238 node[shape="record"]
239 head[label="<prev>prev|<addr>head-prev|<next>next"]
240 tail[label="<prev>prev|<addr>tail-next|<next>next"]
241 nodehead[label="<prev>prev|<addr>head|<next>next"]
242 nodetail[label="<prev>prev|<addr>tail|<next>next"]
243 head:addr -> nodehead:addr -> "..." -> nodetail:addr -> tail:addr [dir=both]
244 head:next -> tail:addr [color=green]
245 tail:prev -> head:addr [color=green]
247 @enddot
248 @param[in] head the head node of a list
249 @param[in] tail the tail node of a list
251 A_INTERN void a_list_del_(a_list const *head, a_list const *tail)
253 a_list_link(head->prev, tail->next);
257 @brief delete a node from a list
258 @dot
259 digraph a_list_del_node {
260 node[shape="record"]
261 subgraph cluster0 {
262 1[label="<head>head|<node>node|<tail>tail"]
264 subgraph cluster1 {
265 0[label="<node>node"]
266 2[label="<head>head|<tail>tail"]
268 1 -> 2
270 @enddot
271 @param[in] node a circular doubly linked list node
273 A_INTERN void a_list_del_node(a_list const *node) { a_list_del_(node, node); }
276 @brief remove a node from a list forward
277 @dot
278 digraph a_list_del_next {
279 node[shape="record"]
280 subgraph cluster0 {
281 1[label="<prev>prev|<node>node|<next>next|<0>0"]
283 subgraph cluster1 {
284 0[label="<0>0"]
285 2[label="<prev>prev|<node>node|<next>next"]
287 1 -> 2
289 @enddot
290 @param[in] node a circular doubly linked list node
292 A_INTERN void a_list_del_next(a_list const *node) { a_list_del_(node->next, node->next); }
295 @brief remove a node from a list backward
296 @dot
297 digraph a_list_del_prev {
298 node[shape="record"]
299 subgraph cluster0 {
300 1[label="<0>0|<prev>prev|<node>node|<next>next"]
302 subgraph cluster1 {
303 2[label="<prev>prev|<node>node|<next>next"]
304 0[label="<0>0"]
306 1 -> 2
308 @enddot
309 @param[in] node a circular doubly linked list node
311 A_INTERN void a_list_del_prev(a_list const *node) { a_list_del_(node->prev, node->prev); }
314 @brief modify a section of a list
315 @dot
316 digraph a_list_set_ {
317 node[shape="record"]
318 subgraph cluster0 {
319 1[label="<prev>prev|<head>head|<tail>tail|<next>next"]
321 subgraph cluster1 {
322 2[label="<prev>prev|<head>head|<tail>tail|<next>next"]
324 1:prev -> 2:head [color=green]
325 2:tail -> 1:next [color=green]
327 @enddot
328 @param[in] head1 the head node of the list1
329 @param[in] tail1 the tail node of the list1
330 @param[in,out] head2 the head node of the list2
331 @param[in,out] tail2 the tail node of the list2
333 A_INTERN void a_list_set_(a_list const *head1, a_list const *tail1, a_list *head2, a_list *tail2)
335 a_list_add_(tail1->next, head1->prev, head2, tail2);
339 @brief modify a node of a list
340 @param[in] ctx the current node
341 @param[in,out] rhs the new node
343 A_INTERN void a_list_set_node(a_list const *ctx, a_list *rhs)
345 a_list_add_(ctx->next, ctx->prev, rhs, rhs);
349 @brief moving a list from another list forward
350 @dot
351 digraph a_list_mov_next {
352 node[shape="record"]
353 subgraph cluster0 {
354 0[label="<0>0|<1>1"]
355 1[label="<prev>prev|<node>node|<next>next"]
357 subgraph cluster1 {
358 2[label="<prev>prev|<node>node|<next>next|<0>0|<1>1"]
360 1 -> 2
362 @enddot
363 @param[in,out] ctx points to circular doubly linked list
364 @param[in] rhs another circular doubly linked list
366 A_INTERN void a_list_mov_next(a_list *ctx, a_list const *rhs)
368 a_list_add_(ctx->next, ctx, rhs->next, rhs->prev);
372 @brief moving a list from another list backward
373 @dot
374 digraph a_list_mov_prev {
375 node[shape="record"]
376 subgraph cluster0 {
377 0[label="<0>0|<1>1"]
378 1[label="<prev>prev|<node>node|<next>next"]
380 subgraph cluster1 {
381 2[label="<0>0|<1>1|<prev>prev|<node>node|<next>next"]
383 1 -> 2
385 @enddot
386 @param[in,out] ctx points to circular doubly linked list
387 @param[in] rhs another circular doubly linked list
389 A_INTERN void a_list_mov_prev(a_list *ctx, a_list const *rhs)
391 a_list_add_(ctx, ctx->prev, rhs->next, rhs->prev);
395 @brief rotate a node in the list backward
396 @dot
397 digraph a_list_rot_next {
398 node[shape="record"]
399 subgraph cluster0 {
400 1[label="<0>0|<1>1|<2>2|<3>3|<prev>prev|<node>node|<next>next"]
402 subgraph cluster1 {
403 2[label="<0>0|<1>1|<2>2|<prev>prev|<node>node|<next>next|<3>3"]
405 1:prev -> 1:3 [color=green]
406 1:next -> 1:0 [color=green]
407 2:prev -> 2:2 [color=blue]
408 2:next -> 2:3 [color=blue]
409 1 -> 2
411 @enddot
412 @param[in,out] ctx points to circular doubly linked list
414 A_INTERN void a_list_rot_next(a_list *ctx)
416 a_list *const node = ctx->prev;
417 a_list_del_(node, node);
418 a_list_add_(ctx->next, ctx, node, node);
422 @brief rotate a node in the list forward
423 @dot
424 digraph a_list_rot_prev {
425 node[shape="record"]
426 subgraph cluster0 {
427 1[label="<prev>prev|<node>node|<next>next|<0>0|<1>1|<2>2|<3>3"]
429 subgraph cluster1 {
430 2[label="<0>0|<prev>prev|<node>node|<next>next|<1>1|<2>2|<3>3"]
432 1:prev -> 1:3 [color=green]
433 1:next -> 1:0 [color=green]
434 2:prev -> 2:0 [color=blue]
435 2:next -> 2:1 [color=blue]
436 1 -> 2
438 @enddot
439 @param[in,out] ctx points to circular doubly linked list
441 A_INTERN void a_list_rot_prev(a_list *ctx)
443 a_list *const node = ctx->next;
444 a_list_del_(node, node);
445 a_list_add_(ctx, ctx->prev, node, node);
449 @brief swap a section of one list and a section of another list
450 @dot
451 digraph a_list_swap_ {
452 node[shape="record"]
453 subgraph cluster0 {
454 1[label="<prev>prev|<head>head|<tail>tail|<next>next"]
456 subgraph cluster1 {
457 2[label="<prev>prev|<head>head|<tail>tail|<next>next"]
459 1:prev -> 2:head [color=green]
460 2:tail -> 1:next [color=green]
461 2:prev -> 1:head [color=blue]
462 1:tail -> 2:next [color=blue]
464 @enddot
465 @param[in,out] head1 the head node of the list1
466 @param[in,out] tail1 the tail node of the list1
467 @param[in,out] head2 the head node of the list2
468 @param[in,out] tail2 the tail node of the list2
470 A_INTERN void a_list_swap_(a_list *head1, a_list *tail1, a_list *head2, a_list *tail2)
472 a_list *const head = tail2->next, *const tail = head2->prev;
473 a_list_add_(tail1->next, head1->prev, head2, tail2);
474 a_list_add_(head, tail, head1, tail1);
478 @brief swap the node lhs and the node rhs
479 @param[in,out] lhs the node on the left
480 @param[in,out] rhs the node on the right
482 A_INTERN void a_list_swap_node(a_list *lhs, a_list *rhs)
484 a_list_swap_(lhs, lhs, rhs, rhs);
487 /*! @} A_LIST */
489 #endif /* a/list.h */