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