From 0924ceab04976976ea9dde594f55c8f7b35cd11f Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 26 Aug 2015 00:22:41 +0000 Subject: [PATCH] Refactor to reduce duplication in OnDiskIterableChainedHashTable's iterators. llvm-svn: 245995 --- llvm/include/llvm/Support/OnDiskHashTable.h | 179 ++++++++++---------- 1 file changed, 88 insertions(+), 91 deletions(-) diff --git a/llvm/include/llvm/Support/OnDiskHashTable.h b/llvm/include/llvm/Support/OnDiskHashTable.h index 08e277ad5ce1..cc40efc5c0c6 100644 --- a/llvm/include/llvm/Support/OnDiskHashTable.h +++ b/llvm/include/llvm/Support/OnDiskHashTable.h @@ -255,6 +255,21 @@ public: "'buckets' must have a 4-byte alignment"); } + /// Read the number of buckets and the number of entries from a hash table + /// produced by OnDiskHashTableGenerator::Emit, and advance the Buckets + /// pointer past them. + static std::pair + readNumBucketsAndEntries(const unsigned char *&Buckets) { + assert((reinterpret_cast(Buckets) & 0x3) == 0 && + "buckets should be 4-byte aligned."); + using namespace llvm::support; + offset_type NumBuckets = + endian::readNext(Buckets); + offset_type NumEntries = + endian::readNext(Buckets); + return std::make_pair(NumBuckets, NumEntries); + } + offset_type getNumBuckets() const { return NumBuckets; } offset_type getNumEntries() const { return NumEntries; } const unsigned char *getBase() const { return Base; } @@ -356,17 +371,11 @@ public: static OnDiskChainedHashTable *Create(const unsigned char *Buckets, const unsigned char *const Base, const Info &InfoObj = Info()) { - using namespace llvm::support; assert(Buckets > Base); - assert((reinterpret_cast(Buckets) & 0x3) == 0 && - "buckets should be 4-byte aligned."); - - offset_type NumBuckets = - endian::readNext(Buckets); - offset_type NumEntries = - endian::readNext(Buckets); - return new OnDiskChainedHashTable(NumBuckets, NumEntries, Buckets, - Base, InfoObj); + auto NumBucketsAndEntries = readNumBucketsAndEntries(Buckets); + return new OnDiskChainedHashTable(NumBucketsAndEntries.first, + NumBucketsAndEntries.second, + Buckets, Base, InfoObj); } }; @@ -385,40 +394,30 @@ public: typedef typename base_type::hash_value_type hash_value_type; typedef typename base_type::offset_type offset_type; - OnDiskIterableChainedHashTable(offset_type NumBuckets, offset_type NumEntries, - const unsigned char *Buckets, - const unsigned char *Payload, - const unsigned char *Base, - const Info &InfoObj = Info()) - : base_type(NumBuckets, NumEntries, Buckets, Base, InfoObj), - Payload(Payload) {} - +private: /// \brief Iterates over all of the keys in the table. - class key_iterator { + class iterator_base { const unsigned char *Ptr; offset_type NumItemsInBucketLeft; offset_type NumEntriesLeft; - Info *InfoObj; public: typedef external_key_type value_type; - key_iterator(const unsigned char *const Ptr, offset_type NumEntries, - Info *InfoObj) - : Ptr(Ptr), NumItemsInBucketLeft(0), NumEntriesLeft(NumEntries), - InfoObj(InfoObj) {} - key_iterator() - : Ptr(nullptr), NumItemsInBucketLeft(0), NumEntriesLeft(0), - InfoObj(0) {} + iterator_base(const unsigned char *const Ptr, offset_type NumEntries) + : Ptr(Ptr), NumItemsInBucketLeft(0), NumEntriesLeft(NumEntries) {} + iterator_base() + : Ptr(nullptr), NumItemsInBucketLeft(0), NumEntriesLeft(0) {} - friend bool operator==(const key_iterator &X, const key_iterator &Y) { + friend bool operator==(const iterator_base &X, const iterator_base &Y) { return X.NumEntriesLeft == Y.NumEntriesLeft; } - friend bool operator!=(const key_iterator &X, const key_iterator &Y) { + friend bool operator!=(const iterator_base &X, const iterator_base &Y) { return X.NumEntriesLeft != Y.NumEntriesLeft; } - key_iterator &operator++() { // Preincrement + /// Move to the next item. + void advance() { using namespace llvm::support; if (!NumItemsInBucketLeft) { // 'Items' starts with a 16-bit unsigned integer representing the @@ -435,25 +434,58 @@ public: --NumItemsInBucketLeft; assert(NumEntriesLeft); --NumEntriesLeft; + } + + /// Get the start of the item as written by the trait (after the hash and + /// immediately before the key and value length). + const unsigned char *getItem() const { + return Ptr + (NumItemsInBucketLeft ? 0 : 2) + sizeof(hash_value_type); + } + }; + +public: + OnDiskIterableChainedHashTable(offset_type NumBuckets, offset_type NumEntries, + const unsigned char *Buckets, + const unsigned char *Payload, + const unsigned char *Base, + const Info &InfoObj = Info()) + : base_type(NumBuckets, NumEntries, Buckets, Base, InfoObj), + Payload(Payload) {} + + /// \brief Iterates over all of the keys in the table. + class key_iterator : public iterator_base { + Info *InfoObj; + + public: + typedef external_key_type value_type; + + key_iterator(const unsigned char *const Ptr, offset_type NumEntries, + Info *InfoObj) + : iterator_base(Ptr, NumEntries), InfoObj(InfoObj) {} + key_iterator() : iterator_base(), InfoObj() {} + + key_iterator &operator++() { + this->advance(); return *this; } key_iterator operator++(int) { // Postincrement - key_iterator tmp = *this; ++*this; return tmp; + key_iterator tmp = *this; + ++*this; + return tmp; + } + + internal_key_type getInternalKey() const { + auto *LocalPtr = this->getItem(); + + // Determine the length of the key and the data. + auto L = Info::ReadKeyDataLength(LocalPtr); + + // Read the key. + return InfoObj->ReadKey(LocalPtr, L.first); } value_type operator*() const { - const unsigned char *LocalPtr = Ptr; - if (!NumItemsInBucketLeft) - LocalPtr += 2; // number of items in bucket - LocalPtr += sizeof(hash_value_type); // Skip the hash. - - // Determine the length of the key and the data. - const std::pair &L = - Info::ReadKeyDataLength(LocalPtr); - - // Read the key. - const internal_key_type &Key = InfoObj->ReadKey(LocalPtr, L.first); - return InfoObj->GetExternalKey(Key); + return InfoObj->GetExternalKey(getInternalKey()); } }; @@ -467,10 +499,7 @@ public: } /// \brief Iterates over all the entries in the table, returning the data. - class data_iterator { - const unsigned char *Ptr; - offset_type NumItemsInBucketLeft; - offset_type NumEntriesLeft; + class data_iterator : public iterator_base { Info *InfoObj; public: @@ -478,51 +507,24 @@ public: data_iterator(const unsigned char *const Ptr, offset_type NumEntries, Info *InfoObj) - : Ptr(Ptr), NumItemsInBucketLeft(0), NumEntriesLeft(NumEntries), - InfoObj(InfoObj) {} - data_iterator() - : Ptr(nullptr), NumItemsInBucketLeft(0), NumEntriesLeft(0), - InfoObj(nullptr) {} - - bool operator==(const data_iterator &X) const { - return X.NumEntriesLeft == NumEntriesLeft; - } - bool operator!=(const data_iterator &X) const { - return X.NumEntriesLeft != NumEntriesLeft; - } + : iterator_base(Ptr, NumEntries), InfoObj(InfoObj) {} + data_iterator() : iterator_base(), InfoObj() {} data_iterator &operator++() { // Preincrement - using namespace llvm::support; - if (!NumItemsInBucketLeft) { - // 'Items' starts with a 16-bit unsigned integer representing the - // number of items in this bucket. - NumItemsInBucketLeft = - endian::readNext(Ptr); - } - Ptr += sizeof(hash_value_type); // Skip the hash. - // Determine the length of the key and the data. - const std::pair &L = - Info::ReadKeyDataLength(Ptr); - Ptr += L.first + L.second; - assert(NumItemsInBucketLeft); - --NumItemsInBucketLeft; - assert(NumEntriesLeft); - --NumEntriesLeft; + this->advance(); return *this; } data_iterator operator++(int) { // Postincrement - data_iterator tmp = *this; ++*this; return tmp; + data_iterator tmp = *this; + ++*this; + return tmp; } value_type operator*() const { - const unsigned char *LocalPtr = Ptr; - if (!NumItemsInBucketLeft) - LocalPtr += 2; // number of items in bucket - LocalPtr += sizeof(hash_value_type); // Skip the hash. + auto *LocalPtr = this->getItem(); // Determine the length of the key and the data. - const std::pair &L = - Info::ReadKeyDataLength(LocalPtr); + auto L = Info::ReadKeyDataLength(LocalPtr); // Read the key. const internal_key_type &Key = InfoObj->ReadKey(LocalPtr, L.first); @@ -555,17 +557,12 @@ public: static OnDiskIterableChainedHashTable * Create(const unsigned char *Buckets, const unsigned char *const Payload, const unsigned char *const Base, const Info &InfoObj = Info()) { - using namespace llvm::support; assert(Buckets > Base); - assert((reinterpret_cast(Buckets) & 0x3) == 0 && - "buckets should be 4-byte aligned."); - - offset_type NumBuckets = - endian::readNext(Buckets); - offset_type NumEntries = - endian::readNext(Buckets); + auto NumBucketsAndEntries = + OnDiskIterableChainedHashTable::readNumBucketsAndEntries(Buckets); return new OnDiskIterableChainedHashTable( - NumBuckets, NumEntries, Buckets, Payload, Base, InfoObj); + NumBucketsAndEntries.first, NumBucketsAndEntries.second, + Buckets, Payload, Base, InfoObj); } };