/* * Copyright (c) 2000-2001 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include #include "termhash.h" #include "hash.h" #include "termhash.h" #include "util.h" #define UB(n) ((1<next) /* size: initial_table_size + number of rehashes */ /* capacity: 2^size (for array size) */ /* ub: 2^size-1 (for array indexing) */ /* inserts: num of elements inserted into the array */ struct term_hash { term_bucket * term_buckets; region rgn; int ub; int size; int capacity; int inserts; }; static int hash(int ub, stamp stamps[], int len); static void post_insert(term_hash tab) deletes; static void rehash(term_hash tab) deletes; static void reinsert(term_hash tab, term_bucket b); static void insert(term_hash tab, gen_e e, stamp * stamps, int len); static void insert_entry(term_hash tab, struct hash_entry *entry); static gen_e walk(term_bucket b, stamp * stamps, int len); static const int primes[] = { 83, 1789, 5189, 5449, 5659, 6703, 7517, 7699, 8287, 8807, 9067, 9587, 10627, 10939, 11239}; /* static const int prime_1 = 83; static const int prime_2 = 1789; */ static const int initial_table_size = INITIAL_TABLE_SIZE; term_hash make_term_hash(region rgn) { int ub, n; int i; region r; term_hash tab = ralloc(rgn, struct term_hash); r = newregion(); ub = UB(initial_table_size); n = CAP(initial_table_size); tab->term_buckets = rarrayalloc(r, n, term_bucket); for (i = 0; i < n; i++) { tab->term_buckets[i] = NULL; } tab->rgn = r; tab->ub = ub; tab->size = initial_table_size; tab->capacity = n; tab->inserts = 0; return tab; } void term_hash_delete(term_hash tab) deletes { deleteregion(tab->rgn); } gen_e term_hash_find(term_hash tab, stamp stamps[], int len) { int hash_val; term_bucket b; hash_val = hash(tab->ub, stamps, len); b = tab->term_buckets[hash_val]; return walk(b, stamps, len); } static gen_e walk(term_bucket b, stamp stamps[], int len) { term_bucket cur; scan_term_bucket(b,cur) { if (len == cur->entry->length && (memcmp(stamps, cur->entry->stamps, sizeof(int)*len) == 0) ) return cur->entry->e; } return NULL; } /* Should call t_hash_find to see if a gen_e with the given stamp */ /* signature is already in the table. If so, insert should return */ /* true and do nothing. */ bool term_hash_insert(term_hash tab, gen_e e, stamp * stamps, int len) deletes { if (term_hash_find(tab, stamps, len) != NULL) { return TRUE; } insert(tab, e, stamps, len); post_insert(tab); return FALSE; } /* Insert an expression e represented by the given stamp array into */ /* the hash table. */ static void insert(term_hash tab, gen_e e, stamp stamps[], int len) { hash_entry entry; stamp * stamp_cpy; int i; entry = ralloc(tab->rgn, struct hash_entry); stamp_cpy = rarrayalloc(tab->rgn, len, stamp); for (i = 0; i < len; i++) { stamp_cpy[i] = stamps[i]; } entry->length = len; entry->stamps = stamp_cpy; entry->e = e; insert_entry(tab, entry); } static void insert_entry(term_hash tab, hash_entry entry) { int hash_val; term_bucket b, new_term_bucket; hash_val = hash(tab->ub, entry->stamps, entry->length); b = tab->term_buckets[hash_val]; new_term_bucket = ralloc(tab->rgn, struct term_bucket); new_term_bucket->entry = entry; new_term_bucket->next = b; tab->term_buckets[hash_val] = new_term_bucket; } static void post_insert(term_hash tab) deletes { if (tab->capacity == ++tab->inserts) { rehash(tab); } } /* Double the size of the hash table and reinsert all of the elements. */ static void rehash(term_hash tab) deletes { region old_rgn; term_bucket * old_term_buckets; int i; int old_table_size = tab->capacity; old_term_buckets = tab->term_buckets; tab->capacity *= 2; tab->ub = UB(++tab->size); old_rgn = tab->rgn; tab->rgn = newregion(); tab->term_buckets = rarrayalloc(tab->rgn, tab->capacity, term_bucket); for (i = 0; i < old_table_size; i++) { if (old_term_buckets[i] != NULL && old_term_buckets[i]->entry != NULL) reinsert(tab, old_term_buckets[i]); } deleteregion(old_rgn); } static void reinsert(term_hash tab, term_bucket b) { term_bucket cur; scan_term_bucket(b,cur) insert(tab, cur->entry->e, cur->entry->stamps, cur->entry->length); } static int hash(int ub, stamp stamps[], int len) { int i, n; n = 0; for (i = 0; i < len; i++) { n = (n + (primes[i % 15] * abs(stamps[i]))) & ub; } return n; }