include/Dictionary.h
author Jens Alfke <jens@mooseyard.com>
Thu Sep 24 10:28:50 2009 -0700 (2009-09-24)
changeset 3 8e3ae153e2c9
parent 0 31a43d94cc26
permissions -rw-r--r--
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.
     1 /*
     2  *  Dictionary.h
     3  *  Ottoman
     4  *
     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.
     8  */
     9 
    10 #ifndef _MOOSEYARD_DICTIONARY_
    11 #define _MOOSEYARD_DICTIONARY_
    12 #include "Base.h"
    13 
    14 namespace Mooseyard {
    15 
    16     typedef uint32_t HashCode;
    17     
    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 {
    21         HashCode hash;
    22         
    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) { }
    29 
    30         static HashCode computeHash (Blob);
    31     };
    32     
    33     
    34     /** An abstract interface for key/value dictionaries.
    35         Dictionary itself is read-only; its subclass MutableDictionary allows changes. */
    36     class Dictionary {
    37     public:
    38         class Iterator;
    39         class ChangeIterator;
    40 
    41         virtual ~Dictionary();
    42         
    43         /** The number of items in the dictionary. */
    44         virtual int count() const =0;
    45         
    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;
    52         
    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;}
    55         
    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;
    59         
    60         /** A singleton empty Dictionary. */
    61         static const Dictionary& kEmpty;
    62         
    63         // utilities
    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);
    67 
    68         static int chooseAnyOldSize (int capacity, float load = kMaxLoadFactor);
    69 
    70         static const int   kMinSize;
    71         static const float kMinLoadFactor;
    72         static const float kMaxLoadFactor;
    73         
    74     protected:
    75         Dictionary();
    76     };
    77     
    78     
    79     /** An abstract interface for mutable key/value dictionaries; extends Dictionary. */
    80     class MutableDictionary : public Dictionary {
    81     public:
    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
    84             the call returns. */
    85         virtual void put (Key, Blob value) =0;
    86         
    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*);
    90         
    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;
    94         
    95         /** Removes all keys and values, returning the dictionary to an empty state. */
    96         virtual void removeAll() = 0;
    97     };
    98     
    99     
   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 {
   104     public:
   105         virtual ~Iterator();
   106         
   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;
   116         
   117         operator bool() const                   {return hasValue();}
   118         Iterator& operator++()                  {next(); return *this;}
   119     };
   120     
   121     class OverlayDictionary;
   122     
   123     
   124     /** An iterator that walks through the differences between two Dictionaries. */
   125     class Dictionary::ChangeIterator :public Dictionary::Iterator {
   126     public:
   127         ChangeIterator (const Dictionary *dict1, const Dictionary *dict2);
   128         explicit ChangeIterator (const OverlayDictionary*);
   129         virtual ~ChangeIterator();
   130         
   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();}
   140         virtual bool next();
   141         
   142     private:
   143         void _init (const Dictionary *dict1, const Dictionary *dict2);
   144         bool _skipMatching();
   145         const Dictionary *_dict2;
   146         Iterator *_iter;
   147         Blob _otherValue;
   148     };
   149     
   150     
   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 {
   154     public:
   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();
   159         
   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;}
   169         
   170         /** Removes all changes, restoring the overlay to look identical to the base. */
   171         void revert();
   172         /** Changes the overlay to a new base, clearing all changes. */
   173         void revertTo (const Dictionary* newBase);
   174         
   175         /** Changes the base without clearing changes. */
   176         void rebase (const Dictionary* newBase);
   177         
   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);}
   185         
   186         class Iterator :public Dictionary::Iterator {
   187         public:
   188             explicit Iterator (const OverlayDictionary&);
   189             virtual Key key() const;
   190             virtual Blob value() const;
   191             virtual bool next();
   192         private:
   193             bool skipCurrentState();
   194             Dictionary::Iterator *_iter;
   195             const MutableDictionary *_overlay;
   196         };
   197         
   198     private:
   199         const Dictionary *_base;
   200         MutableDictionary *_overlay;
   201         int _count;
   202         bool _allRemoved;
   203         friend class ChangeIterator;
   204     };
   205     
   206     
   207 }
   208 
   209 #endif _MOOSEYARD_DICTIONARY_