Parcourir la source

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

This reverts commit 902dee4b8e6dad46787674bbcdd44570709aea02, reversing
changes made to 6130b77adca8648eeae94c4369819ee84a858d8d.
Troy D. Hanson il y a 9 ans
Parent
commit
9e90e97218
2 fichiers modifiés avec 88 ajouts et 31 suppressions
  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
 .General macros
 [width="90%",cols="10m,30m",grid="none",options="header"]
 [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]
 [NOTE]
@@ -1752,6 +1757,11 @@ key_ptr::
     for `HASH_FIND`, this is a pointer to the key to look up in the hash
     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
     (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.
     `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::
 item_ptr::
     pointer to the structure being added, deleted, or looked up, or the current
     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
     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 */
 /* calculate the element whose hash handle address is hhe */
 #define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho)))
 #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)                                     \
 #define HASH_FIND(hh,head,keyptr,keylen,out)                                     \
 do {                                                                             \
 do {                                                                             \
   out=NULL;                                                                      \
   out=NULL;                                                                      \
   if (head != NULL) {                                                            \
   if (head != NULL) {                                                            \
      unsigned _hf_bkt,_hf_hashv;                                                 \
      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) {                      \
      if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv) != 0) {                      \
        HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ],  \
        HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ],  \
                         keyptr,keylen,out);                                      \
                         keyptr,keylen,out);                                      \
@@ -172,14 +191,24 @@ do {
 #define HASH_ADD(hh,head,fieldname,keylen_in,add)                                \
 #define HASH_ADD(hh,head,fieldname,keylen_in,add)                                \
         HASH_ADD_KEYPTR(hh,head,&((add)->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)                   \
 #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 {                                                                             \
 do {                                                                             \
   replaced=NULL;                                                                 \
   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) {                                                          \
   if (replaced!=NULL) {                                                          \
      HASH_DELETE(hh,head,replaced);                                              \
      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)
 } while(0)
 
 
 #define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add)                            \
 #define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add)                            \
@@ -199,14 +228,39 @@ do {
  }                                                                               \
  }                                                                               \
  (head)->hh.tbl->num_items++;                                                    \
  (head)->hh.tbl->num_items++;                                                    \
  (add)->hh.tbl = (head)->hh.tbl;                                                 \
  (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_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt],&(add)->hh);                   \
  HASH_BLOOM_ADD((head)->hh.tbl,(add)->hh.hashv);                                 \
  HASH_BLOOM_ADD((head)->hh.tbl,(add)->hh.hashv);                                 \
  HASH_EMIT_KEY(hh,head,keyptr,keylen_in);                                        \
  HASH_EMIT_KEY(hh,head,keyptr,keylen_in);                                        \
  HASH_FSCK(hh,head);                                                             \
  HASH_FSCK(hh,head);                                                             \
 } while(0)
 } 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 )                                      \
 #define HASH_TO_BKT( hashv, num_bkts, bkt )                                      \
 do {                                                                             \
 do {                                                                             \
   bkt = ((hashv) & ((num_bkts) - 1U));                                           \
   bkt = ((hashv) & ((num_bkts) - 1U));                                           \
@@ -364,7 +418,7 @@ do {
 #endif
 #endif
 
 
 /* The Bernstein hash function, used in Perl prior to v5.6. Note (x<<5+x)=x*33. */
 /* 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 {                                                                             \
 do {                                                                             \
   unsigned _hb_keylen=(unsigned)keylen;                                          \
   unsigned _hb_keylen=(unsigned)keylen;                                          \
   const unsigned char *_hb_key=(const unsigned char*)(key);                      \
   const unsigned char *_hb_key=(const unsigned char*)(key);                      \
@@ -372,13 +426,12 @@ do {
   while (_hb_keylen-- != 0U) {                                                   \
   while (_hb_keylen-- != 0U) {                                                   \
       (hashv) = (((hashv) << 5) + (hashv)) + *_hb_key++;                         \
       (hashv) = (((hashv) << 5) + (hashv)) + *_hb_key++;                         \
   }                                                                              \
   }                                                                              \
-  bkt = (hashv) & (num_bkts-1U);                                                 \
 } while (0)
 } while (0)
 
 
 
 
 /* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at
 /* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at
  * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */
  * 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 {                                                                             \
 do {                                                                             \
   unsigned _sx_i;                                                                \
   unsigned _sx_i;                                                                \
   const unsigned char *_hs_key=(const unsigned char*)(key);                      \
   const unsigned char *_hs_key=(const unsigned char*)(key);                      \
@@ -386,10 +439,9 @@ do {
   for(_sx_i=0; _sx_i < keylen; _sx_i++) {                                        \
   for(_sx_i=0; _sx_i < keylen; _sx_i++) {                                        \
       hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i];                     \
       hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i];                     \
   }                                                                              \
   }                                                                              \
-  bkt = hashv & (num_bkts-1U);                                                   \
 } while (0)
 } while (0)
 /* FNV-1a variation */
 /* FNV-1a variation */
-#define HASH_FNV(key,keylen,num_bkts,hashv,bkt)                                  \
+#define HASH_FNV(key,keylen,hashv)                                               \
 do {                                                                             \
 do {                                                                             \
   unsigned _fn_i;                                                                \
   unsigned _fn_i;                                                                \
   const unsigned char *_hf_key=(const unsigned char*)(key);                      \
   const unsigned char *_hf_key=(const unsigned char*)(key);                      \
@@ -398,10 +450,9 @@ do {
       hashv = hashv ^ _hf_key[_fn_i];                                            \
       hashv = hashv ^ _hf_key[_fn_i];                                            \
       hashv = hashv * 16777619U;                                                 \
       hashv = hashv * 16777619U;                                                 \
   }                                                                              \
   }                                                                              \
-  bkt = hashv & (num_bkts-1U);                                                   \
 } while(0)
 } while(0)
 
 
-#define HASH_OAT(key,keylen,num_bkts,hashv,bkt)                                  \
+#define HASH_OAT(key,keylen,hashv)                                               \
 do {                                                                             \
 do {                                                                             \
   unsigned _ho_i;                                                                \
   unsigned _ho_i;                                                                \
   const unsigned char *_ho_key=(const unsigned char*)(key);                      \
   const unsigned char *_ho_key=(const unsigned char*)(key);                      \
@@ -414,7 +465,6 @@ do {
   hashv += (hashv << 3);                                                         \
   hashv += (hashv << 3);                                                         \
   hashv ^= (hashv >> 11);                                                        \
   hashv ^= (hashv >> 11);                                                        \
   hashv += (hashv << 15);                                                        \
   hashv += (hashv << 15);                                                        \
-  bkt = hashv & (num_bkts-1U);                                                   \
 } while(0)
 } while(0)
 
 
 #define HASH_JEN_MIX(a,b,c)                                                      \
 #define HASH_JEN_MIX(a,b,c)                                                      \
@@ -430,7 +480,7 @@ do {
   c -= a; c -= b; c ^= ( b >> 15 );                                              \
   c -= a; c -= b; c ^= ( b >> 15 );                                              \
 } while (0)
 } while (0)
 
 
-#define HASH_JEN(key,keylen,num_bkts,hashv,bkt)                                  \
+#define HASH_JEN(key,keylen,hashv)                                               \
 do {                                                                             \
 do {                                                                             \
   unsigned _hj_i,_hj_j,_hj_k;                                                    \
   unsigned _hj_i,_hj_j,_hj_k;                                                    \
   unsigned const char *_hj_key=(unsigned const char*)(key);                      \
   unsigned const char *_hj_key=(unsigned const char*)(key);                      \
@@ -468,7 +518,6 @@ do {
      case 1:  _hj_i += _hj_key[0];                                               \
      case 1:  _hj_i += _hj_key[0];                                               \
   }                                                                              \
   }                                                                              \
   HASH_JEN_MIX(_hj_i, _hj_j, hashv);                                             \
   HASH_JEN_MIX(_hj_i, _hj_j, hashv);                                             \
-  bkt = hashv & (num_bkts-1U);                                                   \
 } while(0)
 } while(0)
 
 
 /* The Paul Hsieh hash function */
 /* The Paul Hsieh hash function */
@@ -482,7 +531,7 @@ do {
 #define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)             \
 #define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)             \
                        +(uint32_t)(((const uint8_t *)(d))[0]) )
                        +(uint32_t)(((const uint8_t *)(d))[0]) )
 #endif
 #endif
-#define HASH_SFH(key,keylen,num_bkts,hashv,bkt)                                  \
+#define HASH_SFH(key,keylen,hashv)                                               \
 do {                                                                             \
 do {                                                                             \
   unsigned const char *_sfh_key=(unsigned const char*)(key);                     \
   unsigned const char *_sfh_key=(unsigned const char*)(key);                     \
   uint32_t _sfh_tmp, _sfh_len = (uint32_t)keylen;                                \
   uint32_t _sfh_tmp, _sfh_len = (uint32_t)keylen;                                \
@@ -523,7 +572,6 @@ do {
     hashv += hashv >> 17;                                                        \
     hashv += hashv >> 17;                                                        \
     hashv ^= hashv << 25;                                                        \
     hashv ^= hashv << 25;                                                        \
     hashv += hashv >> 6;                                                         \
     hashv += hashv >> 6;                                                         \
-    bkt = hashv & (num_bkts-1U);                                                 \
 } while(0)
 } while(0)
 
 
 #ifdef HASH_USING_NO_STRICT_ALIASING
 #ifdef HASH_USING_NO_STRICT_ALIASING
@@ -568,7 +616,7 @@ do {                 \
   _h ^= _h >> 16;    \
   _h ^= _h >> 16;    \
 } while(0)
 } while(0)
 
 
-#define HASH_MUR(key,keylen,num_bkts,hashv,bkt)                        \
+#define HASH_MUR(key,keylen,hashv)                                     \
 do {                                                                   \
 do {                                                                   \
   const uint8_t *_mur_data = (const uint8_t*)(key);                    \
   const uint8_t *_mur_data = (const uint8_t*)(key);                    \
   const int _mur_nblocks = (int)(keylen) / 4;                          \
   const int _mur_nblocks = (int)(keylen) / 4;                          \
@@ -603,7 +651,6 @@ do {                                                                   \
   _mur_h1 ^= (uint32_t)(keylen);                                       \
   _mur_h1 ^= (uint32_t)(keylen);                                       \
   MUR_FMIX(_mur_h1);                                                   \
   MUR_FMIX(_mur_h1);                                                   \
   hashv = _mur_h1;                                                     \
   hashv = _mur_h1;                                                     \
-  bkt = hashv & (num_bkts-1U);                                         \
 } while(0)
 } while(0)
 #endif  /* HASH_USING_NO_STRICT_ALIASING */
 #endif  /* HASH_USING_NO_STRICT_ALIASING */