From: Bruno Haible Date: Thu, 27 Jul 2006 12:09:06 +0000 (+0000) Subject: gnulib module 'linkedhash-list'. X-Git-Tag: 0.16.x-branchpoint~319 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e684cf62864413ebd4130e2ed3342a1e63718e2e;p=thirdparty%2Fgettext.git gnulib module 'linkedhash-list'. --- diff --git a/gettext-tools/lib/gl_anyhash_list1.h b/gettext-tools/lib/gl_anyhash_list1.h new file mode 100644 index 000000000..1f1351e7a --- /dev/null +++ b/gettext-tools/lib/gl_anyhash_list1.h @@ -0,0 +1,28 @@ +/* Sequential list data type implemented by a hash table with another list. + Copyright (C) 2006 Free Software Foundation, Inc. + Written by Bruno Haible , 2006. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Common code of + gl_linkedhash_list.c, gl_avltreehash_list.c, gl_rbtreehash_list.c. */ + +/* Hash table entry. */ +struct gl_hash_entry +{ + struct gl_hash_entry *hash_next; /* chain of entries in same bucket */ + size_t hashcode; /* cache of values' common hash code */ +}; +typedef struct gl_hash_entry * gl_hash_entry_t; diff --git a/gettext-tools/lib/gl_anyhash_list2.h b/gettext-tools/lib/gl_anyhash_list2.h new file mode 100644 index 000000000..eb8d6e977 --- /dev/null +++ b/gettext-tools/lib/gl_anyhash_list2.h @@ -0,0 +1,128 @@ +/* Sequential list data type implemented by a hash table with another list. + Copyright (C) 2006 Free Software Foundation, Inc. + Written by Bruno Haible , 2006. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Common code of + gl_linkedhash_list.c, gl_avltreehash_list.c, gl_rbtreehash_list.c. */ + +/* Array of primes, approximately in steps of factor 1.2. + This table was computed by executing the Common Lisp expression + (dotimes (i 244) (format t "nextprime(~D)~%" (ceiling (expt 1.2d0 i)))) + and feeding the result to PARI/gp. */ +static const size_t primes[] = + { + 11, 13, 17, 19, 23, 29, 37, 41, 47, 59, 67, 83, 97, 127, 139, 167, 199, + 239, 293, 347, 419, 499, 593, 709, 853, 1021, 1229, 1471, 1777, 2129, 2543, + 3049, 3659, 4391, 5273, 6323, 7589, 9103, 10937, 13109, 15727, 18899, + 22651, 27179, 32609, 39133, 46957, 56359, 67619, 81157, 97369, 116849, + 140221, 168253, 201907, 242309, 290761, 348889, 418667, 502409, 602887, + 723467, 868151, 1041779, 1250141, 1500181, 1800191, 2160233, 2592277, + 3110741, 3732887, 4479463, 5375371, 6450413, 7740517, 9288589, 11146307, + 13375573, 16050689, 19260817, 23112977, 27735583, 33282701, 39939233, + 47927081, 57512503, 69014987, 82818011, 99381577, 119257891, 143109469, + 171731387, 206077643, 247293161, 296751781, 356102141, 427322587, + 512787097, 615344489, 738413383, 886096061, 1063315271, 1275978331, + 1531174013, 1837408799, 2204890543UL, 2645868653UL, 3175042391UL, + 3810050851UL, +#if SIZE_MAX > 4294967295UL + 4572061027UL, 5486473229UL, 6583767889UL, 7900521449UL, 9480625733UL, + 11376750877UL, 13652101063UL, 16382521261UL, 19659025513UL, 23590830631UL, + 28308996763UL, 33970796089UL, 40764955463UL, 48917946377UL, 58701535657UL, + 70441842749UL, 84530211301UL, 101436253561UL, 121723504277UL, + 146068205131UL, 175281846149UL, 210338215379UL, 252405858521UL, + 302887030151UL, 363464436191UL, 436157323417UL, 523388788231UL, + 628066545713UL, 753679854847UL, 904415825857UL, 1085298991109UL, + 1302358789181UL, 1562830547009UL, 1875396656429UL, 2250475987709UL, + 2700571185239UL, 3240685422287UL, 3888822506759UL, 4666587008147UL, + 5599904409713UL, 6719885291641UL, 8063862349969UL, 9676634819959UL, + 11611961783951UL, 13934354140769UL, 16721224968907UL, 20065469962669UL, + 24078563955191UL, 28894276746229UL, 34673132095507UL, 41607758514593UL, + 49929310217531UL, 59915172260971UL, 71898206713183UL, 86277848055823UL, + 103533417666967UL, 124240101200359UL, 149088121440451UL, 178905745728529UL, + 214686894874223UL, 257624273849081UL, 309149128618903UL, 370978954342639UL, + 445174745211143UL, 534209694253381UL, 641051633104063UL, 769261959724877UL, + 923114351670013UL, 1107737222003791UL, 1329284666404567UL, + 1595141599685509UL, 1914169919622551UL, 2297003903547091UL, + 2756404684256459UL, 3307685621107757UL, 3969222745329323UL, + 4763067294395177UL, 5715680753274209UL, 6858816903929113UL, + 8230580284714831UL, 9876696341657791UL, 11852035609989371UL, + 14222442731987227UL, 17066931278384657UL, 20480317534061597UL, + 24576381040873903UL, 29491657249048679UL, 35389988698858471UL, + 42467986438630267UL, 50961583726356109UL, 61153900471627387UL, + 73384680565952851UL, 88061616679143347UL, 105673940014972061UL, + 126808728017966413UL, 152170473621559703UL, 182604568345871671UL, + 219125482015045997UL, 262950578418055169UL, 315540694101666193UL, + 378648832921999397UL, 454378599506399233UL, 545254319407679131UL, + 654305183289214771UL, 785166219947057701UL, 942199463936469157UL, + 1130639356723763129UL, 1356767228068515623UL, 1628120673682218619UL, + 1953744808418662409UL, 2344493770102394881UL, 2813392524122873857UL, + 3376071028947448339UL, 4051285234736937517UL, 4861542281684325481UL, + 5833850738021191727UL, 7000620885625427969UL, 8400745062750513217UL, + 10080894075300616261UL, 12097072890360739951UL, 14516487468432885797UL, + 17419784962119465179UL, +#endif + SIZE_MAX /* sentinel, to ensure the search terminates */ + }; + +/* Return a suitable prime >= ESTIMATE. */ +static size_t +next_prime (size_t estimate) +{ + size_t i; + + for (i = 0; i < sizeof (primes) / sizeof (primes[0]); i++) + if (primes[i] >= estimate) + return primes[i]; + return SIZE_MAX; /* not a prime, but better than nothing */ +} + +/* Resize the hash table with a new estimated size. */ +static void +hash_resize (gl_list_t list, size_t estimate) +{ + size_t new_size = next_prime (estimate); + + if (new_size > list->table_size) + { + gl_hash_entry_t *old_table = list->table; + /* Allocate the new table. */ + gl_hash_entry_t *new_table = + (gl_hash_entry_t *) xzalloc (new_size * sizeof (gl_hash_entry_t)); + size_t i; + + /* Iterate through the entries of the old table. */ + for (i = list->table_size; i > 0; ) + { + gl_hash_entry_t node = old_table[--i]; + + while (node != NULL) + { + gl_hash_entry_t next = node->hash_next; + /* Add the entry to the new table. */ + size_t index = node->hashcode % new_size; + node->hash_next = new_table[index]; + new_table[index] = node; + + node = next; + } + } + + list->table = new_table; + list->table_size = new_size; + free (old_table); + } +} diff --git a/gettext-tools/lib/gl_anylinked_list1.h b/gettext-tools/lib/gl_anylinked_list1.h new file mode 100644 index 000000000..988657e5c --- /dev/null +++ b/gettext-tools/lib/gl_anylinked_list1.h @@ -0,0 +1,49 @@ +/* Sequential list data type implemented by a linked list. + Copyright (C) 2006 Free Software Foundation, Inc. + Written by Bruno Haible , 2006. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Common code of gl_linked_list.c and gl_linkedhash_list.c. */ + +/* -------------------------- gl_list_t Data Type -------------------------- */ + +/* Concrete list node implementation, valid for this file only. */ +struct gl_list_node_impl +{ +#if WITH_HASHTABLE + struct gl_hash_entry h; /* hash table entry fields; must be first */ +#endif + struct gl_list_node_impl *next; + struct gl_list_node_impl *prev; + const void *value; +}; + +/* Concrete gl_list_impl type, valid for this file only. */ +struct gl_list_impl +{ + struct gl_list_impl_base base; +#if WITH_HASHTABLE + /* A hash table: managed as an array of collision lists. */ + struct gl_hash_entry **table; + size_t table_size; +#endif + /* A circular list anchored at root. + The first node is = root.next, the last node is = root.prev. + The root's value is unused. */ + struct gl_list_node_impl root; + /* Number of list nodes, excluding the root. */ + size_t count; +}; diff --git a/gettext-tools/lib/gl_anylinked_list2.h b/gettext-tools/lib/gl_anylinked_list2.h new file mode 100644 index 000000000..da4e88168 --- /dev/null +++ b/gettext-tools/lib/gl_anylinked_list2.h @@ -0,0 +1,860 @@ +/* Sequential list data type implemented by a linked list. + Copyright (C) 2006 Free Software Foundation, Inc. + Written by Bruno Haible , 2006. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Common code of gl_linked_list.c and gl_linkedhash_list.c. */ + +/* If the symbol SIGNAL_SAFE_LIST is defined, the code is compiled in such + a way that a gl_list_t data structure may be used from within a signal + handler. The operations allowed in the signal handler are: + gl_list_iterator, gl_list_iterator_next, gl_list_iterator_free. + The list and node fields that are therefore accessed from the signal handler + are: + list->root, node->next, node->value. + We are careful to make modifications to these fields only in an order + that maintains the consistency of the list data structure at any moment, + and we use 'volatile' assignments to prevent the compiler from reordering + such assignments. */ +#ifdef SIGNAL_SAFE_LIST +# define ASYNCSAFE(type) *(volatile type *) +#else +# define ASYNCSAFE(type) +#endif + +/* -------------------------- gl_list_t Data Type -------------------------- */ + +static gl_list_t +gl_linked_create_empty (gl_list_implementation_t implementation, + gl_listelement_equals_fn equals_fn, + gl_listelement_hashcode_fn hashcode_fn, + bool allow_duplicates) +{ + struct gl_list_impl *list = + (struct gl_list_impl *) xmalloc (sizeof (struct gl_list_impl)); + + list->base.vtable = implementation; + list->base.equals_fn = equals_fn; + list->base.hashcode_fn = hashcode_fn; + list->base.allow_duplicates = allow_duplicates; +#if WITH_HASHTABLE + list->table_size = 11; + list->table = + (gl_hash_entry_t *) xzalloc (list->table_size * sizeof (gl_hash_entry_t)); +#endif + list->root.next = &list->root; + list->root.prev = &list->root; + list->count = 0; + + return list; +} + +static gl_list_t +gl_linked_create (gl_list_implementation_t implementation, + gl_listelement_equals_fn equals_fn, + gl_listelement_hashcode_fn hashcode_fn, + bool allow_duplicates, + size_t count, const void **contents) +{ + struct gl_list_impl *list = + (struct gl_list_impl *) xmalloc (sizeof (struct gl_list_impl)); + gl_list_node_t tail; + + list->base.vtable = implementation; + list->base.equals_fn = equals_fn; + list->base.hashcode_fn = hashcode_fn; + list->base.allow_duplicates = allow_duplicates; +#if WITH_HASHTABLE + { + size_t estimate = xsum (count, count / 2); /* 1.5 * count */ + if (estimate < 10) + estimate = 10; + list->table_size = next_prime (estimate); + list->table = + (gl_hash_entry_t *) xzalloc (list->table_size * sizeof (gl_hash_entry_t)); + } +#endif + list->count = count; + tail = &list->root; + for (; count > 0; contents++, count--) + { + gl_list_node_t node = + (struct gl_list_node_impl *) + xmalloc (sizeof (struct gl_list_node_impl)); + + node->value = *contents; +#if WITH_HASHTABLE + node->h.hashcode = + (list->base.hashcode_fn != NULL + ? list->base.hashcode_fn (node->value) + : (size_t)(uintptr_t) node->value); + + /* Add node to the hash table. */ + add_to_bucket (list, node); +#endif + + /* Add node to the list. */ + node->prev = tail; + tail->next = node; + tail = node; + } + tail->next = &list->root; + list->root.prev = tail; + + return list; +} + +static size_t +gl_linked_size (gl_list_t list) +{ + return list->count; +} + +static const void * +gl_linked_node_value (gl_list_t list, gl_list_node_t node) +{ + return node->value; +} + +static gl_list_node_t +gl_linked_next_node (gl_list_t list, gl_list_node_t node) +{ + return (node->next != &list->root ? node->next : NULL); +} + +static gl_list_node_t +gl_linked_previous_node (gl_list_t list, gl_list_node_t node) +{ + return (node->prev != &list->root ? node->prev : NULL); +} + +static const void * +gl_linked_get_at (gl_list_t list, size_t position) +{ + size_t count = list->count; + gl_list_node_t node; + + if (!(position < count)) + /* Invalid argument. */ + abort (); + /* Here we know count > 0. */ + if (position <= ((count - 1) / 2)) + { + node = list->root.next; + for (; position > 0; position--) + node = node->next; + } + else + { + position = count - 1 - position; + node = list->root.prev; + for (; position > 0; position--) + node = node->prev; + } + return node->value; +} + +static gl_list_node_t +gl_linked_set_at (gl_list_t list, size_t position, const void *elt) +{ + size_t count = list->count; + gl_list_node_t node; + + if (!(position < count)) + /* Invalid argument. */ + abort (); + /* Here we know count > 0. */ + if (position <= ((count - 1) / 2)) + { + node = list->root.next; + for (; position > 0; position--) + node = node->next; + } + else + { + position = count - 1 - position; + node = list->root.prev; + for (; position > 0; position--) + node = node->prev; + } +#if WITH_HASHTABLE + if (elt != node->value) + { + size_t new_hashcode = + (list->base.hashcode_fn != NULL + ? list->base.hashcode_fn (elt) + : (size_t)(uintptr_t) elt); + + if (new_hashcode != node->h.hashcode) + { + remove_from_bucket (list, node); + node->value = elt; + node->h.hashcode = new_hashcode; + add_to_bucket (list, node); + } + else + node->value = elt; + } +#else + node->value = elt; +#endif + return node; +} + +static gl_list_node_t +gl_linked_search (gl_list_t list, const void *elt) +{ +#if WITH_HASHTABLE + size_t hashcode = + (list->base.hashcode_fn != NULL + ? list->base.hashcode_fn (elt) + : (size_t)(uintptr_t) elt); + size_t index = hashcode % list->table_size; + gl_listelement_equals_fn equals = list->base.equals_fn; + + if (!list->base.allow_duplicates) + { + /* Look for the first match in the hash bucket. */ + gl_list_node_t node; + + for (node = (gl_list_node_t) list->table[index]; + node != NULL; + node = (gl_list_node_t) node->h.hash_next) + if (node->h.hashcode == hashcode + && (equals != NULL + ? equals (elt, node->value) + : elt == node->value)) + return node; + return NULL; + } + else + { + /* Look whether there is more than one match in the hash bucket. */ + bool multiple_matches = false; + gl_list_node_t first_match = NULL; + gl_list_node_t node; + + for (node = (gl_list_node_t) list->table[index]; + node != NULL; + node = (gl_list_node_t) node->h.hash_next) + if (node->h.hashcode == hashcode + && (equals != NULL + ? equals (elt, node->value) + : elt == node->value)) + { + if (first_match == NULL) + first_match = node; + else + { + multiple_matches = true; + break; + } + } + if (!multiple_matches) + return first_match; + else + { + /* We need the match with the smallest index. But we don't have + a fast mapping node -> index. So we have to walk the list. */ + for (node = list->root.next; node != &list->root; node = node->next) + if (node->h.hashcode == hashcode + && (equals != NULL + ? equals (elt, node->value) + : elt == node->value)) + return node; + /* We know there are at least two matches. */ + abort (); + } + } +#else + gl_listelement_equals_fn equals = list->base.equals_fn; + gl_list_node_t node; + + if (equals != NULL) + { + for (node = list->root.next; node != &list->root; node = node->next) + if (equals (elt, node->value)) + return node; + } + else + { + for (node = list->root.next; node != &list->root; node = node->next) + if (elt == node->value) + return node; + } + return NULL; +#endif +} + +static size_t +gl_linked_indexof (gl_list_t list, const void *elt) +{ +#if WITH_HASHTABLE + /* Here the hash table doesn't help much. It only allows us to minimize + the number of equals() calls, by looking up first the node and then + its index. */ + size_t hashcode = + (list->base.hashcode_fn != NULL + ? list->base.hashcode_fn (elt) + : (size_t)(uintptr_t) elt); + size_t index = hashcode % list->table_size; + gl_listelement_equals_fn equals = list->base.equals_fn; + gl_list_node_t node; + + /* First step: Look up the node. */ + if (!list->base.allow_duplicates) + { + /* Look for the first match in the hash bucket. */ + for (node = (gl_list_node_t) list->table[index]; + node != NULL; + node = (gl_list_node_t) node->h.hash_next) + if (node->h.hashcode == hashcode + && (equals != NULL + ? equals (elt, node->value) + : elt == node->value)) + break; + } + else + { + /* Look whether there is more than one match in the hash bucket. */ + bool multiple_matches = false; + gl_list_node_t first_match = NULL; + + for (node = (gl_list_node_t) list->table[index]; + node != NULL; + node = (gl_list_node_t) node->h.hash_next) + if (node->h.hashcode == hashcode + && (equals != NULL + ? equals (elt, node->value) + : elt == node->value)) + { + if (first_match == NULL) + first_match = node; + else + { + multiple_matches = true; + break; + } + } + if (multiple_matches) + { + /* We need the match with the smallest index. But we don't have + a fast mapping node -> index. So we have to walk the list. */ + size_t index; + + for (node = list->root.next, index = 0; + node != &list->root; + node = node->next, index++) + if (node->h.hashcode == hashcode + && (equals != NULL + ? equals (elt, node->value) + : elt == node->value)) + return index; + /* We know there are at least two matches. */ + abort (); + } + node = first_match; + } + + /* Second step: Look up the index of the node. */ + if (node == NULL) + return (size_t)(-1); + else + { + size_t index = 0; + + for (; node->prev != &list->root; node = node->prev) + index++; + + return index; + } +#else + gl_listelement_equals_fn equals = list->base.equals_fn; + gl_list_node_t node; + + if (equals != NULL) + { + size_t index; + for (node = list->root.next, index = 0; + node != &list->root; + node = node->next, index++) + if (equals (elt, node->value)) + return index; + } + else + { + size_t index; + for (node = list->root.next, index = 0; + node != &list->root; + node = node->next, index++) + if (elt == node->value) + return index; + } + return (size_t)(-1); +#endif +} + +static gl_list_node_t +gl_linked_add_first (gl_list_t list, const void *elt) +{ + gl_list_node_t node = + (struct gl_list_node_impl *) xmalloc (sizeof (struct gl_list_node_impl)); + + ASYNCSAFE(const void *) node->value = elt; +#if WITH_HASHTABLE + node->h.hashcode = + (list->base.hashcode_fn != NULL + ? list->base.hashcode_fn (node->value) + : (size_t)(uintptr_t) node->value); + + /* Add node to the hash table. */ + add_to_bucket (list, node); +#endif + + /* Add node to the list. */ + node->prev = &list->root; + ASYNCSAFE(gl_list_node_t) node->next = list->root.next; + node->next->prev = node; + ASYNCSAFE(gl_list_node_t) list->root.next = node; + list->count++; + +#if WITH_HASHTABLE + hash_resize_after_add (list); +#endif + + return node; +} + +static gl_list_node_t +gl_linked_add_last (gl_list_t list, const void *elt) +{ + gl_list_node_t node = + (struct gl_list_node_impl *) xmalloc (sizeof (struct gl_list_node_impl)); + + ASYNCSAFE(const void *) node->value = elt; +#if WITH_HASHTABLE + node->h.hashcode = + (list->base.hashcode_fn != NULL + ? list->base.hashcode_fn (node->value) + : (size_t)(uintptr_t) node->value); + + /* Add node to the hash table. */ + add_to_bucket (list, node); +#endif + + /* Add node to the list. */ + ASYNCSAFE(gl_list_node_t) node->next = &list->root; + node->prev = list->root.prev; + ASYNCSAFE(gl_list_node_t) node->prev->next = node; + list->root.prev = node; + list->count++; + +#if WITH_HASHTABLE + hash_resize_after_add (list); +#endif + + return node; +} + +static gl_list_node_t +gl_linked_add_before (gl_list_t list, gl_list_node_t node, const void *elt) +{ + gl_list_node_t new_node = + (struct gl_list_node_impl *) xmalloc (sizeof (struct gl_list_node_impl)); + + ASYNCSAFE(const void *) new_node->value = elt; +#if WITH_HASHTABLE + new_node->h.hashcode = + (list->base.hashcode_fn != NULL + ? list->base.hashcode_fn (new_node->value) + : (size_t)(uintptr_t) new_node->value); + + /* Add new_node to the hash table. */ + add_to_bucket (list, new_node); +#endif + + /* Add new_node to the list. */ + ASYNCSAFE(gl_list_node_t) new_node->next = node; + new_node->prev = node->prev; + ASYNCSAFE(gl_list_node_t) new_node->prev->next = new_node; + node->prev = new_node; + list->count++; + +#if WITH_HASHTABLE + hash_resize_after_add (list); +#endif + + return new_node; +} + +static gl_list_node_t +gl_linked_add_after (gl_list_t list, gl_list_node_t node, const void *elt) +{ + gl_list_node_t new_node = + (struct gl_list_node_impl *) xmalloc (sizeof (struct gl_list_node_impl)); + + ASYNCSAFE(const void *) new_node->value = elt; +#if WITH_HASHTABLE + new_node->h.hashcode = + (list->base.hashcode_fn != NULL + ? list->base.hashcode_fn (new_node->value) + : (size_t)(uintptr_t) new_node->value); + + /* Add new_node to the hash table. */ + add_to_bucket (list, new_node); +#endif + + /* Add new_node to the list. */ + new_node->prev = node; + ASYNCSAFE(gl_list_node_t) new_node->next = node->next; + new_node->next->prev = new_node; + ASYNCSAFE(gl_list_node_t) node->next = new_node; + list->count++; + +#if WITH_HASHTABLE + hash_resize_after_add (list); +#endif + + return new_node; +} + +static gl_list_node_t +gl_linked_add_at (gl_list_t list, size_t position, const void *elt) +{ + size_t count = list->count; + gl_list_node_t new_node; + + if (!(position <= count)) + /* Invalid argument. */ + abort (); + + new_node = + (struct gl_list_node_impl *) xmalloc (sizeof (struct gl_list_node_impl)); + ASYNCSAFE(const void *) new_node->value = elt; +#if WITH_HASHTABLE + new_node->h.hashcode = + (list->base.hashcode_fn != NULL + ? list->base.hashcode_fn (new_node->value) + : (size_t)(uintptr_t) new_node->value); + + /* Add new_node to the hash table. */ + add_to_bucket (list, new_node); +#endif + + /* Add new_node to the list. */ + if (position <= (count / 2)) + { + gl_list_node_t node; + + node = &list->root; + for (; position > 0; position--) + node = node->next; + new_node->prev = node; + ASYNCSAFE(gl_list_node_t) new_node->next = node->next; + new_node->next->prev = new_node; + ASYNCSAFE(gl_list_node_t) node->next = new_node; + } + else + { + gl_list_node_t node; + + position = count - position; + node = &list->root; + for (; position > 0; position--) + node = node->prev; + ASYNCSAFE(gl_list_node_t) new_node->next = node; + new_node->prev = node->prev; + ASYNCSAFE(gl_list_node_t) new_node->prev->next = new_node; + node->prev = new_node; + } + list->count++; + +#if WITH_HASHTABLE + hash_resize_after_add (list); +#endif + + return new_node; +} + +static bool +gl_linked_remove_node (gl_list_t list, gl_list_node_t node) +{ + gl_list_node_t prev; + gl_list_node_t next; + +#if WITH_HASHTABLE + /* Remove node from the hash table. */ + remove_from_bucket (list, node); +#endif + + /* Remove node from the list. */ + prev = node->prev; + next = node->next; + + ASYNCSAFE(gl_list_node_t) prev->next = next; + next->prev = prev; + list->count--; + + free (node); + return true; +} + +static bool +gl_linked_remove_at (gl_list_t list, size_t position) +{ + size_t count = list->count; + gl_list_node_t removed_node; + + if (!(position < count)) + /* Invalid argument. */ + abort (); + /* Here we know count > 0. */ + if (position <= ((count - 1) / 2)) + { + gl_list_node_t node; + gl_list_node_t after_removed; + + node = &list->root; + for (; position > 0; position--) + node = node->next; + removed_node = node->next; + after_removed = node->next->next; + ASYNCSAFE(gl_list_node_t) node->next = after_removed; + after_removed->prev = node; + } + else + { + gl_list_node_t node; + gl_list_node_t before_removed; + + position = count - 1 - position; + node = &list->root; + for (; position > 0; position--) + node = node->prev; + removed_node = node->prev; + before_removed = node->prev->prev; + node->prev = before_removed; + ASYNCSAFE(gl_list_node_t) before_removed->next = node; + } +#if WITH_HASHTABLE + remove_from_bucket (list, removed_node); +#endif + list->count--; + + free (removed_node); + return true; +} + +static bool +gl_linked_remove (gl_list_t list, const void *elt) +{ + gl_list_node_t node = gl_linked_search (list, elt); + + if (node != NULL) + return gl_linked_remove_node (list, node); + else + return false; +} + +static void +gl_linked_list_free (gl_list_t list) +{ + gl_list_node_t node; + + for (node = list->root.next; node != &list->root; ) + { + gl_list_node_t next = node->next; + free (node); + node = next; + } +#if WITH_HASHTABLE + free (list->table); +#endif + free (list); +} + +/* --------------------- gl_list_iterator_t Data Type --------------------- */ + +static gl_list_iterator_t +gl_linked_iterator (gl_list_t list) +{ + gl_list_iterator_t result; + + result.vtable = list->base.vtable; + result.list = list; + result.p = list->root.next; + result.q = &list->root; + + return result; +} + +static gl_list_iterator_t +gl_linked_iterator_from_to (gl_list_t list, + size_t start_index, size_t end_index) +{ + gl_list_iterator_t result; + size_t n1, n2, n3; + + if (!(start_index <= end_index && end_index <= list->count)) + /* Invalid arguments. */ + abort (); + result.vtable = list->base.vtable; + result.list = list; + n1 = start_index; + n2 = end_index - start_index; + n3 = list->count - end_index; + /* Find the maximum among n1, n2, n3, so as to reduce the number of + loop iterations to n1 + n2 + n3 - max(n1,n2,n3). */ + if (n1 > n2 && n1 > n3) + { + /* n1 is the maximum, use n2 and n3. */ + gl_list_node_t node; + size_t i; + + node = &list->root; + for (i = n3; i > 0; i--) + node = node->prev; + result.q = node; + for (i = n2; i > 0; i--) + node = node->prev; + result.p = node; + } + else if (n2 > n3) + { + /* n2 is the maximum, use n1 and n3. */ + gl_list_node_t node; + size_t i; + + node = list->root.next; + for (i = n1; i > 0; i--) + node = node->next; + result.p = node; + + node = &list->root; + for (i = n3; i > 0; i--) + node = node->prev; + result.q = node; + } + else + { + /* n3 is the maximum, use n1 and n2. */ + gl_list_node_t node; + size_t i; + + node = list->root.next; + for (i = n1; i > 0; i--) + node = node->next; + result.p = node; + for (i = n2; i > 0; i--) + node = node->next; + result.q = node; + } + + return result; +} + +static bool +gl_linked_iterator_next (gl_list_iterator_t *iterator, + const void **eltp, gl_list_node_t *nodep) +{ + if (iterator->p != iterator->q) + { + gl_list_node_t node = (gl_list_node_t) iterator->p; + *eltp = node->value; + if (nodep != NULL) + *nodep = node; + iterator->p = node->next; + return true; + } + else + return false; +} + +static void +gl_linked_iterator_free (gl_list_iterator_t *iterator) +{ +} + +/* ---------------------- Sorted gl_list_t Data Type ---------------------- */ + +static gl_list_node_t +gl_linked_sortedlist_search (gl_list_t list, gl_listelement_compar_fn compar, + const void *elt) +{ + gl_list_node_t node; + + for (node = list->root.next; node != &list->root; node = node->next) + { + int cmp = compar (node->value, elt); + + if (cmp > 0) + break; + if (cmp == 0) + return node; + } + return NULL; +} + +static size_t +gl_linked_sortedlist_indexof (gl_list_t list, gl_listelement_compar_fn compar, + const void *elt) +{ + gl_list_node_t node; + size_t index; + + for (node = list->root.next, index = 0; + node != &list->root; + node = node->next, index++) + { + int cmp = compar (node->value, elt); + + if (cmp > 0) + break; + if (cmp == 0) + return index; + } + return (size_t)(-1); +} + +static gl_list_node_t +gl_linked_sortedlist_add (gl_list_t list, gl_listelement_compar_fn compar, + const void *elt) +{ + gl_list_node_t node; + + for (node = list->root.next; node != &list->root; node = node->next) + if (compar (node->value, elt) >= 0) + return gl_linked_add_before (list, node, elt); + return gl_linked_add_last (list, elt); +} + +static bool +gl_linked_sortedlist_remove (gl_list_t list, gl_listelement_compar_fn compar, + const void *elt) +{ + gl_list_node_t node; + + for (node = list->root.next; node != &list->root; node = node->next) + { + int cmp = compar (node->value, elt); + + if (cmp > 0) + break; + if (cmp == 0) + return gl_linked_remove_node (list, node); + } + return false; +} diff --git a/gettext-tools/lib/gl_linkedhash_list.c b/gettext-tools/lib/gl_linkedhash_list.c new file mode 100644 index 000000000..ca7f7072f --- /dev/null +++ b/gettext-tools/lib/gl_linkedhash_list.c @@ -0,0 +1,123 @@ +/* Sequential list data type implemented by a hash table with a linked list. + Copyright (C) 2006 Free Software Foundation, Inc. + Written by Bruno Haible , 2006. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +/* Specification. */ +#include "gl_linkedhash_list.h" + +#include + +#include "xalloc.h" +#include "xsize.h" +#include "size_max.h" + +#ifndef uintptr_t +# define uintptr_t unsigned long +#endif + +#define WITH_HASHTABLE 1 + +/* -------------------------- gl_list_t Data Type -------------------------- */ + +/* Generic hash-table code. */ +#include "gl_anyhash_list1.h" + +/* Generic linked list code. */ +#include "gl_anylinked_list1.h" + +/* Generic hash-table code. */ +#include "gl_anyhash_list2.h" + +/* Resize the hash table if needed, after list->count was incremented. */ +static inline void +hash_resize_after_add (gl_list_t list) +{ + size_t count = list->count; + size_t estimate = xsum (count, count / 2); /* 1.5 * count */ + if (estimate > list->table_size) + hash_resize (list, estimate); +} + +/* Add a node to the hash table structure. */ +static inline void +add_to_bucket (gl_list_t list, gl_list_node_t node) +{ + size_t index = node->h.hashcode % list->table_size; + + node->h.hash_next = list->table[index]; + list->table[index] = &node->h; +} + +/* Remove a node from the hash table structure. */ +static inline void +remove_from_bucket (gl_list_t list, gl_list_node_t node) +{ + size_t index = node->h.hashcode % list->table_size; + gl_hash_entry_t *p; + + for (p = &list->table[index]; ; p = &(*p)->hash_next) + { + if (*p == &node->h) + { + *p = node->h.hash_next; + break; + } + if (*p == NULL) + /* node is not in the right bucket. Did the hash codes + change inadvertently? */ + abort (); + } +} + +/* Generic linked list code. */ +#include "gl_anylinked_list2.h" + + +const struct gl_list_implementation gl_linkedhash_list_implementation = + { + gl_linked_create_empty, + gl_linked_create, + gl_linked_size, + gl_linked_node_value, + gl_linked_next_node, + gl_linked_previous_node, + gl_linked_get_at, + gl_linked_set_at, + gl_linked_search, + gl_linked_indexof, + gl_linked_add_first, + gl_linked_add_last, + gl_linked_add_before, + gl_linked_add_after, + gl_linked_add_at, + gl_linked_remove_node, + gl_linked_remove_at, + gl_linked_remove, + gl_linked_list_free, + gl_linked_iterator, + gl_linked_iterator_from_to, + gl_linked_iterator_next, + gl_linked_iterator_free, + gl_linked_sortedlist_search, + gl_linked_sortedlist_indexof, + gl_linked_sortedlist_add, + gl_linked_sortedlist_remove + }; diff --git a/gettext-tools/lib/gl_linkedhash_list.h b/gettext-tools/lib/gl_linkedhash_list.h new file mode 100644 index 000000000..d3e71ed95 --- /dev/null +++ b/gettext-tools/lib/gl_linkedhash_list.h @@ -0,0 +1,35 @@ +/* Sequential list data type implemented by a hash table with a linked list. + Copyright (C) 2006 Free Software Foundation, Inc. + Written by Bruno Haible , 2006. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _GL_LINKEDHASH_LIST_H +#define _GL_LINKEDHASH_LIST_H + +#include "gl_list.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern const struct gl_list_implementation gl_linkedhash_list_implementation; +#define GL_LINKEDHASH_LIST &gl_linkedhash_list_implementation + +#ifdef __cplusplus +} +#endif + +#endif /* _GL_LINKEDHASH_LIST_H */