Refactor to reduce duplication in OnDiskIterableChainedHashTable's iterators.
authorRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 26 Aug 2015 00:22:41 +0000 (00:22 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 26 Aug 2015 00:22:41 +0000 (00:22 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@245995 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Support/OnDiskHashTable.h

index 08e277ad5ce1e95783352a1e63b2d2ad4fa1074a..cc40efc5c0c66f9f29a3de2ff76f0a5857482111 100644 (file)
@@ -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<offset_type, offset_type>
+  readNumBucketsAndEntries(const unsigned char *&Buckets) {
+    assert((reinterpret_cast<uintptr_t>(Buckets) & 0x3) == 0 &&
+           "buckets should be 4-byte aligned.");
+    using namespace llvm::support;
+    offset_type NumBuckets =
+        endian::readNext<offset_type, little, aligned>(Buckets);
+    offset_type NumEntries =
+        endian::readNext<offset_type, little, aligned>(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<uintptr_t>(Buckets) & 0x3) == 0 &&
-           "buckets should be 4-byte aligned.");
-
-    offset_type NumBuckets =
-        endian::readNext<offset_type, little, aligned>(Buckets);
-    offset_type NumEntries =
-        endian::readNext<offset_type, little, aligned>(Buckets);
-    return new OnDiskChainedHashTable<Info>(NumBuckets, NumEntries, Buckets,
-                                            Base, InfoObj);
+    auto NumBucketsAndEntries = readNumBucketsAndEntries(Buckets);
+    return new OnDiskChainedHashTable<Info>(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;
     }
 
-    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.
+    internal_key_type getInternalKey() const {
+      auto *LocalPtr = this->getItem();
 
       // Determine the length of the key and the data.
-      const std::pair<offset_type, offset_type> &L =
-          Info::ReadKeyDataLength(LocalPtr);
+      auto L = Info::ReadKeyDataLength(LocalPtr);
 
       // Read the key.
-      const internal_key_type &Key = InfoObj->ReadKey(LocalPtr, L.first);
-      return InfoObj->GetExternalKey(Key);
+      return InfoObj->ReadKey(LocalPtr, L.first);
+    }
+
+    value_type operator*() const {
+      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<uint16_t, little, unaligned>(Ptr);
-      }
-      Ptr += sizeof(hash_value_type); // Skip the hash.
-      // Determine the length of the key and the data.
-      const std::pair<offset_type, offset_type> &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<offset_type, offset_type> &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<uintptr_t>(Buckets) & 0x3) == 0 &&
-           "buckets should be 4-byte aligned.");
-
-    offset_type NumBuckets =
-        endian::readNext<offset_type, little, aligned>(Buckets);
-    offset_type NumEntries =
-        endian::readNext<offset_type, little, aligned>(Buckets);
+    auto NumBucketsAndEntries =
+        OnDiskIterableChainedHashTable<Info>::readNumBucketsAndEntries(Buckets);
     return new OnDiskIterableChainedHashTable<Info>(
-        NumBuckets, NumEntries, Buckets, Payload, Base, InfoObj);
+        NumBucketsAndEntries.first, NumBucketsAndEntries.second,
+        Buckets, Payload, Base, InfoObj);
   }
 };