1 #include <assert.h>
2 
3 #include "osi/include/allocator.h"
4 #include "osi/include/list.h"
5 #include "osi/include/osi.h"
6 
7 struct list_node_t {
8   struct list_node_t *next;
9   void *data;
10 };
11 
12 typedef struct list_t {
13   list_node_t *head;
14   list_node_t *tail;
15   size_t length;
16   list_free_cb free_cb;
17   const allocator_t *allocator;
18 } list_t;
19 
20 static list_node_t *list_free_node_(list_t *list, list_node_t *node);
21 
22 // Hidden constructor, only to be used by the hash map for the allocation tracker.
23 // Behaves the same as |list_new|, except you get to specify the allocator.
list_new_internal(list_free_cb callback,const allocator_t * zeroed_allocator)24 list_t *list_new_internal(list_free_cb callback, const allocator_t *zeroed_allocator) {
25   list_t *list = (list_t *)zeroed_allocator->alloc(sizeof(list_t));
26   if (!list)
27     return NULL;
28 
29   list->free_cb = callback;
30   list->allocator = zeroed_allocator;
31   return list;
32 }
33 
list_new(list_free_cb callback)34 list_t *list_new(list_free_cb callback) {
35   return list_new_internal(callback, &allocator_calloc);
36 }
37 
list_free(list_t * list)38 void list_free(list_t *list) {
39   if (!list)
40     return;
41 
42   list_clear(list);
43   list->allocator->free(list);
44 }
45 
list_is_empty(const list_t * list)46 bool list_is_empty(const list_t *list) {
47   assert(list != NULL);
48   return (list->length == 0);
49 }
50 
list_contains(const list_t * list,const void * data)51 bool list_contains(const list_t *list, const void *data) {
52   assert(list != NULL);
53   assert(data != NULL);
54 
55   for (const list_node_t *node = list_begin(list); node != list_end(list); node = list_next(node)) {
56     if (list_node(node) == data)
57       return true;
58   }
59 
60   return false;
61 }
62 
list_length(const list_t * list)63 size_t list_length(const list_t *list) {
64   assert(list != NULL);
65   return list->length;
66 }
67 
list_front(const list_t * list)68 void *list_front(const list_t *list) {
69   assert(list != NULL);
70   assert(!list_is_empty(list));
71 
72   return list->head->data;
73 }
74 
list_back(const list_t * list)75 void *list_back(const list_t *list) {
76   assert(list != NULL);
77   assert(!list_is_empty(list));
78 
79   return list->tail->data;
80 }
81 
list_back_node(const list_t * list)82 list_node_t *list_back_node(const list_t *list) {
83   assert(list != NULL);
84   assert(!list_is_empty(list));
85 
86   return list->tail;
87 }
88 
list_insert_after(list_t * list,list_node_t * prev_node,void * data)89 bool list_insert_after(list_t *list, list_node_t *prev_node, void *data) {
90   assert(list != NULL);
91   assert(prev_node != NULL);
92   assert(data != NULL);
93 
94   list_node_t *node = (list_node_t *)list->allocator->alloc(sizeof(list_node_t));
95   if (!node)
96     return false;
97 
98   node->next = prev_node->next;
99   node->data = data;
100   prev_node->next = node;
101   if (list->tail == prev_node)
102     list->tail = node;
103   ++list->length;
104   return true;
105 }
106 
list_prepend(list_t * list,void * data)107 bool list_prepend(list_t *list, void *data) {
108   assert(list != NULL);
109   assert(data != NULL);
110 
111   list_node_t *node = (list_node_t *)list->allocator->alloc(sizeof(list_node_t));
112   if (!node)
113     return false;
114   node->next = list->head;
115   node->data = data;
116   list->head = node;
117   if (list->tail == NULL)
118     list->tail = list->head;
119   ++list->length;
120   return true;
121 }
122 
list_append(list_t * list,void * data)123 bool list_append(list_t *list, void *data) {
124   assert(list != NULL);
125   assert(data != NULL);
126 
127   list_node_t *node = (list_node_t *)list->allocator->alloc(sizeof(list_node_t));
128   if (!node)
129     return false;
130   node->next = NULL;
131   node->data = data;
132   if (list->tail == NULL) {
133     list->head = node;
134     list->tail = node;
135   } else {
136     list->tail->next = node;
137     list->tail = node;
138   }
139   ++list->length;
140   return true;
141 }
142 
list_remove(list_t * list,void * data)143 bool list_remove(list_t *list, void *data) {
144   assert(list != NULL);
145   assert(data != NULL);
146 
147   if (list_is_empty(list))
148     return false;
149 
150   if (list->head->data == data) {
151     list_node_t *next = list_free_node_(list, list->head);
152     if (list->tail == list->head)
153       list->tail = next;
154     list->head = next;
155     return true;
156   }
157 
158   for (list_node_t *prev = list->head, *node = list->head->next; node; prev = node, node = node->next)
159     if (node->data == data) {
160       prev->next = list_free_node_(list, node);
161       if (list->tail == node)
162         list->tail = prev;
163       return true;
164     }
165 
166   return false;
167 }
168 
list_clear(list_t * list)169 void list_clear(list_t *list) {
170   assert(list != NULL);
171   for (list_node_t *node = list->head; node; )
172     node = list_free_node_(list, node);
173   list->head = NULL;
174   list->tail = NULL;
175   list->length = 0;
176 }
177 
list_foreach(const list_t * list,list_iter_cb callback,void * context)178 list_node_t *list_foreach(const list_t *list, list_iter_cb callback, void *context) {
179   assert(list != NULL);
180   assert(callback != NULL);
181 
182   for (list_node_t *node = list->head; node; ) {
183     list_node_t *next = node->next;
184     if (!callback(node->data, context))
185       return node;
186     node = next;
187   }
188   return NULL;
189 }
190 
list_begin(const list_t * list)191 list_node_t *list_begin(const list_t *list) {
192   assert(list != NULL);
193   return list->head;
194 }
195 
list_end(UNUSED_ATTR const list_t * list)196 list_node_t *list_end(UNUSED_ATTR const list_t *list) {
197   assert(list != NULL);
198   return NULL;
199 }
200 
list_next(const list_node_t * node)201 list_node_t *list_next(const list_node_t *node) {
202   assert(node != NULL);
203   return node->next;
204 }
205 
list_node(const list_node_t * node)206 void *list_node(const list_node_t *node) {
207   assert(node != NULL);
208   return node->data;
209 }
210 
list_free_node_(list_t * list,list_node_t * node)211 static list_node_t *list_free_node_(list_t *list, list_node_t *node) {
212   assert(list != NULL);
213   assert(node != NULL);
214 
215   list_node_t *next = node->next;
216 
217   if (list->free_cb)
218     list->free_cb(node->data);
219   list->allocator->free(node);
220   --list->length;
221 
222   return next;
223 }
224