1 /* Sequential list data type implemented by a linked list.
2 Copyright (C) 2006 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 bool allow_duplicates)
46 struct gl_list_impl *list = XMALLOC (struct gl_list_impl);
48 list->base.vtable = implementation;
49 list->base.equals_fn = equals_fn;
50 list->base.hashcode_fn = hashcode_fn;
51 list->base.allow_duplicates = allow_duplicates;
53 list->table_size = 11;
54 list->table = XCALLOC (list->table_size, gl_hash_entry_t);
56 list->root.next = &list->root;
57 list->root.prev = &list->root;
64 gl_linked_create (gl_list_implementation_t implementation,
65 gl_listelement_equals_fn equals_fn,
66 gl_listelement_hashcode_fn hashcode_fn,
67 bool allow_duplicates,
68 size_t count, const void **contents)
70 struct gl_list_impl *list = XMALLOC (struct gl_list_impl);
73 list->base.vtable = implementation;
74 list->base.equals_fn = equals_fn;
75 list->base.hashcode_fn = hashcode_fn;
76 list->base.allow_duplicates = allow_duplicates;
79 size_t estimate = xsum (count, count / 2); /* 1.5 * count */
82 list->table_size = next_prime (estimate);
83 list->table = XCALLOC (list->table_size, gl_hash_entry_t);
88 for (; count > 0; contents++, count--)
90 gl_list_node_t node = XMALLOC (struct gl_list_node_impl);
92 node->value = *contents;
95 (list->base.hashcode_fn != NULL
96 ? list->base.hashcode_fn (node->value)
97 : (size_t)(uintptr_t) node->value);
99 /* Add node to the hash table. */
100 add_to_bucket (list, node);
103 /* Add node to the list. */
108 tail->next = &list->root;
109 list->root.prev = tail;
115 gl_linked_size (gl_list_t list)
121 gl_linked_node_value (gl_list_t list, gl_list_node_t node)
126 static gl_list_node_t
127 gl_linked_next_node (gl_list_t list, gl_list_node_t node)
129 return (node->next != &list->root ? node->next : NULL);
132 static gl_list_node_t
133 gl_linked_previous_node (gl_list_t list, gl_list_node_t node)
135 return (node->prev != &list->root ? node->prev : NULL);
139 gl_linked_get_at (gl_list_t list, size_t position)
141 size_t count = list->count;
144 if (!(position < count))
145 /* Invalid argument. */
147 /* Here we know count > 0. */
148 if (position <= ((count - 1) / 2))
150 node = list->root.next;
151 for (; position > 0; position--)
156 position = count - 1 - position;
157 node = list->root.prev;
158 for (; position > 0; position--)
164 static gl_list_node_t
165 gl_linked_set_at (gl_list_t list, size_t position, const void *elt)
167 size_t count = list->count;
170 if (!(position < count))
171 /* Invalid argument. */
173 /* Here we know count > 0. */
174 if (position <= ((count - 1) / 2))
176 node = list->root.next;
177 for (; position > 0; position--)
182 position = count - 1 - position;
183 node = list->root.prev;
184 for (; position > 0; position--)
188 if (elt != node->value)
190 size_t new_hashcode =
191 (list->base.hashcode_fn != NULL
192 ? list->base.hashcode_fn (elt)
193 : (size_t)(uintptr_t) elt);
195 if (new_hashcode != node->h.hashcode)
197 remove_from_bucket (list, node);
199 node->h.hashcode = new_hashcode;
200 add_to_bucket (list, node);
211 static gl_list_node_t
212 gl_linked_search_from_to (gl_list_t list, size_t start_index, size_t end_index,
215 size_t count = list->count;
217 if (!(start_index <= end_index && end_index <= count))
218 /* Invalid arguments. */
223 (list->base.hashcode_fn != NULL
224 ? list->base.hashcode_fn (elt)
225 : (size_t)(uintptr_t) elt);
226 size_t bucket = hashcode % list->table_size;
227 gl_listelement_equals_fn equals = list->base.equals_fn;
229 if (!list->base.allow_duplicates)
231 /* Look for the first match in the hash bucket. */
232 gl_list_node_t found = NULL;
235 for (node = (gl_list_node_t) list->table[bucket];
237 node = (gl_list_node_t) node->h.hash_next)
238 if (node->h.hashcode == hashcode
240 ? equals (elt, node->value)
241 : elt == node->value))
247 /* Look whether found's index is < start_index. */
248 for (node = list->root.next; ; node = node->next)
252 if (--start_index == 0)
255 if (end_index < count)
256 /* Look whether found's index is >= end_index. */
258 end_index = count - end_index;
259 for (node = list->root.prev; ; node = node->prev)
263 if (--end_index == 0)
271 /* Look whether there is more than one match in the hash bucket. */
272 bool multiple_matches = false;
273 gl_list_node_t first_match = NULL;
276 for (node = (gl_list_node_t) list->table[bucket];
278 node = (gl_list_node_t) node->h.hash_next)
279 if (node->h.hashcode == hashcode
281 ? equals (elt, node->value)
282 : elt == node->value))
284 if (first_match == NULL)
288 multiple_matches = true;
292 if (multiple_matches)
294 /* We need the match with the smallest index. But we don't have
295 a fast mapping node -> index. So we have to walk the list. */
296 end_index -= start_index;
297 node = list->root.next;
298 for (; start_index > 0; start_index--)
303 node = node->next, end_index--)
304 if (node->h.hashcode == hashcode
306 ? equals (elt, node->value)
307 : elt == node->value))
309 /* The matches must have all been at indices < start_index or
316 /* Look whether first_match's index is < start_index. */
317 for (node = list->root.next; node != &list->root; node = node->next)
319 if (node == first_match)
321 if (--start_index == 0)
324 if (end_index < list->count)
325 /* Look whether first_match's index is >= end_index. */
327 end_index = list->count - end_index;
328 for (node = list->root.prev; ; node = node->prev)
330 if (node == first_match)
332 if (--end_index == 0)
340 gl_listelement_equals_fn equals = list->base.equals_fn;
341 gl_list_node_t node = list->root.next;
343 end_index -= start_index;
344 for (; start_index > 0; start_index--)
349 for (; end_index > 0; node = node->next, end_index--)
350 if (equals (elt, node->value))
355 for (; end_index > 0; node = node->next, end_index--)
356 if (elt == node->value)
365 gl_linked_indexof_from_to (gl_list_t list, size_t start_index, size_t end_index,
368 size_t count = list->count;
370 if (!(start_index <= end_index && end_index <= count))
371 /* Invalid arguments. */
375 /* Here the hash table doesn't help much. It only allows us to minimize
376 the number of equals() calls, by looking up first the node and then
379 (list->base.hashcode_fn != NULL
380 ? list->base.hashcode_fn (elt)
381 : (size_t)(uintptr_t) elt);
382 size_t bucket = hashcode % list->table_size;
383 gl_listelement_equals_fn equals = list->base.equals_fn;
386 /* First step: Look up the node. */
387 if (!list->base.allow_duplicates)
389 /* Look for the first match in the hash bucket. */
390 for (node = (gl_list_node_t) list->table[bucket];
392 node = (gl_list_node_t) node->h.hash_next)
393 if (node->h.hashcode == hashcode
395 ? equals (elt, node->value)
396 : elt == node->value))
401 /* Look whether there is more than one match in the hash bucket. */
402 bool multiple_matches = false;
403 gl_list_node_t first_match = NULL;
405 for (node = (gl_list_node_t) list->table[bucket];
407 node = (gl_list_node_t) node->h.hash_next)
408 if (node->h.hashcode == hashcode
410 ? equals (elt, node->value)
411 : elt == node->value))
413 if (first_match == NULL)
417 multiple_matches = true;
421 if (multiple_matches)
423 /* We need the match with the smallest index. But we don't have
424 a fast mapping node -> index. So we have to walk the list. */
428 node = list->root.next;
429 for (; start_index > 0; start_index--)
434 node = node->next, index++)
435 if (node->h.hashcode == hashcode
437 ? equals (elt, node->value)
438 : elt == node->value))
440 /* The matches must have all been at indices < start_index or
447 /* Second step: Look up the index of the node. */
454 for (; node->prev != &list->root; node = node->prev)
457 if (index >= start_index && index < end_index)
463 gl_listelement_equals_fn equals = list->base.equals_fn;
464 size_t index = start_index;
465 gl_list_node_t node = list->root.next;
467 for (; start_index > 0; start_index--)
474 node = node->next, index++)
475 if (equals (elt, node->value))
482 node = node->next, index++)
483 if (elt == node->value)
491 static gl_list_node_t
492 gl_linked_add_first (gl_list_t list, const void *elt)
494 gl_list_node_t node = XMALLOC (struct gl_list_node_impl);
496 ASYNCSAFE(const void *) node->value = elt;
499 (list->base.hashcode_fn != NULL
500 ? list->base.hashcode_fn (node->value)
501 : (size_t)(uintptr_t) node->value);
503 /* Add node to the hash table. */
504 add_to_bucket (list, node);
507 /* Add node to the list. */
508 node->prev = &list->root;
509 ASYNCSAFE(gl_list_node_t) node->next = list->root.next;
510 node->next->prev = node;
511 ASYNCSAFE(gl_list_node_t) list->root.next = node;
515 hash_resize_after_add (list);
521 static gl_list_node_t
522 gl_linked_add_last (gl_list_t list, const void *elt)
524 gl_list_node_t node = XMALLOC (struct gl_list_node_impl);
526 ASYNCSAFE(const void *) node->value = elt;
529 (list->base.hashcode_fn != NULL
530 ? list->base.hashcode_fn (node->value)
531 : (size_t)(uintptr_t) node->value);
533 /* Add node to the hash table. */
534 add_to_bucket (list, node);
537 /* Add node to the list. */
538 ASYNCSAFE(gl_list_node_t) node->next = &list->root;
539 node->prev = list->root.prev;
540 ASYNCSAFE(gl_list_node_t) node->prev->next = node;
541 list->root.prev = node;
545 hash_resize_after_add (list);
551 static gl_list_node_t
552 gl_linked_add_before (gl_list_t list, gl_list_node_t node, const void *elt)
554 gl_list_node_t new_node = XMALLOC (struct gl_list_node_impl);
556 ASYNCSAFE(const void *) new_node->value = elt;
558 new_node->h.hashcode =
559 (list->base.hashcode_fn != NULL
560 ? list->base.hashcode_fn (new_node->value)
561 : (size_t)(uintptr_t) new_node->value);
563 /* Add new_node to the hash table. */
564 add_to_bucket (list, new_node);
567 /* Add new_node to the list. */
568 ASYNCSAFE(gl_list_node_t) new_node->next = node;
569 new_node->prev = node->prev;
570 ASYNCSAFE(gl_list_node_t) new_node->prev->next = new_node;
571 node->prev = new_node;
575 hash_resize_after_add (list);
581 static gl_list_node_t
582 gl_linked_add_after (gl_list_t list, gl_list_node_t node, const void *elt)
584 gl_list_node_t new_node = XMALLOC (struct gl_list_node_impl);
586 ASYNCSAFE(const void *) new_node->value = elt;
588 new_node->h.hashcode =
589 (list->base.hashcode_fn != NULL
590 ? list->base.hashcode_fn (new_node->value)
591 : (size_t)(uintptr_t) new_node->value);
593 /* Add new_node to the hash table. */
594 add_to_bucket (list, new_node);
597 /* Add new_node to the list. */
598 new_node->prev = node;
599 ASYNCSAFE(gl_list_node_t) new_node->next = node->next;
600 new_node->next->prev = new_node;
601 ASYNCSAFE(gl_list_node_t) node->next = new_node;
605 hash_resize_after_add (list);
611 static gl_list_node_t
612 gl_linked_add_at (gl_list_t list, size_t position, const void *elt)
614 size_t count = list->count;
615 gl_list_node_t new_node;
617 if (!(position <= count))
618 /* Invalid argument. */
621 new_node = XMALLOC (struct gl_list_node_impl);
622 ASYNCSAFE(const void *) new_node->value = elt;
624 new_node->h.hashcode =
625 (list->base.hashcode_fn != NULL
626 ? list->base.hashcode_fn (new_node->value)
627 : (size_t)(uintptr_t) new_node->value);
629 /* Add new_node to the hash table. */
630 add_to_bucket (list, new_node);
633 /* Add new_node to the list. */
634 if (position <= (count / 2))
639 for (; position > 0; position--)
641 new_node->prev = node;
642 ASYNCSAFE(gl_list_node_t) new_node->next = node->next;
643 new_node->next->prev = new_node;
644 ASYNCSAFE(gl_list_node_t) node->next = new_node;
650 position = count - position;
652 for (; position > 0; position--)
654 ASYNCSAFE(gl_list_node_t) new_node->next = node;
655 new_node->prev = node->prev;
656 ASYNCSAFE(gl_list_node_t) new_node->prev->next = new_node;
657 node->prev = new_node;
662 hash_resize_after_add (list);
669 gl_linked_remove_node (gl_list_t list, gl_list_node_t node)
675 /* Remove node from the hash table. */
676 remove_from_bucket (list, node);
679 /* Remove node from the list. */
683 ASYNCSAFE(gl_list_node_t) prev->next = next;
692 gl_linked_remove_at (gl_list_t list, size_t position)
694 size_t count = list->count;
695 gl_list_node_t removed_node;
697 if (!(position < count))
698 /* Invalid argument. */
700 /* Here we know count > 0. */
701 if (position <= ((count - 1) / 2))
704 gl_list_node_t after_removed;
707 for (; position > 0; position--)
709 removed_node = node->next;
710 after_removed = node->next->next;
711 ASYNCSAFE(gl_list_node_t) node->next = after_removed;
712 after_removed->prev = node;
717 gl_list_node_t before_removed;
719 position = count - 1 - position;
721 for (; position > 0; position--)
723 removed_node = node->prev;
724 before_removed = node->prev->prev;
725 node->prev = before_removed;
726 ASYNCSAFE(gl_list_node_t) before_removed->next = node;
729 remove_from_bucket (list, removed_node);
738 gl_linked_remove (gl_list_t list, const void *elt)
740 gl_list_node_t node = gl_linked_search_from_to (list, 0, list->count, elt);
743 return gl_linked_remove_node (list, node);
749 gl_linked_list_free (gl_list_t list)
753 for (node = list->root.next; node != &list->root; )
755 gl_list_node_t next = node->next;
765 /* --------------------- gl_list_iterator_t Data Type --------------------- */
767 static gl_list_iterator_t
768 gl_linked_iterator (gl_list_t list)
770 gl_list_iterator_t result;
772 result.vtable = list->base.vtable;
774 result.p = list->root.next;
775 result.q = &list->root;
785 static gl_list_iterator_t
786 gl_linked_iterator_from_to (gl_list_t list,
787 size_t start_index, size_t end_index)
789 gl_list_iterator_t result;
792 if (!(start_index <= end_index && end_index <= list->count))
793 /* Invalid arguments. */
795 result.vtable = list->base.vtable;
798 n2 = end_index - start_index;
799 n3 = list->count - end_index;
800 /* Find the maximum among n1, n2, n3, so as to reduce the number of
801 loop iterations to n1 + n2 + n3 - max(n1,n2,n3). */
802 if (n1 > n2 && n1 > n3)
804 /* n1 is the maximum, use n2 and n3. */
809 for (i = n3; i > 0; i--)
812 for (i = n2; i > 0; i--)
818 /* n2 is the maximum, use n1 and n3. */
822 node = list->root.next;
823 for (i = n1; i > 0; i--)
828 for (i = n3; i > 0; i--)
834 /* n3 is the maximum, use n1 and n2. */
838 node = list->root.next;
839 for (i = n1; i > 0; i--)
842 for (i = n2; i > 0; i--)
857 gl_linked_iterator_next (gl_list_iterator_t *iterator,
858 const void **eltp, gl_list_node_t *nodep)
860 if (iterator->p != iterator->q)
862 gl_list_node_t node = (gl_list_node_t) iterator->p;
866 iterator->p = node->next;
874 gl_linked_iterator_free (gl_list_iterator_t *iterator)
878 /* ---------------------- Sorted gl_list_t Data Type ---------------------- */
880 static gl_list_node_t
881 gl_linked_sortedlist_search (gl_list_t list, gl_listelement_compar_fn compar,
886 for (node = list->root.next; node != &list->root; node = node->next)
888 int cmp = compar (node->value, elt);
898 static gl_list_node_t
899 gl_linked_sortedlist_search_from_to (gl_list_t list,
900 gl_listelement_compar_fn compar,
901 size_t low, size_t high,
904 size_t count = list->count;
906 if (!(low <= high && high <= list->count))
907 /* Invalid arguments. */
913 /* Here we know low < count. */
914 size_t position = low;
917 if (position <= ((count - 1) / 2))
919 node = list->root.next;
920 for (; position > 0; position--)
925 position = count - 1 - position;
926 node = list->root.prev;
927 for (; position > 0; position--)
933 int cmp = compar (node->value, elt);
947 gl_linked_sortedlist_indexof (gl_list_t list, gl_listelement_compar_fn compar,
953 for (node = list->root.next, index = 0;
955 node = node->next, index++)
957 int cmp = compar (node->value, elt);
968 gl_linked_sortedlist_indexof_from_to (gl_list_t list,
969 gl_listelement_compar_fn compar,
970 size_t low, size_t high,
973 size_t count = list->count;
975 if (!(low <= high && high <= list->count))
976 /* Invalid arguments. */
982 /* Here we know low < count. */
984 size_t position = low;
987 if (position <= ((count - 1) / 2))
989 node = list->root.next;
990 for (; position > 0; position--)
995 position = count - 1 - position;
996 node = list->root.prev;
997 for (; position > 0; position--)
1003 int cmp = compar (node->value, elt);
1014 return (size_t)(-1);
1017 static gl_list_node_t
1018 gl_linked_sortedlist_add (gl_list_t list, gl_listelement_compar_fn compar,
1021 gl_list_node_t node;
1023 for (node = list->root.next; node != &list->root; node = node->next)
1024 if (compar (node->value, elt) >= 0)
1025 return gl_linked_add_before (list, node, elt);
1026 return gl_linked_add_last (list, elt);
1030 gl_linked_sortedlist_remove (gl_list_t list, gl_listelement_compar_fn compar,
1033 gl_list_node_t node;
1035 for (node = list->root.next; node != &list->root; node = node->next)
1037 int cmp = compar (node->value, elt);
1042 return gl_linked_remove_node (list, node);