Guest User

Untitled

a guest
Jun 30th, 2014
45
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.33 KB | None | 0 0
  1. #include <cstdint>
  2. #include <type_traits>
  3.  
  4. namespace detail
  5. {
  6.     std::uint32_t const FNV_PRIME_32        = 16777619u;
  7.     std::uint64_t const FNV_PRIME_64        = 1099511628211ull;
  8.  
  9.     std::uint32_t const FNV_OFFSETBASIS_32  = 2166136261u;
  10.     std::uint64_t const FNV_OFFSETBASIS_64  = 14695981039346656037ull;
  11.  
  12.     template<unsigned Bits>
  13.     struct FnvDefaultParams
  14.     { };
  15.    
  16.     template<>
  17.     struct FnvDefaultParams<32>
  18.     {
  19.         constexpr static std::uint32_t prime()
  20.         {
  21.             return FNV_PRIME_32;
  22.         }
  23.        
  24.         constexpr static std::uint32_t offsetbasis()
  25.         {
  26.             return FNV_OFFSETBASIS_32;
  27.         }
  28.     };
  29.    
  30.     template<>
  31.     struct FnvDefaultParams<64>
  32.     {
  33.         constexpr static std::uint64_t prime()
  34.         {
  35.             return FNV_PRIME_64;
  36.         }
  37.        
  38.         constexpr static std::uint64_t offsetbasis()
  39.         {
  40.             return FNV_OFFSETBASIS_64;
  41.         }
  42.     };
  43.    
  44.     template<   typename UIntT,
  45.                 UIntT OffsetBasis = detail::FnvDefaultParams<sizeof(UIntT) * 8>::offsetbasis(),
  46.                 UIntT FnvPrime = detail::FnvDefaultParams<sizeof(UIntT) * 8>::prime()>
  47.     UIntT fnv1a(std::uint8_t const* begin, std::uint8_t const* end)
  48.     {
  49.         static_assert(std::is_unsigned<UIntT>::value, "Hash must be an unsigned integer");
  50.        
  51.         UIntT hash = OffsetBasis;
  52.         for(; begin != end; ++begin)
  53.         {
  54.             hash ^= *begin;
  55.             hash *= FnvPrime;
  56.         }
  57.         return hash;
  58.     }
  59.    
  60.     template<   typename UIntT,
  61.                 UIntT OffsetBasis = detail::FnvDefaultParams<sizeof(UIntT) * 8>::offsetbasis(),
  62.                 UIntT FnvPrime = detail::FnvDefaultParams<sizeof(UIntT) * 8>::prime()>
  63.     UIntT fnv1a_zero(char const* begin)
  64.     {
  65.         static_assert(std::is_unsigned<UIntT>::value, "Hash must be an unsigned integer");
  66.        
  67.         UIntT hash = OffsetBasis;
  68.         for(; *begin; ++begin)
  69.         {
  70.             hash ^= *begin;
  71.             hash *= FnvPrime;
  72.         }
  73.         return hash;
  74.     }
  75.    
  76.     std::uint32_t const HASHTABLE_PRIMES[] =
  77.     {
  78.         13, 29, 59, 121, 251, 503, 1009, 2027, 4057, 8117, 16249, 32503,
  79.         65011, 130027, 260081, 520193, 1040387, 2080777, 4161557, 8323151,
  80.         16646317, 33292687, 66585377, 133170769, 266341583, 532683227,
  81.         1065366479, 2130732959, 4261465919
  82.     };
  83.    
  84.     float const HASHTABLE_MAX_LOADFACTOR = 0.5;
  85. }
  86.  
  87. #include <cstring>
  88. #include <cmath>
  89. #include <vector>
  90. #include <cstddef>
  91. #include <limits>
  92. #include <memory>
  93.  
  94. template<typename CharT, typename ValueT>
  95. class StringHashtable
  96. {
  97. private:
  98.     struct Entry
  99.     {
  100.         size_t keyLength;
  101.         Entry* next;
  102.         ValueT value;
  103.         CharT key[1];
  104.     };
  105.    
  106.     unsigned _primeIndex;
  107.     std::unique_ptr<Entry*[]> _buckets;
  108.     size_t _size;
  109.  
  110.     template<typename Value2T>
  111.     static Entry* makeEntry(CharT const* key, size_t keyLength, Value2T&& value)
  112.     {
  113.         auto const MAXA = std::numeric_limits<size_t>::max();
  114.         if(MAXA / sizeof(CharT) < keyLength)
  115.             throw std::bad_alloc();
  116.        
  117.         auto const keySize = keyLength * sizeof(CharT);
  118.         auto const keyOffset = offsetof(Entry, key);
  119.         if(MAXA - keyOffset < keySize)
  120.             throw std::bad_alloc();
  121.        
  122.         Entry* data = (Entry*)std::malloc(keyOffset + keySize);
  123.         if(!data)
  124.             throw std::bad_alloc();
  125.         data->keyLength = keyLength;
  126.         data->next = nullptr;
  127.         new(&data->value) ValueT(std::move(value));
  128.         std::memcpy(data->key, key, keySize);
  129.         return data;
  130.     }
  131.    
  132.     static void destroyEntry(Entry* entry)
  133.     {
  134.         entry->value.~ValueT();
  135.         std::free(entry);
  136.     }
  137.    
  138.     static Entry* destroyEntryList(Entry* first)
  139.     {
  140.         Entry* cur = first;
  141.         while(cur)
  142.         {
  143.             Entry* next = cur->next;
  144.             destroyEntry(cur);
  145.             cur = next;
  146.         };
  147.     }
  148.    
  149.     size_t bucketFor(CharT const* key, size_t keyLength) const
  150.     {
  151.         auto const data = (std::uint8_t const*)key;
  152.         return detail::fnv1a<size_t>(data, data + keyLength * sizeof(CharT)) % bucketCount();
  153.     }
  154.    
  155.     Entry* findEntry(CharT const* key, size_t keyLength, size_t bucketIndex)
  156.     {
  157.         if(!_buckets[bucketIndex])
  158.             return nullptr;
  159.        
  160.         Entry* cur = _buckets[bucketIndex];
  161.         do
  162.         {
  163.             if(keyLength == cur->keyLength)
  164.             {
  165.                 auto const cmpResult = std::memcmp(key, cur->key, keyLength * sizeof(CharT));
  166.                 if(cmpResult == 0)
  167.                     return cur;
  168.             }
  169.         } while(cur = cur->next);
  170.         return nullptr;
  171.     }
  172.    
  173.     template<typename Value2T>
  174.     Entry* insertOrReturn(CharT const* key, size_t keyLength, Value2T&& value, bool* existed = nullptr)
  175.     {
  176.         size_t const bucketIndex = bucketFor(key, keyLength, bucketCount());
  177.         Entry* entry = findEntry(key, keyLength, bucketIndex);
  178.         if(entry)
  179.         {
  180.             if(existed)
  181.                 existed = true;
  182.             return entry;
  183.         }
  184.        
  185.         if(existed)
  186.             existed = false;
  187.         entry = makeEntry(key, keyLength, std::forward<Value2T>(value));
  188.         insertEntry(entry, bucketIndex);
  189.         return entry;
  190.     }
  191.    
  192.     template<bool Rehash = true>
  193.     void insertEntry(Entry* entry, size_t bucketIndex)
  194.     {
  195.         if(Rehash && float(_size) / bucketCount() > detail::HASHTABLE_MAX_LOADFACTOR)
  196.             rehash();
  197.            
  198.         if(!_buckets[bucketIndex])
  199.         {
  200.             _buckets[bucketIndex] = entry;
  201.             _buckets[bucketIndex]->next = nullptr;
  202.         }
  203.         else
  204.         {
  205.             Entry* old = _buckets[bucketIndex];
  206.             _buckets[bucketIndex] = entry;
  207.             _buckets[bucketIndex]->next = old;
  208.         }
  209.         ++_size;
  210.     }
  211.    
  212.     void rehash()
  213.     {
  214.         StringHashtable newTable( (_primeIndex + 1) );
  215.         for(size_t i = 0, count = bucketCount(); i != count; ++i)
  216.         {
  217.             Entry* curEntry = _buckets[i];
  218.             while(curEntry)
  219.             {
  220.                 Entry* next = curEntry->next;
  221.                 size_t const bucketIndex = newTable.bucketFor(curEntry->key, curEntry->keyLength);
  222.                 newTable.insertEntry<false>(curEntry, bucketIndex);
  223.                 curEntry = next;
  224.             }
  225.             _buckets[i] = nullptr;
  226.         }
  227.         swap(newTable);
  228.     }
  229.    
  230.     size_t bucketCount() const
  231.     {
  232.         return detail::HASHTABLE_PRIMES[_primeIndex];
  233.     }
  234.  
  235. public:
  236.     StringHashtable(unsigned primeIndex = 0)
  237.         : _primeIndex(primeIndex), _buckets(new Entry*[bucketCount()]), _size(0)
  238.     {
  239.         std::memset(_buckets.get(), 0, bucketCount() * sizeof(Entry*));
  240.     }
  241.    
  242.     ~StringHashtable()
  243.     {
  244.         for(size_t i = 0, count = bucketCount(); i != count; ++i)
  245.             destroyEntryList(_buckets[i]);
  246.     }
  247.    
  248.     void swap(StringHashtable& other)
  249.     {
  250.         std::swap(_primeIndex, other._primeIndex);
  251.         std::swap(_buckets, other._buckets);
  252.         std::swap(_size, other._size);
  253.     }
  254.    
  255.     ValueT& operator[](std::basic_string<CharT> const& key)
  256.     {        
  257.         auto const bucket = bucketFor(key.data(), key.length());
  258.         Entry* entry = findEntry(key.data(), key.length(), bucket);
  259.         if(entry)
  260.             return entry->value;
  261.         entry = makeEntry(key.data(), key.length(), ValueT());
  262.         insertEntry(entry, bucket);
  263.         return entry->value;
  264.     }
  265.    
  266.     bool contains(std::basic_string<CharT> const& key) const
  267.     {
  268.         auto const bucket = bucketFor(key.data(), key.length());
  269.         return const_cast<StringHashtable*>(this)->findEntry(
  270.             key.data(), key.length(), bucket) != nullptr;
  271.     }
  272.    
  273.     size_t size() const
  274.     {
  275.         return _size;
  276.     }
  277. };
  278.  
  279. #include <fstream>
  280. #include <iostream>
  281.  
  282. int main()
  283. {
  284.     std::vector<std::string> words;
  285.     std::ifstream in("wordsEn.txt");
  286.     std::string curWord;
  287.     while(in >> curWord)
  288.         words.push_back(curWord);
  289.     std::cout << words.size() << " words read\n";
  290.    
  291.     {
  292.         StringHashtable<char, int> ht(0);
  293.         for(std::string const& word : words)
  294.             ht[word] = 1;
  295.  
  296.         std::cout << ht.size() << " pushed into StringHashtable\n";
  297.        
  298.         for(std::string const& word : words)
  299.             if(!ht.contains(word))
  300.                 std::cout << word << " not in StringHashtable!\n";
  301.        
  302.         for(std::string const& word : words)
  303.             if(ht[word] != 1)
  304.                 std::cout << word << " fail! (" << ht[word] << ") ";
  305.         std::cout << std::endl;
  306.        
  307.         ht["octavo"] = 1;
  308.         std::cout << "octavo in StringHashtable: " << (ht.contains("octavo") ? "yes" : "no") << std::endl;
  309.         std::cout << "octavo: " << &ht["octavo"] << "(" << ht["octavo"] << ")" << std::endl;
  310.         std::cout << "octavo: " << &ht["octavo"] << "(" << ht["octavo"] << ")" << std::endl;
  311.         std::cout << "octavo: " << &ht["octavo"] << "(" << ht["octavo"] << ")" << std::endl;
  312.         std::cout << "octavo: " << &ht["octavo"] << "(" << ht["octavo"] << ")" << std::endl;
  313.         std::cout << "octavo: " << &ht["octavo"] << "(" << ht["octavo"] << ")" << std::endl;
  314.     }
  315. }
Advertisement
Add Comment
Please, Sign In to add comment