Guest User

Untitled

a guest
Jul 1st, 2014
41
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 14.86 KB | None | 0 0
  1. #ifndef HEADER_UUID_4D158924626647EF8FFBED8D284A0654
  2. #define HEADER_UUID_4D158924626647EF8FFBED8D284A0654
  3.  
  4. // C++ Standard Library:
  5. #include <memory>
  6. #include <limits>
  7. #include <cstddef>
  8. #include <cstring>
  9. #include <cassert>
  10.  
  11. // Nano:
  12. #include <Nano/Util/Hash.hpp>
  13. #include <Nano/Util/RawAllocator.hpp>
  14.  
  15. namespace nano
  16. {
  17.     namespace util
  18.     {
  19.         namespace detail
  20.         {
  21.             std::uint32_t const STRINGHASHTABLE_PRIMES[] =
  22.             {
  23.                 13, 29, 59, 121, 251, 503, 1009, 2027, 4057, 8117, 16249, 32503,
  24.                 65011, 130027, 260081, 520193, 1040387, 2080777, 4161557, 8323151,
  25.                 16646317, 33292687, 66585377, 133170769, 266341583, 532683227,
  26.                 1065366479, 2130732959, 4261465919
  27.             };
  28.             float const STRINGHASHTABLE_DEFAULT_MAX_LOADFACTOR = 1;
  29.         }
  30.        
  31.         template<typename CharT, typename ValueT, class Allocator = MallocAllocator>
  32.         class StringHashtable
  33.         {
  34.         public:
  35.             typedef CharT CharType;
  36.             typedef ValueT ValueType;
  37.             typedef std::basic_string<CharT> StringType;
  38.            
  39.         private:
  40.             struct Entry
  41.             {
  42.                 std::size_t keyLength;
  43.                 Entry* next;
  44.                 ValueT value;
  45.                 CharT key[1];
  46.             };
  47.            
  48.         public:
  49.             template<typename HashtableT>
  50.             class BasicIterator
  51.             {
  52.             private:
  53.                 HashtableT* _ht;
  54.                 std::size_t _bucket;
  55.                 Entry* _last;
  56.                 Entry* _cur;
  57.                
  58.             public:
  59.                 BasicIterator(HashtableT* ht, std::size_t bucket, Entry* last, Entry* cur)
  60.                     : _ht(ht), _bucket(bucket), _last(last), _cur(cur)
  61.                 { }
  62.                
  63.                 typename HashtableT::CharType const* key() const
  64.                 {
  65.                     assert(_bucket < _ht->bucketCount());
  66.                     return _cur->key;
  67.                 }
  68.                
  69.                 std::size_t keyLength() const
  70.                 {
  71.                     assert(_bucket < _ht->bucketCount());
  72.                     return _cur->keyLength;
  73.                 }
  74.                
  75.                 typename HashtableT::ValueType& value() const
  76.                 {
  77.                     assert(_bucket < _ht->bucketCount());
  78.                     return _cur->value;
  79.                 }
  80.                
  81.                 typename HashtableT::ValueType& operator*() const
  82.                 {
  83.                     return value();
  84.                 }
  85.                
  86.                 typename HashtableT::ValueType* operator->() const
  87.                 {
  88.                     return &value();
  89.                 }
  90.             };
  91.            
  92.             typedef BasicIterator<StringHashtable<CharT, ValueT, Allocator>> Iterator;
  93.             typedef BasicIterator<StringHashtable<CharT, ValueT const, Allocator>> ConstIterator;
  94.             template<typename Value2T>
  95.             using AnyIterator = BasicIterator<StringHashtable<CharT, Value2T, Allocator>>;
  96.  
  97.         private:
  98.             unsigned _primeIndex;
  99.             std::unique_ptr<Entry*[]> _buckets;
  100.             size_t _size;
  101.             Allocator _alloc;
  102.             float _maxLoadFactor;
  103.  
  104.             template<typename... Args>
  105.             Entry* makeEntry(CharT const* key, size_t keyLength, Args&&... args)
  106.             {
  107.                 auto const MAXA = std::numeric_limits<size_t>::max();
  108.                 if(MAXA / sizeof(CharT) < keyLength)
  109.                     throw std::bad_alloc();
  110.                
  111.                 auto const keySize = keyLength * sizeof(CharT);
  112.                 auto const keyOffset = offsetof(Entry, key);
  113.                 if(MAXA - keyOffset < keySize)
  114.                     throw std::bad_alloc();
  115.                
  116.                 Entry* data = (Entry*)_alloc.alloc(keyOffset + keySize);
  117.                 data->keyLength = keyLength;
  118.                 data->next = nullptr;
  119.                 new(&data->value) ValueT(std::forward<Args>(args)...);
  120.                 std::memcpy(data->key, key, keySize);
  121.                 return data;
  122.             }
  123.            
  124.             void destroyEntry(Entry* entry)
  125.             {
  126.                 entry->value.~ValueT();
  127.                 _alloc.free(entry);
  128.             }
  129.            
  130.             void destroyEntryList(Entry* first)
  131.             {
  132.                 Entry* cur = first;
  133.                 while(cur)
  134.                 {
  135.                     Entry* next = cur->next;
  136.                     destroyEntry(cur);
  137.                     cur = next;
  138.                 };
  139.             }
  140.  
  141.             Entry* findEntry(CharT const* key, size_t keyLength, size_t bucketIndex, Entry*& last)
  142.             {
  143.                 if(!_buckets[bucketIndex])
  144.                     return nullptr;
  145.                
  146.                 Entry* cur = _buckets[bucketIndex];
  147.                 last = nullptr;
  148.                 do
  149.                 {
  150.                     if(keyLength == cur->keyLength)
  151.                     {
  152.                         auto const cmpResult = std::memcmp(key, cur->key, keyLength * sizeof(CharT));
  153.                         if(cmpResult == 0)
  154.                             return cur;
  155.                     }
  156.                 } while( (last = cur, cur = cur->next) );
  157.                 return nullptr;
  158.             }
  159.            
  160.             template<bool Rehash = true>
  161.             void insertEntry(Entry* entry, std::size_t bucketIndex)
  162.             {
  163.                 if(Rehash && loadFactor() > maxLoadFactor() && bucketCount() < maxBucketCount())
  164.                 {
  165.                     rehash();
  166.                     bucketIndex = bucket(entry->key, entry->keyLength);
  167.                 }  
  168.                
  169.                    
  170.                 if(!_buckets[bucketIndex])
  171.                 {
  172.                     _buckets[bucketIndex] = entry;
  173.                     _buckets[bucketIndex]->next = nullptr;
  174.                 }
  175.                 else
  176.                 {
  177.                     Entry* old = _buckets[bucketIndex];
  178.                     _buckets[bucketIndex] = entry;
  179.                     _buckets[bucketIndex]->next = old;
  180.                 }
  181.                 ++_size;
  182.             }
  183.            
  184.             void rehash()
  185.             {
  186.                 StringHashtable newTable(_primeIndex + 1, _maxLoadFactor, std::move(_alloc));
  187.                 for(size_t i = 0, count = bucketCount(); i != count; ++i)
  188.                 {
  189.                     Entry* curEntry = _buckets[i];
  190.                     while(curEntry)
  191.                     {
  192.                         Entry* next = curEntry->next;
  193.                         size_t const bucketIndex = newTable.bucketFor(curEntry->key, curEntry->keyLength);
  194.                         newTable.insertEntry<false>(curEntry, bucketIndex);
  195.                         curEntry = next;
  196.                     }
  197.                     _buckets[i] = nullptr;
  198.                 }
  199.                 swap(newTable);
  200.             }
  201.  
  202.         public:
  203.             StringHashtable(unsigned primeIndex = 0,
  204.                     float maxLoadFactor= detail::STRINGHASHTABLE_DEFAULT_MAX_LOADFACTOR,
  205.                     Allocator alloc = Allocator())
  206.                 : _primeIndex(primeIndex), _buckets(new Entry*[bucketCount()]), _size(0),
  207.                   _alloc(std::move(alloc)), _maxLoadFactor(maxLoadFactor)
  208.             {
  209.                 std::memset(_buckets.get(), 0, bucketCount() * sizeof(Entry*));
  210.             }
  211.            
  212.             StringHashtable(StringHashtable const&) = delete;
  213.            
  214.             StringHashtable(StringHashtable&& other)
  215.                 : _primeIndex(other._primeIndex), _buckets(other._buckets), _size(other._size),
  216.                   _alloc(std::move(other._alloc)), _maxLoadFactor(other._maxLoadFactor)  
  217.             { }
  218.            
  219.             ~StringHashtable()
  220.             {
  221.                 if(!Allocator::hasNopFree || !std::is_trivially_destructible<ValueT>::value)
  222.                 {
  223.                     for(size_t i = 0, count = bucketCount(); i != count; ++i)
  224.                         destroyEntryList(_buckets[i]);
  225.                 }
  226.             }
  227.            
  228.             StringHashtable& operator=(StringHashtable const&) = delete;
  229.            
  230.             StringHashtable& operator=(StringHashtable other)
  231.             {
  232.                 swap(other);
  233.             }
  234.  
  235.             ////
  236.             // Capacity
  237.             ////
  238.            
  239.             bool empty() const
  240.             {
  241.                 return size() == 0;
  242.             }
  243.            
  244.             std::size_t size() const
  245.             {
  246.                 return _size;
  247.             }
  248.            
  249.             constexpr std::size_t maxSize() const
  250.             {
  251.                 return std::numeric_limits<std::size_t>::max();
  252.             }
  253.      
  254.             ////
  255.             // Element access
  256.             ////
  257.            
  258.             ValueT& operator[](StringType const& key)
  259.             {        
  260.                 auto const bucket = bucket(key.data(), key.length());
  261.                 Entry* last;
  262.                 Entry* entry = findEntry(key.data(), key.length(), bucket, last);
  263.                 if(entry)
  264.                     return entry->value;
  265.                 entry = makeEntry(key.data(), key.length(), ValueT());
  266.                 insertEntry(entry, bucket);
  267.                 return entry->value;
  268.             }
  269.            
  270.             ValueType& at(CharT const* key, std::size_t keyLength)
  271.             {
  272.                 Entry* last;
  273.                 Entry* entry = findEntry(key.data(), key.length(),
  274.                     bucket(key.data(), key.length()), last);
  275.                 if(!entry)
  276.                     throw std::out_of_range("StringHashtable::at");
  277.                 return entry->value;
  278.             }
  279.            
  280.             ValueType& at(StringType const& key)
  281.             {
  282.                 return at(key.data(), key.length());
  283.             }
  284.            
  285.             ValueType const& at(CharT const* key, std::size_t keyLength) const
  286.             {
  287.                 return const_cast<StringHashtable*>(this)->at(key, keyLength);
  288.             }
  289.            
  290.             ValueType const& at(StringType const& key) const
  291.             {
  292.                 return at(key.data(), key.length());
  293.             }
  294.            
  295.             ////
  296.             // Element lookup
  297.             ////
  298.            
  299.             std::size_t count(CharT const* key, std::size_t keyLength) const
  300.             {
  301.                 Entry* last;
  302.                 auto const bucket = bucket(key.data(), key.length());
  303.                 return (const_cast<StringHashtable*>(this)->findEntry(
  304.                     key.data(), key.length(), bucket, last) != nullptr) ? 1 : 0;
  305.             }
  306.            
  307.             std::size_t count(StringType const& key) const
  308.             {
  309.                 return count(key.data(), key.length());
  310.             }
  311.            
  312.             ////
  313.             // Modifiers
  314.             ////
  315.            
  316.             template<typename Value2T>
  317.             std::pair<Iterator,bool> insert(CharT const* key, std::size_t keyLength, Value2T&& val)
  318.             {
  319.                 bool existed;
  320.                 Entry* last;
  321.                 auto const bucketIndex = bucket(key, keyLength);
  322.                 Entry* entry = insertOrReturn(key, keyLength, std::forward<Value2T>(val),
  323.                         bucketIndex, last,  &existed);
  324.                 return std::make_pair(Iterator(this, bucketIndex, last, entry), existed);
  325.             }
  326.  
  327.             template<typename Value2T>
  328.             std::pair<Iterator,bool> insert(StringType const& key, Value2T&& val)
  329.             {
  330.                 return insert(key.data(), key.length(), std::forward<Value2T>(val));
  331.             }
  332.        
  333.             std::size_t erase(CharT const* key, std::size_t keyLength)
  334.             {
  335.                 Entry* last;
  336.                 auto const curBucket = bucket(key.data(), key.length());
  337.                 Entry* entry = findEntry(key.data(), key.length(), curBucket, last);
  338.                 if(!entry)
  339.                     return 0;
  340.                 if(last)
  341.                 {
  342.                     last->next = entry->next;
  343.                     destroyEntry(entry);
  344.                 }
  345.                 else
  346.                 {
  347.                     _buckets[curBucket] = entry->next;
  348.                     destroyEntry(entry);
  349.                 }
  350.                 return 1;
  351.             }
  352.        
  353.             std::size_t erase(StringType const& key)
  354.             {
  355.                 return erase(key.data(), key.length());
  356.             }
  357.            
  358.             void clear()
  359.             {
  360.                 for(std::size_t i = 0, count = bucketCount(); i != count; ++i)
  361.                 {
  362.                     if(!Allocator::hasNopFree || !std::is_trivially_destructible<ValueT>::value)
  363.                         destroyEntryList(_buckets[i]);
  364.                     _buckets[i] = nullptr;
  365.                 }
  366.             }
  367.  
  368.             void swap(StringHashtable& other)
  369.             {
  370.                 std::swap(_primeIndex, other._primeIndex);
  371.                 std::swap(_buckets, other._buckets);
  372.                 std::swap(_size, other._size);
  373.                 _alloc.swap(other._alloc);
  374.                 std::swap(_maxLoadFactor, other._maxLoadFactor);
  375.             }
  376.            
  377.             ////
  378.             // Buckets
  379.             ////
  380.            
  381.             std::size_t bucketCount() const
  382.             {
  383.                 return detail::STRINGHASHTABLE_PRIMES[_primeIndex];
  384.             }
  385.            
  386.             std::size_t maxBucketCount() const
  387.             {
  388.                 return *(std::end(detail::STRINGHASHTABLE_PRIMES) - 1);
  389.             }
  390.            
  391.             std::size_t bucket(CharT const* key, std::size_t keyLength) const
  392.             {
  393.                 auto const data = (std::uint8_t const*)key;
  394.                 return fnv1a<std::size_t>(data, data + keyLength * sizeof(CharT)) % bucketCount();
  395.             }
  396.            
  397.             std::size_t bucket(StringType const& key) const
  398.             {
  399.                 return bucket(key.data(), key.length());
  400.             }
  401.            
  402.             ////
  403.             // Hash policy
  404.             ////
  405.            
  406.             float loadFactor() const
  407.             {
  408.                 return float(_size) / bucketCount();
  409.             }
  410.            
  411.             void maxLoadFactor(float newFactor)
  412.             {
  413.                 _maxLoadFactor = newFactor;
  414.             }
  415.            
  416.             float maxLoadFactor() const
  417.             {
  418.                 return _maxLoadFactor;
  419.             }
  420.         };
  421.     }
  422. }
  423.  
  424. namespace std
  425. {
  426.     template<typename C, typename V, typename A>
  427.     void swap(nano::util::StringHashtable<C, V, A>& _1, nano::util::StringHashtable<C, V, A>& _2)
  428.     {
  429.         _1.swap(_2);
  430.     }
  431. }
  432.  
  433. #endif // HEADER_UUID_4D158924626647EF8FFBED8D284A0654
Advertisement
Add Comment
Please, Sign In to add comment