head	1.1;
branch	1.1.1;
access;
symbols
	tonic_4:1.1.1.1
	tonic_3:1.1.1.1
	tonic_2:1.1.1.1
	demo:1.1.1.1.0.2
	design_report:1.1.1.1
	dec5:1.1.1.1
	course_staff:1.1.1;
locks; strict;
comment	@# @;


1.1
date	95.12.05.07.17.59;	author hartmans;	state Exp;
branches
	1.1.1.1;
next	;

1.1.1.1
date	95.12.05.07.18.00;	author hartmans;	state Exp;
branches;
next	;


desc
@@



1.1
log
@Initial revision
@
text
@// Copyright 1995 Barbara Liskov

#ifndef _BHASH_T
#define _BHASH_T

#include "bhash.h"

#include <assert.h>
#include <stdlib.h>
#include <unistd.h>

#define BH_PRECBITS ((sizeof(int)<<3) - 2)

#define BH_PHI 1.618033989
/* The golden ratio */

#define BH_HASHMULT 1737350766
/* This is int(PHI * (1<<PRECBITS)), suggested by Knuth as a good hash
   multiplier.
*/

#define BH_MAX_DESIRED_ALPHA 3
/* "alpha" is the ratio of items to the hash table to slots, as described
   in CLR, Chapter 12.
*/

#define BH_EXCESSIVE_RECIPROCAL_ALPHA 20
/* The point at which the hash table tries to shrink because it has
   become too sparse.
*/

#define bhasht bhash<KEY,VALUE,PAIRSET> 

BH_TEMPLATE class bhash_generator : public hash_generator<KEY, VALUE> {
/*
    A "generator" generates all key/value pairs in a hash table. Its
    specification is provided above.
*/
public:
    bhash_generator(bhasht &h) {
	slot = 0;
	hash_table = &h;
	subgenerator = h.pairsets[0].mappings();
    }
    virtual bool get(KEY &k);
    virtual VALUE value() const;
    virtual void remove();
protected:
    bhasht *hash_table;
    int slot;
    hash_generator<KEY, VALUE> *subgenerator;
};

BH_TEMPLATE bool bhash_generator<KEY, VALUE, PAIRSET>::get(KEY &k) {
    hash_generator<KEY, VALUE> *sg = subgenerator;
    if (sg->get(k)) return TRUE;
    do {
	slot++;
	delete sg;
	sg = hash_table->pairsets[slot].mappings();
	if (slot == hash_table->numSlots) {
#ifndef NDEBUG
	    // benevolent side-effects for debugging
	    slot = -1;
	    subgenerator = 0;
#endif
	    return FALSE;
	}
    } while (!sg->get(k));
    subgenerator = sg;
    return TRUE;
}

BH_TEMPLATE void bhash_generator<KEY, VALUE, PAIRSET>::remove() {
    assert(subgenerator != 0);
    subgenerator->remove(); 
    hash_table->numItems--;
}

BH_TEMPLATE VALUE bhash_generator<KEY, VALUE, PAIRSET>::value() const {
    assert(subgenerator != 0);
    return subgenerator->value();
}

BH_TEMPLATE hash_generator<KEY, VALUE> *bhasht::mappings()
{
    return new bhash_generator<KEY, VALUE, PAIRSET>(*this);
}

BH_TEMPLATE generator<KEY> *bhasht::keys() const
{
    return new bhash_generator<KEY, VALUE, PAIRSET>((bhasht &)*this);
	// since we're hiding the hash_generator in a generator,
	// it's okay to cast "this" to be non-const.
}
    
BH_TEMPLATE int bhasht::do_hash(KEY key) const {
    return ((BH_HASHMULT*key.hash())&((1<<BH_PRECBITS) - 1)) >>
	(BH_PRECBITS - slotBits);
}

BH_TEMPLATE bhasht::bhash(int size_hint) {
    numItems = 0;
    sizeup(size_hint);
    pairsets = new PAIRSET[numSlots];
}

BH_TEMPLATE bhasht::~bhash() {
    delete [] pairsets;
}

BH_TEMPLATE void bhasht::copy_items(bhasht const &bh) {
    numItems = 0;
    sizeup(bh.numItems);
    pairsets = new PAIRSET[numSlots];
    hash_generator<KEY, VALUE> *g = ((bhasht &)bh).mappings();
    KEY k;
    while (g->get(k)) add(k, g->value());
    delete g;
}

BH_TEMPLATE bhasht::bhash(bhasht const &bh) {
    copy_items(bh);
}

BH_TEMPLATE bhasht const &bhasht::operator=(bhasht const &bh) {
    if (this == &bh) return *this;
    delete [] pairsets;
    copy_items(bh);
    return *this;
}

BH_TEMPLATE int bhasht::size() const {
    return numItems;
}

BH_TEMPLATE void bhasht::add(KEY key, VALUE value) {
#ifndef NDEBUG
    VALUE dummy(value);
    assert(false == find(key, dummy));
#endif
    pairsets[do_hash(key)].add(key, value);
    numItems++;
}

BH_TEMPLATE bool bhasht::find(KEY key, VALUE &value) const {
    return pairsets[do_hash(key)].find(key, value);
}

BH_TEMPLATE bool bhasht::contains(KEY key) const {
    VALUE value;
    return pairsets[do_hash(key)].find(key, value);
}

BH_TEMPLATE VALUE bhasht::operator[](KEY key) const {
    return pairsets[do_hash(key)].fetch(key);
}

BH_TEMPLATE bool bhasht::store(KEY key, VALUE value) {
    bool result = pairsets[do_hash(key)].store(key, value);
    if (!result) numItems++;
    return result;
}

BH_TEMPLATE bool bhasht::remove(KEY key, VALUE &value) {
    bool result = pairsets[do_hash(key)].remove(key, value);
    if (result) {
	numItems--;
    }
    return result;
}

BH_TEMPLATE void bhasht::allowAutoResize() {
    predict(numItems / BH_MAX_DESIRED_ALPHA);
}


BH_TEMPLATE void bhasht::sizeup(int desired_size) {
    numSlots = 1;
    slotBits = 0;
    while (numSlots < desired_size) { numSlots <<= 1; slotBits++; }
}

BH_TEMPLATE void bhasht::predict(int desired_size)
{
    if (numSlots >= desired_size &&
	numSlots < desired_size * BH_EXCESSIVE_RECIPROCAL_ALPHA) return;
    if (slotBits == BH_PRECBITS &&
	numSlots < desired_size) return; /* can't make it any bigger! */

    int old_slots = numSlots;
    PAIRSET *old_pairsets = pairsets;

    sizeup(desired_size);
    pairsets = new PAIRSET[numSlots];
    numItems = 0;
    
    int i;
    for (i=0; i<old_slots; i++) {
	hash_generator<KEY, VALUE> *g = old_pairsets[i].mappings();
	KEY k;
	while (g->get(k)) add(k, g->value());
	delete g;
    }
    delete old_pairsets;
}

extern "C" { float sqrtf(float); }

BH_TEMPLATE float bhasht::estimateClumping() const {
    int i;
    double sx2=0.;
    int n=numSlots;
    float m = numItems;
    for (i=0; i<n; i++) {
	int x=0;
	hash_generator<KEY, VALUE> *g = pairsets[i].mappings();
	KEY k;
	while (g->get(k)) x++;
	delete g;
        sx2 += x * x;
    }
    return sx2/m - m/n;
}

#endif /* _BHASH_T */
@


1.1.1.1
log
@Need to fix template instantiation problems--importing as appropriate
@
text
@@
