//====================================================================== // File: table.h // Author: Timothy A. Budd // Description: This file contains the interface and implementation // of the dictionary and table template classes. // // Copyright (c) 1992 by Timothy A. Budd. All Rights Reserved. //====================================================================== #ifndef TABLE_H #define TABLE_H #include "iterator.h" #include "vector.h" #include "list.h" #include "hash.h" //---------------------------------------------------------------------- // class association // A single key/value pair, // usually maintained in a dictionary //---------------------------------------------------------------------- template class association { public: // value field is publically accessible V valueField; // constructor association(K initialKey, V initialValue); // assignment can be either to association or value V operator =(association &); V operator =(V val); // accessor methods for key and value K key() const; V value() const; protected: friend int operator == (association & l, association & r) { return l.key() == r.key(); } friend int operator == (association & l, K r) { return l.key() == r; } // key field cannot be altered const K keyField; }; //---------------------------------------------------------------------- // class cAssociation // a form of association that allows elements to be compared //---------------------------------------------------------------------- template class cAssociation : public association { public: // constructor cAssociation(K initialKey, V initialValue); friend int operator == (cAssociation & l, cAssociation & r) { return l.key() == r.key(); } friend int operator == (cAssociation & l, K & r) { return l.key() == r; } friend int operator < (cAssociation & l, cAssociation & r) { return l.key() < r.key(); } friend int operator < (cAssociation & l, K & r) { return l.key() < r; } }; //---------------------------------------------------------------------- // class dictionary // A collection of key/value pairs // implemented as a list of associations //---------------------------------------------------------------------- template class dictionaryIterator; template class table; template class dictionary { public: // constructors dictionary(); dictionary(V initialValue); dictionary(const dictionary & v); // dictionary protocol V & operator [](K key); void deleteAllValues(); int includesKey(K key); int isEmpty() const; void removeKey(K key); void setInitial(V initialValue); private: // data is maintained in a list of associations list &> data; V initialValue; // friends friend class dictionaryIterator; friend class table; // find association with given key association * associatedWith(K key); }; //---------------------------------------------------------------------- // class table // dictionary collection of key/value pairs // implemented using hash tables //---------------------------------------------------------------------- template class table : public hashTable, K, association &> { public: // constructors table(unsigned int max, unsigned int (*f)(const K &)); table(unsigned int max, unsigned int (*f)(const K &), V &); // new table operators V & operator [](K key); void removeKey(K key); void setInitial(V initialValue); protected: iterator &> * makeIterator(unsigned int i); }; //---------------------------------------------------------------------- // class tableIterator // iterator protocol for tables //---------------------------------------------------------------------- template class tableIterator : public hashTableIterator, K, association &> { public: // constructor tableIterator(table & v); }; //---------------------------------------------------------------------- // class orderedDictionary // A ordered collection of key/value pairs // implemented as a list of associations //---------------------------------------------------------------------- template class orderedDictionaryIterator; template class orderedDictionary { public: // constructors orderedDictionary(); orderedDictionary(V initialValue); orderedDictionary(orderedDictionary & v); // dictionary protocol V & operator [](K key); void deleteAllValues(); int includesKey(K key); int isEmpty() const; void removeKey(K key); void setInitial(V initialValue); private: // data is maintained in a list of associations orderedList &> data; V initialValue; // friends friend class orderedDictionaryIterator; friend class table; // find association with given key cAssociation * associatedWith (K key); }; //---------------------------------------------------------------------- // class dictionaryIterator // implementation of iterator protocol for dictionaries //---------------------------------------------------------------------- template class dictionaryIterator : public listIterator &> { public: // constructor dictionaryIterator(dictionary & dict); }; //---------------------------------------------------------------------- // class orderedDictionaryIterator // implementation of iterator protocol for // ordered dictionaries //---------------------------------------------------------------------- template class orderedDictionaryIterator : public listIterator &> { public: // constructor orderedDictionaryIterator(orderedDictionary & dict); }; //---------------------------------------------------------------------- // class sparseMatrix // two dimensional matrix using dictionaries to store rows //---------------------------------------------------------------------- template class sparseMatrix { public: // constructors sparseMatrix(unsigned int n, unsigned int m); sparseMatrix(unsigned int n, unsigned int m, T initial); // only operation is subscript dictionary & operator [](unsigned int n); private: vector< dictionary > data; }; //---------------------------------------------------------------------- // class sparseMatrix2 // second form of sparse matrix, // uses dictionaries for both rows and columns //---------------------------------------------------------------------- template class sparseMatrix2 { public: // constructors sparseMatrix2(unsigned int n, unsigned int m) {} sparseMatrix2(unsigned int n, unsigned int m, T init); dictionary & operator [] (unsigned int n); private: // data areas T initialValue; dictionary< int, dictionary > data; }; //---------------------------------------------------------------------- // class association implementation //---------------------------------------------------------------------- template association:: association(K initialKey, V initialValue) : keyField(initialKey), valueField(initialValue) { // no further initialization } template V association:: operator = (association & anAssociation) { // assignment from an association valueField = anAssociation.valueField; return valueField; } template V association:: operator = (V val) { // assignment from a value valueField = val; return valueField; } template K association::key() const { // return key return keyField; } template V association::value() const { // return value return valueField; } template int operator == (association & left, association & right) { // compare the key values for two associations return left.key() == right.key(); } template int operator == (association & left, K rightKey) { // compare the key values for two associations return left.key() == rightKey; } //---------------------------------------------------------------------- // class dictionary implementation //---------------------------------------------------------------------- template dictionary::dictionary() { // nothing to initialize } template dictionary::dictionary(V val) { // set initial value initialValue = val; } template dictionary:: dictionary(const dictionary & v) { # if 0 // GNU COMPLAINS ABOUT THIS data = *v.data.duplicate(); initialValue = v.initialValue; # endif } template V & dictionary::operator [] (K key) { // return value of association specified by key // first look to see if association is there already association * newassoc = associatedWith(key); // if not there, make a new one if (!newassoc) { newassoc = new association(key, initialValue); assert(newassoc != 0); data.add(*newassoc); } // return reference to value field return newassoc->valueField; } template void dictionary::deleteAllValues() { data.deleteAllValues(); } template int dictionary::includesKey(K key) { // if there is an association, then element is in the dictionary return associatedWith(key) != 0; } template int dictionary::isEmpty() const { return data.isEmpty(); } template void dictionary::removeKey(K key) { // loop over the elements looking for key listIterator &> itr(data); for (itr.init(); ! itr; itr++) if (itr().key() == key) itr.removeCurrent(); } template void dictionary::setInitial(V val) { initialValue = val; } template association * dictionary:: associatedWith(K key) { // return the association with the given key // or the null pointer if no association yet exists listIterator &> itr(data); // loop over the elements, looking for a match for (itr.init(); ! itr; itr++) if (itr().key() == key) { // address of a reference is a pointer return & itr(); } // not found, return null pointer return 0; } //---------------------------------------------------------------------- // class orderedDictionary implementation //---------------------------------------------------------------------- template orderedDictionary::orderedDictionary() { // nothing to initialize } template orderedDictionary:: orderedDictionary(V val) { // set initial value initialValue = val; } template orderedDictionary:: orderedDictionary(orderedDictionary & v) { initialValue = v.initialValue; data.deleteAllValues(); listIterator &> itr(v.data); for (itr.init(); !itr; itr++) data.add(itr()); } template V & orderedDictionary:: operator [] (K key) { // return value of association specified by key // first look to see if association is there already cAssociation * newassoc = associatedWith(key); // if not there, make a new one if (!newassoc) { newassoc = new cAssociation(key, initialValue); assert(newassoc != 0); data.add(*newassoc); } // return reference to value field return newassoc->valueField; } template void orderedDictionary::deleteAllValues() { data.deleteAllValues(); } template int orderedDictionary::includesKey(K key) { // if there is an association, then element is in the dictionary return associatedWith(key) != 0; } template int orderedDictionary::isEmpty() const { return data.isEmpty(); } template void orderedDictionary::removeKey(K key) { // loop over the elements looking for key listIterator &> itr(data); for (itr.init(); ! itr; itr++) if (itr() == key) itr.removeCurrent(); } template void orderedDictionary::setInitial(V val) { initialValue = val; } template cAssociation * orderedDictionary:: associatedWith(K key) { // return the association with the given key // or the null pointer if no association yet exists listIterator &> itr(data); // loop over the elements, looking for a match for (itr.init(); ! itr; itr++) if (itr() == key) { // address of a reference is a pointer return & itr(); } // not found, return null pointer return 0; } //---------------------------------------------------------------------- // class dictionaryIterator implementation //---------------------------------------------------------------------- template dictionaryIterator:: dictionaryIterator(dictionary & dict) : listIterator &>(dict.data) { // no further initialization } //---------------------------------------------------------------------- // class orderedDictionaryIterator implementation //---------------------------------------------------------------------- template orderedDictionaryIterator:: orderedDictionaryIterator(orderedDictionary & dict) : listIterator &>(dict.data) { // no further initialization } //---------------------------------------------------------------------- // class sparseMatrix implementation //---------------------------------------------------------------------- template sparseMatrix:: sparseMatrix(unsigned int n, unsigned int m) : data(n) { // no further initialization } template sparseMatrix:: sparseMatrix(unsigned int n, unsigned int m, T initial) : data(n) { // set the initial value for each dictionary for (unsigned int i = 0; i < n; i++) data[i].setInitial(initial); } template dictionary & sparseMatrix ::operator [](unsigned int n) { // simply return the appropriate dictionary return data[n]; } //---------------------------------------------------------------------- // class sparseMatrix2 implementation //---------------------------------------------------------------------- template sparseMatrix2:: sparseMatrix2(unsigned int n, unsigned int m) : data(n) { // no further initialization } template sparseMatrix2:: sparseMatrix2(unsigned int n, unsigned int m, T initial) : data(n) { // set the initial value for each dictionary for (unsigned int i = 0; i < n; i++) data[i].setInitial(initial); } template dictionary & sparseMatrix2:: operator [] (unsigned int n) { // subscript operator for sparse matrices // if we already have a row, just return it if (data.includesKey(n)) return data[n]; // else make a new entry and set initial value data[n].setInitial(initialValue); return data[n]; } //---------------------------------------------------------------------- // class cAssociation implementation //---------------------------------------------------------------------- template cAssociation::cAssociation(K n, V m) : association(n, m) { // no further initialization } template int operator == (cAssociation & left, cAssociation & right) { // compare the key values for two associations return left.key() == right.key(); } template int operator == (cAssociation & left, K & rightKey) { // compare the key values for two associations return left.key() == rightKey; } template int operator < (cAssociation & left, cAssociation & right) { // compare the key values for two associations return left.key() < right.key(); } template int operator < (cAssociation & left, K & rightKey) { // compare the key value of an associations to a key value return left.key() < rightKey; } //---------------------------------------------------------------------- // class table implementation //---------------------------------------------------------------------- template table:: table(unsigned int max, unsigned int (*f)(const K &)) : hashTable, K, association &>(max, f) { // no further initialization } template table:: table(unsigned int max, unsigned int (*f)(const K &), V & v) : hashTable, K, association &>(max, f) { // set the initial value in each bucket setInitial(v); } template V & table::operator [](K key) { // find right dictionary, then subscript dictionary return buckets[hash(key)][key]; } template void table::removeKey(K key) { // find the right bucket, then remove the key buckets[hash(key)].removeKey(key); } template void table::setInitial(V val) { // set the initial value in each bucket for (int i = 0; i < tablesize; i++) buckets[i].initialValue = val; } template iterator &> * table:: makeIterator(unsigned int i) { return new dictionaryIterator(buckets[i]); } //---------------------------------------------------------------------- // class tableIterator implementation //---------------------------------------------------------------------- template tableIterator:: tableIterator(table & v) : hashTableIterator, K, association &>(v) { // no further initialization } #endif