#ifndef _ASSOCLIST_H #define _ASSOCLIST_H //AssocList.h // An AssocList f holds a set of(key, value) associations, // (just like a HashTable, except operations are slower) // // Implementated as an array of (key, value) pairs, so... // MOST OPERATIONS TAKE O(N) TIME, WHERE N IS THE NUMBER OF KEYS. // (only useful for small lists) // /* public interface: // construct an AssocList default init value for new VALUES: AssocList(VALUE const & def); // construct an AssocList without any default init value AssocList(); // deep copy constructor AssocList(AssocList const & a); // assignment op (deep copy) AssocList& operator=(const AssocList& a); // destructor ~AssocList(); // reset to empty void clear(); // does key have an entry? int exists(KEY const & k) const; // remove entry of key void remove(KEY const & k); // return ref to value associated with key VALUE & operator[](KEY const & k); // return value associated with key, key must exist VALUE operator[](KEY const & k) const; // return array of all keys with entries Array keys() const; // return array of all values associated with keys Array values() const; // "adopt" a (key,value) pair from AssocList a // the pair is removed from a and placed in this // (responsibility for deleting the pair is now ours) void adopt(KEY const & k, AssocList& a); // output friend std::ostream & operator<< <>(std::ostream &, const AssocList &); */ #include #include "Array.h" #include "Comparisons.h" #include "test_utilities.h" template class AssocList { typedef VALUE * PTR; // implementation is as Array of (KEY,VALUE) pairs, struct Pair { KEY k; VALUE v; }; Array pairs; PTR default_init; int find(KEY const & k) const { for (int i = 0; i < pairs.size(); ++i) if (pairs.exists(i) && Equal(pairs[i].k, k)) return i; return -1; } public: void set_default(const VALUE& def) { if (default_init) delete default_init; default_init = new VALUE(def); } ~AssocList() { if (default_init) delete default_init; } AssocList() : default_init(NULL) { } AssocList(const VALUE& def) : default_init(NULL) { set_default(def); } AssocList(AssocList const & a) : pairs(a.pairs), default_init(NULL) { if (a.default_init) set_default(*a.default_init); } AssocList& operator=(const AssocList& a) { pairs = a.pairs; default_init = NULL; if (a.default_init) set_default(*a.default_init); return *this; } void clear() { pairs.clear(); } void remove(KEY const & k) { int i = find(k); if (i == -1) return; pairs.remove(i); } bool exists(KEY const & k) const { return find(k) != -1; } VALUE & operator[](KEY const & k) { int i = find(k); if (i >= 0) return pairs[i].v; // find next free pair pointer for (i = 0; pairs.exists(i); ++i) ; // insert pair for key k and return v pairs[i].k = k; if (default_init) pairs[i].v = *default_init; return pairs[i].v; } VALUE operator[](KEY const & k) const { int i = find(k); if (i >= 0) return pairs[i].v; die("AssocList::operator[] const called with non-existent key"); } Array keys() const { Array a; for (int i = 0; i < pairs.size(); ++i) if (pairs.exists(i)) a[a.size()] = pairs[i].k; return a; } Array values() const { Array a; for (int i = 0; i < pairs.size(); ++i) if (pairs.exists(i)) a[a.size()] = pairs[i].v; return a; } void adopt(KEY const& k, AssocList& a) { // works even if &a = this int i = find(k); int j = a.find(k); if (j != -1) { if (i == -1) do ++i; while (pairs.exists(i)); pairs.adopt(i, a.pairs.orphan(j)); } else if (i != -1) pairs.remove(i); } int size() const { return pairs.size(); } // output friend std::ostream & operator<< <>(std::ostream &, const AssocList &); }; // operator<< template std::ostream & operator<<(std::ostream & out, const AssocList & a) { out << "{"; for (int i = 0; i < a.pairs.size(); ++i) { if (a.pairs.exists(i)) { if (i != 0) out << ", "; out << a.pairs[i].k << " => " << a.pairs[i].v; } } out << "}"; return out; } #endif