Objectively
Ultra-lightweight object oriented framework for GNU C.
Loading...
Searching...
No Matches
List.c
Go to the documentation of this file.
1/*
2 * Objectively: Ultra-lightweight object oriented framework for GNU C.
3 * Copyright (C) 2014 Jay Dolan <jay@jaydolan.com>
4 *
5 * This software is provided 'as-is', without any express or implied
6 * warranty. In no event will the authors be held liable for any damages
7 * arising from the use of this software.
8 *
9 * Permission is granted to anyone to use this software for any purpose,
10 * including commercial applications, and to alter it and redistribute it
11 * freely, subject to the following restrictions:
12 *
13 * 1. The origin of this software must not be misrepresented; you must not
14 * claim that you wrote the original software. If you use this software
15 * in a product, an acknowledgment in the product documentation would be
16 * appreciated but is not required.
17 *
18 * 2. Altered source versions must be plainly marked as such, and must not be
19 * misrepresented as being the original software.
20 *
21 * 3. This notice may not be removed or altered from any source distribution.
22 */
23
24#include "Config.h"
25
26#include <assert.h>
27#include <stdlib.h>
28
29#include "List.h"
30
31#define _Class _List
32
33#pragma mark - Object
34
38static void dealloc(Object *self) {
39
40 List *this = (List *) self;
41 $(this, removeAll);
42
43 super(Object, self, dealloc);
44}
45
46#pragma mark - List
47
52static void append(List *self, const ident element) {
53
54 ListNode *node = calloc(1, sizeof(ListNode));
55 assert(node);
56
57 node->element = element;
58 node->prev = self->tail;
59
60 if (self->tail) {
61 self->tail->next = node;
62 } else {
63 self->head = node;
64 }
65
66 self->tail = node;
67 self->count++;
68}
69
74static bool contains(const List *self, const ident element) {
75 return $(self, nodeForElement, element) != NULL;
76}
77
82static void enumerate(const List *self, ListEnumerator enumerator, ident element) {
83
84 assert(enumerator);
85
86 for (ListNode *node = self->head; node; ) {
87 ListNode *next = node->next;
88 if (enumerator(self, node, element)) {
89 break;
90 }
91 node = next;
92 }
93}
94
99static void filter(List *self, Predicate predicate, ident data) {
100
101 assert(predicate);
102
103 for (ListNode *node = self->head; node; ) {
104 ListNode *next = node->next;
105 if (!predicate(node->element, data)) {
106 $(self, removeNode, node);
107 }
108 node = next;
109 }
110}
111
116static List *filteredList(const List *self, Predicate predicate, ident data) {
117
118 assert(predicate);
119
120 List *list = $(alloc(List), init);
121 for (ListNode *node = self->head; node; node = node->next) {
122 if (predicate(node->element, data)) {
123 $(list, append, node->element);
124 }
125 }
126
127 return list;
128}
129
134static ident find(const List *self, Predicate predicate, ident data) {
135
136 assert(predicate);
137
138 for (ListNode *node = self->head; node; node = node->next) {
139 if (predicate(node->element, data)) {
140 return node->element;
141 }
142 }
143
144 return NULL;
145}
146
147
148
153static List *init(List *self) {
154
155 self = (List *) super(Object, self, init);
156 return self;
157}
158
163static void insertAfter(List *self, ListNode *node, const ident element) {
164
165 if (node == NULL || node == self->tail) {
166 $(self, append, element);
167 return;
168 }
169
170 ListNode *newNode = calloc(1, sizeof(ListNode));
171 assert(newNode);
172
173 newNode->element = element;
174 newNode->prev = node;
175 newNode->next = node->next;
176
177 if (node->next) {
178 node->next->prev = newNode;
179 }
180 node->next = newNode;
181
182 self->count++;
183}
184
189static void map(List *self, Functor functor, ident data) {
190
191 assert(functor);
192
193 for (ListNode *node = self->head; node; node = node->next) {
194 node->element = functor(node->element, data);
195 }
196}
197
202static List *mappedList(const List *self, Functor functor, ident data) {
203
204 assert(functor);
205
206 List *list = $(alloc(List), init);
207 for (ListNode *node = self->head; node; node = node->next) {
208 $(list, append, functor(node->element, data));
209 }
210
211 return list;
212}
213
218static ListNode *nodeForElement(const List *self, const ident element) {
219
220 for (ListNode *node = self->head; node; node = node->next) {
221 if (node->element == element) {
222 return node;
223 }
224 }
225
226 return NULL;
227}
228
233static void prepend(List *self, const ident element) {
234
235 ListNode *node = calloc(1, sizeof(ListNode));
236 assert(node);
237
238 node->element = element;
239 node->next = self->head;
240
241 if (self->head) {
242 self->head->prev = node;
243 } else {
244 self->tail = node;
245 }
246
247 self->head = node;
248 self->count++;
249}
250
255static ident reduce(const List *self, Reducer reducer, ident accumulator, ident data) {
256
257 assert(reducer);
258
259 for (ListNode *node = self->head; node; node = node->next) {
260 accumulator = reducer(node->element, accumulator, data);
261 }
262
263 return accumulator;
264}
265
270static void removeAll(List *self) {
271
272 ListNode *node = self->head;
273 while (node) {
274 ListNode *next = node->next;
275 if (self->destroy) {
276 self->destroy(node->element);
277 }
278 free(node);
279 node = next;
280 }
281
282 self->head = self->tail = NULL;
283 self->count = 0;
284}
285
290static void _remove(List *self, const ident element) {
291
292 ListNode *node = $(self, nodeForElement, element);
293 if (node) {
294 $(self, removeNode, node);
295 }
296}
297
302static void removeNode(List *self, ListNode *node) {
303
304 assert(node);
305
306 if (node->prev) {
307 node->prev->next = node->next;
308 } else {
309 self->head = node->next;
310 }
311
312 if (node->next) {
313 node->next->prev = node->prev;
314 } else {
315 self->tail = node->prev;
316 }
317
318 if (self->destroy) {
319 self->destroy(node->element);
320 }
321
322 free(node);
323 self->count--;
324}
325
330static void _sort(List *self, Comparator comparator) {
331
332 assert(comparator);
333
334 if (self->count < 2) {
335 return;
336 }
337
338 for (ListNode *node = self->head->next; node; ) {
339 ListNode *next = node->next;
340 ident key = node->element;
341
342 ListNode *j = node->prev;
343 while (j && comparator(j->element, key) > OrderSame) {
344 j->next->element = j->element;
345 j = j->prev;
346 }
347
348 (j ? j->next : self->head)->element = key;
349 node = next;
350 }
351}
352
353#pragma mark - Class lifecycle
354
358static void initialize(Class *clazz) {
359
360 ((ObjectInterface *) clazz->interface)->dealloc = dealloc;
361
362 ((ListInterface *) clazz->interface)->append = append;
363 ((ListInterface *) clazz->interface)->contains = contains;
364 ((ListInterface *) clazz->interface)->enumerate = enumerate;
365 ((ListInterface *) clazz->interface)->filter = filter;
366 ((ListInterface *) clazz->interface)->filteredList = filteredList;
367 ((ListInterface *) clazz->interface)->find = find;
368 ((ListInterface *) clazz->interface)->init = init;
369 ((ListInterface *) clazz->interface)->insertAfter = insertAfter;
370 ((ListInterface *) clazz->interface)->map = map;
371 ((ListInterface *) clazz->interface)->mappedList = mappedList;
372 ((ListInterface *) clazz->interface)->nodeForElement = nodeForElement;
373 ((ListInterface *) clazz->interface)->prepend = prepend;
374 ((ListInterface *) clazz->interface)->reduce = reduce;
375 ((ListInterface *) clazz->interface)->removeAll = removeAll;
376 ((ListInterface *) clazz->interface)->remove = _remove;
377 ((ListInterface *) clazz->interface)->removeNode = removeNode;
378 ((ListInterface *) clazz->interface)->sort = _sort;
379}
380
385Class *_List(void) {
386 static Class *clazz;
387 static Once once;
388
389 do_once(&once, {
390 clazz = _initialize(&(const ClassDef) {
391 .name = "List",
392 .superclass = _Object(),
393 .instanceSize = sizeof(List),
394 .interfaceOffset = offsetof(List, interface),
395 .interfaceSize = sizeof(ListInterface),
397 });
398 });
399
400 return clazz;
401}
402
403#undef _Class
Class * _initialize(const ClassDef *def)
Initializes the given Class.
Definition Class.c:86
#define alloc(type)
Allocate and initialize and instance of type.
Definition Class.h:176
#define super(type, obj, method,...)
static Data * data(void)
Definition Data.c:286
static void prepend(List *self, const ident element)
Definition List.c:233
static bool contains(const List *self, const ident element)
Definition List.c:74
static List * init(List *self)
Definition List.c:153
Class * _List(void)
Definition List.c:385
static ident find(const List *self, Predicate predicate, ident data)
Definition List.c:134
static void _remove(List *self, const ident element)
Definition List.c:290
static List * mappedList(const List *self, Functor functor, ident data)
Definition List.c:202
static void removeAll(List *self)
Definition List.c:270
static void insertAfter(List *self, ListNode *node, const ident element)
Definition List.c:163
static void removeNode(List *self, ListNode *node)
Definition List.c:302
static void map(List *self, Functor functor, ident data)
Definition List.c:189
static void filter(List *self, Predicate predicate, ident data)
Definition List.c:99
static void _sort(List *self, Comparator comparator)
Definition List.c:330
static void dealloc(Object *self)
Definition List.c:38
static ListNode * nodeForElement(const List *self, const ident element)
Definition List.c:218
static void append(List *self, const ident element)
Definition List.c:52
static ident reduce(const List *self, Reducer reducer, ident accumulator, ident data)
Definition List.c:255
static void enumerate(const List *self, ListEnumerator enumerator, ident element)
Definition List.c:82
static void initialize(Class *clazz)
Definition List.c:358
static List * filteredList(const List *self, Predicate predicate, ident data)
Definition List.c:116
Doubly-linked lists of raw C pointers.
bool(* ListEnumerator)(const List *list, ListNode *node, ident data)
The ListEnumerator function type.
Definition List.h:44
Class * _Object(void)
Definition Object.c:136
static Unicode next(StringReader *self, StringReaderMode mode)
void * ident
The identity type, similar to Objective-C id.
Definition Types.h:49
bool(* Predicate)(const ident obj, ident data)
The Predicate function type for filtering Objects.
Definition Types.h:111
Order(* Comparator)(const ident obj1, const ident obj2)
The Comparator function type for ordering Objects.
Definition Types.h:82
ident(* Functor)(const ident obj, ident data)
The Functor function type for transforming Objects.
Definition Types.h:103
ident(* Reducer)(const ident obj, ident accumulator, ident data)
The Reducer function type for reducing collections.
Definition Types.h:127
@ OrderSame
Definition Types.h:72
long Once
The Once type.
Definition Once.h:37
#define do_once(once, block)
Executes the given block at most one time.
Definition Once.h:43
ClassDefs are passed to _initialize via an archetype to initialize a Class.
Definition Class.h:41
The runtime representation of a Class.
Definition Class.h:95
ident interface
The interface of the Class.
Definition Class.h:105
Doubly-linked lists of raw C pointers.
Definition List.h:60
ident find(const List *self, Predicate predicate, ident data)
Definition List.c:134
ListNode * head
The head node.
Definition List.h:81
size_t count
The number of elements.
Definition List.h:76
Consumer destroy
Optional destructor called when an element is removed.
Definition List.h:91
ListNode * tail
The tail node.
Definition List.h:86
ListNode * nodeForElement(const List *self, const ident element)
Definition List.c:218
void insertAfter(List *self, ListNode *node, const ident element)
Inserts an element after the given node.
Definition List.c:163
A node in a List.
Definition List.h:49
ListNode * prev
Definition List.h:51
ident element
Definition List.h:50
ListNode * next
Definition List.h:52
Object is the root Class of The Objectively Class hierarchy.
Definition Object.h:46