1 /* Sequential list data type implemented by a linked list.
2 Copyright (C) 2006-2007 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 2, or (at your option)
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, write to the Free Software Foundation,
17 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
19 /* Common code of gl_linked_list.c and gl_linkedhash_list.c. */
21 /* If the symbol SIGNAL_SAFE_LIST is defined, the code is compiled in such
22 a way that a gl_list_t data structure may be used from within a signal
23 handler. The operations allowed in the signal handler are:
24 gl_list_iterator, gl_list_iterator_next, gl_list_iterator_free.
25 The list and node fields that are therefore accessed from the signal handler
27 list->root, node->next, node->value.
28 We are careful to make modifications to these fields only in an order
29 that maintains the consistency of the list data structure at any moment,
30 and we use 'volatile' assignments to prevent the compiler from reordering
32 #ifdef SIGNAL_SAFE_LIST
33 # define ASYNCSAFE(type) *(volatile type *)&
35 # define ASYNCSAFE(type)
38 /* -------------------------- gl_list_t Data Type -------------------------- */
41 gl_linked_create_empty (gl_list_implementation_t implementation,
42 gl_listelement_equals_fn equals_fn,
43 gl_listelement_hashcode_fn hashcode_fn,
44 gl_listelement_dispose_fn dispose_fn,
45 bool allow_duplicates)
47 struct gl_list_impl *list = XMALLOC (struct gl_list_impl);
49 list->base.vtable = implementation;
50 list->base.equals_fn = equals_fn;
51 list->base.hashcode_fn = hashcode_fn;
52 list->base.dispose_fn = dispose_fn;
53 list->base.allow_duplicates = allow_duplicates;
55 list->table_size = 11;
56 list->table = XCALLOC (list->table_size, gl_hash_entry_t);
58 list->root.next = &list->root;
59 list->root.prev = &list->root;
66 gl_linked_create (gl_list_implementation_t implementation,
67 gl_listelement_equals_fn equals_fn,
68 gl_listelement_hashcode_fn hashcode_fn,
69 gl_listelement_dispose_fn dispose_fn,
70 bool allow_duplicates,
71 size_t count, const void **contents)
73 struct gl_list_impl *list = XMALLOC (struct gl_list_impl);
76 list->base.vtable = implementation;
77 list->base.equals_fn = equals_fn;
78 list->base.hashcode_fn = hashcode_fn;
79 list->base.dispose_fn = dispose_fn;
80 list->base.allow_duplicates = allow_duplicates;
83 size_t estimate = xsum (count, count / 2); /* 1.5 * count */
86 list->table_size = next_prime (estimate);
87 list->table = XCALLOC (list->table_size, gl_hash_entry_t);
92 for (; count > 0; contents++, count--)
94 gl_list_node_t node = XMALLOC (struct gl_list_node_impl);
96 node->value = *contents;
99 (list->base.hashcode_fn != NULL
100 ? list->base.hashcode_fn (node->value)
101 : (size_t)(uintptr_t) node->value);
103 /* Add node to the hash table. */
104 add_to_bucket (list, node);
107 /* Add node to the list. */
112 tail->next = &list->root;
113 list->root.prev = tail;
119 gl_linked_size (gl_list_t list)
125 gl_linked_node_value (gl_list_t list, gl_list_node_t node)
130 static gl_list_node_t
131 gl_linked_next_node (gl_list_t list, gl_list_node_t node)
133 return (node->next != &list->root ? node->next : NULL);
136 static gl_list_node_t
137 gl_linked_previous_node (gl_list_t list, gl_list_node_t node)
139 return (node->prev != &list->root ? node->prev : NULL);
143 gl_linked_get_at (gl_list_t list, size_t position)
145 size_t count = list->count;
148 if (!(position < count))
149 /* Invalid argument. */
151 /* Here we know count > 0. */
152 if (position <= ((count - 1) / 2))
154 node = list->root.next;
155 for (; position > 0; position--)
160 position = count - 1 - position;
161 node = list->root.prev;
162 for (; position > 0; position--)
168 static gl_list_node_t
169 gl_linked_set_at (gl_list_t list, size_t position, const void *elt)
171 size_t count = list->count;
174 if (!(position < count))
175 /* Invalid argument. */
177 /* Here we know count > 0. */
178 if (position <= ((count - 1) / 2))
180 node = list->root.next;
181 for (; position > 0; position--)
186 position = count - 1 - position;
187 node = list->root.prev;
188 for (; position > 0; position--)
192 if (elt != node->value)
194 size_t new_hashcode =
195 (list->base.hashcode_fn != NULL
196 ? list->base.hashcode_fn (elt)
197 : (size_t)(uintptr_t) elt);
199 if (new_hashcode != node->h.hashcode)
201 remove_from_bucket (list, node);
203 node->h.hashcode = new_hashcode;
204 add_to_bucket (list, node);
215 static gl_list_node_t
216 gl_linked_search_from_to (gl_list_t list, size_t start_index, size_t end_index,
219 size_t count = list->count;
221 if (!(start_index <= end_index && end_index <= count))
222 /* Invalid arguments. */
227 (list->base.hashcode_fn != NULL
228 ? list->base.hashcode_fn (elt)
229 : (size_t)(uintptr_t) elt);
230 size_t bucket = hashcode % list->table_size;
231 gl_listelement_equals_fn equals = list->base.equals_fn;
233 if (!list->base.allow_duplicates)
235 /* Look for the first match in the hash bucket. */
236 gl_list_node_t found = NULL;
239 for (node = (gl_list_node_t) list->table[bucket];
241 node = (gl_list_node_t) node->h.hash_next)
242 if (node->h.hashcode == hashcode
244 ? equals (elt, node->value)
245 : elt == node->value))
251 /* Look whether found's index is < start_index. */
252 for (node = list->root.next; ; node = node->next)
256 if (--start_index == 0)
259 if (end_index < count)
260 /* Look whether found's index is >= end_index. */
262 end_index = count - end_index;
263 for (node = list->root.prev; ; node = node->prev)
267 if (--end_index == 0)
275 /* Look whether there is more than one match in the hash bucket. */
276 bool multiple_matches = false;
277 gl_list_node_t first_match = NULL;
280 for (node = (gl_list_node_t) list->table[bucket];
282 node = (gl_list_node_t) node->h.hash_next)
283 if (node->h.hashcode == hashcode
285 ? equals (elt, node->value)
286 : elt == node->value))
288 if (first_match == NULL)
292 multiple_matches = true;
296 if (multiple_matches)
298 /* We need the match with the smallest index. But we don't have
299 a fast mapping node -> index. So we have to walk the list. */
300 end_index -= start_index;
301 node = list->root.next;
302 for (; start_index > 0; start_index--)
307 node = node->next, end_index--)
308 if (node->h.hashcode == hashcode
310 ? equals (elt, node->value)
311 : elt == node->value))
313 /* The matches must have all been at indices < start_index or
320 /* Look whether first_match's index is < start_index. */
321 for (node = list->root.next; node != &list->root; node = node->next)
323 if (node == first_match)
325 if (--start_index == 0)
328 if (end_index < list->count)
329 /* Look whether first_match's index is >= end_index. */
331 end_index = list->count - end_index;
332 for (node = list->root.prev; ; node = node->prev)
334 if (node == first_match)
336 if (--end_index == 0)
344 gl_listelement_equals_fn equals = list->base.equals_fn;
345 gl_list_node_t node = list->root.next;
347 end_index -= start_index;
348 for (; start_index > 0; start_index--)
353 for (; end_index > 0; node = node->next, end_index--)
354 if (equals (elt, node->value))
359 for (; end_index > 0; node = node->next, end_index--)
360 if (elt == node->value)
369 gl_linked_indexof_from_to (gl_list_t list, size_t start_index, size_t end_index,
372 size_t count = list->count;
374 if (!(start_index <= end_index && end_index <= count))
375 /* Invalid arguments. */
379 /* Here the hash table doesn't help much. It only allows us to minimize
380 the number of equals() calls, by looking up first the node and then
383 (list->base.hashcode_fn != NULL
384 ? list->base.hashcode_fn (elt)
385 : (size_t)(uintptr_t) elt);
386 size_t bucket = hashcode % list->table_size;
387 gl_listelement_equals_fn equals = list->base.equals_fn;
390 /* First step: Look up the node. */
391 if (!list->base.allow_duplicates)
393 /* Look for the first match in the hash bucket. */
394 for (node = (gl_list_node_t) list->table[bucket];
396 node = (gl_list_node_t) node->h.hash_next)
397 if (node->h.hashcode == hashcode
399 ? equals (elt, node->value)
400 : elt == node->value))
405 /* Look whether there is more than one match in the hash bucket. */
406 bool multiple_matches = false;
407 gl_list_node_t first_match = NULL;
409 for (node = (gl_list_node_t) list->table[bucket];
411 node = (gl_list_node_t) node->h.hash_next)
412 if (node->h.hashcode == hashcode
414 ? equals (elt, node->value)
415 : elt == node->value))
417 if (first_match == NULL)
421 multiple_matches = true;
425 if (multiple_matches)
427 /* We need the match with the smallest index. But we don't have
428 a fast mapping node -> index. So we have to walk the list. */
432 node = list->root.next;
433 for (; start_index > 0; start_index--)
438 node = node->next, index++)
439 if (node->h.hashcode == hashcode
441 ? equals (elt, node->value)
442 : elt == node->value))
444 /* The matches must have all been at indices < start_index or
451 /* Second step: Look up the index of the node. */
458 for (; node->prev != &list->root; node = node->prev)
461 if (index >= start_index && index < end_index)
467 gl_listelement_equals_fn equals = list->base.equals_fn;
468 size_t index = start_index;
469 gl_list_node_t node = list->root.next;
471 for (; start_index > 0; start_index--)
478 node = node->next, index++)
479 if (equals (elt, node->value))
486 node = node->next, index++)
487 if (elt == node->value)
495 static gl_list_node_t
496 gl_linked_add_first (gl_list_t list, const void *elt)
498 gl_list_node_t node = XMALLOC (struct gl_list_node_impl);
500 ASYNCSAFE(const void *) node->value = elt;
503 (list->base.hashcode_fn != NULL
504 ? list->base.hashcode_fn (node->value)
505 : (size_t)(uintptr_t) node->value);
507 /* Add node to the hash table. */
508 add_to_bucket (list, node);
511 /* Add node to the list. */
512 node->prev = &list->root;
513 ASYNCSAFE(gl_list_node_t) node->next = list->root.next;
514 node->next->prev = node;
515 ASYNCSAFE(gl_list_node_t) list->root.next = node;
519 hash_resize_after_add (list);
525 static gl_list_node_t
526 gl_linked_add_last (gl_list_t list, const void *elt)
528 gl_list_node_t node = XMALLOC (struct gl_list_node_impl);
530 ASYNCSAFE(const void *) node->value = elt;
533 (list->base.hashcode_fn != NULL
534 ? list->base.hashcode_fn (node->value)
535 : (size_t)(uintptr_t) node->value);
537 /* Add node to the hash table. */
538 add_to_bucket (list, node);
541 /* Add node to the list. */
542 ASYNCSAFE(gl_list_node_t) node->next = &list->root;
543 node->prev = list->root.prev;
544 ASYNCSAFE(gl_list_node_t) node->prev->next = node;
545 list->root.prev = node;
549 hash_resize_after_add (list);
555 static gl_list_node_t
556 gl_linked_add_before (gl_list_t list, gl_list_node_t node, const void *elt)
558 gl_list_node_t new_node = XMALLOC (struct gl_list_node_impl);
560 ASYNCSAFE(const void *) new_node->value = elt;
562 new_node->h.hashcode =
563 (list->base.hashcode_fn != NULL
564 ? list->base.hashcode_fn (new_node->value)
565 : (size_t)(uintptr_t) new_node->value);
567 /* Add new_node to the hash table. */
568 add_to_bucket (list, new_node);
571 /* Add new_node to the list. */
572 ASYNCSAFE(gl_list_node_t) new_node->next = node;
573 new_node->prev = node->prev;
574 ASYNCSAFE(gl_list_node_t) new_node->prev->next = new_node;
575 node->prev = new_node;
579 hash_resize_after_add (list);
585 static gl_list_node_t
586 gl_linked_add_after (gl_list_t list, gl_list_node_t node, const void *elt)
588 gl_list_node_t new_node = XMALLOC (struct gl_list_node_impl);
590 ASYNCSAFE(const void *) new_node->value = elt;
592 new_node->h.hashcode =
593 (list->base.hashcode_fn != NULL
594 ? list->base.hashcode_fn (new_node->value)
595 : (size_t)(uintptr_t) new_node->value);
597 /* Add new_node to the hash table. */
598 add_to_bucket (list, new_node);
601 /* Add new_node to the list. */
602 new_node->prev = node;
603 ASYNCSAFE(gl_list_node_t) new_node->next = node->next;
604 new_node->next->prev = new_node;
605 ASYNCSAFE(gl_list_node_t) node->next = new_node;
609 hash_resize_after_add (list);
615 static gl_list_node_t
616 gl_linked_add_at (gl_list_t list, size_t position, const void *elt)
618 size_t count = list->count;
619 gl_list_node_t new_node;
621 if (!(position <= count))
622 /* Invalid argument. */
625 new_node = XMALLOC (struct gl_list_node_impl);
626 ASYNCSAFE(const void *) new_node->value = elt;
628 new_node->h.hashcode =
629 (list->base.hashcode_fn != NULL
630 ? list->base.hashcode_fn (new_node->value)
631 : (size_t)(uintptr_t) new_node->value);
633 /* Add new_node to the hash table. */
634 add_to_bucket (list, new_node);
637 /* Add new_node to the list. */
638 if (position <= (count / 2))
643 for (; position > 0; position--)
645 new_node->prev = node;
646 ASYNCSAFE(gl_list_node_t) new_node->next = node->next;
647 new_node->next->prev = new_node;
648 ASYNCSAFE(gl_list_node_t) node->next = new_node;
654 position = count - position;
656 for (; position > 0; position--)
658 ASYNCSAFE(gl_list_node_t) new_node->next = node;
659 new_node->prev = node->prev;
660 ASYNCSAFE(gl_list_node_t) new_node->prev->next = new_node;
661 node->prev = new_node;
666 hash_resize_after_add (list);
673 gl_linked_remove_node (gl_list_t list, gl_list_node_t node)
679 /* Remove node from the hash table. */
680 remove_from_bucket (list, node);
683 /* Remove node from the list. */
687 ASYNCSAFE(gl_list_node_t) prev->next = next;
691 if (list->base.dispose_fn != NULL)
692 list->base.dispose_fn (node->value);
698 gl_linked_remove_at (gl_list_t list, size_t position)
700 size_t count = list->count;
701 gl_list_node_t removed_node;
703 if (!(position < count))
704 /* Invalid argument. */
706 /* Here we know count > 0. */
707 if (position <= ((count - 1) / 2))
710 gl_list_node_t after_removed;
713 for (; position > 0; position--)
715 removed_node = node->next;
716 after_removed = node->next->next;
717 ASYNCSAFE(gl_list_node_t) node->next = after_removed;
718 after_removed->prev = node;
723 gl_list_node_t before_removed;
725 position = count - 1 - position;
727 for (; position > 0; position--)
729 removed_node = node->prev;
730 before_removed = node->prev->prev;
731 node->prev = before_removed;
732 ASYNCSAFE(gl_list_node_t) before_removed->next = node;
735 remove_from_bucket (list, removed_node);
739 if (list->base.dispose_fn != NULL)
740 list->base.dispose_fn (removed_node->value);
746 gl_linked_remove (gl_list_t list, const void *elt)
748 gl_list_node_t node = gl_linked_search_from_to (list, 0, list->count, elt);
751 return gl_linked_remove_node (list, node);
757 gl_linked_list_free (gl_list_t list)
759 gl_listelement_dispose_fn dispose = list->base.dispose_fn;
762 for (node = list->root.next; node != &list->root; )
764 gl_list_node_t next = node->next;
766 dispose (node->value);
776 /* --------------------- gl_list_iterator_t Data Type --------------------- */
778 static gl_list_iterator_t
779 gl_linked_iterator (gl_list_t list)
781 gl_list_iterator_t result;
783 result.vtable = list->base.vtable;
785 result.p = list->root.next;
786 result.q = &list->root;
796 static gl_list_iterator_t
797 gl_linked_iterator_from_to (gl_list_t list,
798 size_t start_index, size_t end_index)
800 gl_list_iterator_t result;
803 if (!(start_index <= end_index && end_index <= list->count))
804 /* Invalid arguments. */
806 result.vtable = list->base.vtable;
809 n2 = end_index - start_index;
810 n3 = list->count - end_index;
811 /* Find the maximum among n1, n2, n3, so as to reduce the number of
812 loop iterations to n1 + n2 + n3 - max(n1,n2,n3). */
813 if (n1 > n2 && n1 > n3)
815 /* n1 is the maximum, use n2 and n3. */
820 for (i = n3; i > 0; i--)
823 for (i = n2; i > 0; i--)
829 /* n2 is the maximum, use n1 and n3. */
833 node = list->root.next;
834 for (i = n1; i > 0; i--)
839 for (i = n3; i > 0; i--)
845 /* n3 is the maximum, use n1 and n2. */
849 node = list->root.next;
850 for (i = n1; i > 0; i--)
853 for (i = n2; i > 0; i--)
868 gl_linked_iterator_next (gl_list_iterator_t *iterator,
869 const void **eltp, gl_list_node_t *nodep)
871 if (iterator->p != iterator->q)
873 gl_list_node_t node = (gl_list_node_t) iterator->p;
877 iterator->p = node->next;
885 gl_linked_iterator_free (gl_list_iterator_t *iterator)
889 /* ---------------------- Sorted gl_list_t Data Type ---------------------- */
891 static gl_list_node_t
892 gl_linked_sortedlist_search (gl_list_t list, gl_listelement_compar_fn compar,
897 for (node = list->root.next; node != &list->root; node = node->next)
899 int cmp = compar (node->value, elt);
909 static gl_list_node_t
910 gl_linked_sortedlist_search_from_to (gl_list_t list,
911 gl_listelement_compar_fn compar,
912 size_t low, size_t high,
915 size_t count = list->count;
917 if (!(low <= high && high <= list->count))
918 /* Invalid arguments. */
924 /* Here we know low < count. */
925 size_t position = low;
928 if (position <= ((count - 1) / 2))
930 node = list->root.next;
931 for (; position > 0; position--)
936 position = count - 1 - position;
937 node = list->root.prev;
938 for (; position > 0; position--)
944 int cmp = compar (node->value, elt);
958 gl_linked_sortedlist_indexof (gl_list_t list, gl_listelement_compar_fn compar,
964 for (node = list->root.next, index = 0;
966 node = node->next, index++)
968 int cmp = compar (node->value, elt);
979 gl_linked_sortedlist_indexof_from_to (gl_list_t list,
980 gl_listelement_compar_fn compar,
981 size_t low, size_t high,
984 size_t count = list->count;
986 if (!(low <= high && high <= list->count))
987 /* Invalid arguments. */
993 /* Here we know low < count. */
995 size_t position = low;
998 if (position <= ((count - 1) / 2))
1000 node = list->root.next;
1001 for (; position > 0; position--)
1006 position = count - 1 - position;
1007 node = list->root.prev;
1008 for (; position > 0; position--)
1014 int cmp = compar (node->value, elt);
1025 return (size_t)(-1);
1028 static gl_list_node_t
1029 gl_linked_sortedlist_add (gl_list_t list, gl_listelement_compar_fn compar,
1032 gl_list_node_t node;
1034 for (node = list->root.next; node != &list->root; node = node->next)
1035 if (compar (node->value, elt) >= 0)
1036 return gl_linked_add_before (list, node, elt);
1037 return gl_linked_add_last (list, elt);
1041 gl_linked_sortedlist_remove (gl_list_t list, gl_listelement_compar_fn compar,
1044 gl_list_node_t node;
1046 for (node = list->root.next; node != &list->root; node = node->next)
1048 int cmp = compar (node->value, elt);
1053 return gl_linked_remove_node (list, node);