Advertisement
Guest User

Untitled

a guest
Oct 1st, 2017
43
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
D 3.97 KB | None | 0 0
  1. module hive.util.cthash;
  2.  
  3. import std.typecons : Nullable;
  4.  
  5. // Adapted from http://stevehanov.ca/blog/index.php?id=119
  6. // Uses a better hash function to prevent locking up the trial-and-error loop
  7. // Doesn't do the unnecessary -1 hack for 1-slot buckets
  8.  
  9. struct CtHash(T)
  10. {
  11.     private int[] ds = [];
  12.     private KeyValue!T[] slots = [];
  13.    
  14.     this(T[string] aa)
  15.     {
  16.         import std.algorithm.searching : canFind;
  17.         import std.algorithm.sorting : sort;
  18.        
  19.         uint n = aa.length;
  20.        
  21.         this.ds.length = n;
  22.         this.slots.length = n;
  23.        
  24.         KeyValue!T[][] buckets;
  25.         buckets.length = n;
  26.         foreach (k, v; aa)
  27.         {
  28.             auto h = hash(0, k);
  29.             buckets[mod(h, n)] ~= KeyValue!T(k, v);
  30.         }
  31.        
  32.         buckets.sort!"a.length > b.length"();
  33.        
  34.         bool[] used;
  35.         used.length = n;
  36.         used[] = false;
  37.        
  38.         uint b = 0;
  39.         while (b < buckets.length && buckets[b].length > 1)
  40.         {
  41.             auto bucket = buckets[b];
  42.            
  43.             int d = 1;
  44.            
  45.             uint[] indices;
  46.             do
  47.             {
  48.                 assert(d < 10000000);
  49.                
  50.                 indices.length = 0;
  51.                 foreach (kv; bucket)
  52.                 {
  53.                     uint index = mod(hash(d, kv.key), n);
  54.                    
  55.                     if (used[index] || indices.canFind(index))
  56.                     {
  57.                         d++;
  58.                         break;
  59.                     }
  60.                    
  61.                     indices ~= index;
  62.                 }
  63.             }
  64.             while (indices.length < bucket.length);
  65.            
  66.             auto h = hash(0, bucket[0].key);
  67.             this.ds[mod(h, n)] = d;
  68.             for (uint i = 0; i < indices.length; i++)
  69.             {
  70.                 uint index = indices[i];
  71.                 this.slots[index] = bucket[i];
  72.                 used[index] = true;
  73.             }
  74.            
  75.             b++;
  76.         }
  77.        
  78.         uint index = 0;
  79.         while (b < buckets.length && buckets[b].length)
  80.         {
  81.             auto bucket = buckets[b];
  82.             assert(bucket.length == 1);
  83.            
  84.             while (used[index])
  85.             {
  86.                 index++;
  87.             }
  88.            
  89.             auto h = hash(0, bucket[0].key);
  90.             this.ds[mod(h, n)] = -index;
  91.             this.slots[index] = bucket[0];
  92.             used[index] = true;
  93.            
  94.             b++;
  95.         }
  96.     }
  97.    
  98.     const uint length()
  99.     {
  100.         return this.slots.length;
  101.     }
  102.    
  103.     const bool has(const string key)
  104.     {
  105.         if (this.length == 0)
  106.         {
  107.             return false;
  108.         }
  109.         else
  110.         {
  111.             auto slot = this.findSlot(key);
  112.             return slot.key == key;
  113.         }
  114.     }
  115.    
  116.     const T find(const string key)
  117.     {
  118.         if (this.length == 0)
  119.         {
  120.             throw new KeyNotFound(key);
  121.         }
  122.         else
  123.         {
  124.             auto slot = this.findSlot(key);
  125.             if (slot.key == key)
  126.             {
  127.                 return slot.value;
  128.             }
  129.             else
  130.             {
  131.                 throw new KeyNotFound(key);
  132.             }
  133.         }
  134.     }
  135.    
  136.     const T find(const string key, T default_)
  137.     {
  138.         if (this.length == 0)
  139.         {
  140.             throw new KeyNotFound(key);
  141.         }
  142.         else
  143.         {
  144.             auto slot = this.findSlot(key);
  145.             if (slot.key == key)
  146.             {
  147.                 return slot.value;
  148.             }
  149.             else
  150.             {
  151.                 return default_;
  152.             }
  153.         }
  154.     }
  155.    
  156.     const private KeyValue!T findSlot(const string key)
  157.     {
  158.         int d = this.ds[mod(hash(0, key), this.length)];
  159.        
  160.         if (d <= 0)
  161.         {
  162.             return this.slots[-d];
  163.         }
  164.         else
  165.         {
  166.             return this.slots[mod(hash(d, key), this.length)];
  167.         }
  168.     }
  169.    
  170.     const T[string] aa()
  171.     {
  172.         T[string] aa;
  173.         foreach (slot; this.slots)
  174.         {
  175.             aa[slot.key] = slot.value;
  176.         }
  177.         return aa;
  178.     }
  179. }
  180.  
  181. private struct KeyValue(T)
  182. {
  183.     string key;
  184.     T value;
  185. }
  186.  
  187. //*
  188. // Jenkins's one-at-a-time hash -- https://en.wikipedia.org/wiki/Jenkins_hash_function#one-at-a-time
  189. private int hash(int d, const string key)
  190. {
  191.     int h = d;
  192.     foreach (char c; key)
  193.     {
  194.         h += c;
  195.         h += h << 10;
  196.         h ^= h >> 6;
  197.     }
  198.     h += h << 3;
  199.     h ^= h >> 11;
  200.     h += h << 15;
  201.     return h;
  202. }
  203. //*/
  204.  
  205. private uint mod(int n, int m)
  206. {
  207.     int r = n % m;
  208.     return r < 0 ? r + m : r;
  209. }
  210.  
  211. class KeyNotFound : Exception
  212. {
  213.     this (string key)
  214.     {
  215.         super("Key `" ~ key ~ "` not found");
  216.     }
  217. }
  218.  
  219. unittest
  220. {
  221.     import std.stdio;
  222.     import std.file;
  223.     import std.array;
  224.     import std.random;
  225.    
  226.     auto dict = File("/usr/share/dict/words").byLineCopy().array();
  227.     auto rnd = Random(42);
  228.    
  229.     foreach (n; 1..100)
  230.     {
  231.         uint[string] aa;
  232.         foreach (word; randomSample(dict, n, rnd))
  233.         {
  234.             aa[word] = uniform!uint(rnd);
  235.         }
  236.        
  237.         CtHash!uint hm = CtHash!uint(aa);
  238.        
  239.         foreach (k, v; aa)
  240.         {
  241.             assert(hm.find(k) == v);
  242.         }
  243.     }
  244. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement