home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World 1998 October
/
PCWorld_1998-10_cd.bin
/
software
/
prehled
/
komix
/
DATA.Z
/
HashTbl.hxx
< prev
next >
Wrap
Text File
|
1996-05-31
|
15KB
|
484 lines
/*---------------------------------------------------------------------------
*
* (c) Westmount Technology 1991
*
* File: @(#)HashTbl.hxx 1.2 (1.7) (1.1)
* Author: sipi (original by K.E. Gorlen)
* Description: implementation of hash tables
* A hash table is an unordered collection of objects in which
* no object is duplicated. Duplicate objects are defined by
* the function Hashable::isEqual.
* The capacity() function returns 1/2 the capacity of the
* hash table and the size() function returns the number of
* objects currently in the hash table.
* For efficiency, the capacity is always a power of two and
* is doubled whenever the table becomes half full.
*
*---------------------------------------------------------------------------
SccsId = @(#)HashTbl.hxx 1.2 (1.7) (1.1)\t11 Nov 1993 Copyright 1992 Westmount Technology */
#ifndef HASHTBL_HXX
#define HASHTBL_HXX
#ifndef TEMPLCONF_HXX
#include "TemplConf.hxx"
#endif
#if HAS_TEMPLATES
#ifndef FLEXARRAY_HXX
#include <FlexArray.hxx>
#endif
class Hashable {
public:
Hashable() {}
virtual ~Hashable();
// Calculate a hash value for this object
//
virtual unsigned hash() const = 0;
// Compare the given key with the key from this Hashable
// If both are equal then return 1 else return 0
//
virtual int isEqual(const Hashable& key) const = 0;
};
class hash_iter;
typedef Hashable *hashptr;
typedef FlexArray<hashptr> hashList;
class HashTbl {
friend class hash_iter;
private:
unsigned count; // number of objects in set
unsigned nbits; // log base 2 of contents.capacity()
unsigned mask; // contents.capacity()-1
hashList contents; // array of pointers to Hashables
int current; // current in array for first/next
private:
// Compute set allocation size.
// Round size up to the next highest power of two, if necessary
//
unsigned setCapacity(unsigned);
// Convert hash key into contents index
//
int getIndex(unsigned long) const;
// Search this set for the specified Hashable
// and return index of object if found or nil slot if not found
//
int findIndexOf(const Hashable&) const;
// Change the capacity of this HashTbl to new size
//
void reSize(unsigned new_size);
public:
static unsigned DEFAULT_SIZE; // HashTbl size
static unsigned EXPANSION_FACTOR; // HashTbl grow factor
public:
HashTbl(unsigned size = HashTbl::DEFAULT_SIZE);
HashTbl(const HashTbl&);
~HashTbl();
HashTbl& operator=(const HashTbl&);
// Add an object to this HashTbl,
// making the HashTbl larger if it becomes half full.
// Return pointer to given object if it does not yet exist
// else return pointer to existing object in HashTbl.
//
Hashable *add(Hashable&);
// Add all objects from given HashTbl to this HashTbl
//
void addAll(const HashTbl&);
// Remove object from HashTbl
// Return pointer to given object of it is removed
// else return 0 if it does not exist in this HashTbl.
//
Hashable *remove(const Hashable&);
// Remove all objects from HashTbl
//
void removeAll();
// Remove all objects present in given HashTbl from HashTbl
//
void removeAll(const HashTbl&);
// Remove all objects from HashTbl and destruct each individual object
//
void destructAll();
// Find object in HashTbl using given key
// Returns 0 if not found else pointer to object
//
Hashable *find(const Hashable& key) const
{return contents.at(findIndexOf(key));}
Hashable *operator[](const Hashable& key) const
{return contents.at(findIndexOf(key));}
// Return 1 if the specified HashTbl equals this HashTbl
// Else return 0
//
int operator==(const HashTbl&) const;
// Return 1 if the specified HashTbl does not equal this HashTbl
// Else return 0
//
int operator!=(const HashTbl& tbl) const {return !(*this==tbl);}
// Walk through HashTbl using index
// Either 0 or a pointer to a Hashable is returned
//
Hashable *at(int index) const {return contents[index];}
// Walk through HashTbl using first/next (no order is defined)
// Returns 0 if the HashTbl is empty or no next element.
//
Hashable *first();
Hashable *next();
// The capacity() function returns 1/2 the capacity of the
// hash table and the size() function returns the number of
// objects currently in the hash table.
//
unsigned capacity() const {return contents.capacity()>>1;}
unsigned size() const {return count;}
};
class hash_iter {
const HashTbl& tbl;
int curr_idx;
public:
hash_iter(const HashTbl& tbl);
~hash_iter();
// Start iterating again
//
void rewind(void);
// Go to next element if there is one
// Sets the iterator in the end-of-iteration state if positioned
// at the last element
//
void advance(void);
// get current entry if there is one
// Effect is undefined if iterator is in end-of-iteration state
//
Hashable* get(void) const { return tbl.at(curr_idx); }
// testing: return non-0 if advanced over the last element
//
int end_of_iteration(void) const { return curr_idx == -1; }
// Shorthands:
operator const void* (void) const
{ return end_of_iteration()? 0: this; }
int operator ! (void) const { return !end_of_iteration(); }
void operator++ (void) { advance(); }
Hashable* operator() (void) const { return get(); }
};
template<class Key, class Value> class hashTbl;
template<class Key, class Value>
class hashIter : private hash_iter {
public:
hash_iter::rewind;
hash_iter::advance;
hash_iter::end_of_iteration;
hash_iter::operator !;
hash_iter::operator++;
hashIter(const hashTbl<Key,Value>& x): hash_iter(x) {}
Value* operator()() { return (Value*) hash_iter::operator()();}
Value* get() { return (Value*) hash_iter::get();}
operator const void* () const
{ return hash_iter::operator const void*(); }
};
template<class Key, class Value>
class hashTbl : private HashTbl {
friend class hashIter<Key, Value>;
public:
hashTbl<Key,Value>& operator=(const hashTbl<Key,Value>& tbl)
{return (hashTbl<Key,Value> &) HashTbl::operator=(tbl);}
hashTbl(unsigned size = HashTbl::DEFAULT_SIZE)
: HashTbl(size) {}
hashTbl(const hashTbl<Key,Value> & tbl)
: HashTbl(tbl) {}
Value *add(Key & x)
{return (Value*)HashTbl::add(x);}
void addAll(const hashTbl<Key,Value> & tbl)
{HashTbl::addAll(tbl);}
Value *remove(const Key & x )
{return (Value*) HashTbl::remove(x);}
Value *find(const Key & x) const
{return (Value*) HashTbl::find(x);}
Value *operator[](const Key & x) const
{return (Value*) HashTbl::operator[](x);}
int operator==(const hashTbl<Key,Value> & tbl) const
{return HashTbl::operator==(tbl);}
int operator!=(const hashTbl<Key,Value> & tbl) const
{return HashTbl::operator!=(tbl);}
Value *at(int index) const
{return (Value*) HashTbl::at(index);}
Value *first()
{return (Value*) HashTbl::first();}
Value *next()
{return (Value*) HashTbl::next();}
void removeAll()
{HashTbl::removeAll();}
void removeAll(const hashTbl<Key,Value> & tbl)
{HashTbl::removeAll(tbl);}
void destructAll()
{HashTbl::destructAll();}
unsigned capacity() const
{return HashTbl::capacity();}
unsigned size() const
{return HashTbl::size();}
};
#else
#ifndef GENERICH
#include <generic.h>
#endif
#ifndef FLEXARRAY_HXX
#include <FlexArray.hxx>
#endif
class Hashable {
public:
Hashable() {}
virtual ~Hashable();
// Calculate a hash value for this object
//
virtual unsigned hash() const = 0;
// Compare the given key with the key from this Hashable
// If both are equal then return 1 else return 0
//
virtual int isEqual(const Hashable& key) const = 0;
};
class hash_iter;
typedef Hashable *hashptr;
declare(FlexArray,hashptr);
typedef hashptr_FlexArray hashList;
class HashTbl {
friend class hash_iter;
private:
unsigned count; // number of objects in set
unsigned nbits; // log base 2 of contents.capacity()
unsigned mask; // contents.capacity()-1
hashList contents; // array of pointers to Hashables
int current; // current in array for first/next
private:
// Compute set allocation size.
// Round size up to the next highest power of two, if necessary
//
unsigned setCapacity(unsigned);
// Convert hash key into contents index
//
int getIndex(unsigned long) const;
// Search this set for the specified Hashable
// and return index of object if found or nil slot if not found
//
int findIndexOf(const Hashable&) const;
// Change the capacity of this HashTbl to new size
//
void reSize(unsigned new_size);
public:
static unsigned DEFAULT_SIZE; // HashTbl size
static unsigned EXPANSION_FACTOR; // HashTbl grow factor
public:
HashTbl(unsigned size = HashTbl::DEFAULT_SIZE);
HashTbl(const HashTbl&);
~HashTbl();
HashTbl& operator=(const HashTbl&);
// Add an object to this HashTbl,
// making the HashTbl larger if it becomes half full.
// Return pointer to given object if it does not yet exist
// else return pointer to existing object in HashTbl.
//
Hashable *add(Hashable&);
// Add all objects from given HashTbl to this HashTbl
//
void addAll(const HashTbl&);
// Remove object from HashTbl
// Return pointer to given object of it is removed
// else return 0 if it does not exist in this HashTbl.
//
Hashable *remove(const Hashable&);
// Remove all objects from HashTbl
//
void removeAll();
// Remove all objects present in given HashTbl from HashTbl
//
void removeAll(const HashTbl&);
// Remove all objects from HashTbl and destruct each individual object
//
void destructAll();
// Find object in HashTbl using given key
// Returns 0 if not found else pointer to object
//
Hashable *find(const Hashable& key) const
{return contents.at(findIndexOf(key));}
Hashable *operator[](const Hashable& key) const
{return contents.at(findIndexOf(key));}
// Return 1 if the specified HashTbl equals this HashTbl
// Else return 0
//
int operator==(const HashTbl&) const;
// Return 1 if the specified HashTbl does not equal this HashTbl
// Else return 0
//
int operator!=(const HashTbl& tbl) const {return !(*this==tbl);}
// Walk through HashTbl using index
// Either 0 or a pointer to a Hashable is returned
//
Hashable *at(int index) const {return contents[index];}
// Walk through HashTbl using first/next (no order is defined)
// Returns 0 if the HashTbl is empty or no next element.
//
Hashable *first();
Hashable *next();
// The capacity() function returns 1/2 the capacity of the
// hash table and the size() function returns the number of
// objects currently in the hash table.
//
unsigned capacity() const {return contents.capacity()>>1;}
unsigned size() const {return count;}
};
class hash_iter {
const HashTbl& tbl;
int curr_idx;
public:
hash_iter(const HashTbl& tbl);
~hash_iter();
// Start iterating again
//
void rewind(void);
// Go to next element if there is one
// Sets the iterator in the end-of-iteration state if positioned
// at the last element
//
void advance(void);
// get current entry if there is one
// Effect is undefined if iterator is in end-of-iteration state
//
Hashable* get(void) const { return tbl.at(curr_idx); }
// testing: return non-0 if advanced over the last element
//
int end_of_iteration(void) const { return curr_idx == -1; }
// Shorthands:
operator const void* (void) const
{ return end_of_iteration()? 0: this; }
int operator ! (void) const { return !end_of_iteration(); }
void operator++ (void) { advance(); }
Hashable* operator() (void) const { return get(); }
};
#define hashTbl(key,keyval) name3(key,keyval,_HashTbl)
#define hashIter(key,keyval) name3(key,keyval,_hash_iter)
#define hashIterdeclare2(key,keyval) \
class hashIter(key,keyval) : private hash_iter { \
public: \
hash_iter::rewind; \
hash_iter::advance; \
hash_iter::end_of_iteration; \
hash_iter::operator !; \
hash_iter::operator++; \
\
hashIter(key,keyval)(const hashTbl(key,keyval)& x): hash_iter(x){}\
keyval* operator()() { return (keyval*) hash_iter::operator()();}\
keyval* get() { return (keyval*) hash_iter::get();} \
operator const void* () const \
{ return hash_iter::operator const void*(); } \
}
#define HashTbldeclare2(key,keyval) \
class hashTbl(key,keyval) : private HashTbl { \
friend class hashIter(key,keyval); \
public: \
hashTbl(key,keyval) & operator=(const hashTbl(key,keyval) & tbl)\
{return (hashTbl(key,keyval) &) HashTbl::operator=(tbl);} \
hashTbl(key,keyval) (unsigned size = HashTbl::DEFAULT_SIZE) \
: HashTbl(size) {} \
hashTbl(key,keyval) (const hashTbl(key,keyval) & tbl) \
: HashTbl(tbl) {} \
keyval *add(key & x) \
{return (keyval*)HashTbl::add(x);} \
void addAll(const hashTbl(key,keyval) & tbl) \
{HashTbl::addAll(tbl);} \
keyval *remove(const key & x ) \
{return (keyval*) HashTbl::remove(x);} \
keyval *find(const key & x) const \
{return (keyval*) HashTbl::find(x);} \
keyval *operator[](const key & x) const \
{return (keyval*) HashTbl::operator[](x);} \
int operator==(const hashTbl(key,keyval) & tbl) const\
{return HashTbl::operator==(tbl);} \
int operator!=(const hashTbl(key,keyval) & tbl) const\
{return HashTbl::operator!=(tbl);} \
keyval *at(int index) const \
{return (keyval*) HashTbl::at(index);} \
keyval *first() \
{return (keyval*) HashTbl::first();} \
keyval *next() \
{return (keyval*) HashTbl::next();} \
void removeAll() \
{HashTbl::removeAll();} \
void removeAll(const hashTbl(key,keyval) & tbl) \
{HashTbl::removeAll(tbl);} \
void destructAll() \
{HashTbl::destructAll();} \
unsigned capacity() const \
{return HashTbl::capacity();} \
unsigned size() const \
{return HashTbl::size();} \
}; \
hashIterdeclare2(key,keyval)
#endif /* HAS_TEMPLATES */
#endif /* HASHTBL_HXX */