1 #include "iwarr.h"
2
3 #include <string.h>
4 #include <assert.h>
5 #include <stdlib.h>
6 #include <errno.h>
7 #include "iwlog.h"
8 #include "sort_r.h"
9
iwarr_sorted_insert(void * restrict els,size_t nels,size_t elsize,void * restrict eptr,int (* cmp)(const void *,const void *),bool skipeq)10 off_t iwarr_sorted_insert(
11 void* restrict els,
12 size_t nels,
13 size_t elsize,
14 void* restrict eptr,
15 int (*cmp)(const void*, const void*),
16 bool skipeq
17 ) {
18 #define EL(idx_) (elsptr + (idx_) * elsize)
19
20 off_t idx = 0,
21 lb = 0,
22 ub = nels - 1;
23 char *elsptr = els;
24 if (nels == 0) {
25 memcpy(els, eptr, elsize);
26 return idx;
27 }
28 while (1) {
29 int cr;
30 idx = (ub + lb) / 2;
31 cr = cmp(EL(idx), eptr);
32 if (!cr) {
33 if (skipeq) {
34 return -1;
35 }
36 break;
37 } else if (cr < 0) {
38 lb = idx + 1;
39 if (lb > ub) {
40 idx = lb;
41 break;
42 }
43 } else {
44 ub = idx - 1;
45 if (lb > ub) {
46 break;
47 }
48 }
49 }
50 memmove(EL(idx + 1), EL(idx), (nels - idx) * elsize);
51 memcpy(EL(idx), eptr, elsize);
52 return idx;
53 #undef EL
54 }
55
iwarr_sorted_remove(void * restrict els,size_t nels,size_t elsize,void * restrict eptr,int (* cmp)(const void *,const void *))56 off_t iwarr_sorted_remove(
57 void* restrict els,
58 size_t nels,
59 size_t elsize,
60 void* restrict eptr,
61 int (*cmp)(const void*, const void*)
62 ) {
63 #define EL(idx_) (elsptr + (idx_) * elsize)
64
65 off_t idx = 0,
66 lb = 0,
67 ub = nels - 1;
68 char *elsptr = els;
69 if (nels == 0) {
70 return -1;
71 }
72 while (1) {
73 int cr;
74 idx = (ub + lb) / 2;
75 cr = cmp(EL(idx), eptr);
76 if (!cr) {
77 if (idx < nels - 1) {
78 memmove(EL(idx), EL(idx + 1), (nels - idx - 1) * elsize);
79 }
80 return idx;
81 } else if (cr < 0) {
82 lb = idx + 1;
83 if (lb > ub) {
84 break;
85 }
86 } else {
87 ub = idx - 1;
88 if (lb > ub) {
89 break;
90 }
91 }
92 }
93 return -1;
94 #undef EL
95 }
96
iwarr_sorted_find(void * restrict els,size_t nels,size_t elsize,void * restrict eptr,int (* cmp)(const void *,const void *))97 off_t iwarr_sorted_find(
98 void* restrict els,
99 size_t nels,
100 size_t elsize,
101 void* restrict eptr,
102 int (*cmp)(const void*, const void*)
103 ) {
104 #define EL(idx_) (elsptr + (idx_) * elsize)
105
106 off_t idx = 0,
107 lb = 0,
108 ub = nels - 1;
109 char *elsptr = els;
110 if (nels == 0) {
111 return -1;
112 }
113 while (1) {
114 int cr;
115 idx = (ub + lb) / 2;
116 cr = cmp(EL(idx), eptr);
117 if (!cr) {
118 return idx;
119 } else if (cr < 0) {
120 lb = idx + 1;
121 if (lb > ub) {
122 break;
123 }
124 } else {
125 ub = idx - 1;
126 if (lb > ub) {
127 break;
128 }
129 }
130 }
131 return -1;
132 #undef EL
133 }
134
iwarr_sorted_find2(void * restrict els,size_t nels,size_t elsize,void * restrict eptr,void * op,bool * found,iwrc (* cmp)(const void *,const void *,void *,int * res))135 off_t iwarr_sorted_find2(
136 void* restrict els,
137 size_t nels,
138 size_t elsize,
139 void* restrict eptr,
140 void *op,
141 bool *found,
142 iwrc (*cmp)(const void*, const void*, void*, int *res)
143 ) {
144 #define EL(idx_) (elsptr + (idx_) * elsize)
145
146 off_t idx = 0,
147 lb = 0,
148 ub = nels - 1;
149 char *elsptr = els;
150 if (nels == 0) {
151 return 0;
152 }
153 while (1) {
154 int cr;
155 idx = (ub + lb) / 2;
156 iwrc rc = cmp(EL(idx), eptr, op, &cr);
157 RCRET(rc);
158 if (!cr) {
159 *found = true;
160 return idx;
161 } else if (cr < 0) {
162 lb = idx + 1;
163 if (lb > ub) {
164 idx = lb;
165 break;
166 }
167 } else {
168 ub = idx - 1;
169 if (lb > ub) {
170 break;
171 }
172 }
173 }
174 *found = false;
175 return idx;
176 #undef EL
177 }
178
179 ///////////////////////////////////////////////////////////////////////////
180 // Fixed sized item list //
181 ///////////////////////////////////////////////////////////////////////////
182
183 #define IWULIST_ALLOC_UNIT 32
184
iwulist_init(IWULIST * list,size_t initial_length,size_t unit_size)185 iwrc iwulist_init(IWULIST *list, size_t initial_length, size_t unit_size) {
186 list->usize = unit_size;
187 list->num = 0;
188 list->start = 0;
189 if (!initial_length) {
190 initial_length = IWULIST_ALLOC_UNIT;
191 }
192 list->anum = initial_length;
193 list->array = malloc(unit_size * initial_length);
194 if (!list->array) {
195 return iwrc_set_errno(IW_ERROR_ALLOC, errno);
196 }
197 return 0;
198 }
199
iwulist_create(size_t initial_length,size_t unit_size)200 IWULIST* iwulist_create(size_t initial_length, size_t unit_size) {
201 IWULIST *list = malloc(sizeof(*list));
202 if (!list) {
203 return 0;
204 }
205 if (iwulist_init(list, initial_length, unit_size)) {
206 free(list);
207 return 0;
208 }
209 return list;
210 }
211
iwulist_clear(IWULIST * list)212 iwrc iwulist_clear(IWULIST *list) {
213 if (list) {
214 free(list->array);
215 return iwulist_init(list, IWULIST_ALLOC_UNIT, list->usize);
216 }
217 return 0;
218 }
219
iwulist_destroy_keep(IWULIST * list)220 void iwulist_destroy_keep(IWULIST *list) {
221 if (list) {
222 free(list->array);
223 memset(list, 0, sizeof(*list));
224 }
225 }
226
iwulist_destroy(IWULIST ** listp)227 void iwulist_destroy(IWULIST **listp) {
228 if (listp) {
229 if (*listp) {
230 iwulist_destroy_keep(*listp);
231 free(*listp);
232 }
233 *listp = 0;
234 }
235 }
236
iwulist_length(IWULIST * list)237 size_t iwulist_length(IWULIST *list) {
238 return list->num;
239 }
240
iwulist_clone(IWULIST * list)241 IWULIST* iwulist_clone(IWULIST *list) {
242 if (!list->num) {
243 return iwulist_create(list->anum, list->usize);
244 }
245 IWULIST *nlist = malloc(sizeof(*nlist));
246 if (!nlist) {
247 return 0;
248 }
249 size_t anum = list->num > IWULIST_ALLOC_UNIT ? list->num : IWULIST_ALLOC_UNIT;
250 nlist->array = malloc(anum * list->usize);
251 if (!nlist->array) {
252 free(nlist);
253 return 0;
254 }
255 memcpy(nlist->array, list->array + list->start, list->num * list->usize);
256 nlist->usize = list->usize;
257 nlist->num = list->num;
258 nlist->anum = anum;
259 nlist->start = 0;
260 return nlist;
261 }
262
iwulist_at(IWULIST * list,size_t index,iwrc * orc)263 void* iwulist_at(IWULIST *list, size_t index, iwrc *orc) {
264 *orc = 0;
265 if (index >= list->num) {
266 *orc = IW_ERROR_OUT_OF_BOUNDS;
267 return 0;
268 }
269 index += list->start;
270 return list->array + index * list->usize;
271 }
272
iwulist_at2(IWULIST * list,size_t index)273 void* iwulist_at2(IWULIST *list, size_t index) {
274 if (index >= list->num) {
275 return 0;
276 }
277 index += list->start;
278 return list->array + index * list->usize;
279 }
280
iwulist_push(IWULIST * list,const void * data)281 iwrc iwulist_push(IWULIST *list, const void *data) {
282 size_t index = list->start + list->num;
283 if (index >= list->anum) {
284 size_t anum = list->anum + list->num + 1;
285 void *nptr = realloc(list->array, anum * list->usize);
286 if (!nptr) {
287 return iwrc_set_errno(IW_ERROR_ALLOC, errno);
288 }
289 list->anum = anum;
290 list->array = nptr;
291 }
292 memcpy(list->array + index * list->usize, data, list->usize);
293 ++list->num;
294 return 0;
295 }
296
iwulist_pop(IWULIST * list)297 iwrc iwulist_pop(IWULIST *list) {
298 if (!list->num) {
299 return IW_ERROR_OUT_OF_BOUNDS;
300 }
301 size_t num = list->num - 1;
302 if ((list->anum > IWULIST_ALLOC_UNIT) && (list->anum >= num * 2)) {
303 if (list->start) {
304 memmove(list->array, list->array + list->start * list->usize, num * list->usize);
305 list->start = 0;
306 }
307 size_t anum = num > IWULIST_ALLOC_UNIT ? num : IWULIST_ALLOC_UNIT;
308 void *nptr = realloc(list->array, anum * list->usize);
309 if (!nptr) {
310 return iwrc_set_errno(IW_ERROR_ALLOC, errno);
311 }
312 list->anum = anum;
313 list->array = nptr;
314 }
315 list->num = num;
316 return 0;
317 }
318
iwulist_shift(IWULIST * list)319 iwrc iwulist_shift(IWULIST *list) {
320 if (!list->num) {
321 return IW_ERROR_OUT_OF_BOUNDS;
322 }
323 size_t num = list->num - 1;
324 size_t start = list->start + 1;
325 if ((list->anum > IWULIST_ALLOC_UNIT) && (list->anum >= num * 2)) {
326 if (start) {
327 memmove(list->array, list->array + start * list->usize, num * list->usize);
328 start = 0;
329 }
330 size_t anum = num > IWULIST_ALLOC_UNIT ? num : IWULIST_ALLOC_UNIT;
331 void *nptr = realloc(list->array, anum * list->usize);
332 if (!nptr) {
333 return iwrc_set_errno(IW_ERROR_ALLOC, errno);
334 }
335 list->anum = anum;
336 list->array = nptr;
337 }
338 list->start = start;
339 list->num = num;
340 return 0;
341 }
342
iwulist_insert(IWULIST * list,size_t index,const void * data)343 iwrc iwulist_insert(IWULIST *list, size_t index, const void *data) {
344 if (index > list->num) {
345 return IW_ERROR_OUT_OF_BOUNDS;
346 }
347 index += list->start;
348 if (list->start + list->num >= list->anum) {
349 size_t anum = list->anum + list->num + 1;
350 void *nptr = realloc(list->array, anum * list->usize);
351 if (!nptr) {
352 return iwrc_set_errno(IW_ERROR_ALLOC, errno);
353 }
354 list->anum = anum;
355 list->array = nptr;
356 }
357 memmove(list->array + (index + 1) * list->usize,
358 list->array + index * list->usize,
359 (list->start + list->num - index) * list->usize);
360 memcpy(list->array + index * list->usize, data, list->usize);
361 ++list->num;
362 return 0;
363 }
364
iwulist_set(IWULIST * list,size_t index,const void * data)365 iwrc iwulist_set(IWULIST *list, size_t index, const void *data) {
366 if (index >= list->num) {
367 return IW_ERROR_OUT_OF_BOUNDS;
368 }
369 index += list->start;
370 memcpy(list->array + index * list->usize, data, list->usize);
371 return 0;
372 }
373
iwulist_remove(IWULIST * list,size_t index)374 iwrc iwulist_remove(IWULIST *list, size_t index) {
375 if (index >= list->num) {
376 return IW_ERROR_OUT_OF_BOUNDS;
377 }
378 index += list->start;
379 --list->num;
380 memmove(list->array + index * list->usize, list->array + (index + 1) * list->usize,
381 (list->start + list->num - index) * list->usize);
382 if ((list->anum > IWULIST_ALLOC_UNIT) && (list->anum >= list->num * 2)) {
383 if (list->start) {
384 memmove(list->array, list->array + list->start * list->usize, list->num * list->usize);
385 list->start = 0;
386 }
387 size_t anum = list->num > IWULIST_ALLOC_UNIT ? list->num : IWULIST_ALLOC_UNIT;
388 void *nptr = realloc(list->array, anum * list->usize);
389 if (!nptr) {
390 return iwrc_set_errno(IW_ERROR_ALLOC, errno);
391 }
392 list->anum = anum;
393 list->array = nptr;
394 }
395 return 0;
396 }
397
iwulist_remove_first_by(IWULIST * list,void * data_ptr)398 bool iwulist_remove_first_by(IWULIST *list, void *data_ptr) {
399 for (size_t i = list->start; i < list->start + list->num; ++i) {
400 void *ptr = list->array + i * list->usize;
401 if (memcmp(data_ptr, ptr, list->usize) == 0) {
402 return iwulist_remove(list, i - list->start) == 0;
403 }
404 }
405 return false;
406 }
407
iwulist_find_first(IWULIST * list,void * data_ptr)408 ssize_t iwulist_find_first(IWULIST *list, void *data_ptr) {
409 for (size_t i = list->start; i < list->start + list->num; ++i) {
410 void *ptr = list->array + i * list->usize;
411 if (memcmp(data_ptr, ptr, list->usize) == 0) {
412 return i - list->start;
413 }
414 }
415 return -1;
416 }
417
iwulist_unshift(IWULIST * list,const void * data)418 iwrc iwulist_unshift(IWULIST *list, const void *data) {
419 if (!list->start) {
420 if (list->num >= list->anum) {
421 size_t anum = list->anum + list->num + 1;
422 void *nptr = realloc(list->array, anum * list->usize);
423 if (!nptr) {
424 return iwrc_set_errno(IW_ERROR_ALLOC, errno);
425 }
426 list->anum = anum;
427 list->array = nptr;
428 }
429 list->start = list->anum - list->num;
430 memmove(list->array + list->start * list->usize, list->array, list->num * list->usize);
431 }
432 memcpy(list->array + (list->start - 1) * list->usize, data, list->usize);
433 --list->start;
434 ++list->num;
435 return 0;
436 }
437
iwulist_sort(IWULIST * list,int (* compar)(const void *,const void *,void *),void * op)438 void iwulist_sort(IWULIST *list, int (*compar)(const void*, const void*, void*), void *op) {
439 sort_r(list->array + list->start * list->usize, list->num, list->usize, compar, op);
440 }
441
442 ///////////////////////////////////////////////////////////////////////////
443 // Array list implementation //
444 ///////////////////////////////////////////////////////////////////////////
445
iwlist_init(IWLIST * list,size_t anum)446 iwrc iwlist_init(IWLIST *list, size_t anum) {
447 if (!anum) {
448 anum = 32;
449 }
450 list->anum = anum;
451 list->array = malloc(sizeof(list->array[0]) * anum);
452 if (!list->array) {
453 return iwrc_set_errno(IW_ERROR_ALLOC, errno);
454 }
455 list->start = 0;
456 list->num = 0;
457 return 0;
458 }
459
iwlist_create(size_t anum)460 IWLIST* iwlist_create(size_t anum) {
461 IWLIST *list = malloc(sizeof(*list));
462 if (!list) {
463 return 0;
464 }
465 if (iwlist_init(list, anum)) {
466 free(list);
467 return 0;
468 }
469 return list;
470 }
471
iwlist_destroy_keep(IWLIST * list)472 void iwlist_destroy_keep(IWLIST *list) {
473 if (list) {
474 IWLISTITEM *array = list->array;
475 if (array) {
476 size_t end = list->start + list->num;
477 for (size_t i = list->start; i < end; ++i) {
478 free(array[i].val);
479 }
480 free(array);
481 }
482 list->array = 0;
483 list->anum = 0;
484 list->num = 0;
485 list->start = 0;
486 }
487 }
488
iwlist_destroy(IWLIST ** listp)489 void iwlist_destroy(IWLIST **listp) {
490 if (listp) {
491 if (*listp) {
492 iwlist_destroy_keep(*listp);
493 free(*listp);
494 }
495 *listp = 0;
496 }
497 }
498
iwlist_length(IWLIST * list)499 size_t iwlist_length(IWLIST *list) {
500 return list->num;
501 }
502
iwlist_clone(IWLIST * list)503 IWLIST* iwlist_clone(IWLIST *list) {
504 size_t num = list->num;
505 if (!num) {
506 return iwlist_create(0);
507 }
508 IWLIST *nlist = malloc(sizeof(*nlist));
509 if (!nlist) {
510 return 0;
511 }
512 const IWLISTITEM *array = list->array + list->start;
513 IWLISTITEM *narray = malloc(sizeof(*narray) * num);
514 if (!narray) {
515 free(nlist);
516 return 0;
517 }
518 for (size_t i = 0; i < num; ++i) {
519 size_t size = array[i].size + 1;
520 narray[i].val = malloc(size);
521 if (!narray[i].val) {
522 free(narray);
523 free(nlist);
524 return 0;
525 }
526 memcpy(narray[i].val, array[i].val, size + 1);
527 }
528 nlist->anum = num;
529 nlist->array = narray;
530 nlist->start = 0;
531 nlist->num = num;
532 return nlist;
533 }
534
iwlist_at(IWLIST * list,size_t index,size_t * osize,iwrc * orc)535 void* iwlist_at(IWLIST *list, size_t index, size_t *osize, iwrc *orc) {
536 *orc = 0;
537 if (index >= list->num) {
538 *orc = IW_ERROR_OUT_OF_BOUNDS;
539 return 0;
540 }
541 index += list->start;
542 if (osize) {
543 *osize = list->array[index].size;
544 }
545 return list->array[index].val;
546 }
547
iwlist_at2(IWLIST * list,size_t index,size_t * osize)548 void* iwlist_at2(IWLIST *list, size_t index, size_t *osize) {
549 if (index >= list->num) {
550 return 0;
551 }
552 index += list->start;
553 if (osize) {
554 *osize = list->array[index].size;
555 }
556 return list->array[index].val;
557 }
558
iwlist_push(IWLIST * list,const void * data,size_t data_size)559 iwrc iwlist_push(IWLIST *list, const void *data, size_t data_size) {
560 size_t index = list->start + list->num;
561 if (index >= list->anum) {
562 size_t anum = list->anum + list->num + 1;
563 void *nptr = realloc(list->array, anum * sizeof(list->array[0]));
564 if (!nptr) {
565 return iwrc_set_errno(IW_ERROR_ALLOC, errno);
566 }
567 list->anum = anum;
568 list->array = nptr;
569 }
570 IWLISTITEM *array = list->array;
571 array[index].val = malloc(data_size + 1);
572 if (!array[index].val) {
573 return iwrc_set_errno(IW_ERROR_ALLOC, errno);
574 }
575 memcpy(array[index].val, data, data_size);
576 array[index].val[data_size] = '\0';
577 array[index].size = data_size;
578 list->num++;
579 return 0;
580 }
581
iwlist_pop(IWLIST * list,size_t * osize,iwrc * orc)582 void* iwlist_pop(IWLIST *list, size_t *osize, iwrc *orc) {
583 *orc = 0;
584 if (!list->num) {
585 *orc = IW_ERROR_OUT_OF_BOUNDS;
586 return 0;
587 }
588 size_t index = list->start + list->num - 1;
589 --list->num;
590 if (osize) {
591 *osize = list->array[index].size;
592 }
593 return list->array[index].val;
594 }
595
iwlist_unshift(IWLIST * list,const void * data,size_t data_size)596 iwrc iwlist_unshift(IWLIST *list, const void *data, size_t data_size) {
597 if (!list->start) {
598 if (list->num >= list->anum) {
599 size_t anum = list->anum + list->num + 1;
600 void *nptr = realloc(list->array, anum * sizeof(list->array[0]));
601 if (!nptr) {
602 return iwrc_set_errno(IW_ERROR_ALLOC, errno);
603 }
604 list->anum = anum;
605 list->array = nptr;
606 }
607 list->start = list->anum - list->num;
608 memmove(list->array + list->start, list->array, list->anum * sizeof(list->array[0]));
609 }
610 size_t index = list->start - 1;
611 list->array[index].val = malloc(data_size + 1);
612 memcpy(list->array[index].val, data, data_size);
613 list->array[index].val[data_size] = '\0';
614 list->array[index].size = data_size;
615 --list->start;
616 ++list->num;
617 return 0;
618 }
619
iwlist_shift(IWLIST * list,size_t * osize,iwrc * orc)620 void* iwlist_shift(IWLIST *list, size_t *osize, iwrc *orc) {
621 *orc = 0;
622 if (!list->num) {
623 *orc = IW_ERROR_OUT_OF_BOUNDS;
624 return 0;
625 }
626 size_t index = list->start;
627 ++list->start;
628 --list->num;
629 *osize = list->array[index].size;
630 void *rv = list->array[index].val;
631 if (!(list->start & 0xff) && (list->start > list->num / 2)) {
632 memmove(list->array, list->array + list->start, list->num * sizeof(list->array[0]));
633 list->start = 0;
634 }
635 return rv;
636 }
637
iwlist_insert(IWLIST * list,size_t index,const void * data,size_t data_size)638 iwrc iwlist_insert(IWLIST *list, size_t index, const void *data, size_t data_size) {
639 if (index > list->num) {
640 return IW_ERROR_OUT_OF_BOUNDS;
641 }
642 index += list->start;
643 if (list->start + list->num >= list->anum) {
644 size_t anum = list->anum + list->num + 1;
645 void *nptr = realloc(list->array, anum * sizeof(list->array[0]));
646 if (!nptr) {
647 return iwrc_set_errno(IW_ERROR_ALLOC, errno);
648 }
649 list->anum = anum;
650 list->array = nptr;
651 }
652 memmove(list->array + index + 1, list->array + index,
653 sizeof(list->array[0]) * (list->start + list->num - index));
654 list->array[index].val = malloc(data_size + 1);
655 memcpy(list->array[index].val, data, data_size);
656 list->array[index].val[data_size] = '\0';
657 list->array[index].size = data_size;
658 list->num++;
659 return 0;
660 }
661
iwlist_set(IWLIST * list,size_t index,const void * data,size_t data_size)662 iwrc iwlist_set(IWLIST *list, size_t index, const void *data, size_t data_size) {
663 if (index >= list->num) {
664 return IW_ERROR_OUT_OF_BOUNDS;
665 }
666 index += list->start;
667 if (data_size > list->array[index].size) {
668 void *nptr = realloc(list->array[index].val, data_size + 1);
669 if (!nptr) {
670 return iwrc_set_errno(IW_ERROR_ALLOC, errno);
671 }
672 list->array[index].val = nptr;
673 }
674 memcpy(list->array[index].val, data, data_size);
675 list->array[index].size = data_size;
676 list->array[index].val[data_size] = '\0';
677 return 0;
678 }
679
iwlist_remove(IWLIST * list,size_t index,size_t * osize,iwrc * orc)680 void* iwlist_remove(IWLIST *list, size_t index, size_t *osize, iwrc *orc) {
681 *orc = 0;
682 if (index >= list->num) {
683 *orc = IW_ERROR_OUT_OF_BOUNDS;
684 return 0;
685 }
686 index += list->start;
687 void *rv = list->array[index].val;
688 *osize = list->array[index].size;
689 --list->num;
690 memmove(list->array + index, list->array + index + 1,
691 sizeof(list->array[0]) * (list->start + list->num - index));
692 return rv;
693 }
694
iwlist_sort(IWLIST * list,int (* compar)(const IWLISTITEM *,const IWLISTITEM *,void *),void * op)695 void iwlist_sort(IWLIST *list, int (*compar)(const IWLISTITEM*, const IWLISTITEM*, void*), void *op) {
696 sort_r(list->array + list->start, list->num, sizeof(list->array[0]),
697 (int (*)(const void*, const void*, void*)) compar, op);
698 }
699