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