Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members

Dict.h

Go to the documentation of this file.
00001 // $Id: Dict.h,v 1.2 2005/03/17 09:22:17 vern Exp $
00002 //
00003 // Copyright (c) 1995, 1996, 1997, 1998, 1999, 2001, 2002, 2003
00004 //      The Regents of the University of California.  All rights reserved.
00005 //
00006 // Redistribution and use in source and binary forms, with or without
00007 // modification, are permitted provided that: (1) source code distributions
00008 // retain the above copyright notice and this paragraph in its entirety, (2)
00009 // distributions including binary code include the above copyright notice and
00010 // this paragraph in its entirety in the documentation or other materials
00011 // provided with the distribution, and (3) all advertising materials mentioning
00012 // features or use of this software display the following acknowledgement:
00013 // ``This product includes software developed by the University of California,
00014 // Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
00015 // the University nor the names of its contributors may be used to endorse
00016 // or promote products derived from this software without specific prior
00017 // written permission.
00018 // THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
00019 // WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
00020 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00021 
00022 #ifndef dict_h
00023 #define dict_h
00024 
00025 #include "List.h"
00026 #include "Hash.h"
00027 
00028 class Dictionary;
00029 class DictEntry;
00030 class IterCookie;
00031 
00032 declare(PList,DictEntry);
00033 declare(PList,IterCookie);
00034 
00035 // Default number of hash buckets in dictionary.  The dictionary will
00036 // increase the size of the hash table as needed.
00037 #define DEFAULT_DICT_SIZE 16
00038 
00039 // Type indicating whether the dictionary should keep track of the order
00040 // of insertions.
00041 typedef enum { ORDERED, UNORDERED } dict_order;
00042 
00043 // Type for function to be called when deleting elements.
00044 typedef void (*dict_delete_func)(void*);
00045 
00046 // A dict_delete_func that just calls delete.
00047 extern void generic_delete_func(void*);
00048 
00049 class Dictionary {
00050 public:
00051         Dictionary(dict_order ordering = UNORDERED,
00052                         int initial_size = DEFAULT_DICT_SIZE);
00053         virtual ~Dictionary();
00054 
00055         // Member functions for looking up a key, inserting/changing its
00056         // contents, and deleting it.  These come in two flavors: one
00057         // which takes a HashKey, and the other which takes a raw key,
00058         // its size, and its (unmodulated) hash.
00059         void* Lookup(const HashKey* key) const
00060                 { return Lookup(key->Key(), key->Size(), key->Hash()); }
00061         void* Lookup(const void* key, int key_size, hash_t hash) const;
00062 
00063         // Returns previous value, or 0 if none.
00064         void* Insert(HashKey* key, void* val)
00065                 {
00066                 return Insert(key->TakeKey(), key->Size(), key->Hash(), val, 0);
00067                 }
00068         // If copy_key is true, then the key is copied, otherwise it's assumed
00069         // that it's a heap pointer that now belongs to the Dictionary to
00070         // manage as needed.
00071         void* Insert(void* key, int key_size, hash_t hash, void* val,
00072                         int copy_key);
00073 
00074         // Removes the given element.  Returns a pointer to the element in
00075         // case it needs to be deleted.  Returns 0 if no such element exists.
00076         // If dontdelete is true, the key's bytes will not be deleted.
00077         void* Remove(const HashKey* key)
00078                 { return Remove(key->Key(), key->Size(), key->Hash()); }
00079         void* Remove(const void* key, int key_size, hash_t hash,
00080                                 bool dont_delete = false);
00081 
00082         // Number of entries.
00083         int Length() const
00084                 { return tbl2 ? num_entries + num_entries2 : num_entries; }
00085 
00086         // Largest it's ever been.
00087         int MaxLength() const
00088                 {
00089                 return tbl2 ?
00090                         max_num_entries + max_num_entries2 : max_num_entries;
00091                 }
00092 
00093         // True if the dictionary is ordered, false otherwise.
00094         int IsOrdered() const           { return order != 0; }
00095 
00096         // If the dictionary is ordered then returns the n'th entry's value;
00097         // the second method also returns the key.  The first entry inserted
00098         // corresponds to n=0.
00099         //
00100         // Returns nil if the dictionary is not ordered or if "n" is out
00101         // of range.
00102         void* NthEntry(int n) const
00103                 {
00104                 const void* key;
00105                 int key_len;
00106                 return NthEntry(n, key, key_len);
00107                 }
00108         void* NthEntry(int n, const void*& key, int& key_len) const;
00109 
00110         // To iterate through the dictionary, first call InitForIteration()
00111         // to get an "iteration cookie".  The cookie can then be handed
00112         // to NextEntry() to get the next entry in the iteration and update
00113         // the cookie.  If NextEntry() indicates no more entries, it will
00114         // also delete the cookie, or the cookie can be manually deleted
00115         // prior to this if no longer needed.
00116         //
00117         // Unexpected results will occur if the elements of
00118         // the dictionary are changed between calls to NextEntry() without
00119         // first calling InitForIteration().
00120         //
00121         // If return_hash is true, a HashKey for the entry is returned in h,
00122         // which should be delete'd when no longer needed.
00123         IterCookie* InitForIteration() const;
00124         void* NextEntry(HashKey*& h, IterCookie*& cookie, int return_hash) const;
00125         void* NextEntry(const void*& key, int& key_len, IterCookie*& cookie)
00126                 const;
00127         void StopIteration(IterCookie* cookie) const;
00128 
00129         void SetDeleteFunc(dict_delete_func f)          { delete_func = f; }
00130 
00131         // With a robust cookie, it is safe to change the dictionary while
00132         // iterating. This means that (i) we will eventually visit all
00133         // unmodified entries as well as all entries added during iteration,
00134         // and (ii) we won't visit any still-unseen entries which are getting
00135         // removed. (We don't get this for free, so only use it if
00136         // necessary.)
00137         void MakeRobustCookie(IterCookie* cookie)
00138                 { cookies.append(cookie); }
00139 
00140         unsigned int MemoryAllocation() const;
00141 
00142 private:
00143         void Init(int size);
00144         void Init2(int size);   // initialize second table for resizing
00145 
00146         // Internal version of Insert().
00147         void* Insert(DictEntry* entry, int copy_key);
00148 
00149         void* DoRemove(DictEntry* entry, hash_t h,
00150                         PList(DictEntry)* chain, int chain_offset);
00151 
00152         int NextPrime(int n) const;
00153         int IsPrime(int n) const;
00154         void StartChangeSize(int new_size);
00155         void FinishChangeSize(void);
00156         void MoveChains(void);
00157 
00158         // The following get and set the "density" threshold - if the
00159         // average hash chain length exceeds this threshold, the
00160         // table will be resized.  The default value is 3.0.
00161         double DensityThresh() const    { return den_thresh; }
00162 
00163         void SetDensityThresh(double thresh)
00164                 {
00165                 den_thresh = thresh;
00166                 thresh_entries = int(thresh * double(num_buckets));
00167                 }
00168 
00169         // Same for the second table, when resizing.
00170         void SetDensityThresh2(double thresh)
00171                 {
00172                 den_thresh2 = thresh;
00173                 thresh_entries2 = int(thresh * double(num_buckets2));
00174                 }
00175 
00176         // Normally we only have tbl.
00177         // When we're resizing, we'll have tbl (old) and tbl2 (new)
00178         // tbl_next_ind keeps track of how much we've moved to tbl2
00179         // (it's the next index we're going to move).
00180         PList(DictEntry)** tbl;
00181         int num_buckets;
00182         int num_entries;
00183         int max_num_entries;
00184         double den_thresh;
00185         int thresh_entries;
00186 
00187         // Resizing table (replicates tbl above).
00188         PList(DictEntry)** tbl2;
00189         int num_buckets2;
00190         int num_entries2;
00191         int max_num_entries2;
00192         double den_thresh2;
00193         int thresh_entries2;
00194 
00195         hash_t tbl_next_ind;
00196 
00197         PList(DictEntry)* order;
00198         dict_delete_func delete_func;
00199 
00200         PList(IterCookie) cookies;
00201 };
00202 
00203 
00204 #define PDict(type) type ## PDict
00205 #define PDictdeclare(type)      \
00206 class PDict(type) : public Dictionary { \
00207 public: \
00208         PDict(type)(dict_order ordering = UNORDERED,    \
00209                         int initial_size = DEFAULT_DICT_SIZE) : \
00210                 Dictionary(ordering, initial_size) {}   \
00211         type* Lookup(const char* key) const     \
00212                 {       \
00213                 HashKey h(key); \
00214                 return (type*) Dictionary::Lookup(&h);  \
00215                 }       \
00216         type* Lookup(const HashKey* key) const  \
00217                 { return (type*) Dictionary::Lookup(key); }     \
00218         type* Insert(const char* key, type* val)        \
00219                 {       \
00220                 HashKey h(key); \
00221                 return (type*) Dictionary::Insert(&h, (void*) val);     \
00222                 }       \
00223         type* Insert(HashKey* key, type* val)   \
00224                 { return (type*) Dictionary::Insert(key, (void*) val); }\
00225         type* NthEntry(int n) const     \
00226                 { return (type*) Dictionary::NthEntry(n); }     \
00227         type* NthEntry(int n, const char*& key) const   \
00228                 {       \
00229                 int key_len;    \
00230                 return (type*) Dictionary::NthEntry(n, (const void*&) key,\
00231                                                         key_len);       \
00232                 }       \
00233         type* NextEntry(IterCookie*& cookie) const      \
00234                 {       \
00235                 HashKey* h; \
00236                 return (type*) Dictionary::NextEntry(h, cookie, 0);     \
00237                 } \
00238         type* NextEntry(HashKey*& h, IterCookie*& cookie) const \
00239                 { return (type*) Dictionary::NextEntry(h, cookie, 1); } \
00240         type* RemoveEntry(const HashKey* key)   \
00241                 { return (type*) Remove(key->Key(), key->Size(),        \
00242                                         key->Hash()); } \
00243 }
00244 
00245 #endif

Generated on Wed Sep 14 02:56:06 2005 for bro_docs by doxygen 1.3.5