| /* Routines for name->symbol lookups in GDB. | |
| Copyright (C) 2003, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. | |
| Contributed by David Carlton <carlton@bactrian.org> and by Kealia, | |
| Inc. | |
| This file is part of GDB. | |
| 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 3 of the License, 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, see <http://www.gnu.org/licenses/>. */ | |
| #include "defs.h" | |
| #include "gdb_obstack.h" | |
| #include "symtab.h" | |
| #include "buildsym.h" | |
| #include "gdb_assert.h" | |
| #include "dictionary.h" | |
| /* This file implements dictionaries, which are tables that associate | |
| symbols to names. They are represented by an opaque type 'struct | |
| dictionary'. That type has various internal implementations, which | |
| you can choose between depending on what properties you need | |
| (e.g. fast lookup, order-preserving, expandable). | |
| Each dictionary starts with a 'virtual function table' that | |
| contains the functions that actually implement the various | |
| operations that dictionaries provide. (Note, however, that, for | |
| the sake of client code, we also provide some functions that can be | |
| implemented generically in terms of the functions in the vtable.) | |
| To add a new dictionary implementation <impl>, what you should do | |
| is: | |
| * Add a new element DICT_<IMPL> to dict_type. | |
| * Create a new structure dictionary_<impl>. If your new | |
| implementation is a variant of an existing one, make sure that | |
| their structs have the same initial data members. Define accessor | |
| macros for your new data members. | |
| * Implement all the functions in dict_vector as static functions, | |
| whose name is the same as the corresponding member of dict_vector | |
| plus _<impl>. You don't have to do this for those members where | |
| you can reuse existing generic functions | |
| (e.g. add_symbol_nonexpandable, free_obstack) or in the case where | |
| your new implementation is a variant of an existing implementation | |
| and where the variant doesn't affect the member function in | |
| question. | |
| * Define a static const struct dict_vector dict_<impl>_vector. | |
| * Define a function dict_create_<impl> to create these | |
| gizmos. Add its declaration to dictionary.h. | |
| To add a new operation <op> on all existing implementations, what | |
| you should do is: | |
| * Add a new member <op> to struct dict_vector. | |
| * If there is useful generic behavior <op>, define a static | |
| function <op>_something_informative that implements that behavior. | |
| (E.g. add_symbol_nonexpandable, free_obstack.) | |
| * For every implementation <impl> that should have its own specific | |
| behavior for <op>, define a static function <op>_<impl> | |
| implementing it. | |
| * Modify all existing dict_vector_<impl>'s to include the appropriate | |
| member. | |
| * Define a function dict_<op> that looks up <op> in the dict_vector | |
| and calls the appropriate function. Add a declaration for | |
| dict_<op> to dictionary.h. | |
| */ | |
| /* An enum representing the various implementations of dictionaries. | |
| Used only for debugging. */ | |
| enum dict_type | |
| { | |
| /* Symbols are stored in a fixed-size hash table. */ | |
| DICT_HASHED, | |
| /* Symbols are stored in an expandable hash table. */ | |
| DICT_HASHED_EXPANDABLE, | |
| /* Symbols are stored in a fixed-size array. */ | |
| DICT_LINEAR, | |
| /* Symbols are stored in an expandable array. */ | |
| DICT_LINEAR_EXPANDABLE | |
| }; | |
| /* The virtual function table. */ | |
| struct dict_vector | |
| { | |
| /* The type of the dictionary. This is only here to make debugging | |
| a bit easier; it's not actually used. */ | |
| enum dict_type type; | |
| /* The function to free a dictionary. */ | |
| void (*free) (struct dictionary *dict); | |
| /* Add a symbol to a dictionary, if possible. */ | |
| void (*add_symbol) (struct dictionary *dict, struct symbol *sym); | |
| /* Iterator functions. */ | |
| struct symbol *(*iterator_first) (const struct dictionary *dict, | |
| struct dict_iterator *iterator); | |
| struct symbol *(*iterator_next) (struct dict_iterator *iterator); | |
| /* Functions to iterate over symbols with a given name. */ | |
| struct symbol *(*iter_name_first) (const struct dictionary *dict, | |
| const char *name, | |
| struct dict_iterator *iterator); | |
| struct symbol *(*iter_name_next) (const char *name, | |
| struct dict_iterator *iterator); | |
| /* A size function, for maint print symtabs. */ | |
| int (*size) (const struct dictionary *dict); | |
| }; | |
| /* Now comes the structs used to store the data for different | |
| implementations. If two implementations have data in common, put | |
| the common data at the top of their structs, ordered in the same | |
| way. */ | |
| struct dictionary_hashed | |
| { | |
| int nbuckets; | |
| struct symbol **buckets; | |
| }; | |
| struct dictionary_hashed_expandable | |
| { | |
| /* How many buckets we currently have. */ | |
| int nbuckets; | |
| struct symbol **buckets; | |
| /* How many syms we currently have; we need this so we will know | |
| when to add more buckets. */ | |
| int nsyms; | |
| }; | |
| struct dictionary_linear | |
| { | |
| int nsyms; | |
| struct symbol **syms; | |
| }; | |
| struct dictionary_linear_expandable | |
| { | |
| /* How many symbols we currently have. */ | |
| int nsyms; | |
| struct symbol **syms; | |
| /* How many symbols we can store before needing to reallocate. */ | |
| int capacity; | |
| }; | |
| /* And now, the star of our show. */ | |
| struct dictionary | |
| { | |
| const struct dict_vector *vector; | |
| union | |
| { | |
| struct dictionary_hashed hashed; | |
| struct dictionary_hashed_expandable hashed_expandable; | |
| struct dictionary_linear linear; | |
| struct dictionary_linear_expandable linear_expandable; | |
| } | |
| data; | |
| }; | |
| /* Accessor macros. */ | |
| #define DICT_VECTOR(d) (d)->vector | |
| /* These can be used for DICT_HASHED_EXPANDABLE, too. */ | |
| #define DICT_HASHED_NBUCKETS(d) (d)->data.hashed.nbuckets | |
| #define DICT_HASHED_BUCKETS(d) (d)->data.hashed.buckets | |
| #define DICT_HASHED_BUCKET(d,i) DICT_HASHED_BUCKETS (d) [i] | |
| #define DICT_HASHED_EXPANDABLE_NSYMS(d) (d)->data.hashed_expandable.nsyms | |
| /* These can be used for DICT_LINEAR_EXPANDABLEs, too. */ | |
| #define DICT_LINEAR_NSYMS(d) (d)->data.linear.nsyms | |
| #define DICT_LINEAR_SYMS(d) (d)->data.linear.syms | |
| #define DICT_LINEAR_SYM(d,i) DICT_LINEAR_SYMS (d) [i] | |
| #define DICT_LINEAR_EXPANDABLE_CAPACITY(d) \ | |
| (d)->data.linear_expandable.capacity | |
| /* The initial size of a DICT_*_EXPANDABLE dictionary. */ | |
| #define DICT_EXPANDABLE_INITIAL_CAPACITY 10 | |
| /* This calculates the number of buckets we'll use in a hashtable, | |
| given the number of symbols that it will contain. */ | |
| #define DICT_HASHTABLE_SIZE(n) ((n)/5 + 1) | |
| /* Accessor macros for dict_iterators; they're here rather than | |
| dictionary.h because code elsewhere should treat dict_iterators as | |
| opaque. */ | |
| /* The dictionary that the iterator is associated to. */ | |
| #define DICT_ITERATOR_DICT(iter) (iter)->dict | |
| /* For linear dictionaries, the index of the last symbol returned; for | |
| hashed dictionaries, the bucket of the last symbol returned. */ | |
| #define DICT_ITERATOR_INDEX(iter) (iter)->index | |
| /* For hashed dictionaries, this points to the last symbol returned; | |
| otherwise, this is unused. */ | |
| #define DICT_ITERATOR_CURRENT(iter) (iter)->current | |
| /* Declarations of functions for vectors. */ | |
| /* Functions that might work across a range of dictionary types. */ | |
| static void add_symbol_nonexpandable (struct dictionary *dict, | |
| struct symbol *sym); | |
| static void free_obstack (struct dictionary *dict); | |
| /* Functions for DICT_HASHED and DICT_HASHED_EXPANDABLE | |
| dictionaries. */ | |
| static struct symbol *iterator_first_hashed (const struct dictionary *dict, | |
| struct dict_iterator *iterator); | |
| static struct symbol *iterator_next_hashed (struct dict_iterator *iterator); | |
| static struct symbol *iter_name_first_hashed (const struct dictionary *dict, | |
| const char *name, | |
| struct dict_iterator *iterator); | |
| static struct symbol *iter_name_next_hashed (const char *name, | |
| struct dict_iterator *iterator); | |
| /* Functions only for DICT_HASHED. */ | |
| static int size_hashed (const struct dictionary *dict); | |
| /* Functions only for DICT_HASHED_EXPANDABLE. */ | |
| static void free_hashed_expandable (struct dictionary *dict); | |
| static void add_symbol_hashed_expandable (struct dictionary *dict, | |
| struct symbol *sym); | |
| static int size_hashed_expandable (const struct dictionary *dict); | |
| /* Functions for DICT_LINEAR and DICT_LINEAR_EXPANDABLE | |
| dictionaries. */ | |
| static struct symbol *iterator_first_linear (const struct dictionary *dict, | |
| struct dict_iterator *iterator); | |
| static struct symbol *iterator_next_linear (struct dict_iterator *iterator); | |
| static struct symbol *iter_name_first_linear (const struct dictionary *dict, | |
| const char *name, | |
| struct dict_iterator *iterator); | |
| static struct symbol *iter_name_next_linear (const char *name, | |
| struct dict_iterator *iterator); | |
| static int size_linear (const struct dictionary *dict); | |
| /* Functions only for DICT_LINEAR_EXPANDABLE. */ | |
| static void free_linear_expandable (struct dictionary *dict); | |
| static void add_symbol_linear_expandable (struct dictionary *dict, | |
| struct symbol *sym); | |
| /* Various vectors that we'll actually use. */ | |
| static const struct dict_vector dict_hashed_vector = | |
| { | |
| DICT_HASHED, /* type */ | |
| free_obstack, /* free */ | |
| add_symbol_nonexpandable, /* add_symbol */ | |
| iterator_first_hashed, /* iterator_first */ | |
| iterator_next_hashed, /* iterator_next */ | |
| iter_name_first_hashed, /* iter_name_first */ | |
| iter_name_next_hashed, /* iter_name_next */ | |
| size_hashed, /* size */ | |
| }; | |
| static const struct dict_vector dict_hashed_expandable_vector = | |
| { | |
| DICT_HASHED_EXPANDABLE, /* type */ | |
| free_hashed_expandable, /* free */ | |
| add_symbol_hashed_expandable, /* add_symbol */ | |
| iterator_first_hashed, /* iterator_first */ | |
| iterator_next_hashed, /* iterator_next */ | |
| iter_name_first_hashed, /* iter_name_first */ | |
| iter_name_next_hashed, /* iter_name_next */ | |
| size_hashed_expandable, /* size */ | |
| }; | |
| static const struct dict_vector dict_linear_vector = | |
| { | |
| DICT_LINEAR, /* type */ | |
| free_obstack, /* free */ | |
| add_symbol_nonexpandable, /* add_symbol */ | |
| iterator_first_linear, /* iterator_first */ | |
| iterator_next_linear, /* iterator_next */ | |
| iter_name_first_linear, /* iter_name_first */ | |
| iter_name_next_linear, /* iter_name_next */ | |
| size_linear, /* size */ | |
| }; | |
| static const struct dict_vector dict_linear_expandable_vector = | |
| { | |
| DICT_LINEAR_EXPANDABLE, /* type */ | |
| free_linear_expandable, /* free */ | |
| add_symbol_linear_expandable, /* add_symbol */ | |
| iterator_first_linear, /* iterator_first */ | |
| iterator_next_linear, /* iterator_next */ | |
| iter_name_first_linear, /* iter_name_first */ | |
| iter_name_next_linear, /* iter_name_next */ | |
| size_linear, /* size */ | |
| }; | |
| /* Declarations of helper functions (i.e. ones that don't go into | |
| vectors). */ | |
| static struct symbol *iterator_hashed_advance (struct dict_iterator *iter); | |
| static void insert_symbol_hashed (struct dictionary *dict, | |
| struct symbol *sym); | |
| static void expand_hashtable (struct dictionary *dict); | |
| /* The creation functions. */ | |
| /* Create a dictionary implemented via a fixed-size hashtable. All | |
| memory it uses is allocated on OBSTACK; the environment is | |
| initialized from SYMBOL_LIST. */ | |
| struct dictionary * | |
| dict_create_hashed (struct obstack *obstack, | |
| const struct pending *symbol_list) | |
| { | |
| struct dictionary *retval; | |
| int nsyms = 0, nbuckets, i; | |
| struct symbol **buckets; | |
| const struct pending *list_counter; | |
| retval = obstack_alloc (obstack, sizeof (struct dictionary)); | |
| DICT_VECTOR (retval) = &dict_hashed_vector; | |
| /* Calculate the number of symbols, and allocate space for them. */ | |
| for (list_counter = symbol_list; | |
| list_counter != NULL; | |
| list_counter = list_counter->next) | |
| { | |
| nsyms += list_counter->nsyms; | |
| } | |
| nbuckets = DICT_HASHTABLE_SIZE (nsyms); | |
| DICT_HASHED_NBUCKETS (retval) = nbuckets; | |
| buckets = obstack_alloc (obstack, nbuckets * sizeof (struct symbol *)); | |
| memset (buckets, 0, nbuckets * sizeof (struct symbol *)); | |
| DICT_HASHED_BUCKETS (retval) = buckets; | |
| /* Now fill the buckets. */ | |
| for (list_counter = symbol_list; | |
| list_counter != NULL; | |
| list_counter = list_counter->next) | |
| { | |
| for (i = list_counter->nsyms - 1; i >= 0; --i) | |
| { | |
| insert_symbol_hashed (retval, list_counter->symbol[i]); | |
| } | |
| } | |
| return retval; | |
| } | |
| /* Create a dictionary implemented via a hashtable that grows as | |
| necessary. The dictionary is initially empty; to add symbols to | |
| it, call dict_add_symbol(). Call dict_free() when you're done with | |
| it. */ | |
| extern struct dictionary * | |
| dict_create_hashed_expandable (void) | |
| { | |
| struct dictionary *retval; | |
| retval = xmalloc (sizeof (struct dictionary)); | |
| DICT_VECTOR (retval) = &dict_hashed_expandable_vector; | |
| DICT_HASHED_NBUCKETS (retval) = DICT_EXPANDABLE_INITIAL_CAPACITY; | |
| DICT_HASHED_BUCKETS (retval) = xcalloc (DICT_EXPANDABLE_INITIAL_CAPACITY, | |
| sizeof (struct symbol *)); | |
| DICT_HASHED_EXPANDABLE_NSYMS (retval) = 0; | |
| return retval; | |
| } | |
| /* Create a dictionary implemented via a fixed-size array. All memory | |
| it uses is allocated on OBSTACK; the environment is initialized | |
| from the SYMBOL_LIST. The symbols are ordered in the same order | |
| that they're found in SYMBOL_LIST. */ | |
| struct dictionary * | |
| dict_create_linear (struct obstack *obstack, | |
| const struct pending *symbol_list) | |
| { | |
| struct dictionary *retval; | |
| int nsyms = 0, i, j; | |
| struct symbol **syms; | |
| const struct pending *list_counter; | |
| retval = obstack_alloc (obstack, sizeof (struct dictionary)); | |
| DICT_VECTOR (retval) = &dict_linear_vector; | |
| /* Calculate the number of symbols, and allocate space for them. */ | |
| for (list_counter = symbol_list; | |
| list_counter != NULL; | |
| list_counter = list_counter->next) | |
| { | |
| nsyms += list_counter->nsyms; | |
| } | |
| DICT_LINEAR_NSYMS (retval) = nsyms; | |
| syms = obstack_alloc (obstack, nsyms * sizeof (struct symbol *)); | |
| DICT_LINEAR_SYMS (retval) = syms; | |
| /* Now fill in the symbols. Start filling in from the back, so as | |
| to preserve the original order of the symbols. */ | |
| for (list_counter = symbol_list, j = nsyms - 1; | |
| list_counter != NULL; | |
| list_counter = list_counter->next) | |
| { | |
| for (i = list_counter->nsyms - 1; | |
| i >= 0; | |
| --i, --j) | |
| { | |
| syms[j] = list_counter->symbol[i]; | |
| } | |
| } | |
| return retval; | |
| } | |
| /* Create a dictionary implemented via an array that grows as | |
| necessary. The dictionary is initially empty; to add symbols to | |
| it, call dict_add_symbol(). Call dict_free() when you're done with | |
| it. */ | |
| struct dictionary * | |
| dict_create_linear_expandable (void) | |
| { | |
| struct dictionary *retval; | |
| retval = xmalloc (sizeof (struct dictionary)); | |
| DICT_VECTOR (retval) = &dict_linear_expandable_vector; | |
| DICT_LINEAR_NSYMS (retval) = 0; | |
| DICT_LINEAR_EXPANDABLE_CAPACITY (retval) | |
| = DICT_EXPANDABLE_INITIAL_CAPACITY; | |
| DICT_LINEAR_SYMS (retval) | |
| = xmalloc (DICT_LINEAR_EXPANDABLE_CAPACITY (retval) | |
| * sizeof (struct symbol *)); | |
| return retval; | |
| } | |
| /* The functions providing the dictionary interface. */ | |
| /* Free the memory used by a dictionary that's not on an obstack. (If | |
| any.) */ | |
| void | |
| dict_free (struct dictionary *dict) | |
| { | |
| (DICT_VECTOR (dict))->free (dict); | |
| } | |
| /* Add SYM to DICT. DICT had better be expandable. */ | |
| void | |
| dict_add_symbol (struct dictionary *dict, struct symbol *sym) | |
| { | |
| (DICT_VECTOR (dict))->add_symbol (dict, sym); | |
| } | |
| /* Initialize ITERATOR to point at the first symbol in DICT, and | |
| return that first symbol, or NULL if DICT is empty. */ | |
| struct symbol * | |
| dict_iterator_first (const struct dictionary *dict, | |
| struct dict_iterator *iterator) | |
| { | |
| return (DICT_VECTOR (dict))->iterator_first (dict, iterator); | |
| } | |
| /* Advance ITERATOR, and return the next symbol, or NULL if there are | |
| no more symbols. */ | |
| struct symbol * | |
| dict_iterator_next (struct dict_iterator *iterator) | |
| { | |
| return (DICT_VECTOR (DICT_ITERATOR_DICT (iterator))) | |
| ->iterator_next (iterator); | |
| } | |
| struct symbol * | |
| dict_iter_name_first (const struct dictionary *dict, | |
| const char *name, | |
| struct dict_iterator *iterator) | |
| { | |
| return (DICT_VECTOR (dict))->iter_name_first (dict, name, iterator); | |
| } | |
| struct symbol * | |
| dict_iter_name_next (const char *name, struct dict_iterator *iterator) | |
| { | |
| return (DICT_VECTOR (DICT_ITERATOR_DICT (iterator))) | |
| ->iter_name_next (name, iterator); | |
| } | |
| int | |
| dict_size (const struct dictionary *dict) | |
| { | |
| return (DICT_VECTOR (dict))->size (dict); | |
| } | |
| /* Now come functions (well, one function, currently) that are | |
| implemented generically by means of the vtable. Typically, they're | |
| rarely used. */ | |
| /* Test to see if DICT is empty. */ | |
| int | |
| dict_empty (struct dictionary *dict) | |
| { | |
| struct dict_iterator iter; | |
| return (dict_iterator_first (dict, &iter) == NULL); | |
| } | |
| /* The functions implementing the dictionary interface. */ | |
| /* Generic functions, where appropriate. */ | |
| static void | |
| free_obstack (struct dictionary *dict) | |
| { | |
| /* Do nothing! */ | |
| } | |
| static void | |
| add_symbol_nonexpandable (struct dictionary *dict, struct symbol *sym) | |
| { | |
| internal_error (__FILE__, __LINE__, | |
| _("dict_add_symbol: non-expandable dictionary")); | |
| } | |
| /* Functions for DICT_HASHED and DICT_HASHED_EXPANDABLE. */ | |
| static struct symbol * | |
| iterator_first_hashed (const struct dictionary *dict, | |
| struct dict_iterator *iterator) | |
| { | |
| DICT_ITERATOR_DICT (iterator) = dict; | |
| DICT_ITERATOR_INDEX (iterator) = -1; | |
| return iterator_hashed_advance (iterator); | |
| } | |
| static struct symbol * | |
| iterator_next_hashed (struct dict_iterator *iterator) | |
| { | |
| struct symbol *next; | |
| next = DICT_ITERATOR_CURRENT (iterator)->hash_next; | |
| if (next == NULL) | |
| return iterator_hashed_advance (iterator); | |
| else | |
| { | |
| DICT_ITERATOR_CURRENT (iterator) = next; | |
| return next; | |
| } | |
| } | |
| static struct symbol * | |
| iterator_hashed_advance (struct dict_iterator *iterator) | |
| { | |
| const struct dictionary *dict = DICT_ITERATOR_DICT (iterator); | |
| int nbuckets = DICT_HASHED_NBUCKETS (dict); | |
| int i; | |
| for (i = DICT_ITERATOR_INDEX (iterator) + 1; i < nbuckets; ++i) | |
| { | |
| struct symbol *sym = DICT_HASHED_BUCKET (dict, i); | |
| if (sym != NULL) | |
| { | |
| DICT_ITERATOR_INDEX (iterator) = i; | |
| DICT_ITERATOR_CURRENT (iterator) = sym; | |
| return sym; | |
| } | |
| } | |
| return NULL; | |
| } | |
| static struct symbol * | |
| iter_name_first_hashed (const struct dictionary *dict, | |
| const char *name, | |
| struct dict_iterator *iterator) | |
| { | |
| unsigned int hash_index | |
| = msymbol_hash_iw (name) % DICT_HASHED_NBUCKETS (dict); | |
| struct symbol *sym; | |
| DICT_ITERATOR_DICT (iterator) = dict; | |
| /* Loop through the symbols in the given bucket, breaking when SYM | |
| first matches. If SYM never matches, it will be set to NULL; | |
| either way, we have the right return value. */ | |
| for (sym = DICT_HASHED_BUCKET (dict, hash_index); | |
| sym != NULL; | |
| sym = sym->hash_next) | |
| { | |
| /* Warning: the order of arguments to strcmp_iw matters! */ | |
| if (strcmp_iw (SYMBOL_SEARCH_NAME (sym), name) == 0) | |
| { | |
| break; | |
| } | |
| } | |
| DICT_ITERATOR_CURRENT (iterator) = sym; | |
| return sym; | |
| } | |
| static struct symbol * | |
| iter_name_next_hashed (const char *name, struct dict_iterator *iterator) | |
| { | |
| struct symbol *next; | |
| for (next = DICT_ITERATOR_CURRENT (iterator)->hash_next; | |
| next != NULL; | |
| next = next->hash_next) | |
| { | |
| if (strcmp_iw (SYMBOL_SEARCH_NAME (next), name) == 0) | |
| break; | |
| } | |
| DICT_ITERATOR_CURRENT (iterator) = next; | |
| return next; | |
| } | |
| /* Insert SYM into DICT. */ | |
| static void | |
| insert_symbol_hashed (struct dictionary *dict, | |
| struct symbol *sym) | |
| { | |
| unsigned int hash_index; | |
| struct symbol **buckets = DICT_HASHED_BUCKETS (dict); | |
| hash_index = (msymbol_hash_iw (SYMBOL_SEARCH_NAME (sym)) | |
| % DICT_HASHED_NBUCKETS (dict)); | |
| sym->hash_next = buckets[hash_index]; | |
| buckets[hash_index] = sym; | |
| } | |
| static int | |
| size_hashed (const struct dictionary *dict) | |
| { | |
| return DICT_HASHED_NBUCKETS (dict); | |
| } | |
| /* Functions only for DICT_HASHED_EXPANDABLE. */ | |
| static void | |
| free_hashed_expandable (struct dictionary *dict) | |
| { | |
| xfree (DICT_HASHED_BUCKETS (dict)); | |
| xfree (dict); | |
| } | |
| static void | |
| add_symbol_hashed_expandable (struct dictionary *dict, | |
| struct symbol *sym) | |
| { | |
| int nsyms = ++DICT_HASHED_EXPANDABLE_NSYMS (dict); | |
| if (DICT_HASHTABLE_SIZE (nsyms) > DICT_HASHED_NBUCKETS (dict)) | |
| expand_hashtable (dict); | |
| insert_symbol_hashed (dict, sym); | |
| DICT_HASHED_EXPANDABLE_NSYMS (dict) = nsyms; | |
| } | |
| static int | |
| size_hashed_expandable (const struct dictionary *dict) | |
| { | |
| return DICT_HASHED_EXPANDABLE_NSYMS (dict); | |
| } | |
| static void | |
| expand_hashtable (struct dictionary *dict) | |
| { | |
| int old_nbuckets = DICT_HASHED_NBUCKETS (dict); | |
| struct symbol **old_buckets = DICT_HASHED_BUCKETS (dict); | |
| int new_nbuckets = 2*old_nbuckets + 1; | |
| struct symbol **new_buckets = xcalloc (new_nbuckets, | |
| sizeof (struct symbol *)); | |
| int i; | |
| DICT_HASHED_NBUCKETS (dict) = new_nbuckets; | |
| DICT_HASHED_BUCKETS (dict) = new_buckets; | |
| for (i = 0; i < old_nbuckets; ++i) | |
| { | |
| struct symbol *sym, *next_sym; | |
| sym = old_buckets[i]; | |
| if (sym != NULL) | |
| { | |
| for (next_sym = sym->hash_next; | |
| next_sym != NULL; | |
| next_sym = sym->hash_next) | |
| { | |
| insert_symbol_hashed (dict, sym); | |
| sym = next_sym; | |
| } | |
| insert_symbol_hashed (dict, sym); | |
| } | |
| } | |
| xfree (old_buckets); | |
| } | |
| /* Functions for DICT_LINEAR and DICT_LINEAR_EXPANDABLE. */ | |
| static struct symbol * | |
| iterator_first_linear (const struct dictionary *dict, | |
| struct dict_iterator *iterator) | |
| { | |
| DICT_ITERATOR_DICT (iterator) = dict; | |
| DICT_ITERATOR_INDEX (iterator) = 0; | |
| return DICT_LINEAR_NSYMS (dict) ? DICT_LINEAR_SYM (dict, 0) : NULL; | |
| } | |
| static struct symbol * | |
| iterator_next_linear (struct dict_iterator *iterator) | |
| { | |
| const struct dictionary *dict = DICT_ITERATOR_DICT (iterator); | |
| if (++DICT_ITERATOR_INDEX (iterator) >= DICT_LINEAR_NSYMS (dict)) | |
| return NULL; | |
| else | |
| return DICT_LINEAR_SYM (dict, DICT_ITERATOR_INDEX (iterator)); | |
| } | |
| static struct symbol * | |
| iter_name_first_linear (const struct dictionary *dict, | |
| const char *name, | |
| struct dict_iterator *iterator) | |
| { | |
| DICT_ITERATOR_DICT (iterator) = dict; | |
| DICT_ITERATOR_INDEX (iterator) = -1; | |
| return iter_name_next_linear (name, iterator); | |
| } | |
| static struct symbol * | |
| iter_name_next_linear (const char *name, struct dict_iterator *iterator) | |
| { | |
| const struct dictionary *dict = DICT_ITERATOR_DICT (iterator); | |
| int i, nsyms = DICT_LINEAR_NSYMS (dict); | |
| struct symbol *sym, *retval = NULL; | |
| for (i = DICT_ITERATOR_INDEX (iterator) + 1; i < nsyms; ++i) | |
| { | |
| sym = DICT_LINEAR_SYM (dict, i); | |
| if (strcmp_iw (SYMBOL_SEARCH_NAME (sym), name) == 0) | |
| { | |
| retval = sym; | |
| break; | |
| } | |
| } | |
| DICT_ITERATOR_INDEX (iterator) = i; | |
| return retval; | |
| } | |
| static int | |
| size_linear (const struct dictionary *dict) | |
| { | |
| return DICT_LINEAR_NSYMS (dict); | |
| } | |
| /* Functions only for DICT_LINEAR_EXPANDABLE. */ | |
| static void | |
| free_linear_expandable (struct dictionary *dict) | |
| { | |
| xfree (DICT_LINEAR_SYMS (dict)); | |
| xfree (dict); | |
| } | |
| static void | |
| add_symbol_linear_expandable (struct dictionary *dict, | |
| struct symbol *sym) | |
| { | |
| int nsyms = ++DICT_LINEAR_NSYMS (dict); | |
| /* Do we have enough room? If not, grow it. */ | |
| if (nsyms > DICT_LINEAR_EXPANDABLE_CAPACITY (dict)) | |
| { | |
| DICT_LINEAR_EXPANDABLE_CAPACITY (dict) *= 2; | |
| DICT_LINEAR_SYMS (dict) | |
| = xrealloc (DICT_LINEAR_SYMS (dict), | |
| DICT_LINEAR_EXPANDABLE_CAPACITY (dict) | |
| * sizeof (struct symbol *)); | |
| } | |
| DICT_LINEAR_SYM (dict, nsyms - 1) = sym; | |
| } |