// name: MultiDict.C // author: J. Michael Word // date written: 8/7/97 // purpose: Implementation for MultiDict // ************************************************************** // NOTICE: This is free software and the source code is freely // available. You are free to redistribute or modify under the // conditions that (1) this notice is not removed or modified // in any way and (2) any modified versions of the program are // also available for free. // ** Absolutely no Warranty ** // Copyright (C) 1999 J. Michael Word // ************************************************************** #include "MultiDict.h" // --------------------------------------------------- // make an empty dictionary for an approx. sz entries // --------------------------------------------------- template MultiDict::MultiDict(const unsigned long sz) { _M = genHashM(sz); _n = 0; _Heads = new MultiLink *[_M]; for (unsigned long i = 0; i < _M; i++) { _Heads[i] = NULL; } } // --------------------- // destroy a dictionary // --------------------- template MultiDict::~MultiDict() { reset(); // drop all entries delete [] _Heads; } // ----------------------------------------------- // associate a value with a key in the dictionary // ----------------------------------------------- template int MultiDict::put(const K& key, const T& value) { unsigned long head = hash(key, _M); MultiLink *prev = NULL, *curr = _Heads[head]; while (curr && (curr->key() < key)) { prev = curr; curr = curr->next(); } if (curr && (curr->key() == key)) { // keys match curr->insert(value); return curr->count(); } else { // no previous entry with this key MultiLink *x = new MultiLink(key); if (prev==NULL) { x->next(_Heads[head]); _Heads[head] = x; } else { x->next(prev->next(x)); } _n++; x->insert(value); return 1; } } // -------------------------------------------------------- // look up an entry by key and return the associated values // -------------------------------------------------------- template Seq MultiDict::get(const K &key) const { MultiLink *curr = _Heads[hash(key, _M)]; while (curr && (curr->key() < key)) { curr = curr->next(); } return (curr && (curr->key() == key)) ? curr->value() : Seq(); } // -------------------------------------------------------- // look up an entry by key and return if it exists // -------------------------------------------------------- template bool MultiDict::exists(const K &key) const { MultiLink *curr = _Heads[hash(key, _M)]; while (curr && (curr->key() < key)) { curr = curr->next(); } return (curr && (curr->key() == key)); } // --------------------------------------- // remove one of our key/sequence entries // --------------------------------------- template bool MultiDict::drop(const K &key) { unsigned long head = hash(key, _M); MultiLink *prev = NULL, *curr = _Heads[head]; while (curr && (curr->key() < key)) { prev = curr; curr = curr->next(); } if (curr && (curr->key() == key)) { // keys match if (prev==NULL) { _Heads[head] = curr->next(NULL); } else { prev->next(curr->next(NULL)); } delete curr; _n--; return TRUE; } else { return FALSE; } } // ---------------------- // drop all dict entries // ---------------------- template void MultiDict::reset() { MultiLink *curr = NULL, *next = NULL; for (unsigned long i = 0; i < _M; i++) { for (curr = _Heads[i]; curr; curr = next) { next = curr->next(NULL); delete curr; } } _n = 0; } // ----------------------- // display dict structure // ----------------------- template void MultiDict::dumpStructure(ostream& os) const { os << endl << _n << " keys in [" << _M << "] ("; for (unsigned long i = 0; i < _M; i++) { int clump = 1; for (MultiLink *curr = _Heads[i]; curr; curr = curr->next()) { os << curr->value().len(); if (curr->next()) { os << ','; clump++; } } if (clump > 3) { os << '(' << i << ')'; } os << ' '; } os << ')' << endl; } // ---------------------------------------- // routine to find and return the next key // ---------------------------------------- template int MultiDictIterator::next(K &nextkey) { if (_i > _dict._M) { return 0; } if (_p != NULL) { _p = _p->next(); } while (_p == NULL) { if (++_i > _dict._M) { return 0; } _p = _dict._Heads[_i-1]; } nextkey = _p->key(); // return next key return _p->count(); }