Fixed a nasty bug in HashDictionary that could cause heap corruption after removing a value. Added a test case to catch that bug. A few tweaks to Hash.
5 * Created by Jens Alfke on 8/23/09.
6 * Copyright 2009 Jens Alfke. All rights reserved.
7 * BSD-Licensed: See the file "LICENSE.txt" for details.
10 #ifndef _MOOSEYARD_DICTIONARY_
11 #define _MOOSEYARD_DICTIONARY_
16 typedef uint32_t HashCode;
18 /** A Key is a data blob treated as a dictionary key.
19 It carries its hash-code around with it, to avoid redundant computation. */
20 struct Key :public Blob {
23 Key () :Blob(), hash(0) { }
24 explicit Key (const Blob &b) :Blob(b), hash(computeHash(b)) { }
25 Key (const Blob &b, HashCode h) :Blob(b), hash(h) { }
26 Key (const char *str) :Blob(str), hash(computeHash(*this)) { }
27 Key (const void *bytes, uint32_t len) :Blob(bytes,len), hash(computeHash(*this)) { }
28 Key (const void *b, uint32_t len, HashCode h) :Blob(b,len), hash(h) { }
30 static HashCode computeHash (Blob);
34 /** An abstract interface for key/value dictionaries.
35 Dictionary itself is read-only; its subclass MutableDictionary allows changes. */
41 virtual ~Dictionary();
43 /** The number of items in the dictionary. */
44 virtual int count() const =0;
46 /** Returns the value associated with the given key.
47 Keys are compared by exact binary data equality.
48 The data pointed to by the value returned is valid at least until the next call to
49 this Dictionary; some subclasses may guarantee a longer lifetime.
50 If there is no value for the given key, a Blob of {NULL, 0} will be returned. */
51 virtual Blob get (Key) const =0;
53 /** Returns true iff there is a value associated with the given key. */
54 virtual bool contains (Key key) const {return get(key).bytes != NULL;}
56 /** Returns a pointer to a new Iterator object that can be used to iterate this Dictionary.
57 The iterator must be deleted when you're done with it. */
58 virtual Iterator* iterate() const =0;
60 /** A singleton empty Dictionary. */
61 static const Dictionary& kEmpty;
64 /** Returns a suggested size for a hash table that can hold 'capacity' items without
65 being more than the 'load' fraction full; result is always a power of two. */
66 static int choosePowerOfTwoSize (int capacity, float load = kMaxLoadFactor);
68 static int chooseAnyOldSize (int capacity, float load = kMaxLoadFactor);
70 static const int kMinSize;
71 static const float kMinLoadFactor;
72 static const float kMaxLoadFactor;
79 /** An abstract interface for mutable key/value dictionaries; extends Dictionary. */
80 class MutableDictionary : public Dictionary {
82 /** Stores the given value for the given key, replacing any prior value.
83 The memory for the key and value is copied, so you don't need to preserve it after
85 virtual void put (Key, Blob value) =0;
87 /** Adds the contents of the given Dictionary to this one.
88 Effectively calls this->put() with every key/value pair in the source Dictionary. */
89 virtual void add (Dictionary*);
91 /** Removes the value for the given key, if any.
92 Returns true if the value was removed, false if there was no value. */
93 virtual bool remove (Key) =0;
95 /** Removes all keys and values, returning the dictionary to an empty state. */
96 virtual void removeAll() = 0;
100 /** Abstract iterator interface. Each Dictionary subclass defines its own.
101 The order in which items are returned is undefined, and in effect quite random, due to
102 the properties of hash tables. */
103 class Dictionary::Iterator {
107 /** The current key the iterator is pointing to. */
108 virtual Key key() const =0;
109 /** The current value the iterator is pointing to. */
110 virtual Blob value() const =0;
111 /** Returns true if the iterator has a current item, or false if it's reached the end. */
112 virtual bool hasValue() const {return key().bytes != 0;}
113 /** Advances the Iterator to the next item. Returns false if it's reached the end.
114 (Note that the order of items is undefined and in practice quite random.) */
115 virtual bool next() =0;
117 operator bool() const {return hasValue();}
118 Iterator& operator++() {next(); return *this;}
121 class OverlayDictionary;
124 /** An iterator that walks through the differences between two Dictionaries. */
125 class Dictionary::ChangeIterator :public Dictionary::Iterator {
127 ChangeIterator (const Dictionary *dict1, const Dictionary *dict2);
128 explicit ChangeIterator (const OverlayDictionary*);
129 virtual ~ChangeIterator();
131 /** Returns the current key, whose values in the two dictionaries differ. */
132 virtual Key key() const {return _iter->key();}
133 /** Returns the corresponding value from dict1.
134 May be empty (NULL,0) if the key does not appear in dict1 (i.e. inserted into dict2.) */
135 virtual Blob value() const {return _iter->value();}
136 /** Returns the corresponding value from dict2.
137 May be empty (NULL,0) if the key does not appear in dict2 (i.e. deleted from dict2.) */
138 virtual Blob otherValue() const {return _otherValue;}
139 virtual bool hasValue() const {return _iter->hasValue();}
143 void _init (const Dictionary *dict1, const Dictionary *dict2);
144 bool _skipMatching();
145 const Dictionary *_dict2;
151 /** Adapter class that allows a Dictionary to appear to be mutable, by using a separate
152 mutable dictionary to remember the changes. */
153 class OverlayDictionary :public MutableDictionary {
155 /** Creates a mutable dictionary that overlays base. Initially its contents will appear
156 identical to base. It can be changed, but the changes will not affect the base. */
157 explicit OverlayDictionary (const Dictionary *base);
158 virtual ~OverlayDictionary();
160 /** The base dictionary this is overlaying. */
161 const Dictionary* base() const {return _base;}
162 /** The dictionary that contains the changes made to the base.
163 Only keys/values that have been changed appear here. */
164 const Dictionary* overlay() const {return _overlay;}
165 /** Returns true if changes have been made. */
166 bool isChanged() const;
167 /** Returns true if the base has been completely replaced by calling removeAll. */
168 bool baseReplaced() const {return _allRemoved;}
170 /** Removes all changes, restoring the overlay to look identical to the base. */
172 /** Changes the overlay to a new base, clearing all changes. */
173 void revertTo (const Dictionary* newBase);
175 /** Changes the base without clearing changes. */
176 void rebase (const Dictionary* newBase);
178 virtual int count() const;
179 virtual Blob get (Key) const;
180 virtual bool contains (Key) const;
181 virtual void put (Key, Blob value);
182 virtual bool remove (Key);
183 virtual void removeAll();
184 virtual Iterator* iterate() const {return new Iterator(*this);}
186 class Iterator :public Dictionary::Iterator {
188 explicit Iterator (const OverlayDictionary&);
189 virtual Key key() const;
190 virtual Blob value() const;
193 bool skipCurrentState();
194 Dictionary::Iterator *_iter;
195 const MutableDictionary *_overlay;
199 const Dictionary *_base;
200 MutableDictionary *_overlay;
203 friend class ChangeIterator;
209 #endif _MOOSEYARD_DICTIONARY_