2
0
Эх сурвалжийг харах

Squashed commit of the following:

commit 9383adf370df9408a2244c53f6ba08b22e995895
Author: Thilo Schulz <[email protected]>
Date:   Tue Jun 28 00:45:11 2016 +0200

    Incorporate Arthur O'Dwyer's suggestions

commit 1494286e16f72b4fa61c4f8195235d038495b3bb
Merge: fa99052 6130b77
Author: Thilo Schulz <[email protected]>
Date:   Mon Jun 27 23:51:46 2016 +0200

    Merge branch 'master' of https://github.com/troydhanson/uthash

    Conflicts:
    	doc/userguide.txt
    	src/uthash.h

commit fa99052d768c0aee2dc2c069eefc507eec85f305
Author: Thilo Schulz <[email protected]>
Date:   Fri Jun 17 14:32:29 2016 +0200

    Better to have no separate target for generation of .gitignore. Check of .gitignore existence and generation of it is always done ad-hoc now.

commit 5cf17157c74fe8648ada71eb15ccd17e7beedf1e
Author: Thilo Schulz <[email protected]>
Date:   Tue Jun 14 22:39:51 2016 +0200

    Uh... just a typo fixed.

commit b0b67951b5460c3af6f366d39a67a5807bc031b5
Author: Thilo Schulz <[email protected]>
Date:   Tue Jun 14 22:28:52 2016 +0200

    Add .gitignore and autogenerate .gitignore in tests/ directory so as to prevent tests from clogging git output

commit e9ec721a19e3c3388b72839d5183166eb0e2aefe
Author: Thilo Schulz <[email protected]>
Date:   Tue Jun 14 22:28:23 2016 +0200

    Shut up a few unused function compiler warnings

commit 682a45a230ea9a40f6e7c808908f68a2bcc575cc
Author: Thilo Schulz <[email protected]>
Date:   Tue Jun 14 22:08:26 2016 +0200

    Update userguide with HASH_SADD*() macro family

commit 9809d8901db6a7be4308887e57ff630e992fc220
Author: Thilo Schulz <[email protected]>
Date:   Tue Jun 14 16:54:19 2016 +0200

    This way round is ANSI-C

commit 5eec55af912aaca665062c493dccf4e0468a3449
Author: Thilo Schulz <[email protected]>
Date:   Tue Jun 14 16:47:22 2016 +0200

    Make sure we conform to ANSI C in variable declaration

commit cdaa14cc6e3dd6e21cdf61736db37f868e7ce343
Author: Thilo Schulz <[email protected]>
Date:   Tue Jun 14 16:36:48 2016 +0200

    Add test case for SADD* macros

commit 24e3ee3373aa5422f8bc4f50b52bbae5f7e4e6b8
Author: Thilo Schulz <[email protected]>
Date:   Tue Jun 14 16:32:50 2016 +0200

    Introduce two separate macros for SADD/ADD as going over checking whether compare function pointer is NULL is cumbersome and prone to throw warnings. Also, this is faster.

commit ae67050122fd24575fd7bf47cb94253365966e1d
Author: Thilo Schulz <[email protected]>
Date:   Tue Jun 14 15:48:46 2016 +0200

    Use proper prototype for compare function

commit b18c6d1dcb98aee23c8935b1f6e29160b4db1a88
Author: Thilo Schulz <[email protected]>
Date:   Tue Jun 14 15:19:31 2016 +0200

    Need to move setting of table pointer as head pointer may change.
    There's no need to set it if the table is newly created, this happens in HASH_MAKE_TABLE() already.

commit d05dc94c5eefa6ea2532b622299b18021a61ccfe
Author: Thilo Schulz <[email protected]>
Date:   Mon Jun 13 19:54:44 2016 +0200

    Remove accidental semicolon

commit 851c803db87b457c3230cb5ec1d985e43a87415b
Author: Thilo Schulz <[email protected]>
Date:   Mon Jun 13 19:45:57 2016 +0200

    - Add HASH_SADD* macro family so new hash table entries can be added to the linked list in an ordered fashion
    - Enclose macro parameters in parenthesis in HASH_REPLACE()
Troy D. Hanson 9 жил өмнө
parent
commit
650214c076
11 өөрчлөгдсөн 557 нэмэгдсэн , 295 устгасан
  1. 3 0
      .gitignore
  2. 220 195
      doc/userguide.html
  3. 50 19
      doc/userguide.txt
  4. 96 56
      src/uthash.h
  5. 8 2
      tests/Makefile
  6. 1 0
      tests/README
  7. 0 5
      tests/test32.c
  8. 0 5
      tests/test34.c
  9. 0 13
      tests/test65.c
  10. 104 0
      tests/test87.ans
  11. 75 0
      tests/test87.c

+ 3 - 0
.gitignore

@@ -0,0 +1,3 @@
+*~
+*.out
+keystat.*

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 220 - 195
doc/userguide.html


+ 50 - 19
doc/userguide.txt

@@ -1141,6 +1141,33 @@ always used with the `users_by_name` hash table).
 ----------------------------------------------------------------------
 
 
+Sorted insertion of new items
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+If you would like to maintain a sorted hash you have two options. The first
+option is to use the HASH_SRT() macro, which will sort any unordered list in
+'O(n log(n))'. This is the best strategy if you're just filling up a hash
+table with items in random order with a single final HASH_SRT() operation
+when all is done. Obviously, this won't do what you want if you need
+the list to be in an ordered state at times between insertion of
+items. You can use HASH_SRT() after every insertion operation, but that will
+yield a computational complexity of 'O(n^2 log(n)'.
+
+The second route you can take is via the sorted add macros.
+The HASH_SADD*() macros work just like their HASH_ADD*() counterparts, but
+with an additional compare function argument:
+
+  int name_sort(struct my_struct *a, struct my_struct *b) {
+    return strcmp(a->name,b->name);
+  }
+
+  HASH_SADD_KEYPTR(hh, items, &item->name, strlen(item->name), item, name_sort);
+
+New items are sorted at insertion time in 'O(n)', thus resulting in a
+total computational complexity of 'O(n^2)' for the creation of the hash
+table with all items.
+For sorted add to work, the list must be in an ordered state before
+insertion of the new item.
+
 Several sort orders
 ~~~~~~~~~~~~~~~~~~~
 It comes as no surprise that two hash tables can have different sort orders, but
@@ -1500,7 +1527,7 @@ ineffective at reducing the chain lengths.
 Imagine a very bad hash function which always puts every item in bucket 0. No
 matter how many times the number of buckets is doubled, the chain length of
 bucket 0 stays the same. In a situation like this, the best behavior is to 
-stop expanding, and accept O(n) lookup performance. This is what uthash
+stop expanding, and accept 'O(n)' lookup performance. This is what uthash
 does. It degrades gracefully if the hash function is ill-suited to the keys.
 
 If two consecutive bucket expansions yield `ideal%` values below 50%, uthash
@@ -1712,23 +1739,27 @@ 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_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)
+|macro                    | arguments
+|HASH_ADD                 | (hh_name, head, keyfield_name, key_len, item_ptr)
+|HASH_ADD_BY_HVAL         | (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_HVAL  | (hh_name, head, key_ptr, key_len, key_hash, item_ptr)
+|HASH_SADD                | (hh_name, head, keyfield_name, key_len, item_ptr, cmp)
+|HASH_SADD_BY_HVAL        | (hh_name, head, keyfield_name, key_len, key_hash, item_ptr, cmp)
+|HASH_SADD_KEYPTR         | (hh_name, head, key_ptr, key_len, item_ptr, cmp)
+|HASH_SADD_KEYPTR_BY_HVAL | (hh_name, head, key_ptr, key_len, key_hash, item_ptr, cmp)
+|HASH_REPLACE             | (hh_name, head, keyfield_name, key_len, item_ptr, replaced_item_ptr)
+|HASH_REPLACE_BY_HVAL     | (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_HVAL        | (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]
@@ -1759,7 +1790,7 @@ key_ptr::
     `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`.
+    `..._BY_HVAL` 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::

+ 96 - 56
src/uthash.h

@@ -102,6 +102,8 @@ 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)))
+/* calculate the hash handle from element address elp */
+#define HH_FROM_ELMT(tbl,elp) ((UT_hash_handle *)(((char*)(elp)) + ((tbl)->hho)))
 
 #define HASH_VALUE(keyptr,keylen,hashv)                                          \
 do {                                                                             \
@@ -122,7 +124,7 @@ do {
   }                                                                              \
 } while (0)
 
-#define HASH_FIND_BY_HASH_VALUE(hh,head,keyptr,keylen,_hf_hashv,out)             \
+#define HASH_FIND_BY_HVAL(hh,head,keyptr,keylen,_hf_hashv,out)                   \
 do {                                                                             \
   out=NULL;                                                                      \
   if (head != NULL) {                                                            \
@@ -188,79 +190,117 @@ do {
   (head)->hh.tbl->signature = HASH_SIGNATURE;                                    \
 } while(0)
 
-#define HASH_ADD(hh,head,fieldname,keylen_in,add)                                \
-        HASH_ADD_KEYPTR(hh,head,&((add)->fieldname),keylen_in,add)
+#define HASH_SADD(hh,head,fieldname,keylen_in,add,cmpfcn)                        \
+    HASH_SADD_KEYPTR(hh,(head),&((add)->fieldname),(keylen_in),(add),cmpfcn)
+
+#define HASH_SADD_BY_HVAL(hh,head,fieldname,keylen_in,hashval,add,cmpfcn)        \
+    HASH_SADD_KEYPTR_BY_HVAL(hh,(head),&((add)->fieldname),                      \
+                             (keylen_in),(add),cmpfcn)
 
-#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_ADD_BY_HVAL(hh,head,fieldname,keylen_in,hashval,add)                \
+        HASH_ADD_KEYPTR_BY_HVAL(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);\
+  HASH_VALUE(&((add)->fieldname), (keylen_in), _hr_hashv);                       \
+  HASH_REPLACE_BY_HVAL(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) \
+#define HASH_REPLACE_BY_HVAL(hh,head,fieldname,keylen_in,hashval,add,replaced)   \
 do {                                                                             \
   replaced=NULL;                                                                 \
-  HASH_FIND_BY_HASH_VALUE(hh,head,&((add)->fieldname),keylen_in,hashval,replaced); \
-  if (replaced!=NULL) {                                                          \
-     HASH_DELETE(hh,head,replaced);                                              \
+  HASH_FIND_BY_HVAL(hh,(head),&((add)->fieldname),                               \
+                          (keylen_in),(hashval),(replaced));                     \
+  if ((replaced)!=NULL) {                                                        \
+     HASH_DELETE(hh,(head),(replaced));                                          \
   }                                                                              \
-  HASH_ADD_BY_HASH_VALUE(hh,head,fieldname,keylen_in,hashval,add);               \
+  HASH_ADD_BY_HVAL(hh,(head),fieldname,(keylen_in),(hashval),(add));             \
 } while(0)
 
-#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add)                            \
+#define HASH_APPEND_LIST(hh, head, 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;                                                 \
- 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);                                                             \
+  (add)->hh.next = NULL;                                                         \
+  (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail);           \
+  (head)->hh.tbl->tail->next = (add);                                            \
+  (head)->hh.tbl->tail = &((add)->hh);                                           \
 } 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;                                                      \
+
+#define HASH_ADD_PROLOGUE(hh,head,keyptr,keylen_in,add)                          \
+  add->hh.key = (char*) keyptr;                                                  \
+  add->hh.keylen = (unsigned) keylen_in;                                         \
+  if (!head) {                                                                   \
+    add->hh.next = NULL;                                                         \
+    add->hh.prev = NULL;                                                         \
+    head = add;                                                                  \
     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);                                                             \
+  } else {
+
+#define HASH_ADD_EPILOGUE(hh,head,keyptr,keylen_in,hashval,add)                  \
+    HASH_APPEND_LIST(hh, head, add);                                             \
+  }                                                                              \
+  head->hh.tbl->num_items++;                                                     \
+  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,add->hh.hashv);                                    \
+  HASH_EMIT_KEY(hh,head,keyptr,keylen_in);                                       \
+  HASH_FSCK(hh,head);                                                            \
 } while(0)
 
+#define HASH_GHV_DIRECT(hh, add, hashval)                                        \
+  (add)->hh.hashv = (hashval)
+#define HASH_GHV_COMPUTE(hh, keyptr, keylen_in, add)                             \
+  HASH_FCN((keyptr), (keylen_in), (add)->hh.hashv)
+
+#define HASH_ADD_SORTED(hh,head,keyptr,keylen_in,hashval,add,cmpfcn)             \
+    HASH_ADD_PROLOGUE(hh,(head),(keyptr),(keylen_in),(add))                      \
+    struct UT_hash_handle *iter = &(head)->hh;                                   \
+    (add)->hh.tbl = (head)->hh.tbl;                                              \
+    do {                                                                         \
+      if(cmpfcn(DECLTYPE(head) ELMT_FROM_HH((head)->hh.tbl, iter), add) > 0)     \
+        break;                                                                   \
+    } while((iter = iter->next));                                                \
+    if(iter) {                                                                   \
+      (add)->hh.next = iter;                                                     \
+      if(((add)->hh.prev = iter->prev))                                          \
+        HH_FROM_ELMT((head)->hh.tbl, iter->prev)->next = add;                    \
+      else                                                                       \
+        (head) = (add);                                                          \
+      iter->prev = add;                                                          \
+    }                                                                            \
+    else                                                                         \
+      HASH_ADD_EPILOGUE(hh,(head),(keyptr),(keylen_in),(hashval),(add))
+
+#define HASH_SADD_KEYPTR_BY_HVAL(hh,head,keyptr,keylen_in,hashval,add,cmpfcn)    \
+do { unsigned _ha_bkt;                                                           \
+    HASH_GHV_DIRECT(hh, add, hashval);                                           \
+    HASH_ADD_SORTED(hh,head,keyptr,keylen_in,hashval,add,cmpfcn)                 \
+
+#define HASH_SADD_KEYPTR(hh,head,keyptr,keylen_in,add,cmpfcn)                    \
+do { unsigned _ha_bkt;                                                           \
+    HASH_GHV_COMPUTE(hh, keyptr, keylen_in, add);                                \
+    HASH_ADD_SORTED(hh,head,keyptr,keylen_in,(add)->hh.hashv,add,cmpfcn)
+
+#define HASH_ADD(hh,head,fieldname,keylen_in,add)                                \
+    HASH_ADD_KEYPTR(hh,(head),&((add)->fieldname),(keylen_in),(add))
+
+#define HASH_ADD_KEYPTR_BY_HVAL(hh,head,keyptr,keylen_in,hashval,add)            \
+do { unsigned _ha_bkt;                                                           \
+    HASH_GHV_DIRECT(hh, add, hashval);                                           \
+    HASH_ADD_PROLOGUE(hh,(head),(keyptr),(keylen_in),(add))                      \
+    (add)->hh.tbl = (head)->hh.tbl;                                              \
+    HASH_ADD_EPILOGUE(hh,(head),(keyptr),(keylen_in),hashval,(add))
+
+#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add)                            \
+do { unsigned _ha_bkt;                                                           \
+    HASH_GHV_COMPUTE(hh, keyptr, keylen_in, add);                                \
+    HASH_ADD_PROLOGUE(hh,(head),(keyptr),(keylen_in),(add))                      \
+    (add)->hh.tbl = (head)->hh.tbl;                                              \
+    HASH_ADD_EPILOGUE(hh,(head),(keyptr),(keylen_in),(add)->hh.hashv,(add))
+
 #define HASH_TO_BKT( hashv, num_bkts, bkt )                                      \
 do {                                                                             \
   bkt = ((hashv) & ((num_bkts) - 1U));                                           \

+ 8 - 2
tests/Makefile

@@ -13,7 +13,7 @@ PROGS = test1 test2 test3 test4 test5 test6 test7 test8 test9   \
         test58 test59 test60 test61 test62 test63 test64 test65 \
         test66 test67 test68 test69 test70 test71 test72 test73 \
         test74 test75 test76 test77 test78 test79 test80 test81 \
-        test82 test83 test84 test85 test86
+        test82 test83 test84 test85 test86 test87
 CFLAGS += -I$(HASHDIR)
 #CFLAGS += -DHASH_BLOOM=16
 #CFLAGS += -O2
@@ -71,6 +71,9 @@ all: $(PROGS) $(UTILS) $(PLAT_UTILS) $(FUNCS) $(SPECIAL_FUNCS) $(TEST_TARGET)
 
 tests_only: $(PROGS) $(TEST_TARGET)
 
+GITIGN = .gitignore
+MKGITIGN = [ -f "$(GITIGN)" ] || echo "$(GITIGN)" > $(GITIGN); grep -q '^\$@$$' $(GITIGN) || echo "$@" >> $(GITIGN)
+
 debug:
 	$(MAKE) all HASH_DEBUG=1
 
@@ -85,12 +88,15 @@ example: example.c $(HASHDIR)/uthash.h
 
 $(PROGS) $(UTILS) : $(HASHDIR)/uthash.h
 	$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $(@).c
+	@$(MKGITIGN)
 
 hashscan : $(HASHDIR)/uthash.h
 	$(CC) $(CPPFLAGS) $(CFLAGS) $(MUR_CFLAGS) $(LDFLAGS) -o $@ $(@).c
+	@$(MKGITIGN)
 
 sleep_test : $(HASHDIR)/uthash.h 
 	$(CC) $(CPPFLAGS) $(CFLAGS) -DHASH_BLOOM=16 $(LDFLAGS) -o $@ $(@).c
+	@$(MKGITIGN)
 
 $(FUNCS) : $(HASHDIR)/uthash.h
 	$(CC) $(CPPFLAGS) $(CFLAGS) -DHASH_FUNCTION=HASH_$@ \
@@ -112,5 +118,5 @@ astyle:
 .PHONY: clean astyle
 
 clean:	
-	rm -f $(UTILS) $(PLAT_UTILS) $(PROGS) test*.out keystat.??? example *.exe
+	rm -f $(UTILS) $(PLAT_UTILS) $(PROGS) test*.out keystat.??? example *.exe $(GITIGN)
 	rm -rf *.dSYM

+ 1 - 0
tests/README

@@ -88,6 +88,7 @@ test83: test HASH_REPLACE_STR with char[] key
 test84: test HASH_REPLACE_STR with char* key
 test85: test HASH_OVERHEAD on null and non null hash
 test86: test *_APPEND_ELEM / *_PREPEND_ELEM (Thilo Schulz)
+test87: test HASH_SADD*() macro family (Thilo Schulz)
 
 Other Make targets
 ================================================================================

+ 0 - 5
tests/test32.c

@@ -10,11 +10,6 @@ typedef struct el {
     struct el *next, *prev;
 } el;
 
-static int namecmp(el *a, el *b)
-{
-    return strcmp(a->bname,b->bname);
-}
-
 int main(int argc, char *argv[])
 {
     el *name, *tmp;

+ 0 - 5
tests/test34.c

@@ -10,11 +10,6 @@ typedef struct el {
     struct el *next, *prev;
 } el;
 
-static int namecmp(el *a, el *b)
-{
-    return strcmp(a->bname,b->bname);
-}
-
 int main(int argc, char *argv[])
 {
     el *name, *tmp;

+ 0 - 13
tests/test65.c

@@ -16,19 +16,6 @@ struct CacheEntry {
 };
 struct CacheEntry *cache = NULL;
 
-static char * /*value*/ find_in_cache(const char *key)
-{
-    struct CacheEntry *entry;
-    HASH_FIND_STR(cache, key, entry);
-    if (entry != NULL) {
-        // remove it (so the subsequent add will throw it on the front of the list)
-        HASH_DELETE(hh, cache, entry);
-        HASH_ADD_KEYPTR(hh, cache, entry->key, strlen(entry->key), entry);
-        return entry->value;
-    }
-    return NULL;
-}
-
 static void add_to_cache(const char *key, const char *value)
 {
     struct CacheEntry *entry, *tmp_entry;

+ 104 - 0
tests/test87.ans

@@ -0,0 +1,104 @@
+1: muh3
+2: muh1
+3: muh5
+5: muh6
+6: muh7
+6: muh9
+8: muh2
+8: muh4
+9: muh10
+10: muh11
+15: muh8
+43: muh12
+###
+1: muh3
+2: muh1
+3: muh5
+5: muh6
+6: muh7
+6: muh9
+8: muh2
+8: muh4
+9: muh10
+10: muh11
+15: muh8
+43: muh12
+###
+1: muh3
+2: muh1
+3: muh5
+5: muh6
+6: muh7
+6: muh9
+8: muh2
+8: muh4
+9: muh10
+10: muh11
+15: muh8
+###
+1: muh3
+3: muh5
+5: muh6
+6: muh7
+6: muh9
+8: muh2
+8: muh4
+9: muh10
+10: muh11
+15: muh8
+###
+1: muh3
+3: muh5
+5: muh6
+6: muh9
+8: muh2
+8: muh4
+9: muh10
+10: muh11
+15: muh8
+###
+3: muh5
+5: muh6
+6: muh9
+8: muh2
+8: muh4
+9: muh10
+10: muh11
+15: muh8
+###
+3: muh5
+5: muh6
+8: muh2
+8: muh4
+9: muh10
+10: muh11
+15: muh8
+###
+3: muh5
+5: muh6
+8: muh4
+9: muh10
+10: muh11
+15: muh8
+###
+3: muh5
+5: muh6
+8: muh4
+9: muh10
+15: muh8
+###
+3: muh5
+5: muh6
+9: muh10
+15: muh8
+###
+3: muh5
+9: muh10
+15: muh8
+###
+9: muh10
+15: muh8
+###
+9: muh10
+###
+###

+ 75 - 0
tests/test87.c

@@ -0,0 +1,75 @@
+#include <stdio.h>
+#include <uthash.h>
+
+typedef struct
+{
+  UT_hash_handle hh;
+
+  char name[32];
+  int weight;
+} hstruct_t;
+
+#define ARRAY_LEN(x) (sizeof(x) / sizeof(*(x)))
+hstruct_t tst[] = {{{}, "muh1", 2}, {{}, "muh2", 8}, {{}, "muh3", 1}, {{}, "muh4", 8}, {{}, "muh5", 3}, {{}, "muh6", 5},
+  {{}, "muh7", 6}, {{}, "muh8", 15}, {{}, "muh9", 6}, {{}, "muh10", 9}, {{}, "muh11", 10}, {{}, "muh12", 43}};
+hstruct_t *hTable;
+
+static int cmpfunc(hstruct_t *s1, hstruct_t *s2)
+{
+  if(s1->weight < s2->weight)
+    return -1;
+  else if(s1->weight > s2->weight)
+    return 1;
+  else
+    return 0;
+}
+
+void printtable(void)
+{
+  hstruct_t *search;
+
+  for(search = hTable; search; search = search->hh.next)
+  {
+    printf("%d: %s\n", search->weight, search->name);
+  }
+  
+  printf("###\n");
+}
+
+void delitem(const char *name)
+{
+  hstruct_t *item;
+  
+  HASH_FIND_STR(hTable, name, item);
+  HASH_DEL(hTable, item);
+  printtable();
+}
+
+int main()
+{
+  int index;
+
+  for(index = 0; index < ARRAY_LEN(tst); index++)
+  {
+    HASH_SADD(hh, hTable, name[0], strlen(tst[index].name), &tst[index], cmpfunc);
+  } 
+
+  printtable();
+  HASH_SORT(hTable, cmpfunc);
+  printtable();
+
+  delitem("muh12");
+  delitem("muh1");
+  delitem("muh7");
+  delitem("muh3");
+  delitem("muh9");
+  delitem("muh2");
+  delitem("muh11");
+  delitem("muh4");
+  delitem("muh6");
+  delitem("muh5");
+  delitem("muh8");
+  delitem("muh10");
+
+  return 0;
+}

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно