LLVM API Documentation

StringMap.h

Go to the documentation of this file.
00001 //===--- StringMap.h - String Hash table map interface ----------*- C++ -*-===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // This file defines the StringMap class.
00011 //
00012 //===----------------------------------------------------------------------===//
00013 
00014 #ifndef LLVM_ADT_STRINGMAP_H
00015 #define LLVM_ADT_STRINGMAP_H
00016 
00017 #include "llvm/Support/Allocator.h"
00018 #include <cstring>
00019 #include <string>
00020 
00021 namespace llvm {
00022   template<typename ValueT>
00023   class StringMapConstIterator;
00024   template<typename ValueT>
00025   class StringMapIterator;
00026   template<typename ValueTy>
00027   class StringMapEntry;
00028 
00029 /// StringMapEntryInitializer - This datatype can be partially specialized for
00030 /// various datatypes in a stringmap to allow them to be initialized when an
00031 /// entry is default constructed for the map.
00032 template<typename ValueTy>
00033 class StringMapEntryInitializer {
00034 public:
00035   template <typename InitTy>
00036   static void Initialize(StringMapEntry<ValueTy> &T, InitTy InitVal) {
00037   }
00038 };
00039 
00040 
00041 /// StringMapEntryBase - Shared base class of StringMapEntry instances.
00042 class StringMapEntryBase {
00043   unsigned StrLen;
00044 public:
00045   explicit StringMapEntryBase(unsigned Len) : StrLen(Len) {}
00046 
00047   unsigned getKeyLength() const { return StrLen; }
00048 };
00049 
00050 /// StringMapImpl - This is the base class of StringMap that is shared among
00051 /// all of its instantiations.
00052 class StringMapImpl {
00053 public:
00054   /// ItemBucket - The hash table consists of an array of these.  If Item is
00055   /// non-null, this is an extant entry, otherwise, it is a hole.
00056   struct ItemBucket {
00057     /// FullHashValue - This remembers the full hash value of the key for
00058     /// easy scanning.
00059     unsigned FullHashValue;
00060 
00061     /// Item - This is a pointer to the actual item object.
00062     StringMapEntryBase *Item;
00063   };
00064 
00065 protected:
00066   ItemBucket *TheTable;
00067   unsigned NumBuckets;
00068   unsigned NumItems;
00069   unsigned NumTombstones;
00070   unsigned ItemSize;
00071 protected:
00072   explicit StringMapImpl(unsigned itemSize) : ItemSize(itemSize) {
00073     // Initialize the map with zero buckets to allocation.
00074     TheTable = 0;
00075     NumBuckets = 0;
00076     NumItems = 0;
00077     NumTombstones = 0;
00078   }
00079   StringMapImpl(unsigned InitSize, unsigned ItemSize);
00080   void RehashTable();
00081 
00082   /// ShouldRehash - Return true if the table should be rehashed after a new
00083   /// element was recently inserted.
00084   bool ShouldRehash() const {
00085     // If the hash table is now more than 3/4 full, or if fewer than 1/8 of
00086     // the buckets are empty (meaning that many are filled with tombstones),
00087     // grow the table.
00088     return NumItems*4 > NumBuckets*3 ||
00089            NumBuckets-(NumItems+NumTombstones) < NumBuckets/8;
00090   }
00091 
00092   /// LookupBucketFor - Look up the bucket that the specified string should end
00093   /// up in.  If it already exists as a key in the map, the Item pointer for the
00094   /// specified bucket will be non-null.  Otherwise, it will be null.  In either
00095   /// case, the FullHashValue field of the bucket will be set to the hash value
00096   /// of the string.
00097   unsigned LookupBucketFor(const char *KeyStart, const char *KeyEnd);
00098 
00099   /// FindKey - Look up the bucket that contains the specified key. If it exists
00100   /// in the map, return the bucket number of the key.  Otherwise return -1.
00101   /// This does not modify the map.
00102   int FindKey(const char *KeyStart, const char *KeyEnd) const;
00103 
00104   /// RemoveKey - Remove the specified StringMapEntry from the table, but do not
00105   /// delete it.  This aborts if the value isn't in the table.
00106   void RemoveKey(StringMapEntryBase *V);
00107 
00108   /// RemoveKey - Remove the StringMapEntry for the specified key from the
00109   /// table, returning it.  If the key is not in the table, this returns null.
00110   StringMapEntryBase *RemoveKey(const char *KeyStart, const char *KeyEnd);
00111 private:
00112   void init(unsigned Size);
00113 public:
00114   static StringMapEntryBase *getTombstoneVal() {
00115     return (StringMapEntryBase*)-1;
00116   }
00117 
00118   unsigned getNumBuckets() const { return NumBuckets; }
00119   unsigned getNumItems() const { return NumItems; }
00120 
00121   bool empty() const { return NumItems == 0; }
00122   unsigned size() const { return NumItems; }
00123 };
00124 
00125 /// StringMapEntry - This is used to represent one value that is inserted into
00126 /// a StringMap.  It contains the Value itself and the key: the string length
00127 /// and data.
00128 template<typename ValueTy>
00129 class StringMapEntry : public StringMapEntryBase {
00130 public:
00131   ValueTy second;
00132 
00133   explicit StringMapEntry(unsigned strLen)
00134     : StringMapEntryBase(strLen), second() {}
00135   StringMapEntry(unsigned strLen, const ValueTy &V)
00136     : StringMapEntryBase(strLen), second(V) {}
00137 
00138   const ValueTy &getValue() const { return second; }
00139   ValueTy &getValue() { return second; }
00140 
00141   void setValue(const ValueTy &V) { second = V; }
00142 
00143   /// getKeyData - Return the start of the string data that is the key for this
00144   /// value.  The string data is always stored immediately after the
00145   /// StringMapEntry object.
00146   const char *getKeyData() const {return reinterpret_cast<const char*>(this+1);}
00147 
00148   const char *first() const { return getKeyData(); }
00149 
00150   /// Create - Create a StringMapEntry for the specified key and default
00151   /// construct the value.
00152   template<typename AllocatorTy, typename InitType>
00153   static StringMapEntry *Create(const char *KeyStart, const char *KeyEnd,
00154                                 AllocatorTy &Allocator,
00155                                 InitType InitVal) {
00156     unsigned KeyLength = static_cast<unsigned>(KeyEnd-KeyStart);
00157 
00158     // Okay, the item doesn't already exist, and 'Bucket' is the bucket to fill
00159     // in.  Allocate a new item with space for the string at the end and a null
00160     // terminator.
00161 
00162     unsigned AllocSize = static_cast<unsigned>(sizeof(StringMapEntry))+
00163       KeyLength+1;
00164     unsigned Alignment = alignof<StringMapEntry>();
00165 
00166     StringMapEntry *NewItem =
00167       static_cast<StringMapEntry*>(Allocator.Allocate(AllocSize,Alignment));
00168 
00169     // Default construct the value.
00170     new (NewItem) StringMapEntry(KeyLength);
00171 
00172     // Copy the string information.
00173     char *StrBuffer = const_cast<char*>(NewItem->getKeyData());
00174     memcpy(StrBuffer, KeyStart, KeyLength);
00175     StrBuffer[KeyLength] = 0;  // Null terminate for convenience of clients.
00176 
00177     // Initialize the value if the client wants to.
00178     StringMapEntryInitializer<ValueTy>::Initialize(*NewItem, InitVal);
00179     return NewItem;
00180   }
00181 
00182   template<typename AllocatorTy>
00183   static StringMapEntry *Create(const char *KeyStart, const char *KeyEnd,
00184                                 AllocatorTy &Allocator) {
00185     return Create(KeyStart, KeyEnd, Allocator, 0);
00186   }
00187 
00188 
00189   /// Create - Create a StringMapEntry with normal malloc/free.
00190   template<typename InitType>
00191   static StringMapEntry *Create(const char *KeyStart, const char *KeyEnd,
00192                                 InitType InitVal) {
00193     MallocAllocator A;
00194     return Create(KeyStart, KeyEnd, A, InitVal);
00195   }
00196 
00197   static StringMapEntry *Create(const char *KeyStart, const char *KeyEnd) {
00198     return Create(KeyStart, KeyEnd, 0);
00199   }
00200 
00201   /// GetStringMapEntryFromValue - Given a value that is known to be embedded
00202   /// into a StringMapEntry, return the StringMapEntry itself.
00203   static StringMapEntry &GetStringMapEntryFromValue(ValueTy &V) {
00204     StringMapEntry *EPtr = 0;
00205     char *Ptr = reinterpret_cast<char*>(&V) -
00206                   (reinterpret_cast<char*>(&EPtr->second) -
00207                    reinterpret_cast<char*>(EPtr));
00208     return *reinterpret_cast<StringMapEntry*>(Ptr);
00209   }
00210   static const StringMapEntry &GetStringMapEntryFromValue(const ValueTy &V) {
00211     return GetStringMapEntryFromValue(const_cast<ValueTy&>(V));
00212   }
00213 
00214   /// Destroy - Destroy this StringMapEntry, releasing memory back to the
00215   /// specified allocator.
00216   template<typename AllocatorTy>
00217   void Destroy(AllocatorTy &Allocator) {
00218     // Free memory referenced by the item.
00219     this->~StringMapEntry();
00220     Allocator.Deallocate(this);
00221   }
00222 
00223   /// Destroy this object, releasing memory back to the malloc allocator.
00224   void Destroy() {
00225     MallocAllocator A;
00226     Destroy(A);
00227   }
00228 };
00229 
00230 
00231 /// StringMap - This is an unconventional map that is specialized for handling
00232 /// keys that are "strings", which are basically ranges of bytes. This does some
00233 /// funky memory allocation and hashing things to make it extremely efficient,
00234 /// storing the string data *after* the value in the map.
00235 template<typename ValueTy, typename AllocatorTy = MallocAllocator>
00236 class StringMap : public StringMapImpl {
00237   AllocatorTy Allocator;
00238   typedef StringMapEntry<ValueTy> MapEntryTy;
00239 public:
00240   StringMap() : StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))) {}
00241   explicit StringMap(unsigned InitialSize)
00242     : StringMapImpl(InitialSize, static_cast<unsigned>(sizeof(MapEntryTy))) {}
00243 
00244   AllocatorTy &getAllocator() { return Allocator; }
00245   const AllocatorTy &getAllocator() const { return Allocator; }
00246 
00247   typedef const char* key_type;
00248   typedef ValueTy mapped_type;
00249   typedef StringMapEntry<ValueTy> value_type;
00250   typedef size_t size_type;
00251 
00252   typedef StringMapConstIterator<ValueTy> const_iterator;
00253   typedef StringMapIterator<ValueTy> iterator;
00254 
00255   iterator begin() {
00256     return iterator(TheTable, NumBuckets == 0);
00257   }
00258   iterator end() {
00259     return iterator(TheTable+NumBuckets, true);
00260   }
00261   const_iterator begin() const {
00262     return const_iterator(TheTable, NumBuckets == 0);
00263   }
00264   const_iterator end() const {
00265     return const_iterator(TheTable+NumBuckets, true);
00266   }
00267 
00268   iterator find(const char *KeyStart, const char *KeyEnd) {
00269     int Bucket = FindKey(KeyStart, KeyEnd);
00270     if (Bucket == -1) return end();
00271     return iterator(TheTable+Bucket);
00272   }
00273   iterator find(const char *Key) {
00274     return find(Key, Key + strlen(Key));
00275   }
00276   iterator find(const std::string &Key) {
00277     const char* key_start = (Key.empty() ? NULL : &Key[0]);
00278     return find(key_start, key_start + Key.size());
00279   }
00280 
00281   const_iterator find(const char *KeyStart, const char *KeyEnd) const {
00282     int Bucket = FindKey(KeyStart, KeyEnd);
00283     if (Bucket == -1) return end();
00284     return const_iterator(TheTable+Bucket);
00285   }
00286   const_iterator find(const char *Key) const {
00287     return find(Key, Key + strlen(Key));
00288   }
00289   const_iterator find(const std::string &Key) const {
00290     const char* key_start = (Key.empty() ? NULL : &Key[0]);
00291     return find(key_start, key_start + Key.size());
00292   }
00293 
00294   ValueTy& operator[](const char *Key) {
00295     value_type& entry = GetOrCreateValue(Key, Key + strlen(Key));
00296     return entry.getValue();
00297   }
00298   ValueTy& operator[](const std::string &Key) {
00299     const char* key_start = (Key.empty() ? NULL : &Key[0]);
00300     value_type& entry = GetOrCreateValue(key_start, key_start + Key.size());
00301     return entry.getValue();
00302   }
00303 
00304   size_type count(const char *KeyStart, const char *KeyEnd) const {
00305     return find(KeyStart, KeyEnd) == end() ? 0 : 1;
00306   }
00307   size_type count(const char *Key) const {
00308     return count(Key, Key + strlen(Key));
00309   }
00310   size_type count(const std::string &Key) const {
00311     const char* key_start = (Key.empty() ? NULL : &Key[0]);
00312     return count(key_start, key_start + Key.size());
00313   }
00314 
00315   /// insert - Insert the specified key/value pair into the map.  If the key
00316   /// already exists in the map, return false and ignore the request, otherwise
00317   /// insert it and return true.
00318   bool insert(MapEntryTy *KeyValue) {
00319     unsigned BucketNo =
00320       LookupBucketFor(KeyValue->getKeyData(),
00321                       KeyValue->getKeyData()+KeyValue->getKeyLength());
00322     ItemBucket &Bucket = TheTable[BucketNo];
00323     if (Bucket.Item && Bucket.Item != getTombstoneVal())
00324       return false;  // Already exists in map.
00325 
00326     if (Bucket.Item == getTombstoneVal())
00327       --NumTombstones;
00328     Bucket.Item = KeyValue;
00329     ++NumItems;
00330 
00331     if (ShouldRehash())
00332       RehashTable();
00333     return true;
00334   }
00335 
00336   // clear - Empties out the StringMap
00337   void clear() {
00338     if (empty()) return;
00339 
00340     // Zap all values, resetting the keys back to non-present (not tombstone),
00341     // which is safe because we're removing all elements.
00342     for (ItemBucket *I = TheTable, *E = TheTable+NumBuckets; I != E; ++I) {
00343       if (I->Item && I->Item != getTombstoneVal()) {
00344         static_cast<MapEntryTy*>(I->Item)->Destroy(Allocator);
00345         I->Item = 0;
00346       }
00347     }
00348 
00349     NumItems = 0;
00350   }
00351 
00352   /// GetOrCreateValue - Look up the specified key in the table.  If a value
00353   /// exists, return it.  Otherwise, default construct a value, insert it, and
00354   /// return.
00355   template <typename InitTy>
00356   StringMapEntry<ValueTy> &GetOrCreateValue(const char *KeyStart,
00357                                             const char *KeyEnd,
00358                                             InitTy Val) {
00359     unsigned BucketNo = LookupBucketFor(KeyStart, KeyEnd);
00360     ItemBucket &Bucket = TheTable[BucketNo];
00361     if (Bucket.Item && Bucket.Item != getTombstoneVal())
00362       return *static_cast<MapEntryTy*>(Bucket.Item);
00363 
00364     MapEntryTy *NewItem = MapEntryTy::Create(KeyStart, KeyEnd, Allocator, Val);
00365 
00366     if (Bucket.Item == getTombstoneVal())
00367       --NumTombstones;
00368     ++NumItems;
00369 
00370     // Fill in the bucket for the hash table.  The FullHashValue was already
00371     // filled in by LookupBucketFor.
00372     Bucket.Item = NewItem;
00373 
00374     if (ShouldRehash())
00375       RehashTable();
00376     return *NewItem;
00377   }
00378 
00379   StringMapEntry<ValueTy> &GetOrCreateValue(const char *KeyStart,
00380                                             const char *KeyEnd) {
00381     return GetOrCreateValue(KeyStart, KeyEnd, 0);
00382   }
00383 
00384   /// remove - Remove the specified key/value pair from the map, but do not
00385   /// erase it.  This aborts if the key is not in the map.
00386   void remove(MapEntryTy *KeyValue) {
00387     RemoveKey(KeyValue);
00388   }
00389 
00390   void erase(iterator I) {
00391     MapEntryTy &V = *I;
00392     remove(&V);
00393     V.Destroy(Allocator);
00394   }
00395 
00396   bool erase(const char *Key) {
00397     iterator I = find(Key);
00398     if (I == end()) return false;
00399     erase(I);
00400     return true;
00401   }
00402 
00403   bool erase(const std::string &Key) {
00404     iterator I = find(Key);
00405     if (I == end()) return false;
00406     erase(I);
00407     return true;
00408   }
00409 
00410   ~StringMap() {
00411     clear();
00412     free(TheTable);
00413   }
00414 private:
00415   StringMap(const StringMap &);  // FIXME: Implement.
00416   void operator=(const StringMap &);  // FIXME: Implement.
00417 };
00418 
00419 
00420 template<typename ValueTy>
00421 class StringMapConstIterator {
00422 protected:
00423   StringMapImpl::ItemBucket *Ptr;
00424 public:
00425   typedef StringMapEntry<ValueTy> value_type;
00426 
00427   explicit StringMapConstIterator(StringMapImpl::ItemBucket *Bucket,
00428                                   bool NoAdvance = false)
00429   : Ptr(Bucket) {
00430     if (!NoAdvance) AdvancePastEmptyBuckets();
00431   }
00432 
00433   const value_type &operator*() const {
00434     return *static_cast<StringMapEntry<ValueTy>*>(Ptr->Item);
00435   }
00436   const value_type *operator->() const {
00437     return static_cast<StringMapEntry<ValueTy>*>(Ptr->Item);
00438   }
00439 
00440   bool operator==(const StringMapConstIterator &RHS) const {
00441     return Ptr == RHS.Ptr;
00442   }
00443   bool operator!=(const StringMapConstIterator &RHS) const {
00444     return Ptr != RHS.Ptr;
00445   }
00446 
00447   inline StringMapConstIterator& operator++() {          // Preincrement
00448     ++Ptr;
00449     AdvancePastEmptyBuckets();
00450     return *this;
00451   }
00452   StringMapConstIterator operator++(int) {        // Postincrement
00453     StringMapConstIterator tmp = *this; ++*this; return tmp;
00454   }
00455 
00456 private:
00457   void AdvancePastEmptyBuckets() {
00458     while (Ptr->Item == 0 || Ptr->Item == StringMapImpl::getTombstoneVal())
00459       ++Ptr;
00460   }
00461 };
00462 
00463 template<typename ValueTy>
00464 class StringMapIterator : public StringMapConstIterator<ValueTy> {
00465 public:
00466   explicit StringMapIterator(StringMapImpl::ItemBucket *Bucket,
00467                              bool NoAdvance = false)
00468     : StringMapConstIterator<ValueTy>(Bucket, NoAdvance) {
00469   }
00470   StringMapEntry<ValueTy> &operator*() const {
00471     return *static_cast<StringMapEntry<ValueTy>*>(this->Ptr->Item);
00472   }
00473   StringMapEntry<ValueTy> *operator->() const {
00474     return static_cast<StringMapEntry<ValueTy>*>(this->Ptr->Item);
00475   }
00476 };
00477 
00478 }
00479 
00480 #endif