• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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