librfn
An ad-hoc utility library
list.c
Go to the documentation of this file.
1 /*
2  * list.c
3  *
4  * Part of librfn (a general utility library from redfelineninja.org.uk)
5  *
6  * Copyright (C) 2013 Daniel Thompson <daniel@redfelineninja.org.uk>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as published
10  * by the Free Software Foundation; either version 3 of the License, or
11  * (at your option) any later version.
12  */
13 
14 #include <assert.h>
15 #include <stdint.h>
16 #include <stdlib.h>
17 
18 #include "librfn/util.h"
19 #include "librfn/list.h"
20 
21 void list_insert(list_t *list, list_node_t *node)
22 {
23  assert(NULL == node->next);
24 
25  if (list->head) {
26  list->tail->next = node;
27  } else {
28  list->head = node;
29  }
30 
31  list->tail = node;
32 }
33 
35  list_node_compare_t *nodecmp)
36 {
37  assert(NULL == node->next);
38 
39  /* fast path for empty list */
40  if (!list->head) {
41  list->head = node;
42  list->tail = node;
43  return;
44  }
45 
46  /* fast path for insert at end */
47  if (nodecmp(node, list->tail) >= 0) {
48  list->tail->next = node;
49  list->tail = node;
50  return;
51  }
52 
53  /* search the list until we find the correct place to insert the
54  * new node. we know (from the fast path above) that at least the
55  * tail node matches the loop termination condition.
56  */
57  list_iterator_t iter;
58  for (list_node_t *curr = list_iterate(list, &iter);
59  nodecmp(node, curr) >= 0;
60  curr = list_iterator_next(&iter))
61  assert(curr);
62  list_iterator_insert(&iter, node);
63 }
64 
65 void list_push(list_t *list, list_node_t *node)
66 {
67  assert(NULL == node->next);
68 
69  if (list->head) {
70  node->next = list->head;
71  } else {
72  list->tail = node;
73  }
74  list->head = node;
75 }
76 
78 {
79  list_node_t *node;
80 
81  if (!list->head)
82  return NULL;
83 
84  node = list->head;
85  list->head = node->next;
86  node->next = NULL;
87 
88  return node;
89 }
90 
92 {
93  iter->prevnext = &list->head;
94  iter->list = list;
95 
96  return list->head;
97 }
98 
100 {
101  list_node_t *curr = *(iter->prevnext);
102 
103  if (curr) {
104  iter->prevnext = &curr->next;
105  return curr->next;
106  }
107 
108  return NULL;
109 }
110 
111 /* Once the insertion has been made the iterator points to the *new* node.
112  */
114 {
115  list_node_t *curr = *(iter->prevnext);
116 
117  *(iter->prevnext) = node;
118  node->next = curr;
119 
120  if (!curr)
121  iter->list->tail = node;
122 }
123 
125 {
126  list_node_t *curr = *(iter->prevnext);
127  assert(curr);
128 
129  /* Make sure we maintain the list's tail pointer correctly if we
130  * are removing the final node in a list.
131  *
132  * Careful code review will reveal that, strictly speaking, prev
133  * is not actually "correct" if the list contains only one node
134  * because prevnext doesn't point to a node's next pointer, instead
135  * it points to the list's head pointer.
136  *
137  * In practice this doesn't matter because if the list contains only
138  * a single node then when we remove the node we will set list->head
139  * to NULL. When the head is NULL we can write any pointer we like
140  * into list->tail since its value is considered invalid when head
141  * is NULL.
142  */
143  list_node_t *prev = containerof(iter->prevnext, list_node_t, next);
144  if (iter->list->tail == curr)
145  iter->list->tail = prev;
146 
147  /* Remove the node (and invalidate its link pointer) */
148  *(iter->prevnext) = curr->next;
149  curr->next = NULL;
150 
151 
152  return *(iter->prevnext);
153 }
154 
156 {
157  list_iterator_t myiter;
158 
159  if (NULL == iter)
160  iter = &myiter;
161 
162  for (list_node_t *curr = list_iterate(list, iter);
163  curr;
164  curr = list_iterator_next(iter))
165  if (curr == node)
166  return true;
167 
168  return false;
169 }
170 
171 bool list_remove(list_t *list, list_node_t *node)
172 {
173  list_iterator_t iter;
174 
175  if (list_contains(list, node, &iter)) {
176  list_iterator_remove(&iter);
177  return true;
178  }
179 
180  return false;
181 }
#define containerof(ptr, type, member)
Definition: util.h:35
list_node_t * list_iterate(list_t *list, list_iterator_t *iter)
Definition: list.c:91
Definition: list.h:39
bool list_contains(list_t *list, list_node_t *node, list_iterator_t *iter)
Definition: list.c:155
list_node_t * list_iterator_next(list_iterator_t *iter)
Definition: list.c:99
list_t * list
Definition: list.h:47
void list_iterator_insert(list_iterator_t *iter, list_node_t *node)
Definition: list.c:113
struct list_node * next
Definition: list.h:35
int list_node_compare_t(list_node_t *, list_node_t *)
Definition: list.h:50
list_node_t * list_iterator_remove(list_iterator_t *iter)
Definition: list.c:124
list_node_t ** prevnext
Definition: list.h:46
void list_insert(list_t *list, list_node_t *node)
Definition: list.c:21
list_node_t * tail
Definition: list.h:41
Definition: list.h:34
void list_insert_sorted(list_t *list, list_node_t *node, list_node_compare_t *nodecmp)
Definition: list.c:34
list_node_t * head
Definition: list.h:40
list_node_t * list_extract(list_t *list)
Definition: list.c:77
void list_push(list_t *list, list_node_t *node)
Definition: list.c:65
bool list_remove(list_t *list, list_node_t *node)
Definition: list.c:171