1 /*
2  # This file is part of the Astrometry.net suite.
3  # Licensed under a 3-clause BSD style license - see LICENSE
4  */
5 
6 #include <stdio.h>
7 #include <string.h>
8 #include <stdlib.h>
9 #include <stdarg.h>
10 #include <assert.h>
11 
12 #include "bl.h"
13 
14 #include "keywords.h"
15 
16 #include "bl.ph"
17 #include "log.h"
18 
19 static bl_node* bl_new_node(bl* list);
20 static void bl_remove_from_node(bl* list, bl_node* node,
21                                 bl_node* prev, int index_in_node);
22 
23 // Defined in bl.ph (private header):
24 // free_node
25 // NODE_DATA
26 // NODE_CHARDATA
27 // NODE_INTDATA
28 // NODE_DOUBLEDATA
29 
30 // Defined in bl.inc (inlined functions):
31 // bl_size
32 // bl_access
33 // il_size
34 // il_get
35 
36 // NOTE!, if you make changes here, also see bl-sort.c !
37 
38 //#define DEFINE_SORT 1
39 #define DEFINE_SORT 0
40 #define nl il
41 #define number int
42 #define NL_PRINT(x) printf("%i", x)
43 #include "bl-nl.c"
44 #undef nl
45 #undef number
46 #undef NL_PRINT
47 
48 #define nl ll
49 #define number int64_t
50 #define NL_PRINT(x) printf("%lli", (long long int)x)
51 #include "bl-nl.c"
52 #undef nl
53 #undef number
54 #undef NL_PRINT
55 
56 #define nl fl
57 #define number float
58 #define NL_PRINT(x) printf("%f", (float)x)
59 #include "bl-nl.c"
60 #undef nl
61 #undef number
62 #undef NL_PRINT
63 
64 #define nl dl
65 #define number double
66 #define NL_PRINT(x) printf("%g", x)
67 #include "bl-nl.c"
68 #undef nl
69 #undef number
70 #undef NL_PRINT
71 
72 #undef DEFINE_SORT
73 #define DEFINE_SORT 0
74 #define nl pl
75 #define number void*
76 #define NL_PRINT(x) printf("%p", x)
77 #include "bl-nl.c"
78 #undef nl
79 #undef number
80 #undef NL_PRINT
81 #undef DEFINE_SORT
82 
83 
84 
bl_datasize(const bl * list)85 Pure int bl_datasize(const bl* list) {
86     if (!list)
87         return 0;
88     return list->datasize;
89 }
90 
91 
bl_split(bl * src,bl * dest,size_t split)92 void bl_split(bl* src, bl* dest, size_t split) {
93     bl_node* node;
94     size_t nskipped;
95     size_t ind;
96     size_t ntaken = src->N - split;
97     node = find_node(src, split, &nskipped);
98     ind = split - nskipped;
99     if (ind == 0) {
100         // this whole node belongs to "dest".
101         if (split) {
102             // we need to get the previous node...
103             bl_node* last = find_node(src, split-1, NULL);
104             last->next = NULL;
105             src->tail = last;
106         } else {
107             // we've removed everything from "src".
108             src->head = NULL;
109             src->tail = NULL;
110         }
111     } else {
112         // create a new node to hold the second half of the items in "node".
113         bl_node* newnode = bl_new_node(dest);
114         newnode->N = (node->N - ind);
115         newnode->next = node->next;
116         memcpy(NODE_CHARDATA(newnode),
117                NODE_CHARDATA(node) + (ind * src->datasize),
118                newnode->N * src->datasize);
119         node->N -= (node->N - ind);
120         node->next = NULL;
121         src->tail = node;
122         // to make the code outside this block work...
123         node = newnode;
124     }
125 
126     // append it to "dest".
127     if (dest->tail) {
128         dest->tail->next = node;
129         dest->N += ntaken;
130     } else {
131         dest->head = node;
132         dest->tail = node;
133         dest->N += ntaken;
134     }
135 
136     // adjust "src".
137     src->N -= ntaken;
138     src->last_access = NULL;
139 }
140 
bl_init(bl * list,int blocksize,int datasize)141 void bl_init(bl* list, int blocksize, int datasize) {
142     list->head = NULL;
143     list->tail = NULL;
144     list->N = 0;
145     list->blocksize = blocksize;
146     list->datasize  = datasize;
147     list->last_access = NULL;
148     list->last_access_n = 0;
149 }
150 
bl_new(int blocksize,int datasize)151 bl* bl_new(int blocksize, int datasize) {
152     bl* rtn;
153     rtn = malloc(sizeof(bl));
154     if (!rtn) {
155         printf("Couldn't allocate memory for a bl.\n");
156         return NULL;
157     }
158     bl_init(rtn, blocksize, datasize);
159     return rtn;
160 }
161 
bl_free(bl * list)162 void bl_free(bl* list) {
163     if (!list) return;
164     bl_remove_all(list);
165     free(list);
166 }
167 
bl_remove_all(bl * list)168 void bl_remove_all(bl* list) {
169     bl_node *n, *lastnode;
170     lastnode = NULL;
171     for (n=list->head; n; n=n->next) {
172         if (lastnode)
173             bl_free_node(lastnode);
174         lastnode = n;
175     }
176     if (lastnode)
177         bl_free_node(lastnode);
178     list->head = NULL;
179     list->tail = NULL;
180     list->N = 0;
181     list->last_access = NULL;
182     list->last_access_n = 0;
183 }
184 
bl_remove_all_but_first(bl * list)185 void bl_remove_all_but_first(bl* list) {
186     bl_node *n, *lastnode;
187     lastnode = NULL;
188 
189     if (list->head) {
190         for (n=list->head->next; n; n=n->next) {
191             if (lastnode)
192                 bl_free_node(lastnode);
193             lastnode = n;
194         }
195         if (lastnode)
196             bl_free_node(lastnode);
197         list->head->next = NULL;
198         list->head->N = 0;
199         list->tail = list->head;
200     } else {
201         list->head = NULL;
202         list->tail = NULL;
203     }
204     list->N = 0;
205     list->last_access = NULL;
206     list->last_access_n = 0;
207 }
208 
bl_remove_from_node(bl * list,bl_node * node,bl_node * prev,int index_in_node)209 static void bl_remove_from_node(bl* list, bl_node* node,
210                                 bl_node* prev, int index_in_node) {
211     // if we're removing the last element at this node, then
212     // remove this node from the linked list.
213     if (node->N == 1) {
214         // if we're removing the first node...
215         if (prev == NULL) {
216             list->head = node->next;
217             // if it's the first and only node...
218             if (list->head == NULL) {
219                 list->tail = NULL;
220             }
221         } else {
222             // if we're removing the last element from
223             // the tail node...
224             if (node == list->tail) {
225                 list->tail = prev;
226             }
227             prev->next = node->next;
228         }
229         bl_free_node(node);
230     } else {
231         int ncopy;
232         // just remove this element...
233         ncopy = node->N - index_in_node - 1;
234         if (ncopy > 0) {
235             memmove(NODE_CHARDATA(node) + index_in_node * list->datasize,
236                     NODE_CHARDATA(node) + (index_in_node+1) * list->datasize,
237                     ncopy * list->datasize);
238         }
239         node->N--;
240     }
241     list->N--;
242 }
243 
bl_remove_index(bl * list,size_t index)244 void bl_remove_index(bl* list, size_t index) {
245     // find the node (and previous node) at which element 'index'
246     // can be found.
247     bl_node *node, *prev;
248     size_t nskipped = 0;
249     for (node=list->head, prev=NULL;
250          node;
251          prev=node, node=node->next) {
252 
253         if (index < (nskipped + node->N))
254             break;
255         nskipped += node->N;
256     }
257     assert(node);
258     bl_remove_from_node(list, node, prev, index-nskipped);
259     list->last_access = NULL;
260     list->last_access_n = 0;
261 }
262 
bl_remove_index_range(bl * list,size_t start,size_t length)263 void bl_remove_index_range(bl* list, size_t start, size_t length) {
264     // find the node (and previous node) at which element 'start'
265     // can be found.
266     bl_node *node, *prev;
267     size_t nskipped = 0;
268     list->last_access = NULL;
269     list->last_access_n = 0;
270     for (node=list->head, prev=NULL;
271          node;
272          prev=node, node=node->next) {
273 
274         if (start < (nskipped + node->N))
275             break;
276 
277         nskipped += node->N;
278     }
279 
280     // begin by removing any indices that are at the end of a block.
281     if (start > nskipped) {
282         // we're not removing everything at this node.
283         size_t istart;
284         size_t n;
285         istart = start - nskipped;
286         if ((istart + length) < node->N) {
287             // we're removing a chunk of elements from the middle of this
288             // block.  move elements from the end into the removed chunk.
289             memmove(NODE_CHARDATA(node) + istart * list->datasize,
290                     NODE_CHARDATA(node) + (istart + length) * list->datasize,
291                     (node->N - (istart + length)) * list->datasize);
292             // we're done!
293             node->N -= length;
294             list->N -= length;
295             return;
296         } else {
297             // we're removing everything from 'istart' to the end of this
298             // block.  just change the "N" values.
299             n = (node->N - istart);
300             node->N -= n;
301             list->N -= n;
302             length -= n;
303             start += n;
304             nskipped = start;
305             prev = node;
306             node = node->next;
307         }
308     }
309 
310     // remove complete blocks.
311     for (;;) {
312         size_t n;
313         bl_node* todelete;
314         if (length == 0 || length < node->N)
315             break;
316         // we're skipping this whole block.
317         n = node->N;
318         length -= n;
319         start += n;
320         list->N -= n;
321         nskipped += n;
322         todelete = node;
323         node = node->next;
324         bl_free_node(todelete);
325     }
326     if (prev)
327         prev->next = node;
328     else
329         list->head = node;
330 
331     if (!node)
332         list->tail = prev;
333 
334     // remove indices from the beginning of the last block.
335     // note that we may have removed everything from the tail of the list,
336     // no "node" may be null.
337     if (node && length>0) {
338         //printf("removing %i from end.\n", length);
339         memmove(NODE_CHARDATA(node),
340                 NODE_CHARDATA(node) + length * list->datasize,
341                 (node->N - length) * list->datasize);
342         node->N -= length;
343         list->N -= length;
344     }
345 }
346 
clear_list(bl * list)347 static void clear_list(bl* list) {
348     list->head = NULL;
349     list->tail = NULL;
350     list->N = 0;
351     list->last_access = NULL;
352     list->last_access_n = 0;
353 }
354 
bl_append_list(bl * list1,bl * list2)355 void bl_append_list(bl* list1, bl* list2) {
356     list1->last_access = NULL;
357     list1->last_access_n = 0;
358     if (list1->datasize != list2->datasize) {
359         printf("Error: cannot append bls with different data sizes!\n");
360         assert(0);
361         exit(0);
362     }
363     if (list1->blocksize != list2->blocksize) {
364         printf("Error: cannot append bls with different block sizes!\n");
365         assert(0);
366         exit(0);
367     }
368 
369     // if list1 is empty, then just copy over list2's head and tail.
370     if (list1->head == NULL) {
371         list1->head = list2->head;
372         list1->tail = list2->tail;
373         list1->N = list2->N;
374         // remove everything from list2 (to avoid sharing nodes)
375         clear_list(list2);
376         return;
377     }
378 
379     // if list2 is empty, then do nothing.
380     if (list2->head == NULL)
381         return;
382 
383     // otherwise, append list2's head to list1's tail.
384     list1->tail->next = list2->head;
385     list1->tail = list2->tail;
386     list1->N += list2->N;
387     // remove everything from list2 (to avoid sharing nodes)
388     clear_list(list2);
389 }
390 
bl_new_node(bl * list)391 static bl_node* bl_new_node(bl* list) {
392     bl_node* rtn;
393     // merge the mallocs for the node and its data into one malloc.
394     rtn = malloc(sizeof(bl_node) + list->datasize * list->blocksize);
395     if (!rtn) {
396         printf("Couldn't allocate memory for a bl node!\n");
397         return NULL;
398     }
399     //rtn->data = (char*)rtn + sizeof(bl_node);
400     rtn->N = 0;
401     rtn->next = NULL;
402     return rtn;
403 }
404 
bl_append_node(bl * list,bl_node * node)405 static void bl_append_node(bl* list, bl_node* node) {
406     node->next = NULL;
407     if (!list->head) {
408         // first node to be added.
409         list->head = node;
410         list->tail = node;
411     } else {
412         list->tail->next = node;
413         list->tail = node;
414     }
415     list->N += node->N;
416 }
417 
418 /*
419  * Append an item to this bl node.  If this node is full, then create a new
420  * node and insert it into the list.
421  *
422  * Returns the location where the new item was copied.
423  */
bl_node_append(bl * list,bl_node * node,const void * data)424 void* bl_node_append(bl* list, bl_node* node, const void* data) {
425     void* dest;
426     if (node->N == list->blocksize) {
427         // create a new node and insert it after the current node.
428         bl_node* newnode;
429         newnode = bl_new_node(list);
430         newnode->next = node->next;
431         node->next = newnode;
432         if (list->tail == node)
433             list->tail = newnode;
434         node = newnode;
435     }
436     // space remains at this node.  add item.
437     dest = NODE_CHARDATA(node) + node->N * list->datasize;
438     if (data)
439         memcpy(dest, data, list->datasize);
440     node->N++;
441     list->N++;
442     return dest;
443 }
444 
bl_append(bl * list,const void * data)445 void* bl_append(bl* list, const void* data) {
446     if (!list->tail)
447         // empty list; create a new node.
448         bl_append_node(list, bl_new_node(list));
449     // append the item to the tail.  if the tail node is full, a new tail node may be created.
450     return bl_node_append(list, list->tail, data);
451 }
452 
bl_push(bl * list,const void * data)453 void* bl_push(bl* list, const void* data) {
454     return bl_append(list, data);
455 }
456 
bl_pop(bl * list,void * into)457 void bl_pop(bl* list, void* into) {
458     assert(list->N > 0);
459     bl_get(list, list->N-1, into);
460     bl_remove_index(list, list->N-1);
461 }
462 
bl_print_structure(bl * list)463 void bl_print_structure(bl* list) {
464     bl_node* n;
465     printf("bl: head %p, tail %p, N %zu\n", list->head, list->tail, list->N);
466     for (n=list->head; n; n=n->next) {
467         printf("[N=%i] ", n->N);
468     }
469     printf("\n");
470 }
471 
bl_get(bl * list,size_t n,void * dest)472 void bl_get(bl* list, size_t n, void* dest) {
473     assert(list->N > 0);
474     char* src = bl_access(list, n);
475     memcpy(dest, src, list->datasize);
476 }
477 
bl_find_ind_and_element(bl * list,const void * data,int (* compare)(const void * v1,const void * v2),void ** presult,ptrdiff_t * pindex)478 static void bl_find_ind_and_element(bl* list, const void* data,
479                                     int (*compare)(const void* v1, const void* v2),
480                                     void** presult, ptrdiff_t* pindex) {
481     ptrdiff_t lower, upper;
482     int cmp = -2;
483     void* result;
484     lower = -1;
485     upper = list->N;
486     while (lower < (upper-1)) {
487         ptrdiff_t mid;
488         mid = (upper + lower) / 2;
489         cmp = compare(data, bl_access(list, mid));
490         if (cmp >= 0) {
491             lower = mid;
492         } else {
493             upper = mid;
494         }
495     }
496     if (lower == -1 || compare(data, (result = bl_access(list, lower)))) {
497         *presult = NULL;
498         if (pindex)
499             *pindex = -1;
500         return;
501     }
502     *presult = result;
503     if (pindex)
504         *pindex = lower;
505 }
506 
507 /**
508  * Finds a node for which the given compare() function
509  * returns zero when passed the given 'data' pointer
510  * and elements from the list.
511  */
bl_find(bl * list,const void * data,int (* compare)(const void * v1,const void * v2))512 void* bl_find(bl* list, const void* data,
513               int (*compare)(const void* v1, const void* v2)) {
514     void* rtn;
515     bl_find_ind_and_element(list, data, compare, &rtn, NULL);
516     return rtn;
517 }
518 
bl_find_index(bl * list,const void * data,int (* compare)(const void * v1,const void * v2))519 ptrdiff_t bl_find_index(bl* list, const void* data,
520                         int (*compare)(const void* v1, const void* v2)) {
521     void* val;
522     ptrdiff_t ind;
523     bl_find_ind_and_element(list, data, compare, &val, &ind);
524     return ind;
525 }
526 
bl_insert_sorted(bl * list,const void * data,int (* compare)(const void * v1,const void * v2))527 size_t bl_insert_sorted(bl* list, const void* data,
528                         int (*compare)(const void* v1, const void* v2)) {
529     ptrdiff_t lower, upper;
530     lower = -1;
531     upper = list->N;
532     while (lower < (upper-1)) {
533         ptrdiff_t mid;
534         int cmp;
535         mid = (upper + lower) / 2;
536         cmp = compare(data, bl_access(list, mid));
537         if (cmp >= 0) {
538             lower = mid;
539         } else {
540             upper = mid;
541         }
542     }
543     bl_insert(list, lower+1, data);
544     return lower+1;
545 }
546 
bl_insert_unique_sorted(bl * list,const void * data,int (* compare)(const void * v1,const void * v2))547 ptrdiff_t bl_insert_unique_sorted(bl* list, const void* data,
548                                   int (*compare)(const void* v1, const void* v2)) {
549     // This is just straightforward binary search - really should
550     // use the block structure...
551     ptrdiff_t lower, upper;
552     lower = -1;
553     upper = list->N;
554     while (lower < (upper-1)) {
555         ptrdiff_t mid;
556         int cmp;
557         mid = (upper + lower) / 2;
558         cmp = compare(data, bl_access(list, mid));
559         if (cmp >= 0) {
560             lower = mid;
561         } else {
562             upper = mid;
563         }
564     }
565 
566     if (lower >= 0) {
567         if (compare(data, bl_access(list, lower)) == 0) {
568             return BL_NOT_FOUND;
569         }
570     }
571     bl_insert(list, lower+1, data);
572     return lower+1;
573 }
574 
bl_set(bl * list,size_t index,const void * data)575 void bl_set(bl* list, size_t index, const void* data) {
576     bl_node* node;
577     size_t nskipped;
578     void* dataloc;
579 
580     node = find_node(list, index, &nskipped);
581     dataloc = NODE_CHARDATA(node) + (index - nskipped) * list->datasize;
582     memcpy(dataloc, data, list->datasize);
583     // update the last_access member...
584     list->last_access = node;
585     list->last_access_n = nskipped;
586 }
587 
588 /**
589  * Insert the element "data" into the list, such that its index is "index".
590  * All elements that previously had indices "index" and above are moved
591  * one position to the right.
592  */
bl_insert(bl * list,size_t index,const void * data)593 void bl_insert(bl* list, size_t index, const void* data) {
594     bl_node* node;
595     size_t nskipped;
596 
597     if (list->N == index) {
598         bl_append(list, data);
599         return;
600     }
601 
602     node = find_node(list, index, &nskipped);
603 
604     list->last_access = node;
605     list->last_access_n = nskipped;
606 
607     // if the node is full:
608     //   if we're inserting at the end of this node, then create a new node.
609     //   else, shift all but the last element, add in this element, and
610     //     add the last element to a new node.
611     if (node->N == list->blocksize) {
612         int localindex, nshift;
613         bl_node* next = node->next;
614         bl_node* destnode;
615         localindex = index - nskipped;
616 
617         // if the next node exists and is not full, then insert the overflowing
618         // element at the front.  otherwise, create a new node.
619         if (next && (next->N < list->blocksize)) {
620             // shift the existing elements up by one position...
621             memmove(NODE_CHARDATA(next) + list->datasize,
622                     NODE_CHARDATA(next),
623                     next->N * list->datasize);
624             destnode = next;
625         } else {
626             // create and insert a new node.
627             bl_node* newnode = bl_new_node(list);
628             newnode->next = next;
629             node->next = newnode;
630             if (!newnode->next)
631                 list->tail = newnode;
632             destnode = newnode;
633         }
634 
635         if (localindex == node->N) {
636             // the new element becomes the first element in the destination node.
637             memcpy(NODE_CHARDATA(destnode), data, list->datasize);
638         } else {
639             // the last element in this node is added to the destination node.
640             memcpy(NODE_CHARDATA(destnode), NODE_CHARDATA(node) + (node->N-1)*list->datasize, list->datasize);
641             // shift the end portion of this node up by one...
642             nshift = node->N - localindex - 1;
643             memmove(NODE_CHARDATA(node) + (localindex+1) * list->datasize,
644                     NODE_CHARDATA(node) + localindex * list->datasize,
645                     nshift * list->datasize);
646             // insert the new element...
647             memcpy(NODE_CHARDATA(node) + localindex * list->datasize, data, list->datasize);
648         }
649 
650         destnode->N++;
651         list->N++;
652 
653     } else {
654         // shift...
655         int localindex, nshift;
656         localindex = index - nskipped;
657         nshift = node->N - localindex;
658         memmove(NODE_CHARDATA(node) + (localindex+1) * list->datasize,
659                 NODE_CHARDATA(node) + localindex * list->datasize,
660                 nshift * list->datasize);
661         // insert...
662         memcpy(NODE_CHARDATA(node) + localindex * list->datasize,
663                data, list->datasize);
664         node->N++;
665         list->N++;
666     }
667 }
668 
bl_access_const(const bl * list,size_t n)669 void* bl_access_const(const bl* list, size_t n) {
670     bl_node* node;
671     size_t nskipped;
672     node = find_node(list, n, &nskipped);
673     // grab the element.
674     return NODE_CHARDATA(node) + (n - nskipped) * list->datasize;
675 }
676 
bl_copy(bl * list,size_t start,size_t length,void * vdest)677 void bl_copy(bl* list, size_t start, size_t length, void* vdest) {
678     bl_node* node;
679     size_t nskipped;
680     char* dest;
681     if (length <= 0)
682         return;
683     node = find_node(list, start, &nskipped);
684 
685     // we've found the node containing "start".  keep copying elements and
686     // moving down the list until we've copied all "length" elements.
687     dest = vdest;
688     while (length > 0) {
689         size_t take, avail;
690         char* src;
691         // number of elements we want to take.
692         take = length;
693         // number of elements available at this node.
694         avail = node->N - (start - nskipped);
695         if (take > avail)
696             take = avail;
697         src = NODE_CHARDATA(node) + (start - nskipped) * list->datasize;
698         memcpy(dest, src, take * list->datasize);
699 
700         dest += take * list->datasize;
701         start += take;
702         length -= take;
703         nskipped += node->N;
704         node = node->next;
705     }
706     // update the last_access member...
707     list->last_access = node;
708     list->last_access_n = nskipped;
709 }
710 
bl_check_consistency(bl * list)711 int bl_check_consistency(bl* list) {
712     bl_node* node;
713     size_t N;
714     int tailok = 1;
715     int nempty = 0;
716     int nnull = 0;
717 
718     // if one of head or tail is NULL, they had both better be NULL!
719     if (!list->head)
720         nnull++;
721     if (!list->tail)
722         nnull++;
723     if (nnull == 1) {
724         fprintf(stderr, "bl_check_consistency: head is %p, and tail is %p.\n",
725                 list->head, list->tail);
726         return 1;
727     }
728 
729     N = 0;
730     for (node=list->head; node; node=node->next) {
731         N += node->N;
732         if (!node->N) {
733             // this block is empty.
734             nempty++;
735         }
736         // are we at the last node?
737         if (!node->next) {
738             tailok = (list->tail == node) ? 1 : 0;
739         }
740     }
741     if (!tailok) {
742         fprintf(stderr, "bl_check_consistency: tail pointer is wrong.\n");
743         return 1;
744     }
745     if (nempty) {
746         fprintf(stderr, "bl_check_consistency: %i empty blocks.\n", nempty);
747         return 1;
748     }
749     if (N != list->N) {
750         fprintf(stderr, "bl_check_consistency: list->N is %zu, but sum of blocks is %zu.\n",
751                 list->N, N);
752         return 1;
753     }
754     return 0;
755 }
756 
bl_check_sorted(bl * list,int (* compare)(const void * v1,const void * v2),int isunique)757 int bl_check_sorted(bl* list,
758                     int (*compare)(const void* v1, const void* v2),
759                     int isunique) {
760     size_t i, N;
761     size_t nbad = 0;
762     void* v2 = NULL;
763     N = bl_size(list);
764     if (N)
765         v2 = bl_access(list, 0);
766     for (i=1; i<N; i++) {
767         void* v1;
768         int cmp;
769         v1 = v2;
770         v2 = bl_access(list, i);
771         cmp = compare(v1, v2);
772         if (isunique) {
773             if (cmp >= 0) {
774                 nbad++;
775             }
776         } else {
777             if (cmp > 0) {
778                 nbad++;
779             }
780         }
781     }
782     if (nbad) {
783         fprintf(stderr, "bl_check_sorted: %zu are out of order.\n", nbad);
784         return 1;
785     }
786     return 0;
787 }
788 
memswap(void * v1,void * v2,int len)789 static void memswap(void* v1, void* v2, int len) {
790     unsigned char tmp;
791     unsigned char* c1 = v1;
792     unsigned char* c2 = v2;
793     int i;
794     for (i=0; i<len; i++) {
795         tmp = *c1;
796         *c1 = *c2;
797         *c2 = tmp;
798         c1++;
799         c2++;
800     }
801 }
802 
bl_reverse(bl * list)803 void bl_reverse(bl* list) {
804     // reverse each block, and reverse the order of the blocks.
805     pl* blocks;
806     bl_node* node;
807     bl_node* lastnode;
808     int i;
809 
810     // reverse each block
811     blocks = pl_new(256);
812     for (node=list->head; node; node=node->next) {
813         for (i=0; i<(node->N/2); i++) {
814             memswap(NODE_CHARDATA(node) + i * list->datasize,
815                     NODE_CHARDATA(node) + (node->N - 1 - i) * list->datasize,
816                     list->datasize);
817         }
818         pl_append(blocks, node);
819     }
820 
821     // reverse the blocks
822     lastnode = NULL;
823     for (i=pl_size(blocks)-1; i>=0; i--) {
824         node = pl_get(blocks, i);
825         if (lastnode)
826             lastnode->next = node;
827         lastnode = node;
828     }
829     if (lastnode)
830         lastnode->next = NULL;
831     pl_free(blocks);
832 
833     // swap head and tail
834     node = list->head;
835     list->head = list->tail;
836     list->tail = node;
837 
838     list->last_access = NULL;
839     list->last_access_n = 0;
840 }
841 
bl_extend(bl * list)842 void* bl_extend(bl* list) {
843     return bl_append(list, NULL);
844 }
845 
846 
847 
848 // special-case pointer list accessors...
bl_compare_pointers_ascending(const void * v1,const void * v2)849 int bl_compare_pointers_ascending(const void* v1, const void* v2) {
850     void* p1 = *(void**)v1;
851     void* p2 = *(void**)v2;
852     if (p1 > p2) return 1;
853     else if (p1 < p2) return -1;
854     else return 0;
855 }
856 
pl_free_elements(pl * list)857 void  pl_free_elements(pl* list) {
858     size_t i;
859     for (i=0; i<pl_size(list); i++) {
860         free(pl_get(list, i));
861     }
862 }
863 
pl_insert_sorted(pl * list,const void * data,int (* compare)(const void * v1,const void * v2))864 size_t pl_insert_sorted(pl* list, const void* data, int (*compare)(const void* v1, const void* v2)) {
865     // we don't just call bl_insert_sorted because then we end up passing
866     // "void**" rather than "void*" args to the compare function, which
867     // violates the principle of least surprise.
868     ptrdiff_t lower, upper;
869     lower = -1;
870     upper = list->N;
871     while (lower < (upper-1)) {
872         ptrdiff_t mid;
873         int cmp;
874         mid = (upper + lower) / 2;
875         cmp = compare(data, pl_get(list, mid));
876         if (cmp >= 0) {
877             lower = mid;
878         } else {
879             upper = mid;
880         }
881     }
882     bl_insert(list, lower+1, &data);
883     return lower+1;
884 }
885 
886 /*
887  void pl_set(pl* list, int index, void* data) {
888  int i;
889  int nadd = (index+1) - list->N;
890  if (nadd > 0) {
891  // enlarge the list to hold 'nadd' more entries.
892  for (i=0; i<nadd; i++) {
893  pl_append(list, NULL);
894  }
895  }
896  bl_set(list, index, &data);
897  }
898  */
899 
sl_remove_duplicates(sl * lst)900 void sl_remove_duplicates(sl* lst) {
901     size_t i, j;
902     for (i=0; i<sl_size(lst); i++) {
903         const char* s1 = sl_get(lst, i);
904         for (j=i+1; j<sl_size(lst); j++) {
905             const char* s2 = sl_get(lst, j);
906             if (strcmp(s1, s2) == 0) {
907                 sl_remove(lst, j);
908                 j--;
909             }
910         }
911     }
912 }
913 
sl_new(int blocksize)914 sl* sl_new(int blocksize) {
915     pl* lst = pl_new(blocksize);
916     assert(lst);
917     return lst;
918 }
919 
sl_init2(sl * list,int blocksize)920 void sl_init2(sl* list, int blocksize) {
921     pl_init(list, blocksize);
922 }
923 
sl_free2(sl * list)924 void sl_free2(sl* list) {
925     size_t i;
926     if (!list) return;
927     for (i=0; i<sl_size(list); i++)
928         free(sl_get(list, i));
929     bl_free(list);
930 }
931 
sl_split(sl * lst,const char * str,const char * sepstring)932 sl* sl_split(sl* lst, const char* str, const char* sepstring) {
933     int seplen;
934     const char* s;
935     char* next_sep;
936     if (!lst)
937         lst = sl_new(4);
938     seplen = strlen(sepstring);
939     s = str;
940     while (s && *s) {
941         next_sep = strstr(s, sepstring);
942         if (!next_sep) {
943             sl_append(lst, s);
944             break;
945         }
946         //logverb("Appending: '%.*s'\n", (int)(next_sep - s), s);
947         sl_appendf(lst, "%.*s", (int)(next_sep - s), s);
948         s = next_sep + seplen;
949     }
950     return lst;
951 }
952 
sl_free_nonrecursive(sl * list)953 void sl_free_nonrecursive(sl* list) {
954     bl_free(list);
955 }
956 
sl_append_contents(sl * dest,sl * src)957 void sl_append_contents(sl* dest, sl* src) {
958     size_t i;
959     if (!src)
960         return;
961     for (i=0; i<sl_size(src); i++) {
962         char* str = sl_get(src, i);
963         sl_append(dest, str);
964     }
965 }
966 
sl_index_of(sl * lst,const char * str)967 ptrdiff_t sl_index_of(sl* lst, const char* str) {
968     size_t i;
969     for (i=0; i<sl_size(lst); i++) {
970         char* s = sl_get(lst, i);
971         if (strcmp(s, str) == 0)
972             return i;
973     }
974     return BL_NOT_FOUND;
975 }
976 
sl_last_index_of(sl * lst,const char * str)977 ptrdiff_t sl_last_index_of(sl* lst, const char* str) {
978     ptrdiff_t i;
979     for (i=sl_size(lst)-1; i>=0; i--) {
980         char* s = sl_get(lst, i);
981         if (strcmp(s, str) == 0)
982             return i;
983     }
984     return BL_NOT_FOUND;
985 }
986 
987 // Returns 0 if the string is not in the sl, 1 otherwise.
988 // (same as sl_index_of(lst, str) > -1)
sl_contains(sl * lst,const char * str)989 int sl_contains(sl* lst, const char* str) {
990     return (sl_index_of(lst, str) > -1);
991 }
992 
sl_reverse(sl * list)993 void sl_reverse(sl* list) {
994     bl_reverse(list);
995 }
996 
sl_append(sl * list,const char * data)997 char* sl_append(sl* list, const char* data) {
998     char* copy;
999     if (data) {
1000         copy = strdup(data);
1001         assert(copy);
1002     } else
1003         copy = NULL;
1004     pl_append(list, copy);
1005     return copy;
1006 }
1007 
sl_append_array(sl * list,const char ** strings,size_t n)1008 void sl_append_array(sl* list, const char**strings, size_t n) {
1009     size_t i;
1010     for (i=0; i<n; i++)
1011         sl_append(list, strings[i]);
1012 }
1013 
sl_append_nocopy(sl * list,const char * data)1014 void sl_append_nocopy(sl* list, const char* data) {
1015     pl_append(list, data);
1016 }
1017 
sl_push(sl * list,const char * data)1018 char* sl_push(sl* list, const char* data) {
1019     char* copy = strdup(data);
1020     pl_push(list, copy);
1021     return copy;
1022 }
1023 
sl_pop(sl * list)1024 char* sl_pop(sl* list) {
1025     return pl_pop(list);
1026 }
1027 
sl_get(sl * list,size_t n)1028 char* sl_get(sl* list, size_t n) {
1029     return pl_get(list, n);
1030 }
1031 
sl_get_const(const sl * list,size_t n)1032 char* sl_get_const(const sl* list, size_t n) {
1033     return pl_get_const(list, n);
1034 }
1035 
sl_set(sl * list,size_t index,const char * value)1036 char* sl_set(sl* list, size_t index, const char* value) {
1037     char* copy;
1038     assert(index >= 0);
1039     copy = strdup(value);
1040     if (index < list->N) {
1041         // we're replacing an existing value - free it!
1042         free(sl_get(list, index));
1043         bl_set(list, index, &copy);
1044     } else {
1045         // pad
1046         size_t i;
1047         for (i=list->N; i<index; i++)
1048             sl_append_nocopy(list, NULL);
1049         sl_append(list, copy);
1050     }
1051     return copy;
1052 }
1053 
sl_check_consistency(sl * list)1054 int sl_check_consistency(sl* list) {
1055     return bl_check_consistency(list);
1056 }
1057 
sl_insert(sl * list,size_t indx,const char * data)1058 char* sl_insert(sl* list, size_t indx, const char* data) {
1059     char* copy = strdup(data);
1060     bl_insert(list, indx, &copy);
1061     return copy;
1062 }
1063 
sl_insert_nocopy(sl * list,size_t indx,const char * str)1064 void sl_insert_nocopy(sl* list, size_t indx, const char* str) {
1065     bl_insert(list, indx, &str);
1066 }
1067 
sl_remove_from(sl * list,size_t start)1068 void sl_remove_from(sl* list, size_t start) {
1069     sl_remove_index_range(list, start, sl_size(list) - start);
1070 }
1071 
sl_remove_string(sl * list,const char * string)1072 ptrdiff_t sl_remove_string(sl* list, const char* string) {
1073     return pl_remove_value(list, string);
1074 }
1075 
sl_remove_string_bycaseval(sl * list,const char * string)1076 char* sl_remove_string_bycaseval(sl* list, const char* string) {
1077     size_t N = sl_size(list);
1078     size_t i;
1079     for (i=0; i<N; i++) {
1080         char* str = sl_get(list, i);
1081         if (strcasecmp(str, string) == 0) {
1082             char* s = sl_get(list, i);
1083             sl_remove(list, i);
1084             return s;
1085         }
1086     }
1087     return NULL;
1088 }
1089 
sl_remove_string_byval(sl * list,const char * string)1090 ptrdiff_t sl_remove_string_byval(sl* list, const char* string) {
1091     size_t N = sl_size(list);
1092     size_t i;
1093     for (i=0; i<N; i++) {
1094         char* str = sl_get(list, i);
1095         if (strcmp(str, string) == 0) {
1096             sl_remove(list, i);
1097             return i;
1098         }
1099     }
1100     return BL_NOT_FOUND;
1101 }
1102 
sl_remove_index_range(sl * list,size_t start,size_t length)1103 void sl_remove_index_range(sl* list, size_t start, size_t length) {
1104     size_t i;
1105     assert(list);
1106     assert(start + length <= list->N);
1107     assert(start >= 0);
1108     assert(length >= 0);
1109     for (i=0; i<length; i++) {
1110         char* str = sl_get(list, start + i);
1111         free(str);
1112     }
1113     bl_remove_index_range(list, start, length);
1114 }
1115 
sl_remove(sl * list,size_t index)1116 void sl_remove(sl* list, size_t index) {
1117     bl_remove_index(list, index);
1118 }
1119 
sl_remove_all(sl * list)1120 void  sl_remove_all(sl* list) {
1121     size_t i;
1122     if (!list) return;
1123     for (i=0; i<sl_size(list); i++)
1124         free(pl_get(list, i));
1125     bl_remove_all(list);
1126 }
1127 
sl_merge_lists(sl * list1,sl * list2)1128 void   sl_merge_lists(sl* list1, sl* list2) {
1129     bl_append_list(list1, list2);
1130 }
1131 
sl_print(sl * list)1132 void sl_print(sl* list) {
1133     bl_node* n;
1134     int i;
1135     for (n=list->head; n; n=n->next) {
1136         printf("[\n");
1137         for (i=0; i<n->N; i++)
1138             printf("  \"%s\"\n", ((char**)NODE_DATA(n))[i]);
1139         printf("]\n");
1140     }
1141 }
1142 
sljoin(sl * list,const char * join,int forward)1143 static char* sljoin(sl* list, const char* join, int forward) {
1144     size_t start, end, inc;
1145 
1146     size_t len = 0;
1147     size_t i, N;
1148     char* rtn;
1149     size_t offset;
1150     size_t JL;
1151 
1152     if (sl_size(list) == 0)
1153         return strdup("");
1154 
1155     // step through the list forward or backward?
1156     if (forward) {
1157         start = 0;
1158         end = sl_size(list);
1159         inc = 1;
1160     } else {
1161         start = sl_size(list) - 1;
1162         end = -1;
1163         inc = -1;
1164     }
1165 
1166     JL = strlen(join);
1167     N = sl_size(list);
1168     for (i=0; i<N; i++)
1169         len += strlen(sl_get(list, i));
1170     len += ((N-1) * JL);
1171     rtn = malloc(len + 1);
1172     if (!rtn)
1173         return rtn;
1174     offset = 0;
1175     for (i=start; i!=end; i+= inc) {
1176         char* str = sl_get(list, i);
1177         size_t L = strlen(str);
1178         if (i != start) {
1179             memcpy(rtn + offset, join, JL);
1180             offset += JL;
1181         }
1182         memcpy(rtn + offset, str, L);
1183         offset += L;
1184     }
1185     assert(offset == len);
1186     rtn[offset] = '\0';
1187     return rtn;
1188 }
1189 
sl_join(sl * list,const char * join)1190 char*  sl_join(sl* list, const char* join) {
1191     return sljoin(list, join, 1);
1192 }
1193 
sl_join_reverse(sl * list,const char * join)1194 char*  sl_join_reverse(sl* list, const char* join) {
1195     return sljoin(list, join, 0);
1196 }
1197 
sl_implode(sl * list,const char * join)1198 char*  sl_implode(sl* list, const char* join) {
1199     return sl_join(list, join);
1200 }
1201 
sl_appendf(sl * list,const char * format,...)1202 char* sl_appendf(sl* list, const char* format, ...) {
1203     char* str;
1204     va_list lst;
1205     va_start(lst, format);
1206     str = sl_appendvf(list, format, lst);
1207     va_end(lst);
1208     return str;
1209 }
1210 
sl_appendvf(sl * list,const char * format,va_list va)1211 char* sl_appendvf(sl* list, const char* format, va_list va) {
1212     char* str;
1213     if (vasprintf(&str, format, va) == -1)
1214         return NULL;
1215     sl_append_nocopy(list, str);
1216     return str;
1217 }
1218 
sl_insert_sortedf(sl * list,const char * format,...)1219 char* sl_insert_sortedf(sl* list, const char* format, ...) {
1220     va_list lst;
1221     char* str;
1222     va_start(lst, format);
1223     if (vasprintf(&str, format, lst) == -1)
1224         return NULL;
1225     sl_insert_sorted_nocopy(list, str);
1226     va_end(lst);
1227     return str;
1228 }
1229 
sl_insertf(sl * list,size_t index,const char * format,...)1230 char* sl_insertf(sl* list, size_t index, const char* format, ...) {
1231     va_list lst;
1232     char* str;
1233     va_start(lst, format);
1234     if (vasprintf(&str, format, lst) == -1)
1235         return NULL;
1236     sl_insert_nocopy(list, index, str);
1237     va_end(lst);
1238     return str;
1239 }
1240 
bl_compare_strings_ascending(const void * v1,const void * v2)1241 int bl_compare_strings_ascending(const void* v1, const void* v2) {
1242     const char* str1 = v1;
1243     const char* str2 = v2;
1244     return strcoll(str1, str2);
1245 }
1246 
sl_insert_sorted_nocopy(sl * list,const char * string)1247 void sl_insert_sorted_nocopy(sl* list, const char* string) {
1248     pl_insert_sorted(list, string, bl_compare_strings_ascending);
1249 }
1250 
sl_insert_sorted(sl * list,const char * string)1251 char* sl_insert_sorted(sl* list, const char* string) {
1252     char* copy = strdup(string);
1253     pl_insert_sorted(list, copy, bl_compare_strings_ascending);
1254     return copy;
1255 }
1256 
1257 #define InlineDefine InlineDefineC
1258 #include "bl.inc"
1259 #undef InlineDefine
1260 
1261