mountlist: Use Linux code on Android.
[gnulib.git] / lib / gl_anylinked_list2.h
blobdc7f2cd56c580b2430d69315295c47206db84740
1 /* Sequential list data type implemented by a linked list.
2 Copyright (C) 2006-2019 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2006.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
18 /* Common code of gl_linked_list.c and gl_linkedhash_list.c. */
20 /* If the symbol SIGNAL_SAFE_LIST is defined, the code is compiled in such
21 a way that a gl_list_t data structure may be used from within a signal
22 handler. The operations allowed in the signal handler are:
23 gl_list_iterator, gl_list_iterator_next, gl_list_iterator_free.
24 The list and node fields that are therefore accessed from the signal handler
25 are:
26 list->root, node->next, node->value.
27 We are careful to make modifications to these fields only in an order
28 that maintains the consistency of the list data structure at any moment,
29 and we use 'volatile' assignments to prevent the compiler from reordering
30 such assignments. */
31 #ifdef SIGNAL_SAFE_LIST
32 # define ASYNCSAFE(type) *(type volatile *)&
33 #else
34 # define ASYNCSAFE(type)
35 #endif
37 /* -------------------------- gl_list_t Data Type -------------------------- */
39 static gl_list_t
40 gl_linked_nx_create_empty (gl_list_implementation_t implementation,
41 gl_listelement_equals_fn equals_fn,
42 gl_listelement_hashcode_fn hashcode_fn,
43 gl_listelement_dispose_fn dispose_fn,
44 bool allow_duplicates)
46 struct gl_list_impl *list =
47 (struct gl_list_impl *) malloc (sizeof (struct gl_list_impl));
49 if (list == NULL)
50 return NULL;
52 list->base.vtable = implementation;
53 list->base.equals_fn = equals_fn;
54 list->base.hashcode_fn = hashcode_fn;
55 list->base.dispose_fn = dispose_fn;
56 list->base.allow_duplicates = allow_duplicates;
57 #if WITH_HASHTABLE
58 list->table_size = 11;
59 list->table =
60 (gl_hash_entry_t *) calloc (list->table_size, sizeof (gl_hash_entry_t));
61 if (list->table == NULL)
62 goto fail;
63 #endif
64 list->root.next = &list->root;
65 list->root.prev = &list->root;
66 list->count = 0;
68 return list;
70 #if WITH_HASHTABLE
71 fail:
72 free (list);
73 return NULL;
74 #endif
77 static gl_list_t
78 gl_linked_nx_create (gl_list_implementation_t implementation,
79 gl_listelement_equals_fn equals_fn,
80 gl_listelement_hashcode_fn hashcode_fn,
81 gl_listelement_dispose_fn dispose_fn,
82 bool allow_duplicates,
83 size_t count, const void **contents)
85 struct gl_list_impl *list =
86 (struct gl_list_impl *) malloc (sizeof (struct gl_list_impl));
87 gl_list_node_t tail;
89 if (list == NULL)
90 return NULL;
92 list->base.vtable = implementation;
93 list->base.equals_fn = equals_fn;
94 list->base.hashcode_fn = hashcode_fn;
95 list->base.dispose_fn = dispose_fn;
96 list->base.allow_duplicates = allow_duplicates;
97 #if WITH_HASHTABLE
99 size_t estimate = xsum (count, count / 2); /* 1.5 * count */
100 if (estimate < 10)
101 estimate = 10;
102 list->table_size = next_prime (estimate);
103 if (size_overflow_p (xtimes (list->table_size, sizeof (gl_hash_entry_t))))
104 goto fail1;
105 list->table =
106 (gl_hash_entry_t *) calloc (list->table_size, sizeof (gl_hash_entry_t));
107 if (list->table == NULL)
108 goto fail1;
110 #endif
111 list->count = count;
112 tail = &list->root;
113 for (; count > 0; contents++, count--)
115 gl_list_node_t node =
116 (struct gl_list_node_impl *) malloc (sizeof (struct gl_list_node_impl));
118 if (node == NULL)
119 goto fail2;
121 node->value = *contents;
122 #if WITH_HASHTABLE
123 node->h.hashcode =
124 (list->base.hashcode_fn != NULL
125 ? list->base.hashcode_fn (node->value)
126 : (size_t)(uintptr_t) node->value);
128 /* Add node to the hash table. */
129 if (add_to_bucket (list, node) < 0)
131 free (node);
132 goto fail2;
134 #endif
136 /* Add node to the list. */
137 node->prev = tail;
138 tail->next = node;
139 tail = node;
141 tail->next = &list->root;
142 list->root.prev = tail;
144 return list;
146 fail2:
148 gl_list_node_t node;
150 for (node = tail; node != &list->root; )
152 gl_list_node_t prev = node->prev;
154 free (node);
155 node = prev;
158 #if WITH_HASHTABLE
159 free (list->table);
160 fail1:
161 #endif
162 free (list);
163 return NULL;
166 static size_t _GL_ATTRIBUTE_PURE
167 gl_linked_size (gl_list_t list)
169 return list->count;
172 static const void * _GL_ATTRIBUTE_PURE
173 gl_linked_node_value (gl_list_t list, gl_list_node_t node)
175 return node->value;
178 static int
179 gl_linked_node_nx_set_value (gl_list_t list, gl_list_node_t node,
180 const void *elt)
182 #if WITH_HASHTABLE
183 if (elt != node->value)
185 size_t new_hashcode =
186 (list->base.hashcode_fn != NULL
187 ? list->base.hashcode_fn (elt)
188 : (size_t)(uintptr_t) elt);
190 if (new_hashcode != node->h.hashcode)
192 remove_from_bucket (list, node);
193 node->value = elt;
194 node->h.hashcode = new_hashcode;
195 if (add_to_bucket (list, node) < 0)
197 /* Out of memory. We removed node from a bucket but cannot add
198 it to another bucket. In order to avoid inconsistencies, we
199 must remove node entirely from the list. */
200 gl_list_node_t before_removed = node->prev;
201 gl_list_node_t after_removed = node->next;
202 ASYNCSAFE(gl_list_node_t) before_removed->next = after_removed;
203 after_removed->prev = before_removed;
204 list->count--;
205 free (node);
206 return -1;
209 else
210 node->value = elt;
212 #else
213 node->value = elt;
214 #endif
215 return 0;
218 static gl_list_node_t _GL_ATTRIBUTE_PURE
219 gl_linked_next_node (gl_list_t list, gl_list_node_t node)
221 return (node->next != &list->root ? node->next : NULL);
224 static gl_list_node_t _GL_ATTRIBUTE_PURE
225 gl_linked_previous_node (gl_list_t list, gl_list_node_t node)
227 return (node->prev != &list->root ? node->prev : NULL);
230 static const void * _GL_ATTRIBUTE_PURE
231 gl_linked_get_at (gl_list_t list, size_t position)
233 size_t count = list->count;
234 gl_list_node_t node;
236 if (!(position < count))
237 /* Invalid argument. */
238 abort ();
239 /* Here we know count > 0. */
240 if (position <= ((count - 1) / 2))
242 node = list->root.next;
243 for (; position > 0; position--)
244 node = node->next;
246 else
248 position = count - 1 - position;
249 node = list->root.prev;
250 for (; position > 0; position--)
251 node = node->prev;
253 return node->value;
256 static gl_list_node_t
257 gl_linked_nx_set_at (gl_list_t list, size_t position, const void *elt)
259 size_t count = list->count;
260 gl_list_node_t node;
262 if (!(position < count))
263 /* Invalid argument. */
264 abort ();
265 /* Here we know count > 0. */
266 if (position <= ((count - 1) / 2))
268 node = list->root.next;
269 for (; position > 0; position--)
270 node = node->next;
272 else
274 position = count - 1 - position;
275 node = list->root.prev;
276 for (; position > 0; position--)
277 node = node->prev;
279 #if WITH_HASHTABLE
280 if (elt != node->value)
282 size_t new_hashcode =
283 (list->base.hashcode_fn != NULL
284 ? list->base.hashcode_fn (elt)
285 : (size_t)(uintptr_t) elt);
287 if (new_hashcode != node->h.hashcode)
289 remove_from_bucket (list, node);
290 node->value = elt;
291 node->h.hashcode = new_hashcode;
292 if (add_to_bucket (list, node) < 0)
294 /* Out of memory. We removed node from a bucket but cannot add
295 it to another bucket. In order to avoid inconsistencies, we
296 must remove node entirely from the list. */
297 gl_list_node_t before_removed = node->prev;
298 gl_list_node_t after_removed = node->next;
299 ASYNCSAFE(gl_list_node_t) before_removed->next = after_removed;
300 after_removed->prev = before_removed;
301 list->count--;
302 free (node);
303 return NULL;
306 else
307 node->value = elt;
309 #else
310 node->value = elt;
311 #endif
312 return node;
315 static gl_list_node_t _GL_ATTRIBUTE_PURE
316 gl_linked_search_from_to (gl_list_t list, size_t start_index, size_t end_index,
317 const void *elt)
319 size_t count = list->count;
321 if (!(start_index <= end_index && end_index <= count))
322 /* Invalid arguments. */
323 abort ();
325 #if WITH_HASHTABLE
326 size_t hashcode =
327 (list->base.hashcode_fn != NULL
328 ? list->base.hashcode_fn (elt)
329 : (size_t)(uintptr_t) elt);
330 size_t bucket = hashcode % list->table_size;
331 gl_listelement_equals_fn equals = list->base.equals_fn;
333 if (!list->base.allow_duplicates)
335 /* Look for the first match in the hash bucket. */
336 gl_list_node_t found = NULL;
337 gl_list_node_t node;
339 for (node = (gl_list_node_t) list->table[bucket];
340 node != NULL;
341 node = (gl_list_node_t) node->h.hash_next)
342 if (node->h.hashcode == hashcode
343 && (equals != NULL
344 ? equals (elt, node->value)
345 : elt == node->value))
347 found = node;
348 break;
350 if (start_index > 0)
351 /* Look whether found's index is < start_index. */
352 for (node = list->root.next; ; node = node->next)
354 if (node == found)
355 return NULL;
356 if (--start_index == 0)
357 break;
359 if (end_index < count)
360 /* Look whether found's index is >= end_index. */
362 end_index = count - end_index;
363 for (node = list->root.prev; ; node = node->prev)
365 if (node == found)
366 return NULL;
367 if (--end_index == 0)
368 break;
371 return found;
373 else
375 /* Look whether there is more than one match in the hash bucket. */
376 bool multiple_matches = false;
377 gl_list_node_t first_match = NULL;
378 gl_list_node_t node;
380 for (node = (gl_list_node_t) list->table[bucket];
381 node != NULL;
382 node = (gl_list_node_t) node->h.hash_next)
383 if (node->h.hashcode == hashcode
384 && (equals != NULL
385 ? equals (elt, node->value)
386 : elt == node->value))
388 if (first_match == NULL)
389 first_match = node;
390 else
392 multiple_matches = true;
393 break;
396 if (multiple_matches)
398 /* We need the match with the smallest index. But we don't have
399 a fast mapping node -> index. So we have to walk the list. */
400 end_index -= start_index;
401 node = list->root.next;
402 for (; start_index > 0; start_index--)
403 node = node->next;
405 for (;
406 end_index > 0;
407 node = node->next, end_index--)
408 if (node->h.hashcode == hashcode
409 && (equals != NULL
410 ? equals (elt, node->value)
411 : elt == node->value))
412 return node;
413 /* The matches must have all been at indices < start_index or
414 >= end_index. */
415 return NULL;
417 else
419 if (start_index > 0)
420 /* Look whether first_match's index is < start_index. */
421 for (node = list->root.next; node != &list->root; node = node->next)
423 if (node == first_match)
424 return NULL;
425 if (--start_index == 0)
426 break;
428 if (end_index < list->count)
429 /* Look whether first_match's index is >= end_index. */
431 end_index = list->count - end_index;
432 for (node = list->root.prev; ; node = node->prev)
434 if (node == first_match)
435 return NULL;
436 if (--end_index == 0)
437 break;
440 return first_match;
443 #else
444 gl_listelement_equals_fn equals = list->base.equals_fn;
445 gl_list_node_t node = list->root.next;
447 end_index -= start_index;
448 for (; start_index > 0; start_index--)
449 node = node->next;
451 if (equals != NULL)
453 for (; end_index > 0; node = node->next, end_index--)
454 if (equals (elt, node->value))
455 return node;
457 else
459 for (; end_index > 0; node = node->next, end_index--)
460 if (elt == node->value)
461 return node;
463 return NULL;
464 #endif
468 static size_t _GL_ATTRIBUTE_PURE
469 gl_linked_indexof_from_to (gl_list_t list, size_t start_index, size_t end_index,
470 const void *elt)
472 size_t count = list->count;
474 if (!(start_index <= end_index && end_index <= count))
475 /* Invalid arguments. */
476 abort ();
478 #if WITH_HASHTABLE
479 /* Here the hash table doesn't help much. It only allows us to minimize
480 the number of equals() calls, by looking up first the node and then
481 its index. */
482 size_t hashcode =
483 (list->base.hashcode_fn != NULL
484 ? list->base.hashcode_fn (elt)
485 : (size_t)(uintptr_t) elt);
486 size_t bucket = hashcode % list->table_size;
487 gl_listelement_equals_fn equals = list->base.equals_fn;
488 gl_list_node_t node;
490 /* First step: Look up the node. */
491 if (!list->base.allow_duplicates)
493 /* Look for the first match in the hash bucket. */
494 for (node = (gl_list_node_t) list->table[bucket];
495 node != NULL;
496 node = (gl_list_node_t) node->h.hash_next)
497 if (node->h.hashcode == hashcode
498 && (equals != NULL
499 ? equals (elt, node->value)
500 : elt == node->value))
501 break;
503 else
505 /* Look whether there is more than one match in the hash bucket. */
506 bool multiple_matches = false;
507 gl_list_node_t first_match = NULL;
509 for (node = (gl_list_node_t) list->table[bucket];
510 node != NULL;
511 node = (gl_list_node_t) node->h.hash_next)
512 if (node->h.hashcode == hashcode
513 && (equals != NULL
514 ? equals (elt, node->value)
515 : elt == node->value))
517 if (first_match == NULL)
518 first_match = node;
519 else
521 multiple_matches = true;
522 break;
525 if (multiple_matches)
527 /* We need the match with the smallest index. But we don't have
528 a fast mapping node -> index. So we have to walk the list. */
529 size_t index;
531 index = start_index;
532 node = list->root.next;
533 for (; start_index > 0; start_index--)
534 node = node->next;
536 for (;
537 index < end_index;
538 node = node->next, index++)
539 if (node->h.hashcode == hashcode
540 && (equals != NULL
541 ? equals (elt, node->value)
542 : elt == node->value))
543 return index;
544 /* The matches must have all been at indices < start_index or
545 >= end_index. */
546 return (size_t)(-1);
548 node = first_match;
551 /* Second step: Look up the index of the node. */
552 if (node == NULL)
553 return (size_t)(-1);
554 else
556 size_t index = 0;
558 for (; node->prev != &list->root; node = node->prev)
559 index++;
561 if (index >= start_index && index < end_index)
562 return index;
563 else
564 return (size_t)(-1);
566 #else
567 gl_listelement_equals_fn equals = list->base.equals_fn;
568 size_t index = start_index;
569 gl_list_node_t node = list->root.next;
571 for (; start_index > 0; start_index--)
572 node = node->next;
574 if (equals != NULL)
576 for (;
577 index < end_index;
578 node = node->next, index++)
579 if (equals (elt, node->value))
580 return index;
582 else
584 for (;
585 index < end_index;
586 node = node->next, index++)
587 if (elt == node->value)
588 return index;
590 return (size_t)(-1);
591 #endif
595 static gl_list_node_t
596 gl_linked_nx_add_first (gl_list_t list, const void *elt)
598 gl_list_node_t node =
599 (struct gl_list_node_impl *) malloc (sizeof (struct gl_list_node_impl));
601 if (node == NULL)
602 return NULL;
604 ASYNCSAFE(const void *) node->value = elt;
605 #if WITH_HASHTABLE
606 node->h.hashcode =
607 (list->base.hashcode_fn != NULL
608 ? list->base.hashcode_fn (node->value)
609 : (size_t)(uintptr_t) node->value);
611 /* Add node to the hash table. */
612 if (add_to_bucket (list, node) < 0)
614 free (node);
615 return NULL;
617 #endif
619 /* Add node to the list. */
620 node->prev = &list->root;
621 ASYNCSAFE(gl_list_node_t) node->next = list->root.next;
622 node->next->prev = node;
623 ASYNCSAFE(gl_list_node_t) list->root.next = node;
624 list->count++;
626 #if WITH_HASHTABLE
627 hash_resize_after_add (list);
628 #endif
630 return node;
633 static gl_list_node_t
634 gl_linked_nx_add_last (gl_list_t list, const void *elt)
636 gl_list_node_t node =
637 (struct gl_list_node_impl *) malloc (sizeof (struct gl_list_node_impl));
639 if (node == NULL)
640 return NULL;
642 ASYNCSAFE(const void *) node->value = elt;
643 #if WITH_HASHTABLE
644 node->h.hashcode =
645 (list->base.hashcode_fn != NULL
646 ? list->base.hashcode_fn (node->value)
647 : (size_t)(uintptr_t) node->value);
649 /* Add node to the hash table. */
650 if (add_to_bucket (list, node) < 0)
652 free (node);
653 return NULL;
655 #endif
657 /* Add node to the list. */
658 ASYNCSAFE(gl_list_node_t) node->next = &list->root;
659 node->prev = list->root.prev;
660 ASYNCSAFE(gl_list_node_t) node->prev->next = node;
661 list->root.prev = node;
662 list->count++;
664 #if WITH_HASHTABLE
665 hash_resize_after_add (list);
666 #endif
668 return node;
671 static gl_list_node_t
672 gl_linked_nx_add_before (gl_list_t list, gl_list_node_t node, const void *elt)
674 gl_list_node_t new_node =
675 (struct gl_list_node_impl *) malloc (sizeof (struct gl_list_node_impl));
677 if (new_node == NULL)
678 return NULL;
680 ASYNCSAFE(const void *) new_node->value = elt;
681 #if WITH_HASHTABLE
682 new_node->h.hashcode =
683 (list->base.hashcode_fn != NULL
684 ? list->base.hashcode_fn (new_node->value)
685 : (size_t)(uintptr_t) new_node->value);
687 /* Add new_node to the hash table. */
688 if (add_to_bucket (list, new_node) < 0)
690 free (new_node);
691 return NULL;
693 #endif
695 /* Add new_node to the list. */
696 ASYNCSAFE(gl_list_node_t) new_node->next = node;
697 new_node->prev = node->prev;
698 ASYNCSAFE(gl_list_node_t) new_node->prev->next = new_node;
699 node->prev = new_node;
700 list->count++;
702 #if WITH_HASHTABLE
703 hash_resize_after_add (list);
704 #endif
706 return new_node;
709 static gl_list_node_t
710 gl_linked_nx_add_after (gl_list_t list, gl_list_node_t node, const void *elt)
712 gl_list_node_t new_node =
713 (struct gl_list_node_impl *) malloc (sizeof (struct gl_list_node_impl));
715 if (new_node == NULL)
716 return NULL;
718 ASYNCSAFE(const void *) new_node->value = elt;
719 #if WITH_HASHTABLE
720 new_node->h.hashcode =
721 (list->base.hashcode_fn != NULL
722 ? list->base.hashcode_fn (new_node->value)
723 : (size_t)(uintptr_t) new_node->value);
725 /* Add new_node to the hash table. */
726 if (add_to_bucket (list, new_node) < 0)
728 free (new_node);
729 return NULL;
731 #endif
733 /* Add new_node to the list. */
734 new_node->prev = node;
735 ASYNCSAFE(gl_list_node_t) new_node->next = node->next;
736 new_node->next->prev = new_node;
737 ASYNCSAFE(gl_list_node_t) node->next = new_node;
738 list->count++;
740 #if WITH_HASHTABLE
741 hash_resize_after_add (list);
742 #endif
744 return new_node;
747 static gl_list_node_t
748 gl_linked_nx_add_at (gl_list_t list, size_t position, const void *elt)
750 size_t count = list->count;
751 gl_list_node_t new_node;
753 if (!(position <= count))
754 /* Invalid argument. */
755 abort ();
757 new_node = (struct gl_list_node_impl *) malloc (sizeof (struct gl_list_node_impl));
758 if (new_node == NULL)
759 return NULL;
761 ASYNCSAFE(const void *) new_node->value = elt;
762 #if WITH_HASHTABLE
763 new_node->h.hashcode =
764 (list->base.hashcode_fn != NULL
765 ? list->base.hashcode_fn (new_node->value)
766 : (size_t)(uintptr_t) new_node->value);
768 /* Add new_node to the hash table. */
769 if (add_to_bucket (list, new_node) < 0)
771 free (new_node);
772 return NULL;
774 #endif
776 /* Add new_node to the list. */
777 if (position <= (count / 2))
779 gl_list_node_t node;
781 node = &list->root;
782 for (; position > 0; position--)
783 node = node->next;
784 new_node->prev = node;
785 ASYNCSAFE(gl_list_node_t) new_node->next = node->next;
786 new_node->next->prev = new_node;
787 ASYNCSAFE(gl_list_node_t) node->next = new_node;
789 else
791 gl_list_node_t node;
793 position = count - position;
794 node = &list->root;
795 for (; position > 0; position--)
796 node = node->prev;
797 ASYNCSAFE(gl_list_node_t) new_node->next = node;
798 new_node->prev = node->prev;
799 ASYNCSAFE(gl_list_node_t) new_node->prev->next = new_node;
800 node->prev = new_node;
802 list->count++;
804 #if WITH_HASHTABLE
805 hash_resize_after_add (list);
806 #endif
808 return new_node;
811 static bool
812 gl_linked_remove_node (gl_list_t list, gl_list_node_t node)
814 gl_list_node_t prev;
815 gl_list_node_t next;
817 #if WITH_HASHTABLE
818 /* Remove node from the hash table. */
819 remove_from_bucket (list, node);
820 #endif
822 /* Remove node from the list. */
823 prev = node->prev;
824 next = node->next;
826 ASYNCSAFE(gl_list_node_t) prev->next = next;
827 next->prev = prev;
828 list->count--;
830 if (list->base.dispose_fn != NULL)
831 list->base.dispose_fn (node->value);
832 free (node);
833 return true;
836 static bool
837 gl_linked_remove_at (gl_list_t list, size_t position)
839 size_t count = list->count;
840 gl_list_node_t removed_node;
842 if (!(position < count))
843 /* Invalid argument. */
844 abort ();
845 /* Here we know count > 0. */
846 if (position <= ((count - 1) / 2))
848 gl_list_node_t node;
849 gl_list_node_t after_removed;
851 node = &list->root;
852 for (; position > 0; position--)
853 node = node->next;
854 removed_node = node->next;
855 after_removed = node->next->next;
856 ASYNCSAFE(gl_list_node_t) node->next = after_removed;
857 after_removed->prev = node;
859 else
861 gl_list_node_t node;
862 gl_list_node_t before_removed;
864 position = count - 1 - position;
865 node = &list->root;
866 for (; position > 0; position--)
867 node = node->prev;
868 removed_node = node->prev;
869 before_removed = node->prev->prev;
870 node->prev = before_removed;
871 ASYNCSAFE(gl_list_node_t) before_removed->next = node;
873 #if WITH_HASHTABLE
874 remove_from_bucket (list, removed_node);
875 #endif
876 list->count--;
878 if (list->base.dispose_fn != NULL)
879 list->base.dispose_fn (removed_node->value);
880 free (removed_node);
881 return true;
884 static bool
885 gl_linked_remove (gl_list_t list, const void *elt)
887 gl_list_node_t node = gl_linked_search_from_to (list, 0, list->count, elt);
889 if (node != NULL)
890 return gl_linked_remove_node (list, node);
891 else
892 return false;
895 static void
896 gl_linked_list_free (gl_list_t list)
898 gl_listelement_dispose_fn dispose = list->base.dispose_fn;
899 gl_list_node_t node;
901 for (node = list->root.next; node != &list->root; )
903 gl_list_node_t next = node->next;
904 if (dispose != NULL)
905 dispose (node->value);
906 free (node);
907 node = next;
909 #if WITH_HASHTABLE
910 free (list->table);
911 #endif
912 free (list);
915 /* --------------------- gl_list_iterator_t Data Type --------------------- */
917 static gl_list_iterator_t
918 gl_linked_iterator (gl_list_t list)
920 gl_list_iterator_t result;
922 result.vtable = list->base.vtable;
923 result.list = list;
924 result.p = list->root.next;
925 result.q = &list->root;
926 #if defined GCC_LINT || defined lint
927 result.i = 0;
928 result.j = 0;
929 result.count = 0;
930 #endif
932 return result;
935 static gl_list_iterator_t
936 gl_linked_iterator_from_to (gl_list_t list,
937 size_t start_index, size_t end_index)
939 gl_list_iterator_t result;
940 size_t n1, n2, n3;
942 if (!(start_index <= end_index && end_index <= list->count))
943 /* Invalid arguments. */
944 abort ();
945 result.vtable = list->base.vtable;
946 result.list = list;
947 n1 = start_index;
948 n2 = end_index - start_index;
949 n3 = list->count - end_index;
950 /* Find the maximum among n1, n2, n3, so as to reduce the number of
951 loop iterations to n1 + n2 + n3 - max(n1,n2,n3). */
952 if (n1 > n2 && n1 > n3)
954 /* n1 is the maximum, use n2 and n3. */
955 gl_list_node_t node;
956 size_t i;
958 node = &list->root;
959 for (i = n3; i > 0; i--)
960 node = node->prev;
961 result.q = node;
962 for (i = n2; i > 0; i--)
963 node = node->prev;
964 result.p = node;
966 else if (n2 > n3)
968 /* n2 is the maximum, use n1 and n3. */
969 gl_list_node_t node;
970 size_t i;
972 node = list->root.next;
973 for (i = n1; i > 0; i--)
974 node = node->next;
975 result.p = node;
977 node = &list->root;
978 for (i = n3; i > 0; i--)
979 node = node->prev;
980 result.q = node;
982 else
984 /* n3 is the maximum, use n1 and n2. */
985 gl_list_node_t node;
986 size_t i;
988 node = list->root.next;
989 for (i = n1; i > 0; i--)
990 node = node->next;
991 result.p = node;
992 for (i = n2; i > 0; i--)
993 node = node->next;
994 result.q = node;
997 #if defined GCC_LINT || defined lint
998 result.i = 0;
999 result.j = 0;
1000 result.count = 0;
1001 #endif
1003 return result;
1006 static bool
1007 gl_linked_iterator_next (gl_list_iterator_t *iterator,
1008 const void **eltp, gl_list_node_t *nodep)
1010 if (iterator->p != iterator->q)
1012 gl_list_node_t node = (gl_list_node_t) iterator->p;
1013 *eltp = node->value;
1014 if (nodep != NULL)
1015 *nodep = node;
1016 iterator->p = node->next;
1017 return true;
1019 else
1020 return false;
1023 static void
1024 gl_linked_iterator_free (gl_list_iterator_t *iterator)
1028 /* ---------------------- Sorted gl_list_t Data Type ---------------------- */
1030 static gl_list_node_t _GL_ATTRIBUTE_PURE
1031 gl_linked_sortedlist_search (gl_list_t list, gl_listelement_compar_fn compar,
1032 const void *elt)
1034 gl_list_node_t node;
1036 for (node = list->root.next; node != &list->root; node = node->next)
1038 int cmp = compar (node->value, elt);
1040 if (cmp > 0)
1041 break;
1042 if (cmp == 0)
1043 return node;
1045 return NULL;
1048 static gl_list_node_t _GL_ATTRIBUTE_PURE
1049 gl_linked_sortedlist_search_from_to (gl_list_t list,
1050 gl_listelement_compar_fn compar,
1051 size_t low, size_t high,
1052 const void *elt)
1054 size_t count = list->count;
1056 if (!(low <= high && high <= list->count))
1057 /* Invalid arguments. */
1058 abort ();
1060 high -= low;
1061 if (high > 0)
1063 /* Here we know low < count. */
1064 size_t position = low;
1065 gl_list_node_t node;
1067 if (position <= ((count - 1) / 2))
1069 node = list->root.next;
1070 for (; position > 0; position--)
1071 node = node->next;
1073 else
1075 position = count - 1 - position;
1076 node = list->root.prev;
1077 for (; position > 0; position--)
1078 node = node->prev;
1083 int cmp = compar (node->value, elt);
1085 if (cmp > 0)
1086 break;
1087 if (cmp == 0)
1088 return node;
1089 node = node->next;
1091 while (--high > 0);
1093 return NULL;
1096 static size_t _GL_ATTRIBUTE_PURE
1097 gl_linked_sortedlist_indexof (gl_list_t list, gl_listelement_compar_fn compar,
1098 const void *elt)
1100 gl_list_node_t node;
1101 size_t index;
1103 for (node = list->root.next, index = 0;
1104 node != &list->root;
1105 node = node->next, index++)
1107 int cmp = compar (node->value, elt);
1109 if (cmp > 0)
1110 break;
1111 if (cmp == 0)
1112 return index;
1114 return (size_t)(-1);
1117 static size_t _GL_ATTRIBUTE_PURE
1118 gl_linked_sortedlist_indexof_from_to (gl_list_t list,
1119 gl_listelement_compar_fn compar,
1120 size_t low, size_t high,
1121 const void *elt)
1123 size_t count = list->count;
1125 if (!(low <= high && high <= list->count))
1126 /* Invalid arguments. */
1127 abort ();
1129 high -= low;
1130 if (high > 0)
1132 /* Here we know low < count. */
1133 size_t index = low;
1134 size_t position = low;
1135 gl_list_node_t node;
1137 if (position <= ((count - 1) / 2))
1139 node = list->root.next;
1140 for (; position > 0; position--)
1141 node = node->next;
1143 else
1145 position = count - 1 - position;
1146 node = list->root.prev;
1147 for (; position > 0; position--)
1148 node = node->prev;
1153 int cmp = compar (node->value, elt);
1155 if (cmp > 0)
1156 break;
1157 if (cmp == 0)
1158 return index;
1159 node = node->next;
1160 index++;
1162 while (--high > 0);
1164 return (size_t)(-1);
1167 static gl_list_node_t
1168 gl_linked_sortedlist_nx_add (gl_list_t list, gl_listelement_compar_fn compar,
1169 const void *elt)
1171 gl_list_node_t node;
1173 for (node = list->root.next; node != &list->root; node = node->next)
1174 if (compar (node->value, elt) >= 0)
1175 return gl_linked_nx_add_before (list, node, elt);
1176 return gl_linked_nx_add_last (list, elt);
1179 static bool
1180 gl_linked_sortedlist_remove (gl_list_t list, gl_listelement_compar_fn compar,
1181 const void *elt)
1183 gl_list_node_t node;
1185 for (node = list->root.next; node != &list->root; node = node->next)
1187 int cmp = compar (node->value, elt);
1189 if (cmp > 0)
1190 break;
1191 if (cmp == 0)
1192 return gl_linked_remove_node (list, node);
1194 return false;