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_insert_after(list_t * list,list_node_t * prev_node,void * data)82 bool list_insert_after(list_t *list, list_node_t *prev_node, void *data) {
83   assert(list != NULL);
84   assert(prev_node != NULL);
85   assert(data != NULL);
86 
87   list_node_t *node = (list_node_t *)list->allocator->alloc(sizeof(list_node_t));
88   if (!node)
89     return false;
90 
91   node->next = prev_node->next;
92   node->data = data;
93   prev_node->next = node;
94   if (list->tail == prev_node)
95     list->tail = node;
96   ++list->length;
97   return true;
98 }
99 
list_prepend(list_t * list,void * data)100 bool list_prepend(list_t *list, void *data) {
101   assert(list != NULL);
102   assert(data != NULL);
103 
104   list_node_t *node = (list_node_t *)list->allocator->alloc(sizeof(list_node_t));
105   if (!node)
106     return false;
107   node->next = list->head;
108   node->data = data;
109   list->head = node;
110   if (list->tail == NULL)
111     list->tail = list->head;
112   ++list->length;
113   return true;
114 }
115 
list_append(list_t * list,void * data)116 bool list_append(list_t *list, void *data) {
117   assert(list != NULL);
118   assert(data != NULL);
119 
120   list_node_t *node = (list_node_t *)list->allocator->alloc(sizeof(list_node_t));
121   if (!node)
122     return false;
123   node->next = NULL;
124   node->data = data;
125   if (list->tail == NULL) {
126     list->head = node;
127     list->tail = node;
128   } else {
129     list->tail->next = node;
130     list->tail = node;
131   }
132   ++list->length;
133   return true;
134 }
135 
list_remove(list_t * list,void * data)136 bool list_remove(list_t *list, void *data) {
137   assert(list != NULL);
138   assert(data != NULL);
139 
140   if (list_is_empty(list))
141     return false;
142 
143   if (list->head->data == data) {
144     list_node_t *next = list_free_node_(list, list->head);
145     if (list->tail == list->head)
146       list->tail = next;
147     list->head = next;
148     return true;
149   }
150 
151   for (list_node_t *prev = list->head, *node = list->head->next; node; prev = node, node = node->next)
152     if (node->data == data) {
153       prev->next = list_free_node_(list, node);
154       if (list->tail == node)
155         list->tail = prev;
156       return true;
157     }
158 
159   return false;
160 }
161 
list_clear(list_t * list)162 void list_clear(list_t *list) {
163   assert(list != NULL);
164   for (list_node_t *node = list->head; node; )
165     node = list_free_node_(list, node);
166   list->head = NULL;
167   list->tail = NULL;
168   list->length = 0;
169 }
170 
list_foreach(const list_t * list,list_iter_cb callback)171 void list_foreach(const list_t *list, list_iter_cb callback) {
172   assert(list != NULL);
173   assert(callback != NULL);
174 
175   for (list_node_t *node = list->head; node; ) {
176     list_node_t *next = node->next;
177     callback(node->data);
178     node = next;
179   }
180 }
181 
list_begin(const list_t * list)182 list_node_t *list_begin(const list_t *list) {
183   assert(list != NULL);
184   return list->head;
185 }
186 
list_end(UNUSED_ATTR const list_t * list)187 list_node_t *list_end(UNUSED_ATTR const list_t *list) {
188   assert(list != NULL);
189   return NULL;
190 }
191 
list_next(const list_node_t * node)192 list_node_t *list_next(const list_node_t *node) {
193   assert(node != NULL);
194   return node->next;
195 }
196 
list_node(const list_node_t * node)197 void *list_node(const list_node_t *node) {
198   assert(node != NULL);
199   return node->data;
200 }
201 
list_free_node_(list_t * list,list_node_t * node)202 static list_node_t *list_free_node_(list_t *list, list_node_t *node) {
203   assert(list != NULL);
204   assert(node != NULL);
205 
206   list_node_t *next = node->next;
207 
208   if (list->free_cb)
209     list->free_cb(node->data);
210   list->allocator->free(node);
211   --list->length;
212 
213   return next;
214 }
215