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_unshift(IWULIST * list,const void * data)398 iwrc iwulist_unshift(IWULIST *list, const void *data) {
399 if (!list->start) {
400 if (list->num >= list->anum) {
401 size_t anum = list->anum + list->num + 1;
402 void *nptr = realloc(list->array, anum * list->usize);
403 if (!nptr) {
404 return iwrc_set_errno(IW_ERROR_ALLOC, errno);
405 }
406 list->anum = anum;
407 list->array = nptr;
408 }
409 list->start = list->anum - list->num;
410 memmove(list->array + list->start * list->usize, list->array, list->num * list->usize);
411 }
412 memcpy(list->array + (list->start - 1) * list->usize, data, list->usize);
413 --list->start;
414 ++list->num;
415 return 0;
416 }
417
iwulist_sort(IWULIST * list,int (* compar)(const void *,const void *,void *),void * op)418 void iwulist_sort(IWULIST *list, int (*compar)(const void*, const void*, void*), void *op) {
419 sort_r(list->array + list->start * list->usize, list->num, list->usize, compar, op);
420 }
421
422 ///////////////////////////////////////////////////////////////////////////
423 // Array list implementation //
424 ///////////////////////////////////////////////////////////////////////////
425
iwlist_init(IWLIST * list,size_t anum)426 iwrc iwlist_init(IWLIST *list, size_t anum) {
427 if (!anum) {
428 anum = 32;
429 }
430 list->anum = anum;
431 list->array = malloc(sizeof(list->array[0]) * anum);
432 if (!list->array) {
433 return iwrc_set_errno(IW_ERROR_ALLOC, errno);
434 }
435 list->start = 0;
436 list->num = 0;
437 return 0;
438 }
439
iwlist_create(size_t anum)440 IWLIST* iwlist_create(size_t anum) {
441 IWLIST *list = malloc(sizeof(*list));
442 if (!list) {
443 return 0;
444 }
445 if (iwlist_init(list, anum)) {
446 free(list);
447 return 0;
448 }
449 return list;
450 }
451
iwlist_destroy_keep(IWLIST * list)452 void iwlist_destroy_keep(IWLIST *list) {
453 if (list) {
454 IWLISTITEM *array = list->array;
455 if (array) {
456 size_t end = list->start + list->num;
457 for (size_t i = list->start; i < end; ++i) {
458 free(array[i].val);
459 }
460 free(array);
461 }
462 list->array = 0;
463 list->anum = 0;
464 list->num = 0;
465 list->start = 0;
466 }
467 }
468
iwlist_destroy(IWLIST ** listp)469 void iwlist_destroy(IWLIST **listp) {
470 if (listp) {
471 if (*listp) {
472 iwlist_destroy_keep(*listp);
473 free(*listp);
474 }
475 *listp = 0;
476 }
477 }
478
iwlist_length(IWLIST * list)479 size_t iwlist_length(IWLIST *list) {
480 return list->num;
481 }
482
iwlist_clone(IWLIST * list)483 IWLIST* iwlist_clone(IWLIST *list) {
484 size_t num = list->num;
485 if (!num) {
486 return iwlist_create(0);
487 }
488 IWLIST *nlist = malloc(sizeof(*nlist));
489 if (!nlist) {
490 return 0;
491 }
492 const IWLISTITEM *array = list->array + list->start;
493 IWLISTITEM *narray = malloc(sizeof(*narray) * num);
494 if (!narray) {
495 free(nlist);
496 return 0;
497 }
498 for (size_t i = 0; i < num; ++i) {
499 size_t size = array[i].size + 1;
500 narray[i].val = malloc(size);
501 if (!narray[i].val) {
502 free(narray);
503 free(nlist);
504 return 0;
505 }
506 memcpy(narray[i].val, array[i].val, size + 1);
507 }
508 nlist->anum = num;
509 nlist->array = narray;
510 nlist->start = 0;
511 nlist->num = num;
512 return nlist;
513 }
514
iwlist_at(IWLIST * list,size_t index,size_t * osize,iwrc * orc)515 void* iwlist_at(IWLIST *list, size_t index, size_t *osize, iwrc *orc) {
516 *orc = 0;
517 if (index >= list->num) {
518 *orc = IW_ERROR_OUT_OF_BOUNDS;
519 return 0;
520 }
521 index += list->start;
522 if (osize) {
523 *osize = list->array[index].size;
524 }
525 return list->array[index].val;
526 }
527
iwlist_at2(IWLIST * list,size_t index,size_t * osize)528 void* iwlist_at2(IWLIST *list, size_t index, size_t *osize) {
529 if (index >= list->num) {
530 return 0;
531 }
532 index += list->start;
533 if (osize) {
534 *osize = list->array[index].size;
535 }
536 return list->array[index].val;
537 }
538
iwlist_push(IWLIST * list,const void * data,size_t data_size)539 iwrc iwlist_push(IWLIST *list, const void *data, size_t data_size) {
540 size_t index = list->start + list->num;
541 if (index >= list->anum) {
542 size_t anum = list->anum + list->num + 1;
543 void *nptr = realloc(list->array, anum * sizeof(list->array[0]));
544 if (!nptr) {
545 return iwrc_set_errno(IW_ERROR_ALLOC, errno);
546 }
547 list->anum = anum;
548 list->array = nptr;
549 }
550 IWLISTITEM *array = list->array;
551 array[index].val = malloc(data_size + 1);
552 if (!array[index].val) {
553 return iwrc_set_errno(IW_ERROR_ALLOC, errno);
554 }
555 memcpy(array[index].val, data, data_size);
556 array[index].val[data_size] = '\0';
557 array[index].size = data_size;
558 list->num++;
559 return 0;
560 }
561
iwlist_pop(IWLIST * list,size_t * osize,iwrc * orc)562 void* iwlist_pop(IWLIST *list, size_t *osize, iwrc *orc) {
563 *orc = 0;
564 if (!list->num) {
565 *orc = IW_ERROR_OUT_OF_BOUNDS;
566 return 0;
567 }
568 size_t index = list->start + list->num - 1;
569 --list->num;
570 if (osize) {
571 *osize = list->array[index].size;
572 }
573 return list->array[index].val;
574 }
575
iwlist_unshift(IWLIST * list,const void * data,size_t data_size)576 iwrc iwlist_unshift(IWLIST *list, const void *data, size_t data_size) {
577 if (!list->start) {
578 if (list->num >= list->anum) {
579 size_t anum = list->anum + list->num + 1;
580 void *nptr = realloc(list->array, anum * sizeof(list->array[0]));
581 if (!nptr) {
582 return iwrc_set_errno(IW_ERROR_ALLOC, errno);
583 }
584 list->anum = anum;
585 list->array = nptr;
586 }
587 list->start = list->anum - list->num;
588 memmove(list->array + list->start, list->array, list->anum * sizeof(list->array[0]));
589 }
590 size_t index = list->start - 1;
591 list->array[index].val = malloc(data_size + 1);
592 memcpy(list->array[index].val, data, data_size);
593 list->array[index].val[data_size] = '\0';
594 list->array[index].size = data_size;
595 --list->start;
596 ++list->num;
597 return 0;
598 }
599
iwlist_shift(IWLIST * list,size_t * osize,iwrc * orc)600 void* iwlist_shift(IWLIST *list, size_t *osize, iwrc *orc) {
601 *orc = 0;
602 if (!list->num) {
603 *orc = IW_ERROR_OUT_OF_BOUNDS;
604 return 0;
605 }
606 size_t index = list->start;
607 ++list->start;
608 --list->num;
609 *osize = list->array[index].size;
610 void *rv = list->array[index].val;
611 if (!(list->start & 0xff) && (list->start > list->num / 2)) {
612 memmove(list->array, list->array + list->start, list->num * sizeof(list->array[0]));
613 list->start = 0;
614 }
615 return rv;
616 }
617
iwlist_insert(IWLIST * list,size_t index,const void * data,size_t data_size)618 iwrc iwlist_insert(IWLIST *list, size_t index, const void *data, size_t data_size) {
619 if (index > list->num) {
620 return IW_ERROR_OUT_OF_BOUNDS;
621 }
622 index += list->start;
623 if (list->start + list->num >= list->anum) {
624 size_t anum = list->anum + list->num + 1;
625 void *nptr = realloc(list->array, anum * sizeof(list->array[0]));
626 if (!nptr) {
627 return iwrc_set_errno(IW_ERROR_ALLOC, errno);
628 }
629 list->anum = anum;
630 list->array = nptr;
631 }
632 memmove(list->array + index + 1, list->array + index,
633 sizeof(list->array[0]) * (list->start + list->num - index));
634 list->array[index].val = malloc(data_size + 1);
635 memcpy(list->array[index].val, data, data_size);
636 list->array[index].val[data_size] = '\0';
637 list->array[index].size = data_size;
638 list->num++;
639 return 0;
640 }
641
iwlist_set(IWLIST * list,size_t index,const void * data,size_t data_size)642 iwrc iwlist_set(IWLIST *list, size_t index, const void *data, size_t data_size) {
643 if (index >= list->num) {
644 return IW_ERROR_OUT_OF_BOUNDS;
645 }
646 index += list->start;
647 if (data_size > list->array[index].size) {
648 void *nptr = realloc(list->array[index].val, data_size + 1);
649 if (!nptr) {
650 return iwrc_set_errno(IW_ERROR_ALLOC, errno);
651 }
652 list->array[index].val = nptr;
653 }
654 memcpy(list->array[index].val, data, data_size);
655 list->array[index].size = data_size;
656 list->array[index].val[data_size] = '\0';
657 return 0;
658 }
659
iwlist_remove(IWLIST * list,size_t index,size_t * osize,iwrc * orc)660 void* iwlist_remove(IWLIST *list, size_t index, size_t *osize, iwrc *orc) {
661 *orc = 0;
662 if (index >= list->num) {
663 *orc = IW_ERROR_OUT_OF_BOUNDS;
664 return 0;
665 }
666 index += list->start;
667 void *rv = list->array[index].val;
668 *osize = list->array[index].size;
669 --list->num;
670 memmove(list->array + index, list->array + index + 1,
671 sizeof(list->array[0]) * (list->start + list->num - index));
672 return rv;
673 }
674
iwlist_sort(IWLIST * list,int (* compar)(const IWLISTITEM *,const IWLISTITEM *,void *),void * op)675 void iwlist_sort(IWLIST *list, int (*compar)(const IWLISTITEM*, const IWLISTITEM*, void*), void *op) {
676 sort_r(list->array + list->start, list->num, sizeof(list->array[0]),
677 (int (*)(const void*, const void*, void*)) compar, op);
678 }
679