Files
cdesktop/cde/programs/dtinfo/DtMmdb/dynhash/imp_die.C
2018-04-28 12:30:20 -06:00

632 lines
13 KiB
C

/*
* 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 libraries 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 <iostream>
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<B; i++ ) {
delete bucket_array[i];
}
bucket_holder* x = free_list_head;
while ( x ) {
bucket_holder* y = x -> 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<B; delete bucket_array[i++] );
delete [] bucket_array ;
}
B = new_H/2;
bucket_array = new imp_bucketPtr[B];
if ( hash_table ) {
delete [] hash_table;
}
hash_table = new data_tPtr[new_H];
H = new_H;
}
void imp_die::init_table()
{
int i;
for ( i = 0; i < B; i++ ) {
bucket_array[i] = 0 ;
}
for ( i = 0; i < H; i++ ) {
hash_table[i] = 0;
}
}
void imp_die::clean()
{
n = 0;
collect_all_keys();
int i;
for ( i=0; i<B; i++ ) {
if ( bucket_array[i] ) {
delete bucket_array[i];
bucket_array[i] = 0 ;
}
}
for ( i=0; i<H; i++ )
hash_table[i] = 0;
}
/*****************************/
// collect all keys into
// bcuket_list_head
/*****************************/
void imp_die::collect_all_keys()
{
for ( int i = 0; i < B; i++ )
if ( bucket_array[i] ) {
bucket_holder *x ;
if ( free_list_head ) {
x = free_list_head ;
//debug(cerr, "get from free list");
free_list_head = free_list_head -> 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;
}