/* * CDE - Common Desktop Environment * * Copyright (c) 1993-2012, The Open Group. All rights reserved. * * These libraries and programs are free software; you can * redistribute them and/or modify them under the terms of the GNU * Lesser General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * These libraries and programs are distributed in the hope that * they will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public * License along with these librararies and programs; if not, write * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301 USA */ /* * $XConsortium: imp_die.C /main/5 1996/08/21 15:52:00 drk $ * * Copyright (c) 1993 HAL Computer Systems International, Ltd. * All rights reserved. Unpublished -- rights reserved under * the Copyright Laws of the United States. USE OF A COPYRIGHT * NOTICE IS PRECAUTIONARY ONLY AND DOES NOT IMPLY PUBLICATION * OR DISCLOSURE. * * THIS SOFTWARE CONTAINS CONFIDENTIAL INFORMATION AND TRADE * SECRETS OF HAL COMPUTER SYSTEMS INTERNATIONAL, LTD. USE, * DISCLOSURE, OR REPRODUCTION IS PROHIBITED WITHOUT THE * PRIOR EXPRESS WRITTEN PERMISSION OF HAL COMPUTER SYSTEMS * INTERNATIONAL, LTD. * * RESTRICTED RIGHTS LEGEND * Use, duplication, or disclosure by the Government is subject * to the restrictions as set forth in subparagraph (c)(l)(ii) * of the Rights in Technical Data and Computer Software clause * at DFARS 252.227-7013. * * HAL COMPUTER SYSTEMS INTERNATIONAL, LTD. * 1315 Dell Avenue * Campbell, CA 95008 * */ #include "dynhash/imp_die.h" #ifdef C_API #include "utility/c_iostream.h" #else #include using namespace std; #endif int steps[] = { 2, 3, 5, 7, 11, 13, 17, 21, 23, 29, 31, 37, 41, 43, 47, 51 }; int no_steps; #define PRIME_LEVLE_2 2147483647 imp_die::imp_die(int prime, int expected_n) : p(prime), H(0), B(0), n(0), bucket_array(0), hash_table(0), free_list_head(0), collected_records(0) { alloc_table(int(2.5*expected_n)); init_table(); rand_generator.seed(); k = rand_generator.rand(); no_steps = sizeof(steps) / sizeof(int); } imp_die::~imp_die() { //debug(cerr, H); //debug(cerr, B); //debug(cerr, n); for ( int i = 0; i next; delete x; x = y ; } x = collected_records; while ( x ) { bucket_holder* y = x -> next; delete x -> data_ptr; delete x; x = y ; } delete hash_table; delete bucket_array ; } //********************************************************** // allocate new memory for the bucket table and hash table. // H is the size of the bucket table before // expansion. new\_H is the new size. //********************************************************** void imp_die::alloc_table(int new_H) { if ( bucket_array ) { for ( int i = 0; i next; } else { //debug(cerr, "get from new"); x = new bucket_holder; } //debug(cerr, int(x)); x -> data_ptr = bucket_array[i] -> remove_all(); delete bucket_array[i]; bucket_array[i] = 0; x -> next = collected_records; collected_records = x; } } /*****************************/ // rehash all keys /*****************************/ Boolean imp_die::rehash() { while ( 1 ) { collect_all_keys(); if ( 2*n > H ) alloc_table(2*H); init_table(); k = rand_generator.rand(); bucket_holder *x = collected_records; while ( x ) { data_t* y = x -> data_ptr; while ( y ) { data_t *z = (data_t*)(y -> v_succ); y -> v_pred = 0; y -> v_succ = 0; int hash = y -> bucket_num(k, p, B); if ( bucket_array[hash] == 0 ) bucket_array[hash] = new imp_bucket; bucket_array[hash] -> insert(y); y = z; } x = x -> next; } free_list_head = collected_records; collected_records = 0; Boolean rehash_done = true; for ( int i = 0; i < B; i++ ) if ( bucket_array[i] ) { if ( bucket_rehash(i) == false ) { debug(cerr, i); debug(cerr, *bucket_array[i]); rehash_done = false; break; //throw(stringException("rehash() failed")); } } if ( rehash_done == true ) return true; } } /************************************/ // insert /************************************/ Boolean imp_die::insert(data_t& v) { n++; int hash = v.bucket_num(k, p, B); if ( bucket_insert(hash, v) == false ) rehash(); return true; } /******************************************/ // remove operation /******************************************/ Boolean imp_die::remove(data_t& v) { MESSAGE(cerr, "imp_die::remove(data_t& v)"); int hash = v.bucket_num(k, p, B); /*********************************/ // assure the bucket is not empty /*********************************/ if ( bucket_remove(hash, v) == false ) return false; n--; /*********************************/ // delete the bucket if it becomes // empty /*********************************/ if ( bucket_array[hash] -> empty() == true ) { delete bucket_array[hash]; bucket_array[hash] = 0; } return true; } /*******************************************************/ // first level hash function /*******************************************************/ int imp_die::h(int key) const { return abs( k * key ) % p % B; } //static to_print = false; /****************************************/ // select a proper value for parameter k /****************************************/ Boolean imp_die::bucket_fix_k(int bucket_num) { int loops = 0; Boolean injective = false; imp_bucket& x = *bucket_array[bucket_num]; /* MESSAGE(cerr, "bucket_fix_k()"); debug(cerr, x); if ( bucket_num == 412 ) to_print = true; else to_print = false; */ while ( injective == false && loops < H ) { injective = test_injective(x); if ( injective == false ) { loops ++; x.k = abs(rand_generator.rand()) % ( p - 1 ) + 1; } } return true; } Boolean imp_die::test_injective(imp_bucket& x) { //MESSAGE(cerr, "test_injective()"); long ind_out = x.first(); while ( ind_out != 0 ) { data_t* out = x(ind_out); /* if ( to_print == true ) { debug(cerr, x.k); debug(cerr, x.rotate); debug(cerr, p); debug(cerr, M); } */ int hash_out = out -> slot_num(x.k, x.rotate, PRIME_LEVLE_2, H); long ind_in = ind_out; x.next(ind_in); while ( ind_in != 0 ) { data_t* in = x(ind_in); int hash_in = in -> slot_num(x.k, x.rotate, PRIME_LEVLE_2, H); if ( hash_out == hash_in ) { /* if ( to_print == true ) { debug(cerr, x); debug(cerr, ind_in); debug(cerr, ind_out); debug(cerr, hash_in); debug(cerr, hash_out); } */ return false; } x.next(ind_in); } x.next(ind_out); } return true; } Boolean imp_die::bucket_rotate(int bucket_num) { imp_bucket& x = *bucket_array[bucket_num]; int loops = 0; int z = rand_generator.rand(); x.rotate = z % (H - 1) + 1; int step = steps[z % no_steps]; Boolean all_fit = false; int hash; while ( all_fit == false && loops < H ) { long ind = x.first(); while ( ind != 0 ) { data_t* data_ptr = x(ind); hash = data_ptr -> slot_num(x.k, x.rotate, PRIME_LEVLE_2, H); if ( hash_table[hash] != 0 ) { long ind1 = x.first(); while ( ind1 != ind ) { hash = x(ind1) -> slot_num(x.k, x.rotate, PRIME_LEVLE_2, H); hash_table[hash] = 0; x.next(ind1); } loops ++; x.rotate += step; break; } hash_table[hash] = data_ptr; x.next(ind); } all_fit = ( ind == 0 ) ? true : false; } return all_fit ; } Boolean imp_die::bucket_insert(int bucket_num, data_t& v) { if ( bucket_array[bucket_num] == 0 ) { bucket_array[bucket_num] = new imp_bucket(); } imp_bucketPtr x = bucket_array[bucket_num]; data_t* y = 0; if ( collected_records ) { bucket_holder* first_list = collected_records; y = first_list -> data_ptr; first_list -> data_ptr = (data_t*)(y -> v_succ); if ( first_list -> data_ptr == 0 ) { collected_records = collected_records -> next; delete first_list; } *y = v; } else y = new data_t(v); x -> insert(y); int hash = y -> slot_num(x->k, x->rotate, PRIME_LEVLE_2, H); if ( hash_table[hash] == 0 ) { hash_table[hash] = y; return true; } //******************************* // clear the hash table entries //******************************* long ind = x -> first(); while ( ind ) { int hash = (*x)(ind) -> slot_num(x->k, x->rotate, PRIME_LEVLE_2, H); if ( hash_table[hash] && *hash_table[hash] == *(*x)(ind) ) hash_table[hash] = 0; x -> next(ind); } return bucket_rehash(bucket_num); /* debug(cerr, bucket_num); debug(cerr, int(x)); debug(cerr, int(bucket_array)); debug(cerr, int(bucket_array[bucket_num])); */ } //******************************* // rehash keys in the bucket //******************************* Boolean imp_die::bucket_rehash(int bucket_num) { bucket_fix_k(bucket_num); return bucket_rotate(bucket_num); } Boolean imp_die::bucket_remove(int bucket_num, data_t& v) { imp_bucketPtr x = bucket_array[bucket_num]; if ( x == 0 ) return false; int hash = v.slot_num(x->k, x->rotate, PRIME_LEVLE_2, H); if ( hash_table[hash] && *hash_table[hash] == v ) { x -> delete_cell(hash_table[hash]); delete hash_table[hash]; hash_table[hash] = 0; //MESSAGE(cerr, "afterremove the entry"); //debug(cerr, *x); return true; } else return false; } Boolean imp_die::bucket_member(int bucket_num, data_t& v) const { /* debug(cerr, bucket_num); debug(cerr, v); */ imp_bucketPtr x = bucket_array[bucket_num]; if ( x == 0 ) { //MESSAGE(cerr, "empty bucket"); //debug(cerr, int(bucket_array)); return false; } int hash = v.slot_num(x->k, x->rotate, PRIME_LEVLE_2, H); if ( hash_table[hash] ) { v.dt = hash_table[hash] -> dt; if ( *hash_table[hash] == v ) { /* MESSAGE(cerr, "hash table entry match"); debug(cerr, int(this)); debug(cerr, v); debug(cerr, *hash_table[hash]); */ return true; } else { return false; } } else { return false; } } int imp_die::first_bucket() { if ( B > 0 ) return 0; else return -1; } void imp_die::next_bucket(int& ind) { if ( ind >= B ) ind = -1; else ind++; } imp_bucket* imp_die::get_bucket(int& ind) { while ( ind < B && bucket_array[ind] == 0 ) ind++; if ( ind >= B ) return 0; else return bucket_array[ind]; } /*******************************************************/ // print operation /*******************************************************/ ostream& imp_die::asciiOut(ostream& out) { int ind = first_bucket(); while ( ind != -1 ) { imp_bucket* bucket = get_bucket(ind); if ( bucket ) out << *bucket; next_bucket(ind); } return out; } istream& imp_die::asciiIn(istream& in) { data_t actor; while ( in >> actor ) { insert(actor); } return in; } ostream& imp_die::asciiOut(ostream& out, print_func_ptr_t print_f) { int ind = first_bucket(); while ( ind != -1 ) { imp_bucket* bucket = get_bucket(ind); if ( bucket ) { bucket -> asciiOut(out, print_f); } next_bucket(ind); } return out; }