// svdict.h see license.txt for copyright and terms of use // dictionary of void*, indexed by string (case-sensitive) // (c) Scott McPeak, 2000 // created by modifying strdict; at some point strdict should // be rewritten to use this module #ifndef __SVDICT_H #define __SVDICT_H #include // ostream #include "str.h" // string #include "macros.h" // DMEMB #include "xassert.h" // xassert #include "typ.h" // MUTABLE #include "strhash.h" // StringHash // constness: for this class, 'const' means the *mapping* from string // to void* won't change; but I don't prevent the thing pointed-at // by the void* from changing (would like multiple levels of constness..) class StringVoidDict { private: // types // 3/16/03: I believe the reason I stored the information both in a // hash table and in a linked list is to be able to support efficient // alphabetical iteration class Node { public: Node *next; string key; void *value; public: Node(char const *k, void *v, Node *n = NULL) : next(n), key(k), value(v) {} ~Node() {} static char const *getKey(Node const *n); }; public: // types // function for general foreach; return false to continue, // true to stop iterating typedef bool (*ForeachFn)(string const &key, void *value, void *extra); // function type to delete void*s while emptying typedef void (*DelFn)(void *value); // Note: some care must be taken when dealing with Iters, because // they can be invalidated when held across modifications to // structure of the underlying dictionary class Iter { private: Node *current; public: Iter(Node *n) : current(n) {} Iter(StringVoidDict &dict) { operator=(dict.getIter()); } Iter(Iter const &obj) : DMEMB(current) {} Iter& operator= (Iter const &obj) { CMEMB(current); return *this; } bool isDone() const { return current == NULL; } Iter& next() { xassert(current); current = current->next; return *this; } // 'next' returns a value primarily to allow use in for-loop comma exprs string &key() const { return current->key; } void *&value() const { return current->value; } long private_getCurrent() const { return (long)current; } }; friend class Iter; // iterator that can't modify the dictionary entries class IterC : protected Iter { public: IterC(Node const *n) : Iter(const_cast(n)) {} IterC(StringVoidDict const &dict) : Iter(const_cast(dict)) {} IterC(IterC const &obj) : Iter(obj) {} IterC& operator= (IterC const &obj) { Iter::operator=(obj); return *this; } // some operations can be made available unchanged Iter::isDone; Iter::next; Iter::private_getCurrent; // others must be const-ified string const &key() const { return Iter::key(); } void const *&value() const { return (void const *&)Iter::value(); } }; private: // data // first list node (possibly NULL) Node *top; // hash table to improve lookup performance StringHash hash; // invariants: // list is well-formed structurally // every node is in the hash table, and vice versa protected: // funcs void selfCheck() const; // throw exception if invariants violated void verifySorted() const; // throw exception if list isn't sorted void /*mutable*/ sort(); // arrange nodes in alphabetically sorted order // (mutable because this isn't supposed to be visible from the outside) public: StringVoidDict(); // initializes to empty dictionary StringVoidDict(StringVoidDict const &obj); ~StringVoidDict(); StringVoidDict& operator= (StringVoidDict const &obj); // comparison is done by pointer equality of void* bool operator== (StringVoidDict const &obj) const; NOTEQUAL_OPERATOR(StringVoidDict) // ------- selectors --------- int size() const; // retrieve # of mappings bool isEmpty() const; // returns true if size() is 0 bool isNotEmpty() const { return !isEmpty(); } bool query(char const *key, void *&value) const; // if 'key' is mapped to a value, put it into 'value' and return true; // otherwise, return false void *queryf(char const *key) const; // return the value corresponding to 'key', or throw an exception of it's // not mapped void *queryif(char const *key) const; // return the value corresponding to 'key', or return NULL bool isMapped(char const *key) const; // return true if 'key' is mapped to a value // -------- mutators ----------- void add(char const *key, void *value); // add a mapping from 'key' to 'value'; 'key' must initially be unmapped void *modify(char const *key, void *newValue); // change the existing value for 'key', which must exist, to 'newValue'; // the old value is returned void *remove(char const *key); // remove the mapping from 'key', which must exist; it is returned void emptyAndDel(DelFn func); // apply the deletion func to all values, during empty() void empty(); // remove all mappings // --------- iters ------------- Iter getIter(); // retrieve an iterator (the iterator remains valid only as long as // the structure of the dictionary does not get modified); // values will be iterated in *alphabetical* order IterC getIterC() const; // retrieve a const iterator Iter find(char const *key); // return an iterator pointing to 'key', or an iterator // that isDone() if 'key' isn't mapped void foreach(ForeachFn func, void *extra=NULL) const; // apply 'func' to every mapping, in alphabetical order // ------------ misc -------------- INSERT_OSTREAM(StringVoidDict) string toString() const; // debugging... long private_getTopAddr() const { return (long)top; } }; #endif // __SVDICT_H