• 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 
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