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, ©);
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, ©);
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