home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
a_arrays.zip
/
ASSOC.CPP
next >
Wrap
Text File
|
1994-10-31
|
14KB
|
333 lines
/***************************************************************
* file: ASSOC.CPP
* purpose: template class for associative arrays
* contains:
* ASSOCIATION_BASE - core routines for the ASSOCIATION template
* ASSOCIATION - association between strings and data objects
* copyright: 1994 by David Weber. Unlimited use granted in EXE, OBJ,
* or LIB formats. Do not sell as source without asking first.
* environment:
* tested Borland C++ 4.01 and Zortech C++ 3.1r2
* history:
* 10-02-94 - initial code, based on an earlier C module
**************************************************************/
#include "assoc.hpp"
/************************************************
* function: ASSOCIATION_BASE::ASSOCIATION_BASE(unsigned int data_size,unsigned int estimated_size)
* Constructor for an associative array
* parameters: byte size of a data element and the estimated size of array
* returns: nothing
************************************************/
ASSOCIATION_BASE::ASSOCIATION_BASE(unsigned int data_size,unsigned int estimated_size)
{
clear_pointers(); // preset as invalid
sizeofdata = data_size; // set up sizes
array_size = estimated_size;
fill_level = 0; // empty to start
allocate_array(); // allocate space
}
/************************************************
* function: ASSOCIATION_BASE::~ASSOCIATION_BASE()
* Destructor for an associative array
* parameters: none
* returns: nothing
************************************************/
ASSOCIATION_BASE::~ASSOCIATION_BASE()
{
delete_pointers(); // delete storage
clear_pointers(); // just for tidiness
}
/************************************************
* function: ASSOCIATION_BASE::ASSOCIATION_BASE(const ASSOCIATION_BASE &original)
* copy constructor for class
* parameters: previous associative array to copy
* returns: nothing
************************************************/
ASSOCIATION_BASE::ASSOCIATION_BASE(const ASSOCIATION_BASE &original)
{
clear_pointers(); // no heap to start
*this = original; // piggyback on assignment operator
}
/************************************************
* function: ASSOCIATION_BASE & ASSOCIATION_BASE::operator=(const ASSOCIATION_BASE &original)
* assigment operator for class
* parameters: previous associative array to copy
* returns: *this
************************************************/
ASSOCIATION_BASE & ASSOCIATION_BASE::operator=(const ASSOCIATION_BASE &original)
{
delete_pointers(); // remove old storage
clear_pointers(); // no heap to start
array_size = original.array_size; // essential data
fill_level = original.fill_level;
sizeofdata = original.sizeofdata;
allocate_array(); // allocate heap
if (!*this) // valid?
return *this;
// copy hash, keys, links and data; this only works cuz linkage is via offsets
memcpy(hash_list,original.hash_list,array_size * sizeof(unsigned int));
memcpy(key_list,original.key_list,fill_level * sizeof(const char *));
memcpy(link_list,original.link_list,fill_level * sizeof(unsigned int));
memcpy(data_list,original.data_list,array_size * sizeofdata);
return *this;
}
/************************************************
* function: ASSOCIATION_BASE::ASSOCIATION_BASE(const char **keys,const char *data,unsigned int data_size,unsigned int count)
* static initialization constructor, build an associative array with
* pre-existing key and data arrays.
* parameters: pointer to an array of keys, pointer to an array of data
* expressed as chars, size of array in elements
* returns: nothing
************************************************/
ASSOCIATION_BASE::ASSOCIATION_BASE(const char **keys,const char *data,unsigned int data_size,unsigned int count)
{
unsigned int i;
clear_pointers(); // mark storage as invalid
sizeofdata = data_size; // set up sizes
array_size = count;
fill_level = 0; // empty to start
allocate_array(); // allocate space
if (!*this) // valid?
return;
for (i = 0 ; i < count ; i++, keys++, data += sizeofdata)
insert(*keys,data); // add info
}
/************************************************
* function: int ASSOCIATION_BASE::insert(const char *key,const char *data)
* Insert an entry into the associative array. The caller is responsible for
* storage of the key;
* parameters: const pointer to key string and const or non const pointer to data
* returns: 1 if inserted OK or 0 if a bad key
************************************************/
int ASSOCIATION_BASE::insert(const char *key,const char *data)
{
unsigned int index,k;
if (key == 0) // no null keys allowed
return 0;
if (fill_level >= array_size)
if (!expand_array())
return 0;
index = hash(key); // find start in array
for (k = hash_list[index] ; k != ASSOC_NULL ; k = link_list[k])
{ // see if already exists
if (ASSOC_STRCMP(key,key_list[k]) == 0)
{ // replace current data
memcpy(data_list+k*sizeofdata,data,sizeofdata);
return 1;
}
}
key_list[fill_level] = key; // put in new data
link_list[fill_level] = hash_list[index];
hash_list[index] = fill_level;
memcpy(data_list+fill_level*sizeofdata,data,sizeofdata);
fill_level++;
return 1;
}
/************************************************
* function: int ASSOCIATION_BASE::remove(const char *key)
* Remove an entry from the associative array
* parameters: const pointer to the key string
* returns: 1 if removed or 0 if not found in the array
************************************************/
int ASSOCIATION_BASE::remove(const char *key)
{
unsigned int k,*l;
if (key == 0) // no null keys allowed
return 0;
for (l=hash_list+hash(key), k=*l ; k != ASSOC_NULL ; l=link_list+k, k=*l)
{ // find entry
if (ASSOC_STRCMP(key,key_list[k]) == 0)
{
*l = link_list[k]; // unlink
fill_level--; // level shrinks
key_list[k] = key_list[fill_level];// move top of pile into "removed"
link_list[k] = link_list[fill_level];
memcpy(data_list+k*sizeofdata,data_list+fill_level*sizeofdata,sizeofdata);
for (l = hash_list+hash(key_list[k]) ; *l != ASSOC_NULL ; l = link_list + *l)
if (*l == fill_level)
{ // fix link to what was top of pile
*l = k;
break;
}
return 1;
}
}
return 0; // doesn't exist
}
/************************************************
* function: char *ASSOCIATION_BASE::find(const char *key)
* Lookup an entry in the associative array and return a non const pointer
* parameters: const pointer to the key string
* returns:non const pointer to the data associated with the key
************************************************/
char *ASSOCIATION_BASE::find(const char *key)
{
unsigned int k;
if (key == 0) // no null keys allowed
return 0;
for (k = hash_list[hash(key)] ; k != ASSOC_NULL ; k = link_list[k])
{ // follow chain in array
if (ASSOC_STRCMP(key,key_list[k]) == 0)
return data_list + k * sizeofdata;
}
return 0; // not found
}
/************************************************
* function: const char *ASSOCIATION_BASE::first(void)
* Find the first key string in the array. Follow this by
* next() calls until a 0 is returned. Inserting or Removing
* from an array while you are iterating will invalidate the
* iteration sequence (but doesn't mess up the array).
* parameters: none
* returns: first key string encountered or 0 if none
************************************************/
const char *ASSOCIATION_BASE::first(void)
{
iteration = 0; // start from beginning
return next(); // and search
}
/************************************************
* function: const char *ASSOCIATION_BASE::next(void)
* Find the next key string in the array, call first()
* to start iteration.
* parameters: nothing
* returns: next key string encountered or 0 if all done
************************************************/
const char *ASSOCIATION_BASE::next(void)
{
while (iteration < fill_level) // until end of data
return key_list[iteration++]; // return key
return 0;
}
/************************************************
* function: char *ASSOCIATION_BASE::reference(const char *key)
* find a key and return a reference to its data if it is there
* otherwise insert a place for it and return a reference to the
* zeroed out hole
* parameters: const pointer to the key string
* returns: pointer to associated data (which may be zeroed out)
************************************************/
char *ASSOCIATION_BASE::reference(const char *key)
{
unsigned int k,index;
if (key == 0) // no null keys allowed
return 0;
index = hash(key);
for (k = hash_list[index] ; k != ASSOC_NULL ; k = link_list[k])
{ // follow chain in array
if (ASSOC_STRCMP(key,key_list[k]) == 0)
return data_list + k * sizeofdata; // found it
}
if (fill_level >= array_size) // expand if necessary
if (!expand_array())
return 0;
key_list[fill_level] = key; // put in hole for new data
link_list[fill_level] = hash_list[index];
hash_list[index] = fill_level;
memset(data_list+sizeofdata*fill_level,0,sizeofdata);
return data_list + sizeofdata*fill_level++;// return pointer to hole
}
/************************************************
* function: unsigned int ASSOCIATION_BASE::hash(const char *key)
* local function calculates a hash. Designed to minimize clustering.
* parameters: key string
* returns: hash value clipped to array size
************************************************/
unsigned int ASSOCIATION_BASE::hash(const char *key)
{
unsigned int index;
const unsigned char *k;
for (index=0x5555, k=ASSOC_CAST(const unsigned char *,key) ; *k != 0 ; k++)
index = (index << 1) ^ ASSOC_MAP(*k);// hash key
return index % array_size; // fit in array
}
/************************************************
* function: void ASSOCIATION_BASE::allocate_array(void)
* local function allocates and initializes the array
* parameters: none
* returns: nothing
************************************************/
void ASSOCIATION_BASE::allocate_array(void)
{
unsigned int i;
hash_list = new unsigned int[array_size]; // allocate hash array
key_list = new const char *[array_size]; // allocate key pointers
link_list = new unsigned int[array_size]; // allocate key linkage
data_list = new char[array_size*sizeofdata];// allocate storage for data
ASSOC_MEM_CHECK(hash_list); // validate resources
ASSOC_MEM_CHECK(key_list);
ASSOC_MEM_CHECK(link_list);
ASSOC_MEM_CHECK(data_list);
for (i = 0 ; i < array_size ; i++)
hash_list[i] = ASSOC_NULL; // preset with nothing
}
/************************************************
* function: int ASSOCIATION_BASE::expand_array(void)
* double the size of the array
* parameters: none
* returns: 1 if expanded OK or 0 if failed
************************************************/
int ASSOCIATION_BASE::expand_array(void)
{ // if array full, increase size
const char **old_key;
char *old_data;
unsigned int i,index;
old_key = key_list; // save old data
old_data = data_list;
delete [] hash_list; // remove pointer storage
hash_list = 0;
delete [] link_list;
link_list = 0;
array_size <<= 1; // new size
allocate_array(); // new array
if (!*this) // valid?
return 0;
memcpy(key_list,old_key,fill_level*sizeof(const char *));
memcpy(data_list,old_data,sizeofdata*fill_level);
for (i = 0 ; i < fill_level ; i++)
{ // rehash old data into new array
index = hash(old_key[i]);
link_list[i] = hash_list[index];
hash_list[index] = i;
}
delete [] old_key; // blow away old storage
delete [] old_data;
return 1;
}