Forráskód Böngészése

Revert "Merge pull request #76 from troydhanson/revert-72-hashvalue"

This reverts commit 902dee4b8e6dad46787674bbcdd44570709aea02, reversing
changes made to 6130b77adca8648eeae94c4369819ee84a858d8d.
Troy D. Hanson 9 éve
szülő
commit
9e90e97218
2 módosított fájl, 88 hozzáadás és 31 törlés
  1. 22 12
      doc/userguide.txt
  2. 66 19
      src/uthash.h

+ 22 - 12
doc/userguide.txt

@@ -1712,18 +1712,23 @@ than `hh`, or if your key's data type isn't `int` or `char[]`.
 .General macros
 [width="90%",cols="10m,30m",grid="none",options="header"]
 |===============================================================================
-|macro          | arguments
-|HASH_ADD       | (hh_name, head, keyfield_name, key_len, item_ptr)
-|HASH_ADD_KEYPTR| (hh_name, head, key_ptr, key_len, item_ptr)
-|HASH_REPLACE   | (hh_name, head, keyfield_name, key_len, item_ptr, replaced_item_ptr)
-|HASH_FIND      | (hh_name, head, key_ptr, key_len, item_ptr)
-|HASH_DELETE    | (hh_name, head, item_ptr)
-|HASH_SRT       | (hh_name, head, cmp)
-|HASH_CNT       | (hh_name, head)
-|HASH_CLEAR     | (hh_name, head)
-|HASH_SELECT    | (dst_hh_name, dst_head, src_hh_name, src_head, condition)
-|HASH_ITER      | (hh_name, head, item_ptr, tmp_item_ptr)
-|HASH_OVERHEAD  | (hh_name, head)
+|macro                        | arguments
+|HASH_ADD                     | (hh_name, head, keyfield_name, key_len, item_ptr)
+|HASH_ADD_BY_HASH_VALUE       | (hh_name, head, keyfield_name, key_len, key_hash, item_ptr)
+|HASH_ADD_KEYPTR              | (hh_name, head, key_ptr, key_len, item_ptr)
+|HASH_ADD_KEYPTR_BY_HASH_VALUE| (hh_name, head, key_ptr, key_len, key_hash, item_ptr)
+|HASH_REPLACE                 | (hh_name, head, keyfield_name, key_len, item_ptr, replaced_item_ptr)
+|HASH_REPLACE_BY_HASH_VALUE   | (hh_name, head, keyfield_name, key_len, key_hash, item_ptr, replaced_item_ptr)
+|HASH_FIND                    | (hh_name, head, key_ptr, key_len, item_ptr)
+|HASH_FIND_BY_HASH_VALUE      | (hh_name, head, key_ptr, key_len, key_hash, item_ptr)
+|HASH_DELETE                  | (hh_name, head, item_ptr)
+|HASH_VALUE                   | (key_ptr, key_len, key_hash)
+|HASH_SRT                     | (hh_name, head, cmp)
+|HASH_CNT                     | (hh_name, head)
+|HASH_CLEAR                   | (hh_name, head)
+|HASH_SELECT                  | (dst_hh_name, dst_head, src_hh_name, src_head, condition)
+|HASH_ITER                    | (hh_name, head, item_ptr, tmp_item_ptr)
+|HASH_OVERHEAD                | (hh_name, head)
 |===============================================================================
 
 [NOTE]
@@ -1752,6 +1757,11 @@ key_ptr::
     for `HASH_FIND`, this is a pointer to the key to look up in the hash
     (since it's a pointer, you can't directly pass a literal value here). For
     `HASH_ADD_KEYPTR`, this is the address of the key of the item being added.
+key_hash::
+    the hash value of the provided key. This is an input parameter for the
+    `..._BY_HASH_VALUE` macros, and an output parameter for `HASH_VALUE`.
+    Reusing a cached hash value can be a performance optimization if
+    you're going to do repeated lookups for the same key.
 item_ptr::
     pointer to the structure being added, deleted, or looked up, or the current
     pointer during iteration. This is an input parameter for `HASH_ADD` and

+ 66 - 19
src/uthash.h

@@ -103,12 +103,31 @@ typedef unsigned char uint8_t;
 /* calculate the element whose hash handle address is hhe */
 #define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho)))
 
+#define HASH_VALUE(keyptr,keylen,hashv)                                          \
+do {                                                                             \
+ HASH_FCN(keyptr, keylen, hashv);                                                \
+} while (0)
+
 #define HASH_FIND(hh,head,keyptr,keylen,out)                                     \
 do {                                                                             \
   out=NULL;                                                                      \
   if (head != NULL) {                                                            \
      unsigned _hf_bkt,_hf_hashv;                                                 \
-     HASH_FCN(keyptr,keylen, (head)->hh.tbl->num_buckets, _hf_hashv, _hf_bkt);   \
+     HASH_FCN(keyptr, keylen, _hf_hashv);                                        \
+     HASH_TO_BKT(_hf_hashv, (head)->hh.tbl->num_buckets, _hf_bkt);               \
+     if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv) != 0) {                      \
+       HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ],  \
+                        keyptr,keylen,out);                                      \
+     }                                                                           \
+  }                                                                              \
+} while (0)
+
+#define HASH_FIND_BY_HASH_VALUE(hh,head,keyptr,keylen,_hf_hashv,out)             \
+do {                                                                             \
+  out=NULL;                                                                      \
+  if (head != NULL) {                                                            \
+     unsigned _hf_bkt;                                                           \
+     HASH_TO_BKT(_hf_hashv, (head)->hh.tbl->num_buckets, _hf_bkt);               \
      if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv) != 0) {                      \
        HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ],  \
                         keyptr,keylen,out);                                      \
@@ -172,14 +191,24 @@ do {
 #define HASH_ADD(hh,head,fieldname,keylen_in,add)                                \
         HASH_ADD_KEYPTR(hh,head,&((add)->fieldname),keylen_in,add)
 
+#define HASH_ADD_BY_HASH_VALUE(hh,head,fieldname,keylen_in,hashval,add)          \
+        HASH_ADD_KEYPTR_BY_HASH_VALUE(hh,head,&((add)->fieldname),keylen_in,hashval,add)
+
 #define HASH_REPLACE(hh,head,fieldname,keylen_in,add,replaced)                   \
+do {                                                                             \
+  unsigned _hr_hashv;                                                            \
+  HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv);                         \
+  HASH_REPLACE_BY_HASH_VALUE(hh,head,fieldname,keylen_in,_hr_hashv,add,replaced);\
+} while(0)
+
+#define HASH_REPLACE_BY_HASH_VALUE(hh,head,fieldname,keylen_in,hashval,add,replaced) \
 do {                                                                             \
   replaced=NULL;                                                                 \
-  HASH_FIND(hh,head,&((add)->fieldname),keylen_in,replaced);                     \
+  HASH_FIND_BY_HASH_VALUE(hh,head,&((add)->fieldname),keylen_in,hashval,replaced); \
   if (replaced!=NULL) {                                                          \
      HASH_DELETE(hh,head,replaced);                                              \
   }                                                                              \
-  HASH_ADD(hh,head,fieldname,keylen_in,add);                                     \
+  HASH_ADD_BY_HASH_VALUE(hh,head,fieldname,keylen_in,hashval,add);               \
 } while(0)
 
 #define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add)                            \
@@ -199,14 +228,39 @@ do {
  }                                                                               \
  (head)->hh.tbl->num_items++;                                                    \
  (add)->hh.tbl = (head)->hh.tbl;                                                 \
- HASH_FCN(keyptr,keylen_in, (head)->hh.tbl->num_buckets,                         \
-         (add)->hh.hashv, _ha_bkt);                                              \
+ HASH_FCN(keyptr, keylen_in, (add)->hh.hashv);                                   \
+ HASH_TO_BKT((add)->hh.hashv, (head)->hh.tbl->num_buckets, _ha_bkt);             \
  HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt],&(add)->hh);                   \
  HASH_BLOOM_ADD((head)->hh.tbl,(add)->hh.hashv);                                 \
  HASH_EMIT_KEY(hh,head,keyptr,keylen_in);                                        \
  HASH_FSCK(hh,head);                                                             \
 } while(0)
 
+#define HASH_ADD_KEYPTR_BY_HASH_VALUE(hh,head,keyptr,keylen_in,hashval,add)      \
+do {                                                                             \
+ unsigned _ha_bkt;                                                               \
+ (add)->hh.next = NULL;                                                          \
+ (add)->hh.key = (char*)(keyptr);                                                \
+ (add)->hh.keylen = (unsigned)(keylen_in);                                       \
+ if (!(head)) {                                                                  \
+    head = (add);                                                                \
+    (head)->hh.prev = NULL;                                                      \
+    HASH_MAKE_TABLE(hh,head);                                                    \
+ } else {                                                                        \
+    (head)->hh.tbl->tail->next = (add);                                          \
+    (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail);         \
+    (head)->hh.tbl->tail = &((add)->hh);                                         \
+ }                                                                               \
+ (head)->hh.tbl->num_items++;                                                    \
+ (add)->hh.tbl = (head)->hh.tbl;                                                 \
+ (add)->hh.hashv = hashval;                                                      \
+ HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt);                     \
+ HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt],&(add)->hh);                   \
+ HASH_BLOOM_ADD((head)->hh.tbl,hashval);                                         \
+ HASH_EMIT_KEY(hh,head,keyptr,keylen_in);                                        \
+ HASH_FSCK(hh,head);                                                             \
+} while(0)
+
 #define HASH_TO_BKT( hashv, num_bkts, bkt )                                      \
 do {                                                                             \
   bkt = ((hashv) & ((num_bkts) - 1U));                                           \
@@ -364,7 +418,7 @@ do {
 #endif
 
 /* The Bernstein hash function, used in Perl prior to v5.6. Note (x<<5+x)=x*33. */
-#define HASH_BER(key,keylen,num_bkts,hashv,bkt)                                  \
+#define HASH_BER(key,keylen,hashv)                                               \
 do {                                                                             \
   unsigned _hb_keylen=(unsigned)keylen;                                          \
   const unsigned char *_hb_key=(const unsigned char*)(key);                      \
@@ -372,13 +426,12 @@ do {
   while (_hb_keylen-- != 0U) {                                                   \
       (hashv) = (((hashv) << 5) + (hashv)) + *_hb_key++;                         \
   }                                                                              \
-  bkt = (hashv) & (num_bkts-1U);                                                 \
 } while (0)
 
 
 /* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at
  * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */
-#define HASH_SAX(key,keylen,num_bkts,hashv,bkt)                                  \
+#define HASH_SAX(key,keylen,hashv)                                               \
 do {                                                                             \
   unsigned _sx_i;                                                                \
   const unsigned char *_hs_key=(const unsigned char*)(key);                      \
@@ -386,10 +439,9 @@ do {
   for(_sx_i=0; _sx_i < keylen; _sx_i++) {                                        \
       hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i];                     \
   }                                                                              \
-  bkt = hashv & (num_bkts-1U);                                                   \
 } while (0)
 /* FNV-1a variation */
-#define HASH_FNV(key,keylen,num_bkts,hashv,bkt)                                  \
+#define HASH_FNV(key,keylen,hashv)                                               \
 do {                                                                             \
   unsigned _fn_i;                                                                \
   const unsigned char *_hf_key=(const unsigned char*)(key);                      \
@@ -398,10 +450,9 @@ do {
       hashv = hashv ^ _hf_key[_fn_i];                                            \
       hashv = hashv * 16777619U;                                                 \
   }                                                                              \
-  bkt = hashv & (num_bkts-1U);                                                   \
 } while(0)
 
-#define HASH_OAT(key,keylen,num_bkts,hashv,bkt)                                  \
+#define HASH_OAT(key,keylen,hashv)                                               \
 do {                                                                             \
   unsigned _ho_i;                                                                \
   const unsigned char *_ho_key=(const unsigned char*)(key);                      \
@@ -414,7 +465,6 @@ do {
   hashv += (hashv << 3);                                                         \
   hashv ^= (hashv >> 11);                                                        \
   hashv += (hashv << 15);                                                        \
-  bkt = hashv & (num_bkts-1U);                                                   \
 } while(0)
 
 #define HASH_JEN_MIX(a,b,c)                                                      \
@@ -430,7 +480,7 @@ do {
   c -= a; c -= b; c ^= ( b >> 15 );                                              \
 } while (0)
 
-#define HASH_JEN(key,keylen,num_bkts,hashv,bkt)                                  \
+#define HASH_JEN(key,keylen,hashv)                                               \
 do {                                                                             \
   unsigned _hj_i,_hj_j,_hj_k;                                                    \
   unsigned const char *_hj_key=(unsigned const char*)(key);                      \
@@ -468,7 +518,6 @@ do {
      case 1:  _hj_i += _hj_key[0];                                               \
   }                                                                              \
   HASH_JEN_MIX(_hj_i, _hj_j, hashv);                                             \
-  bkt = hashv & (num_bkts-1U);                                                   \
 } while(0)
 
 /* The Paul Hsieh hash function */
@@ -482,7 +531,7 @@ do {
 #define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)             \
                        +(uint32_t)(((const uint8_t *)(d))[0]) )
 #endif
-#define HASH_SFH(key,keylen,num_bkts,hashv,bkt)                                  \
+#define HASH_SFH(key,keylen,hashv)                                               \
 do {                                                                             \
   unsigned const char *_sfh_key=(unsigned const char*)(key);                     \
   uint32_t _sfh_tmp, _sfh_len = (uint32_t)keylen;                                \
@@ -523,7 +572,6 @@ do {
     hashv += hashv >> 17;                                                        \
     hashv ^= hashv << 25;                                                        \
     hashv += hashv >> 6;                                                         \
-    bkt = hashv & (num_bkts-1U);                                                 \
 } while(0)
 
 #ifdef HASH_USING_NO_STRICT_ALIASING
@@ -568,7 +616,7 @@ do {                 \
   _h ^= _h >> 16;    \
 } while(0)
 
-#define HASH_MUR(key,keylen,num_bkts,hashv,bkt)                        \
+#define HASH_MUR(key,keylen,hashv)                                     \
 do {                                                                   \
   const uint8_t *_mur_data = (const uint8_t*)(key);                    \
   const int _mur_nblocks = (int)(keylen) / 4;                          \
@@ -603,7 +651,6 @@ do {                                                                   \
   _mur_h1 ^= (uint32_t)(keylen);                                       \
   MUR_FMIX(_mur_h1);                                                   \
   hashv = _mur_h1;                                                     \
-  bkt = hashv & (num_bkts-1U);                                         \
 } while(0)
 #endif  /* HASH_USING_NO_STRICT_ALIASING */