libcstl
Loading...
Searching...
No Matches
slist.c
Go to the documentation of this file.
1/*!
2 * @file
3 */
4
5#include "cstl/slist.h"
6
7#include <assert.h>
8
9/*! @private */
10static void * __cstl_slist_element(const struct cstl_slist * const s,
11 const struct cstl_slist_node * const n)
12{
13 return (void *)((uintptr_t)n - s->off);
14}
15
16/*! @private */
17static struct cstl_slist_node * __cstl_slist_node(
18 const struct cstl_slist * const s, const void * const e)
19{
20 return (struct cstl_slist_node *)((uintptr_t)e + s->off);
21}
22
23/*! @private */
24static void __cstl_slist_insert_after(struct cstl_slist * const sl,
25 struct cstl_slist_node * const in,
26 struct cstl_slist_node * const nn)
27{
28 assert(sl->t->n == NULL);
29 nn->n = in->n;
30 in->n = nn;
31
32 if (sl->t == in) {
33 sl->t = nn;
34 }
35
36 sl->count++;
37 assert(sl->t->n == NULL);
38}
39
40/*! @private */
41static struct cstl_slist_node * __cstl_slist_erase_after(
42 struct cstl_slist * const sl, struct cstl_slist_node * const e)
43{
44 struct cstl_slist_node * const n = e->n;
45
46 assert(sl->t->n == NULL);
47 e->n = n->n;
48 if (sl->t == n) {
49 sl->t = e;
50 }
51 assert(sl->t->n == NULL);
52
53 sl->count--;
54
55 return n;
56}
57
58void cstl_slist_insert_after(struct cstl_slist * const sl,
59 void * const e, void * const n)
60{
61 __cstl_slist_insert_after(
62 sl, __cstl_slist_node(sl, e), __cstl_slist_node(sl, n));
63}
64
65void * cstl_slist_erase_after(struct cstl_slist * const sl, void * const e)
66{
67 return __cstl_slist_element(
68 sl, __cstl_slist_erase_after(sl, __cstl_slist_node(sl, e)));
69}
70
71void cstl_slist_push_front(struct cstl_slist * const sl, void * const e)
72{
73 __cstl_slist_insert_after(sl, &sl->h, __cstl_slist_node(sl, e));
74}
75
76void cstl_slist_push_back(struct cstl_slist * const sl, void * const e)
77{
78 __cstl_slist_insert_after(sl, sl->t, __cstl_slist_node(sl, e));
79}
80
81void * cstl_slist_pop_front(struct cstl_slist * const sl)
82{
83 return __cstl_slist_element(sl, __cstl_slist_erase_after(sl, &sl->h));
84}
85
86void * cstl_slist_front(const struct cstl_slist * const sl)
87{
88 if (sl->t == &sl->h) {
89 return NULL;
90 }
91 return __cstl_slist_element(sl, sl->h.n);
92}
93
94void * cstl_slist_back(const struct cstl_slist * const sl)
95{
96 if (sl->t == &sl->h) {
97 return NULL;
98 }
99 return __cstl_slist_element(sl, sl->t);
100}
101
102void cstl_slist_reverse(struct cstl_slist * const sl)
103{
104 if (cstl_slist_size(sl) > 1) {
105 struct cstl_slist_node * const c = sl->h.n;
106
107 /*
108 * while there is a node after the current
109 * node, splice that next node out and reinsert
110 * it at the head of the list.
111 */
112 while (c->n != NULL) {
113 struct cstl_slist_node * const n = c->n;
114
115 c->n = n->n;
116 n->n = sl->h.n;
117 sl->h.n = n;
118 }
119
120 sl->t = c;
121 assert(sl->t->n == NULL);
122 }
123}
124
125void cstl_slist_concat(struct cstl_slist * const dst,
126 struct cstl_slist * const src)
127{
128 if (cstl_slist_size(src) > 0 && dst->off == src->off) {
129 assert(dst->t->n == NULL);
130 dst->t->n = src->h.n;
131 dst->t = src->t;
132 assert(dst->t->n == NULL);
133
134 dst->count += src->count;
135
136 cstl_slist_init(src, src->off);
137 }
138}
139
140void cstl_slist_sort(struct cstl_slist * const sl,
141 cstl_compare_func_t * const cmp, void * const cmp_p)
142{
143 if (cstl_slist_size(sl) > 1) {
144 struct cstl_slist _sl[2];
145 struct cstl_slist_node * t;
146
147 cstl_slist_init(&_sl[0], sl->off);
148 cstl_slist_init(&_sl[1], sl->off);
149
150 /* split the list in half */
151
152 for (t = &sl->h;
153 _sl[0].count < sl->count / 2;
154 t = t->n, _sl[0].count++)
155 ;
156
157 _sl[0].h.n = sl->h.n;
158 _sl[0].t = t;
159
160 _sl[1].h.n = t->n;
161 _sl[1].t = sl->t;
162 t->n = NULL;
163
164 _sl[1].count = sl->count - _sl[0].count;
165 cstl_slist_init(sl, sl->off);
166
167 /* sort the halves */
168 cstl_slist_sort(&_sl[0], cmp, cmp_p);
169 cstl_slist_sort(&_sl[1], cmp, cmp_p);
170
171 /*
172 * merge the two halves back together by
173 * moving the lesser element from the front
174 * of the two lists to the end of the output
175 */
176 while (cstl_slist_size(&_sl[0]) > 0
177 && cstl_slist_size(&_sl[1]) > 0) {
178 struct cstl_slist * l;
179
180 if (cmp(__cstl_slist_element(&_sl[0], _sl[0].h.n),
181 __cstl_slist_element(&_sl[1], _sl[1].h.n),
182 cmp_p) <= 0) {
183 l = &_sl[0];
184 } else {
185 l = &_sl[1];
186 }
187
188 __cstl_slist_insert_after(sl, sl->t,
189 __cstl_slist_erase_after(l, &l->h));
190 }
191
192 /* concatenate whatever is left */
193 if (cstl_slist_size(&_sl[0]) > 0) {
194 cstl_slist_concat(sl, &_sl[0]);
195 } else {
196 cstl_slist_concat(sl, &_sl[1]);
197 }
198 }
199}
200
201int cstl_slist_foreach(struct cstl_slist * const sl,
202 cstl_visit_func_t * const visit, void * const p)
203{
204 struct cstl_slist_node * c = sl->h.n;
205 int res = 0;
206
207 while (c != NULL && res == 0) {
208 struct cstl_slist_node * const n = c->n;
209 res = visit(__cstl_slist_element(sl, c), p);
210 c = n;
211 }
212
213 return res;
214}
215
216void cstl_slist_clear(struct cstl_slist * const sl,
217 cstl_xtor_func_t * const clr)
218{
219 struct cstl_slist_node * h;
220
221 h = sl->h.n;
222 while (h != NULL) {
223 struct cstl_slist_node * const n = h->n;
224 clr(__cstl_slist_element(sl, h), NULL);
225 h = n;
226 }
227
228 cstl_slist_init(sl, sl->off);
229}
230
231void cstl_slist_swap(struct cstl_slist * const a, struct cstl_slist * const b)
232{
233 struct cstl_slist t;
234
235 cstl_swap(a, b, &t, sizeof(t));
236
237#ifndef NO_DOC
238#define CSTL_SLIST_FIX_SWAP(SL) \
239 do { \
240 if (SL->count == 0) { \
241 SL->t = &SL->h; \
242 } \
243 } while (0)
244
245 CSTL_SLIST_FIX_SWAP(a);
246 CSTL_SLIST_FIX_SWAP(b);
247
248#undef CSTL_SLIST_FIX_SWAP
249#endif
250}
251
252#ifdef __cfg_test__
253// GCOV_EXCL_START
254#include <check.h>
255#include <stdlib.h>
256
257struct integer
258{
259 int v;
260 struct cstl_slist_node sn;
261};
262
263static int cmp_integer(const void * const a, const void * const b,
264 void * const p)
265{
266 (void)p;
267 return ((struct integer *)a)->v - ((struct integer *)b)->v;
268}
269
270static void __test_cstl_slist_free(void * const p, void * const x)
271{
272 (void)x;
273 free(p);
274}
275
276static void __test__cstl_slist_fill(
277 struct cstl_slist * const sl, const size_t n)
278{
279 unsigned int i;
280
281 for (i = 0; i < n; i++) {
282 struct integer * in = malloc(sizeof(*in));
283
284 in->v = rand() % n;
285 cstl_slist_push_front(sl, in);
286 }
287
288 ck_assert_uint_eq(n, cstl_slist_size(sl));
289}
290
291START_TEST(simple)
292{
293 DECLARE_CSTL_SLIST(l, struct integer, sn);
294 struct integer a, b, c;
295
296 a.v = 0; b.v = 1; c.v = 2;
297
298 ck_assert_int_eq(cstl_slist_size(&l), 0);
299 ck_assert_ptr_null(cstl_slist_front(&l));
300 ck_assert_ptr_null(cstl_slist_back(&l));
301
302 cstl_slist_push_front(&l, &a);
303 ck_assert_int_eq(cstl_slist_size(&l), 1);
304 ck_assert_ptr_eq(cstl_slist_front(&l), &a);
305 ck_assert_ptr_eq(cstl_slist_back(&l), &a);
306
307 cstl_slist_insert_after(&l, &a, &b);
308 ck_assert_int_eq(cstl_slist_size(&l), 2);
309 ck_assert_ptr_eq(cstl_slist_front(&l), &a);
310 ck_assert_ptr_eq(cstl_slist_back(&l), &b);
311
312 cstl_slist_push_back(&l, &c);
313 ck_assert_int_eq(cstl_slist_size(&l), 3);
314 ck_assert_ptr_eq(cstl_slist_front(&l), &a);
315 ck_assert_ptr_eq(cstl_slist_back(&l), &c);
316
318 ck_assert_int_eq(cstl_slist_size(&l), 2);
319
320 ck_assert_ptr_eq(cstl_slist_pop_front(&l), &a);
321 ck_assert_int_eq(cstl_slist_size(&l), 1);
322
323 ck_assert_ptr_eq(cstl_slist_pop_front(&l), &c);
324 ck_assert_int_eq(cstl_slist_size(&l), 0);
325}
326END_TEST
327
328START_TEST(fill)
329{
330 static const size_t n = 100;
331 DECLARE_CSTL_SLIST(sl, struct integer, sn);
332
333 __test__cstl_slist_fill(&sl, n);
334
335 cstl_slist_clear(&sl, __test_cstl_slist_free);
336 ck_assert_uint_eq(cstl_slist_size(&sl), 0);
337}
338END_TEST
339
340START_TEST(concat)
341{
342 static const size_t n = 4;
343 DECLARE_CSTL_SLIST(l1, struct integer, sn);
344 DECLARE_CSTL_SLIST(l2, struct integer, sn);
345
346 __test__cstl_slist_fill(&l1, n);
347 __test__cstl_slist_fill(&l2, n);
348
349 cstl_slist_concat(&l1, &l2);
350 ck_assert_uint_eq(cstl_slist_size(&l1), 2 * n);
351 ck_assert_uint_eq(cstl_slist_size(&l2), 0);
352
353 cstl_slist_clear(&l1, __test_cstl_slist_free);
354 cstl_slist_clear(&l2, __test_cstl_slist_free);
355}
356END_TEST
357
358static int cstl_slist_verify_sorted(void * const e, void * const p)
359{
360 struct integer ** in = p;
361
362 if (*in != NULL) {
363 ck_assert_int_ge(((struct integer *)e)->v, (*in)->v);
364 }
365
366 *in = e;
367
368 return 0;
369}
370
371START_TEST(sort)
372{
373 static const size_t n = 100;
374 DECLARE_CSTL_SLIST(l, struct integer, sn);
375
376 struct integer * in = NULL;
377
378 __test__cstl_slist_fill(&l, n);
379
380 cstl_slist_sort(&l, cmp_integer, NULL);
381 ck_assert_uint_eq(n, cstl_slist_size(&l));
382 cstl_slist_foreach(&l, cstl_slist_verify_sorted, &in);
383
384 cstl_slist_clear(&l, __test_cstl_slist_free);
385 ck_assert_uint_eq(cstl_slist_size(&l), 0);
386}
387END_TEST
388
389static int cstl_slist_verify_sorted_rev(void * const e, void * const p)
390{
391 struct integer ** in = p;
392
393 if (*in != NULL) {
394 ck_assert_int_le(((struct integer *)e)->v, (*in)->v);
395 }
396
397 *in = e;
398
399 return 0;
400}
401
402START_TEST(reverse)
403{
404 static const size_t n = 100;
405 DECLARE_CSTL_SLIST(l, struct integer, sn);
406
407 struct integer * in = NULL;
408
409 __test__cstl_slist_fill(&l, n);
410
411 cstl_slist_sort(&l, cmp_integer, NULL);
413 cstl_slist_foreach(&l, cstl_slist_verify_sorted_rev, &in);
414
415 cstl_slist_clear(&l, __test_cstl_slist_free);
416 ck_assert_uint_eq(cstl_slist_size(&l), 0);
417}
418END_TEST
419
420START_TEST(swap)
421{
422 DECLARE_CSTL_SLIST(l1, struct integer, sn);
423 DECLARE_CSTL_SLIST(l2, struct integer, sn);
424
425 __test__cstl_slist_fill(&l1, 0);
426 cstl_slist_swap(&l1, &l2);
427 ck_assert_int_eq(cstl_slist_size(&l1), 0);
428 ck_assert_int_eq(cstl_slist_size(&l2), 0);
429 cstl_slist_clear(&l1, __test_cstl_slist_free);
430 cstl_slist_clear(&l2, __test_cstl_slist_free);
431
432 __test__cstl_slist_fill(&l1, 1);
433 cstl_slist_swap(&l1, &l2);
434 ck_assert_int_eq(cstl_slist_size(&l1), 0);
435 ck_assert_int_eq(cstl_slist_size(&l2), 1);
436 cstl_slist_clear(&l1, __test_cstl_slist_free);
437 cstl_slist_clear(&l2, __test_cstl_slist_free);
438
439 __test__cstl_slist_fill(&l1, 2);
440 cstl_slist_swap(&l1, &l2);
441 ck_assert_int_eq(cstl_slist_size(&l1), 0);
442 ck_assert_int_eq(cstl_slist_size(&l2), 2);
443 cstl_slist_clear(&l1, __test_cstl_slist_free);
444 cstl_slist_clear(&l2, __test_cstl_slist_free);
445
446 __test__cstl_slist_fill(&l1, 2);
447 __test__cstl_slist_fill(&l2, 3);
448 cstl_slist_swap(&l1, &l2);
449 ck_assert_int_eq(cstl_slist_size(&l1), 3);
450 ck_assert_int_eq(cstl_slist_size(&l2), 2);
451 cstl_slist_clear(&l1, __test_cstl_slist_free);
452 cstl_slist_clear(&l2, __test_cstl_slist_free);
453}
454END_TEST
455
456Suite * slist_suite(void)
457{
458 Suite * const s = suite_create("slist");
459
460 TCase * tc;
461
462 tc = tcase_create("slist");
463 tcase_add_test(tc, simple);
464 tcase_add_test(tc, fill);
465 tcase_add_test(tc, concat);
466 tcase_add_test(tc, sort);
467 tcase_add_test(tc, reverse);
468 tcase_add_test(tc, swap);
469 suite_add_tcase(s, tc);
470
471 return s;
472}
473
474// GCOV_EXCL_STOP
475#endif
static void cstl_swap(void *const x, void *const y, void *const t, const size_t sz)
Swap values at two memory locations via use of a third.
Definition common.h:137
void cstl_xtor_func_t(void *obj, void *priv)
Type for functions called to construct, clear, or destroy an object.
Definition common.h:97
int cstl_visit_func_t(void *obj, void *priv)
Type for visit callbacks from objects supporting foreach.
Definition common.h:65
int cstl_compare_func_t(const void *obj1, const void *obj2, void *priv)
Function type for comparing (in)equality of two objects.
Definition common.h:49
void * cstl_slist_back(const struct cstl_slist *const sl)
Get a pointer to the last object in the list.
Definition slist.c:94
void cstl_slist_insert_after(struct cstl_slist *const sl, void *const e, void *const n)
Insert a new object into the list.
Definition slist.c:58
void * cstl_slist_pop_front(struct cstl_slist *const sl)
Remove the first item in the list and return it.
Definition slist.c:81
void cstl_slist_clear(struct cstl_slist *const sl, cstl_xtor_func_t *const clr)
Remove objects from and reinitialize a list.
Definition slist.c:216
void cstl_slist_reverse(struct cstl_slist *const sl)
Reverse the order of items in the list.
Definition slist.c:102
static size_t cstl_slist_size(const struct cstl_slist *sl)
Get the number of objects in the list.
Definition slist.h:118
void cstl_slist_sort(struct cstl_slist *const sl, cstl_compare_func_t *const cmp, void *const cmp_p)
Sort the items in a list.
Definition slist.c:140
void cstl_slist_push_front(struct cstl_slist *const sl, void *const e)
Insert a new object at the front of the list.
Definition slist.c:71
#define DECLARE_CSTL_SLIST(NAME, TYPE, MEMB)
(Statically) declare and initialize a list
Definition slist.h:92
void cstl_slist_swap(struct cstl_slist *const a, struct cstl_slist *const b)
Swap the list objects at the two given locations.
Definition slist.c:231
int cstl_slist_foreach(struct cstl_slist *const sl, cstl_visit_func_t *const visit, void *const p)
Call a user-supplied function for each object in a list.
Definition slist.c:201
void * cstl_slist_front(const struct cstl_slist *const sl)
Get a pointer to the first object in the list.
Definition slist.c:86
static void cstl_slist_init(struct cstl_slist *const sl, const size_t off)
Initialize a slist object.
Definition slist.h:102
void * cstl_slist_erase_after(struct cstl_slist *const sl, void *const e)
Remove an object from the list.
Definition slist.c:65
void cstl_slist_concat(struct cstl_slist *const dst, struct cstl_slist *const src)
Append one list to the end of another.
Definition slist.c:125
void cstl_slist_push_back(struct cstl_slist *const sl, void *const e)
Insert a new object at the back of the list.
Definition slist.c:76
Node to anchor an element within a list.
Definition slist.h:40
List object.
Definition slist.h:54