diff options
author | Toni Uhlig <matzeton@googlemail.com> | 2021-09-15 17:04:21 +0200 |
---|---|---|
committer | Toni Uhlig <matzeton@googlemail.com> | 2021-09-15 17:04:21 +0200 |
commit | 1fa53c5bf8d0717f784c79abaa5111f88ab00221 (patch) | |
tree | 5003411ee362757cb14882bd3d92c98ce8ce3dff | |
parent | c8bf38e5fb717d40635a2a89b22ed71b0de4266b (diff) |
Squashed 'dependencies/uthash/' changes from 8e67ced..bf15263
bf15263 Fix a "bug" in the example where option 3 interfered with option 1's counter.
b6e24ef Use `malloc(sizeof *s)` in example code.
a109c6b Stop using `gets` in example.c.
c85c9e1 fix: fix utstack example's compiling error
86e6776 Replace *.github.com urls with *.github.io (#227)
e493aa9 Bump version to 2.3.0.
ae2ac52 Fix README.md to display the *actual* TravisCI status.
134e241 Silence -Wswitch-default warnings, and add it to the TravisCI config.
62fefa6 Fix some typos in userguide.txt, and re-remove spaces in macro definitions.
37d2021 tests: add whitespaces to example code
524ca1a doc: add whitespaces to documentation
0f6c619 Fix a typo in the documentation for HASH_COUNT. NFC.
388134a Rename uthash_memcmp to HASH_KEYCMP, step 3.
053bed1 Eliminate HASH_FCN; change the handling of HASH_FUNCTION to match HASH_KEYCMP.
f0e1bd9 Refactor test93.c to avoid scan-build warnings.
45af88c Remove two dead writes in tests, to silence scan-build warnings.
66e2668 Bump version to 2.2.0.
973bd67 uthash.h: Swap multiplicands to put the widest ones first.
15ad042 Always include <stdint.h>, unless HASH_NO_STDINT is defined by the user.
6b4768b Rename uthash_memcmp to HASH_KEYCMP, step 2.
e64c7f0 Update tests/README to describe the most recently added tests. NFC.
c62796c HASH_CLEAR after some tests, to eliminate "memory leak" warnings.
7f0aadb Support spaces in $exe path
0831d9a uthash.h: fix compiler warning -Wcast-qual
ba2fbfd utarray.h: preserve constness in utarray_str_cpy
git-subtree-dir: dependencies/uthash
git-subtree-split: bf15263081be6229be31addd48566df93921cb46
-rw-r--r-- | .travis.yml | 2 | ||||
-rw-r--r-- | LICENSE | 2 | ||||
-rw-r--r-- | README.md | 4 | ||||
-rw-r--r-- | doc/ChangeLog.txt | 17 | ||||
-rw-r--r-- | doc/index.html | 8 | ||||
-rw-r--r-- | doc/license.html | 4 | ||||
-rw-r--r-- | doc/userguide.txt | 222 | ||||
-rw-r--r-- | doc/utarray.txt | 2 | ||||
-rw-r--r-- | doc/utlist.txt | 2 | ||||
-rw-r--r-- | doc/utringbuffer.txt | 2 | ||||
-rw-r--r-- | doc/utstack.txt | 2 | ||||
-rw-r--r-- | doc/utstring.txt | 2 | ||||
-rw-r--r-- | package.json | 2 | ||||
-rw-r--r-- | src/utarray.h | 9 | ||||
-rw-r--r-- | src/uthash.h | 64 | ||||
-rw-r--r-- | src/utlist.h | 4 | ||||
-rw-r--r-- | src/utringbuffer.h | 4 | ||||
-rw-r--r-- | src/utstack.h | 8 | ||||
-rw-r--r-- | src/utstring.h | 4 | ||||
-rw-r--r-- | tests/Makefile | 2 | ||||
-rw-r--r-- | tests/README | 9 | ||||
-rw-r--r-- | tests/example.c | 86 | ||||
-rw-r--r-- | tests/hashscan.c | 2 | ||||
-rwxr-xr-x | tests/keystats | 4 | ||||
-rw-r--r-- | tests/test10.c | 3 | ||||
-rw-r--r-- | tests/test6.c | 13 | ||||
-rw-r--r-- | tests/test65.c | 2 | ||||
-rw-r--r-- | tests/test76.c | 7 | ||||
-rw-r--r-- | tests/test77.c | 4 | ||||
-rw-r--r-- | tests/test88.ans | 20 | ||||
-rw-r--r-- | tests/test88.c | 8 | ||||
-rw-r--r-- | tests/test93.c | 37 | ||||
-rw-r--r-- | tests/test96.ans | 40 | ||||
-rw-r--r-- | tests/test96.c | 48 |
34 files changed, 377 insertions, 272 deletions
diff --git a/.travis.yml b/.travis.yml index 4e51ee2d9..62646943b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ matrix: compiler: clang - os: osx script: -- make -C tests EXTRA_CFLAGS="-W -Wall -Wextra" +- make -C tests EXTRA_CFLAGS="-W -Wall -Wextra -Wswitch-default" - make -C tests clean ; make -C tests pedantic - make -C tests clean ; make -C tests pedantic EXTRA_CFLAGS=-DNO_DECLTYPE - make -C tests clean ; make -C tests cplusplus @@ -1,4 +1,4 @@ -Copyright (c) 2005-2018, Troy D. Hanson http://troydhanson.github.com/uthash/ +Copyright (c) 2005-2021, Troy D. Hanson http://troydhanson.github.io/uthash/ All rights reserved. Redistribution and use in source and binary forms, with or without @@ -1,8 +1,8 @@ -[](https://travis-ci.org/troydhanson/uthash) +[](https://travis-ci.org/troydhanson/uthash) Documentation for uthash is available at: -http://troydhanson.github.com/uthash/ +https://troydhanson.github.io/uthash/ diff --git a/doc/ChangeLog.txt b/doc/ChangeLog.txt index 281de80fe..3fa955782 100644 --- a/doc/ChangeLog.txt +++ b/doc/ChangeLog.txt @@ -5,6 +5,21 @@ Click to return to the link:index.html[uthash home page]. NOTE: This ChangeLog may be incomplete and/or incorrect. See the git commit log. +Version 2.3.0 (2021-02-25) +-------------------------- +* remove HASH_FCN; the HASH_FUNCTION and HASH_KEYCMP macros now behave similarly +* remove uthash_memcmp (deprecated in v2.1.0) in favor of HASH_KEYCMP +* silence -Wswitch-default warnings (thanks, Olaf Bergmann!) + +Version 2.2.0 (2020-12-17) +-------------------------- +* add HASH_NO_STDINT for platforms without C99 <stdint.h> +* silence many -Wcast-qual warnings (thanks, Olaf Bergmann!) +* skip hash computation when finding in an empty hash (thanks, Huansong Fu!) +* rename oom to utarray_oom, in utarray.h (thanks, Hong Xu!) +* rename oom to utstring_oom, in utstring.h (thanks, Hong Xu!) +* remove MurmurHash/HASH_MUR + Version 2.1.0 (2018-12-20) -------------------------- * silence some Clang static analysis warnings @@ -56,7 +71,7 @@ Version 1.9.8 (2013-03-10) * `HASH_REPLACE` now in uthash (thanks, Nick Vatamaniuc!) * fixed clang warnings (thanks wynnw!) * fixed `utarray_insert` when inserting past array end (thanks Rob Willett!) -* you can now find http://troydhanson.github.com/uthash/[uthash on GitHub] +* you can now find http://troydhanson.github.io/uthash/[uthash on GitHub] * there's a https://groups.google.com/d/forum/uthash[uthash Google Group] * uthash has been downloaded 29,000+ times since 2006 on SourceForge diff --git a/doc/index.html b/doc/index.html index 11b120e22..2f86ba1dc 100644 --- a/doc/index.html +++ b/doc/index.html @@ -14,7 +14,7 @@ <div id="topnav"> <a href="http://github.com/troydhanson/uthash">GitHub page</a> > - uthash home <!-- http://troydhanson.github.com/uthash/ --> + uthash home <!-- http://troydhanson.github.io/uthash/ --> <a href="https://twitter.com/share" class="twitter-share-button" data-via="troydhanson">Tweet</a> <script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script> @@ -72,7 +72,7 @@ struct my_struct { struct my_struct *users = NULL; void add_user(struct my_struct *s) { - HASH_ADD_INT( users, id, s ); + HASH_ADD_INT(users, id, s); } </pre> @@ -86,7 +86,7 @@ Example 2. Looking up an item in a hash. struct my_struct *find_user(int user_id) { struct my_struct *s; - HASH_FIND_INT( users, &user_id, s ); + HASH_FIND_INT(users, &user_id, s); return s; } @@ -100,7 +100,7 @@ Example 3. Deleting an item from a hash. <pre> void delete_user(struct my_struct *user) { - HASH_DEL( users, user); + HASH_DEL(users, user); } </pre> diff --git a/doc/license.html b/doc/license.html index c70684558..9a4b9ef35 100644 --- a/doc/license.html +++ b/doc/license.html @@ -13,7 +13,7 @@ </div> <!-- banner --> <div id="topnav"> - <a href="http://troydhanson.github.com/uthash/">uthash home</a> > + <a href="http://troydhanson.github.io/uthash/">uthash home</a> > BSD license </div> @@ -21,7 +21,7 @@ <div id="mid"> <div id="main"> <pre> -Copyright (c) 2005-2018, Troy D. Hanson http://troydhanson.github.com/uthash/ +Copyright (c) 2005-2021, Troy D. Hanson http://troydhanson.github.io/uthash/ All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/doc/userguide.txt b/doc/userguide.txt index 4d8ce8f0a..39fa7d1ed 100644 --- a/doc/userguide.txt +++ b/doc/userguide.txt @@ -1,7 +1,7 @@ uthash User Guide ================= Troy D. Hanson, Arthur O'Dwyer -v2.1.0, December 2018 +v2.3.0, February 2021 To download uthash, follow this link back to the https://github.com/troydhanson/uthash[GitHub project page]. @@ -215,10 +215,10 @@ a unique value. Then call `HASH_ADD`. (Here we use the convenience macro void add_user(int user_id, char *name) { struct my_struct *s; - s = malloc(sizeof(struct my_struct)); + s = malloc(sizeof *s); s->id = user_id; strcpy(s->name, name); - HASH_ADD_INT( users, id, s ); /* id: name of key field */ + HASH_ADD_INT(users, id, s); /* id: name of key field */ } ---------------------------------------------------------------------- @@ -227,7 +227,7 @@ second parameter is the 'name' of the key field. Here, this is `id`. The last parameter is a pointer to the structure being added. [[validc]] -.Wait.. the field name is a parameter? +.Wait.. the parameter is a field name? ******************************************************************************* If you find it strange that `id`, which is the 'name of a field' in the structure, can be passed as a parameter... welcome to the world of macros. Don't @@ -256,10 +256,10 @@ Otherwise we just modify the structure that already exists. struct my_struct *s; HASH_FIND_INT(users, &user_id, s); /* id already in the hash? */ - if (s==NULL) { + if (s == NULL) { s = (struct my_struct *)malloc(sizeof *s); s->id = user_id; - HASH_ADD_INT( users, id, s ); /* id: name of key field */ + HASH_ADD_INT(users, id, s); /* id: name of key field */ } strcpy(s->name, name); } @@ -284,7 +284,7 @@ right. /* bad */ void add_user(struct my_struct *users, int user_id, char *name) { ... - HASH_ADD_INT( users, id, s ); + HASH_ADD_INT(users, id, s); } You really need to pass 'a pointer' to the hash pointer: @@ -292,7 +292,7 @@ You really need to pass 'a pointer' to the hash pointer: /* good */ void add_user(struct my_struct **users, int user_id, char *name) { ... ... - HASH_ADD_INT( *users, id, s ); + HASH_ADD_INT(*users, id, s); } Note that we dereferenced the pointer in the `HASH_ADD` also. @@ -319,7 +319,7 @@ To look up a structure in a hash, you need its key. Then call `HASH_FIND`. struct my_struct *find_user(int user_id) { struct my_struct *s; - HASH_FIND_INT( users, &user_id, s ); /* s: output pointer */ + HASH_FIND_INT(users, &user_id, s); /* s: output pointer */ return s; } ---------------------------------------------------------------------- @@ -376,8 +376,8 @@ void delete_all() { struct my_struct *current_user, *tmp; HASH_ITER(hh, users, current_user, tmp) { - HASH_DEL(users,current_user); /* delete; users advances to next */ - free(current_user); /* optional- if you want to free */ + HASH_DEL(users, current_user); /* delete; users advances to next */ + free(current_user); /* optional- if you want to free */ } } ---------------------------------------------------------------------- @@ -387,7 +387,7 @@ All-at-once deletion If you only want to delete all the items, but not free them or do any per-element clean up, you can do this more efficiently in a single operation: - HASH_CLEAR(hh,users); + HASH_CLEAR(hh, users); Afterward, the list head (here, `users`) will be set to `NULL`. @@ -403,7 +403,7 @@ num_users = HASH_COUNT(users); printf("there are %u users\n", num_users); ---------------------------------------------------------------------- -Incidentally, this works even the list (`users`, here) is `NULL`, in +Incidentally, this works even if the list head (here, `users`) is `NULL`, in which case the count is 0. Iterating and sorting @@ -417,7 +417,7 @@ following the `hh.next` pointer. void print_users() { struct my_struct *s; - for(s=users; s != NULL; s=s->hh.next) { + for (s = users; s != NULL; s = s->hh.next) { printf("user id %d: name %s\n", s->id, s->name); } } @@ -430,7 +430,7 @@ the hash, starting from any known item. Deletion-safe iteration ^^^^^^^^^^^^^^^^^^^^^^^ In the example above, it would not be safe to delete and free `s` in the body -of the 'for' loop, (because `s` is derefenced each time the loop iterates). +of the 'for' loop, (because `s` is dereferenced each time the loop iterates). This is easy to rewrite correctly (by copying the `s->hh.next` pointer to a temporary variable 'before' freeing `s`), but it comes up often enough that a deletion-safe iteration macro, `HASH_ITER`, is included. It expands to a @@ -452,14 +452,14 @@ doubly-linked list. ******************************************************************************* If you're using uthash in a C++ program, you need an extra cast on the `for` -iterator, e.g., `s=(struct my_struct*)s->hh.next`. +iterator, e.g., `s = static_cast<my_struct*>(s->hh.next)`. Sorting ^^^^^^^ The items in the hash are visited in "insertion order" when you follow the `hh.next` pointer. You can sort the items into a new order using `HASH_SORT`. - HASH_SORT( users, name_sort ); + HASH_SORT(users, name_sort); The second argument is a pointer to a comparison function. It must accept two pointer arguments (the items to compare), and must return an `int` which is @@ -479,20 +479,20 @@ Below, `name_sort` and `id_sort` are two examples of sort functions. .Sorting the items in the hash ---------------------------------------------------------------------- -int name_sort(struct my_struct *a, struct my_struct *b) { - return strcmp(a->name,b->name); +int by_name(const struct my_struct *a, const struct my_struct *b) { + return strcmp(a->name, b->name); } -int id_sort(struct my_struct *a, struct my_struct *b) { +int by_id(const struct my_struct *a, const struct my_struct *b) { return (a->id - b->id); } void sort_by_name() { - HASH_SORT(users, name_sort); + HASH_SORT(users, by_name); } void sort_by_id() { - HASH_SORT(users, id_sort); + HASH_SORT(users, by_id); } ---------------------------------------------------------------------- @@ -516,85 +516,100 @@ Follow the prompts to try the program. .A complete program ---------------------------------------------------------------------- -#include <stdio.h> /* gets */ +#include <stdio.h> /* printf */ #include <stdlib.h> /* atoi, malloc */ #include <string.h> /* strcpy */ #include "uthash.h" struct my_struct { int id; /* key */ - char name[10]; + char name[21]; UT_hash_handle hh; /* makes this structure hashable */ }; struct my_struct *users = NULL; -void add_user(int user_id, char *name) { +void add_user(int user_id, const char *name) +{ struct my_struct *s; HASH_FIND_INT(users, &user_id, s); /* id already in the hash? */ - if (s==NULL) { - s = (struct my_struct *)malloc(sizeof *s); - s->id = user_id; - HASH_ADD_INT( users, id, s ); /* id: name of key field */ + if (s == NULL) { + s = (struct my_struct*)malloc(sizeof *s); + s->id = user_id; + HASH_ADD_INT(users, id, s); /* id is the key field */ } strcpy(s->name, name); } -struct my_struct *find_user(int user_id) { +struct my_struct *find_user(int user_id) +{ struct my_struct *s; - HASH_FIND_INT( users, &user_id, s ); /* s: output pointer */ + HASH_FIND_INT(users, &user_id, s); /* s: output pointer */ return s; } -void delete_user(struct my_struct *user) { +void delete_user(struct my_struct *user) +{ HASH_DEL(users, user); /* user: pointer to deletee */ free(user); } -void delete_all() { - struct my_struct *current_user, *tmp; +void delete_all() +{ + struct my_struct *current_user; + struct my_struct *tmp; - HASH_ITER(hh, users, current_user, tmp) { - HASH_DEL(users, current_user); /* delete it (users advances to next) */ - free(current_user); /* free it */ - } + HASH_ITER(hh, users, current_user, tmp) { + HASH_DEL(users, current_user); /* delete it (users advances to next) */ + free(current_user); /* free it */ + } } -void print_users() { +void print_users() +{ struct my_struct *s; - for(s=users; s != NULL; s=(struct my_struct*)(s->hh.next)) { + for (s = users; s != NULL; s = (struct my_struct*)(s->hh.next)) { printf("user id %d: name %s\n", s->id, s->name); } } -int name_sort(struct my_struct *a, struct my_struct *b) { - return strcmp(a->name,b->name); +int by_name(const struct my_struct *a, const struct my_struct *b) +{ + return strcmp(a->name, b->name); } -int id_sort(struct my_struct *a, struct my_struct *b) { +int by_id(const struct my_struct *a, const struct my_struct *b) +{ return (a->id - b->id); } -void sort_by_name() { - HASH_SORT(users, name_sort); -} - -void sort_by_id() { - HASH_SORT(users, id_sort); +const char *getl(const char *prompt) +{ + static char buf[21]; + char *p; + printf("%s? ", prompt); fflush(stdout); + p = fgets(buf, sizeof(buf), stdin); + if (p == NULL || (p = strchr(buf, '\n')) == NULL) { + puts("Invalid input!"); + exit(EXIT_FAILURE); + } + *p = '\0'; + return buf; } -int main(int argc, char *argv[]) { - char in[10]; - int id=1, running=1; +int main() +{ + int id = 1; + int running = 1; struct my_struct *s; - unsigned num_users; + int temp; while (running) { printf(" 1. add user\n"); - printf(" 2. add/rename user by id\n"); + printf(" 2. add or rename user by id\n"); printf(" 3. find user\n"); printf(" 4. delete user\n"); printf(" 5. delete all users\n"); @@ -603,47 +618,44 @@ int main(int argc, char *argv[]) { printf(" 8. print users\n"); printf(" 9. count users\n"); printf("10. quit\n"); - gets(in); - switch(atoi(in)) { + switch (atoi(getl("Command"))) { case 1: - printf("name?\n"); - add_user(id++, gets(in)); + add_user(id++, getl("Name (20 char max)")); break; case 2: - printf("id?\n"); - gets(in); id = atoi(in); - printf("name?\n"); - add_user(id, gets(in)); + temp = atoi(getl("ID")); + add_user(temp, getl("Name (20 char max)")); break; case 3: - printf("id?\n"); - s = find_user(atoi(gets(in))); + s = find_user(atoi(getl("ID to find"))); printf("user: %s\n", s ? s->name : "unknown"); break; case 4: - printf("id?\n"); - s = find_user(atoi(gets(in))); - if (s) delete_user(s); - else printf("id unknown\n"); + s = find_user(atoi(getl("ID to delete"))); + if (s) { + delete_user(s); + } else { + printf("id unknown\n"); + } break; case 5: delete_all(); break; case 6: - sort_by_name(); + HASH_SORT(users, by_name); break; case 7: - sort_by_id(); + HASH_SORT(users, by_id); break; case 8: print_users(); break; case 9: - num_users=HASH_COUNT(users); - printf("there are %u users\n", num_users); + temp = HASH_COUNT(users); + printf("there are %d users\n", temp); break; case 10: - running=0; + running = 0; break; } } @@ -720,10 +732,10 @@ int main(int argc, char *argv[]) { s = (struct my_struct *)malloc(sizeof *s); strcpy(s->name, names[i]); s->id = i; - HASH_ADD_STR( users, name, s ); + HASH_ADD_STR(users, name, s); } - HASH_FIND_STR( users, "betty", s); + HASH_FIND_STR(users, "betty", s); if (s) printf("betty's id is %d\n", s->id); /* free the hash table contents */ @@ -766,10 +778,10 @@ int main(int argc, char *argv[]) { s = (struct my_struct *)malloc(sizeof *s); s->name = names[i]; s->id = i; - HASH_ADD_KEYPTR( hh, users, s->name, strlen(s->name), s ); + HASH_ADD_KEYPTR(hh, users, s->name, strlen(s->name), s); } - HASH_FIND_STR( users, "betty", s); + HASH_FIND_STR(users, "betty", s); if (s) printf("betty's id is %d\n", s->id); /* free the hash table contents */ @@ -812,12 +824,12 @@ int main() { if (!e) return -1; e->key = (void*)someaddr; e->i = 1; - HASH_ADD_PTR(hash,key,e); + HASH_ADD_PTR(hash, key, e); HASH_FIND_PTR(hash, &someaddr, d); if (d) printf("found\n"); /* release memory */ - HASH_DEL(hash,e); + HASH_DEL(hash, e); free(e); return 0; } @@ -924,7 +936,7 @@ int main(int argc, char *argv[]) { int beijing[] = {0x5317, 0x4eac}; /* UTF-32LE for 北京 */ /* allocate and initialize our structure */ - msg = (msg_t *)malloc( sizeof(msg_t) + sizeof(beijing) ); + msg = (msg_t *)malloc(sizeof(msg_t) + sizeof(beijing)); memset(msg, 0, sizeof(msg_t)+sizeof(beijing)); /* zero fill */ msg->len = sizeof(beijing); msg->encoding = UTF32; @@ -936,16 +948,16 @@ int main(int argc, char *argv[]) { - offsetof(msg_t, encoding); /* offset of first key field */ /* add our structure to the hash table */ - HASH_ADD( hh, msgs, encoding, keylen, msg); + HASH_ADD(hh, msgs, encoding, keylen, msg); /* look it up to prove that it worked :-) */ - msg=NULL; + msg = NULL; lookup_key = (lookup_key_t *)malloc(sizeof(*lookup_key) + sizeof(beijing)); memset(lookup_key, 0, sizeof(*lookup_key) + sizeof(beijing)); lookup_key->encoding = UTF32; memcpy(lookup_key->text, beijing, sizeof(beijing)); - HASH_FIND( hh, msgs, &lookup_key->encoding, keylen, msg ); + HASH_FIND(hh, msgs, &lookup_key->encoding, keylen, msg); if (msg) printf("found \n"); free(lookup_key); @@ -1028,7 +1040,7 @@ typedef struct item { UT_hash_handle hh; } item_t; -item_t *items=NULL; +item_t *items = NULL; int main(int argc, char *argvp[]) { item_t *item1, *item2, *tmp1, *tmp2; @@ -1119,7 +1131,7 @@ always used with the `users_by_name` hash table). int i; char *name; - s = malloc(sizeof(struct my_struct)); + s = malloc(sizeof *s); s->id = 1; strcpy(s->username, "thanson"); @@ -1128,7 +1140,7 @@ always used with the `users_by_name` hash table). HASH_ADD(hh2, users_by_name, username, strlen(s->username), s); /* find user by ID in the "users_by_id" hash table */ - i=1; + i = 1; HASH_FIND(hh1, users_by_id, &i, sizeof(int), s); if (s) printf("found id %d: %s\n", i, s->username); @@ -1155,7 +1167,7 @@ The `HASH_ADD_INORDER*` macros work just like their `HASH_ADD*` counterparts, bu with an additional comparison-function argument: int name_sort(struct my_struct *a, struct my_struct *b) { - return strcmp(a->name,b->name); + return strcmp(a->name, b->name); } HASH_ADD_KEYPTR_INORDER(hh, items, &item->name, strlen(item->name), item, name_sort); @@ -1183,7 +1195,7 @@ Now we can define two sort functions, then use `HASH_SRT`. } int sort_by_name(struct my_struct *a, struct my_struct *b) { - return strcmp(a->username,b->username); + return strcmp(a->username, b->username); } HASH_SRT(hh1, users_by_id, sort_by_id); @@ -1240,7 +1252,8 @@ for a structure to be usable with `HASH_SELECT`, it must have two or more hash handles. (As described <<multihash,here>>, a structure can exist in many hash tables at the same time; it must have a separate hash handle for each one). - user_t *users=NULL, *admins=NULL; /* two hash tables */ + user_t *users = NULL; /* hash table of users */ + user_t *admins = NULL; /* hash table of admins */ typedef struct { int id; @@ -1252,25 +1265,26 @@ Now suppose we have added some users, and want to select just the administrator users who have id's less than 1024. #define is_admin(x) (((user_t*)x)->id < 1024) - HASH_SELECT(ah,admins,hh,users,is_admin); + HASH_SELECT(ah, admins, hh, users, is_admin); The first two parameters are the 'destination' hash handle and hash table, the second two parameters are the 'source' hash handle and hash table, and the last -parameter is the 'select condition'. Here we used a macro `is_admin()` but we +parameter is the 'select condition'. Here we used a macro `is_admin(x)` but we could just as well have used a function. - int is_admin(void *userv) { - user_t *user = (user_t*)userv; + int is_admin(const void *userv) { + user_t *user = (const user_t*)userv; return (user->id < 1024) ? 1 : 0; } If the select condition always evaluates to true, this operation is -essentially a 'merge' of the source hash into the destination hash. Of course, -the source hash remains unchanged under any use of `HASH_SELECT`. It only adds -items to the destination hash selectively. +essentially a 'merge' of the source hash into the destination hash. + +`HASH_SELECT` adds items to the destination without removing them from +the source; the source hash table remains unchanged. The destination hash table +must not be the same as the source hash table. -The two hash handles must differ. An example of using `HASH_SELECT` is included -in `tests/test36.c`. +An example of using `HASH_SELECT` is included in `tests/test36.c`. [[hash_keycompare]] Specifying an alternate key comparison function @@ -1290,7 +1304,7 @@ that do not provide `memcmp`, you can substitute your own implementation. ---------------------------------------------------------------------------- #undef HASH_KEYCMP -#define HASH_KEYCMP(a,b,len) bcmp(a,b,len) +#define HASH_KEYCMP(a,b,len) bcmp(a, b, len) ---------------------------------------------------------------------------- Another reason to substitute your own key comparison function is if your "key" is not @@ -1631,7 +1645,7 @@ If your application uses its own custom allocator, uthash can use them too. /* re-define, specifying alternate functions */ #define uthash_malloc(sz) my_malloc(sz) -#define uthash_free(ptr,sz) my_free(ptr) +#define uthash_free(ptr, sz) my_free(ptr) ... ---------------------------------------------------------------------------- @@ -1647,7 +1661,7 @@ provide these functions, you can substitute your own implementations. ---------------------------------------------------------------------------- #undef uthash_bzero -#define uthash_bzero(a,len) my_bzero(a,len) +#define uthash_bzero(a, len) my_bzero(a, len) #undef uthash_strlen #define uthash_strlen(s) my_strlen(s) @@ -1754,7 +1768,7 @@ concurrent readers (since uthash 1.5). For example using pthreads you can create an rwlock like this: pthread_rwlock_t lock; - if (pthread_rwlock_init(&lock,NULL) != 0) fatal("can't create rwlock"); + if (pthread_rwlock_init(&lock, NULL) != 0) fatal("can't create rwlock"); Then, readers must acquire the read lock before doing any `HASH_FIND` calls or before iterating over the hash elements: @@ -1795,10 +1809,10 @@ In order to use the convenience macros, |=============================================================================== |macro | arguments |HASH_ADD_INT | (head, keyfield_name, item_ptr) -|HASH_REPLACE_INT | (head, keyfiled_name, item_ptr,replaced_item_ptr) +|HASH_REPLACE_INT | (head, keyfield_name, item_ptr, replaced_item_ptr) |HASH_FIND_INT | (head, key_ptr, item_ptr) |HASH_ADD_STR | (head, keyfield_name, item_ptr) -|HASH_REPLACE_STR | (head,keyfield_name, item_ptr, replaced_item_ptr) +|HASH_REPLACE_STR | (head, keyfield_name, item_ptr, replaced_item_ptr) |HASH_FIND_STR | (head, key_ptr, item_ptr) |HASH_ADD_PTR | (head, keyfield_name, item_ptr) |HASH_REPLACE_PTR | (head, keyfield_name, item_ptr, replaced_item_ptr) diff --git a/doc/utarray.txt b/doc/utarray.txt index 25d94e260..8ef940b53 100644 --- a/doc/utarray.txt +++ b/doc/utarray.txt @@ -1,7 +1,7 @@ utarray: dynamic array macros for C =================================== Troy D. Hanson <tdh@tkhanson.net> -v2.1.0, December 2018 +v2.3.0, February 2021 Here's a link back to the https://github.com/troydhanson/uthash[GitHub project page]. diff --git a/doc/utlist.txt b/doc/utlist.txt index 06b6b00dc..47dc625ef 100644 --- a/doc/utlist.txt +++ b/doc/utlist.txt @@ -1,7 +1,7 @@ utlist: linked list macros for C structures =========================================== Troy D. Hanson <tdh@tkhanson.net> -v2.1.0, December 2018 +v2.3.0, February 2021 Here's a link back to the https://github.com/troydhanson/uthash[GitHub project page]. diff --git a/doc/utringbuffer.txt b/doc/utringbuffer.txt index 86206c1e5..02eb6cf5f 100644 --- a/doc/utringbuffer.txt +++ b/doc/utringbuffer.txt @@ -1,7 +1,7 @@ utringbuffer: dynamic ring-buffer macros for C ============================================== Arthur O'Dwyer <arthur.j.odwyer@gmail.com> -v2.1.0, December 2018 +v2.3.0, February 2021 Here's a link back to the https://github.com/troydhanson/uthash[GitHub project page]. diff --git a/doc/utstack.txt b/doc/utstack.txt index 0c628c06d..bcfc3bffb 100644 --- a/doc/utstack.txt +++ b/doc/utstack.txt @@ -1,7 +1,7 @@ utstack: intrusive stack macros for C ===================================== Arthur O'Dwyer <arthur.j.odwyer@gmail.com> -v2.1.0, December 2018 +v2.3.0, February 2021 Here's a link back to the https://github.com/troydhanson/uthash[GitHub project page]. diff --git a/doc/utstring.txt b/doc/utstring.txt index 56e2f4c00..30678591c 100644 --- a/doc/utstring.txt +++ b/doc/utstring.txt @@ -1,7 +1,7 @@ utstring: dynamic string macros for C ===================================== Troy D. Hanson <tdh@tkhanson.net> -v2.1.0, December 2018 +v2.3.0, February 2021 Here's a link back to the https://github.com/troydhanson/uthash[GitHub project page]. diff --git a/package.json b/package.json index 28377541f..b5a2f241e 100644 --- a/package.json +++ b/package.json @@ -24,5 +24,5 @@ "src/utstring.h" ], - "version": "2.1.0" + "version": "2.3.0" } diff --git a/src/utarray.h b/src/utarray.h index 6b6201820..3a5106666 100644 --- a/src/utarray.h +++ b/src/utarray.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2008-2018, Troy D. Hanson http://troydhanson.github.com/uthash/ +Copyright (c) 2008-2021, Troy D. Hanson http://troydhanson.github.io/uthash/ All rights reserved. Redistribution and use in source and binary forms, with or without @@ -26,7 +26,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef UTARRAY_H #define UTARRAY_H -#define UTARRAY_VERSION 2.1.0 +#define UTARRAY_VERSION 2.3.0 #include <stddef.h> /* size_t */ #include <string.h> /* memset, etc */ @@ -232,8 +232,9 @@ typedef struct { /* last we pre-define a few icd for common utarrays of ints and strings */ static void utarray_str_cpy(void *dst, const void *src) { - char **_src = (char**)src, **_dst = (char**)dst; - *_dst = (*_src == NULL) ? NULL : strdup(*_src); + char *const *srcc = (char *const *)src; + char **dstc = (char**)dst; + *dstc = (*srcc == NULL) ? NULL : strdup(*srcc); } static void utarray_str_dtor(void *elt) { char **eltc = (char**)elt; diff --git a/src/uthash.h b/src/uthash.h index 5e5866a35..9a396b617 100644 --- a/src/uthash.h +++ b/src/uthash.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2018, Troy D. Hanson http://troydhanson.github.com/uthash/ +Copyright (c) 2003-2021, Troy D. Hanson http://troydhanson.github.io/uthash/ All rights reserved. Redistribution and use in source and binary forms, with or without @@ -24,12 +24,22 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef UTHASH_H #define UTHASH_H -#define UTHASH_VERSION 2.1.0 +#define UTHASH_VERSION 2.3.0 #include <string.h> /* memcmp, memset, strlen */ #include <stddef.h> /* ptrdiff_t */ #include <stdlib.h> /* exit */ +#if defined(HASH_DEFINE_OWN_STDINT) && HASH_DEFINE_OWN_STDINT +/* This codepath is provided for backward compatibility, but I plan to remove it. */ +#warning "HASH_DEFINE_OWN_STDINT is deprecated; please use HASH_NO_STDINT instead" +typedef unsigned int uint32_t; +typedef unsigned char uint8_t; +#elif defined(HASH_NO_STDINT) && HASH_NO_STDINT +#else +#include <stdint.h> /* uint8_t, uint32_t */ +#endif + /* These macros use decltype or the earlier __typeof GNU extension. As decltype is only available in newer compilers (VS2010 or gcc 4.3+ when compiling c++ source) this code uses whatever method is needed @@ -62,23 +72,6 @@ do { } while (0) #endif -/* a number of the hash function use uint32_t which isn't defined on Pre VS2010 */ -#if defined(_WIN32) -#if defined(_MSC_VER) && _MSC_VER >= 1600 -#include <stdint.h> -#elif defined(__WATCOMC__) || defined(__MINGW32__) || defined(__CYGWIN__) -#include <stdint.h> -#else -typedef unsigned int uint32_t; -typedef unsigned char uint8_t; -#endif -#elif defined(__GNUC__) && !defined(__VXWORKS__) -#include <stdint.h> -#else -typedef unsigned int uint32_t; -typedef unsigned char uint8_t; -#endif - #ifndef uthash_malloc #define uthash_malloc(sz) malloc(sz) /* malloc fcn */ #endif @@ -92,15 +85,12 @@ typedef unsigned char uint8_t; #define uthash_strlen(s) strlen(s) #endif -#ifdef uthash_memcmp -/* This warning will not catch programs that define uthash_memcmp AFTER including uthash.h. */ -#warning "uthash_memcmp is deprecated; please use HASH_KEYCMP instead" -#else -#define uthash_memcmp(a,b,n) memcmp(a,b,n) +#ifndef HASH_FUNCTION +#define HASH_FUNCTION(keyptr,keylen,hashv) HASH_JEN(keyptr, keylen, hashv) #endif #ifndef HASH_KEYCMP -#define HASH_KEYCMP(a,b,n) uthash_memcmp(a,b,n) +#define HASH_KEYCMP(a,b,n) memcmp(a,b,n) #endif #ifndef uthash_noexpand_fyi @@ -158,7 +148,7 @@ do { #define HASH_VALUE(keyptr,keylen,hashv) \ do { \ - HASH_FCN(keyptr, keylen, hashv); \ + HASH_FUNCTION(keyptr, keylen, hashv); \ } while (0) #define HASH_FIND_BYHASHVALUE(hh,head,keyptr,keylen,hashval,out) \ @@ -408,7 +398,7 @@ do { do { \ IF_HASH_NONFATAL_OOM( int _ha_oomed = 0; ) \ (add)->hh.hashv = (hashval); \ - (add)->hh.key = (char*) (keyptr); \ + (add)->hh.key = (const void*) (keyptr); \ (add)->hh.keylen = (unsigned) (keylen_in); \ if (!(head)) { \ (add)->hh.next = NULL; \ @@ -590,13 +580,6 @@ do { #define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) #endif -/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */ -#ifdef HASH_FUNCTION -#define HASH_FCN HASH_FUNCTION -#else -#define HASH_FCN HASH_JEN -#endif - /* The Bernstein hash function, used in Perl prior to v5.6. Note (x<<5+x)=x*33. */ #define HASH_BER(key,keylen,hashv) \ do { \ @@ -695,7 +678,8 @@ do { case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); /* FALLTHROUGH */ \ case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); /* FALLTHROUGH */ \ case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); /* FALLTHROUGH */ \ - case 1: _hj_i += _hj_key[0]; \ + case 1: _hj_i += _hj_key[0]; /* FALLTHROUGH */ \ + default: ; \ } \ HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ } while (0) @@ -743,6 +727,8 @@ do { case 1: hashv += *_sfh_key; \ hashv ^= hashv << 10; \ hashv += hashv >> 1; \ + break; \ + default: ; \ } \ \ /* Force "avalanching" of final 127 bits */ \ @@ -764,7 +750,7 @@ do { } \ while ((out) != NULL) { \ if ((out)->hh.hashv == (hashval) && (out)->hh.keylen == (keylen_in)) { \ - if (HASH_KEYCMP((out)->hh.key, keyptr, keylen_in) == 0) { \ + if (HASH_KEYCMP((out)->hh.key, keyptr, keylen_in) == 0) { \ break; \ } \ } \ @@ -850,12 +836,12 @@ do { struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ - 2UL * (tbl)->num_buckets * sizeof(struct UT_hash_bucket)); \ + sizeof(struct UT_hash_bucket) * (tbl)->num_buckets * 2U); \ if (!_he_new_buckets) { \ HASH_RECORD_OOM(oomed); \ } else { \ uthash_bzero(_he_new_buckets, \ - 2UL * (tbl)->num_buckets * sizeof(struct UT_hash_bucket)); \ + sizeof(struct UT_hash_bucket) * (tbl)->num_buckets * 2U); \ (tbl)->ideal_chain_maxlen = \ ((tbl)->num_items >> ((tbl)->log2_num_buckets+1U)) + \ ((((tbl)->num_items & (((tbl)->num_buckets*2U)-1U)) != 0U) ? 1U : 0U); \ @@ -1142,7 +1128,7 @@ typedef struct UT_hash_handle { void *next; /* next element in app order */ struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ struct UT_hash_handle *hh_next; /* next hh in bucket order */ - void *key; /* ptr to enclosing struct's key */ + const void *key; /* ptr to enclosing struct's key */ unsigned keylen; /* enclosing struct's key len */ unsigned hashv; /* result of hash-fcn(key) */ } UT_hash_handle; diff --git a/src/utlist.h b/src/utlist.h index 5bb1ac9b7..1979448a7 100644 --- a/src/utlist.h +++ b/src/utlist.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2007-2018, Troy D. Hanson http://troydhanson.github.com/uthash/ +Copyright (c) 2007-2021, Troy D. Hanson http://troydhanson.github.io/uthash/ All rights reserved. Redistribution and use in source and binary forms, with or without @@ -24,7 +24,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef UTLIST_H #define UTLIST_H -#define UTLIST_VERSION 2.1.0 +#define UTLIST_VERSION 2.3.0 #include <assert.h> diff --git a/src/utringbuffer.h b/src/utringbuffer.h index ce2890e60..c2b2e673c 100644 --- a/src/utringbuffer.h +++ b/src/utringbuffer.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2015-2018, Troy D. Hanson http://troydhanson.github.com/uthash/ +Copyright (c) 2015-2021, Troy D. Hanson http://troydhanson.github.io/uthash/ All rights reserved. Redistribution and use in source and binary forms, with or without @@ -26,7 +26,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef UTRINGBUFFER_H #define UTRINGBUFFER_H -#define UTRINGBUFFER_VERSION 2.1.0 +#define UTRINGBUFFER_VERSION 2.3.0 #include <stdlib.h> #include <string.h> diff --git a/src/utstack.h b/src/utstack.h index 3b0c1a0df..fc390de10 100644 --- a/src/utstack.h +++ b/src/utstack.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2018-2018, Troy D. Hanson http://troydhanson.github.com/uthash/ +Copyright (c) 2018-2021, Troy D. Hanson http://troydhanson.github.io/uthash/ All rights reserved. Redistribution and use in source and binary forms, with or without @@ -24,7 +24,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef UTSTACK_H #define UTSTACK_H -#define UTSTACK_VERSION 2.1.0 +#define UTSTACK_VERSION 2.3.0 /* * This file contains macros to manipulate a singly-linked list as a stack. @@ -35,9 +35,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * struct item { * int id; * struct item *next; - * } + * }; * - * struct item *stack = NULL: + * struct item *stack = NULL; * * int main() { * int count; diff --git a/src/utstring.h b/src/utstring.h index 4cf5ffd3d..f6a33af3e 100644 --- a/src/utstring.h +++ b/src/utstring.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2008-2018, Troy D. Hanson http://troydhanson.github.com/uthash/ +Copyright (c) 2008-2021, Troy D. Hanson http://troydhanson.github.io/uthash/ All rights reserved. Redistribution and use in source and binary forms, with or without @@ -26,7 +26,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef UTSTRING_H #define UTSTRING_H -#define UTSTRING_VERSION 2.1.0 +#define UTSTRING_VERSION 2.3.0 #include <stdlib.h> #include <string.h> diff --git a/tests/Makefile b/tests/Makefile index fcb751984..31f0cc240 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -12,7 +12,7 @@ PROGS = test1 test2 test3 test4 test5 test6 test7 test8 test9 \ test66 test67 test68 test69 test70 test71 test72 test73 \ test74 test75 test76 test77 test78 test79 test80 test81 \ test82 test83 test84 test85 test86 test87 test88 test89 \ - test90 test91 test92 test93 test94 test95 + test90 test91 test92 test93 test94 test95 test96 CFLAGS += -I$(HASHDIR) #CFLAGS += -DHASH_BLOOM=16 #CFLAGS += -O2 diff --git a/tests/README b/tests/README index fc25b9b41..a287de670 100644 --- a/tests/README +++ b/tests/README @@ -7,7 +7,7 @@ test2: make 10-item hash, lookup items with even keys, print test3: make 10-item hash, delete items with even keys, print others test4: 10 structs have dual hash handles, separate keys test5: 10 structs have dual hash handles, lookup evens by alt key -test6: test alt malloc macros (and alt memcmp macro) +test6: test alt malloc macros (and alt key-comparison macro) test7: test alt malloc macros with 1000 structs so bucket expansion occurs test8: test num_items counter in UT_hash_handle test9: test "find" after bucket expansion @@ -89,10 +89,15 @@ 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_ADD_INORDER() macro (Thilo Schulz) -test88: test alt memcmp and strlen macros +test88: test alt key-comparison and strlen macros test89: test code from the tinydtls project test90: regression-test HASH_ADD_KEYPTR_INORDER (IronBug) test91: test LL_INSERT_INORDER etc. +test92: HASH_NONFATAL_OOM +test93: alt_fatal +test94: utlist with fields named other than 'next' and 'prev' +test95: utstack +test96: HASH_FUNCTION + HASH_KEYCMP Other Make targets ================================================================================ diff --git a/tests/example.c b/tests/example.c index a85f422d4..99263027f 100644 --- a/tests/example.c +++ b/tests/example.c @@ -1,25 +1,25 @@ -#include <stdio.h> /* gets */ +#include <stdio.h> /* printf */ #include <stdlib.h> /* atoi, malloc */ #include <string.h> /* strcpy */ #include "uthash.h" struct my_struct { int id; /* key */ - char name[10]; + char name[21]; UT_hash_handle hh; /* makes this structure hashable */ }; struct my_struct *users = NULL; -void add_user(int user_id, char *name) +void add_user(int user_id, const char *name) { struct my_struct *s; HASH_FIND_INT(users, &user_id, s); /* id already in the hash? */ - if (s==NULL) { - s = (struct my_struct*)malloc(sizeof(struct my_struct)); + if (s == NULL) { + s = (struct my_struct*)malloc(sizeof *s); s->id = user_id; - HASH_ADD_INT( users, id, s ); /* id: name of key field */ + HASH_ADD_INT(users, id, s); /* id is the key field */ } strcpy(s->name, name); } @@ -28,23 +28,24 @@ struct my_struct *find_user(int user_id) { struct my_struct *s; - HASH_FIND_INT( users, &user_id, s ); /* s: output pointer */ + HASH_FIND_INT(users, &user_id, s); /* s: output pointer */ return s; } void delete_user(struct my_struct *user) { - HASH_DEL( users, user); /* user: pointer to deletee */ + HASH_DEL(users, user); /* user: pointer to deletee */ free(user); } void delete_all() { - struct my_struct *current_user, *tmp; + struct my_struct *current_user; + struct my_struct *tmp; HASH_ITER(hh, users, current_user, tmp) { - HASH_DEL(users,current_user); /* delete it (users advances to next) */ - free(current_user); /* free it */ + HASH_DEL(users, current_user); /* delete it (users advances to next) */ + free(current_user); /* free it */ } } @@ -52,41 +53,45 @@ void print_users() { struct my_struct *s; - for(s=users; s != NULL; s=(struct my_struct*)(s->hh.next)) { + for (s = users; s != NULL; s = (struct my_struct*)(s->hh.next)) { printf("user id %d: name %s\n", s->id, s->name); } } -int name_sort(struct my_struct *a, struct my_struct *b) +int by_name(const struct my_struct *a, const struct my_struct *b) { - return strcmp(a->name,b->name); + return strcmp(a->name, b->name); } -int id_sort(struct my_struct *a, struct my_struct *b) +int by_id(const struct my_struct *a, const struct my_struct *b) { return (a->id - b->id); } -void sort_by_name() +const char *getl(const char *prompt) { - HASH_SORT(users, name_sort); -} - -void sort_by_id() -{ - HASH_SORT(users, id_sort); + static char buf[21]; + char *p; + printf("%s? ", prompt); fflush(stdout); + p = fgets(buf, sizeof(buf), stdin); + if (p == NULL || (p = strchr(buf, '\n')) == NULL) { + puts("Invalid input!"); + exit(EXIT_FAILURE); + } + *p = '\0'; + return buf; } int main() { - char in[10]; - int id=1, running=1; + int id = 1; + int running = 1; struct my_struct *s; - unsigned num_users; + int temp; while (running) { printf(" 1. add user\n"); - printf(" 2. add/rename user by id\n"); + printf(" 2. add or rename user by id\n"); printf(" 3. find user\n"); printf(" 4. delete user\n"); printf(" 5. delete all users\n"); @@ -95,27 +100,20 @@ int main() printf(" 8. print users\n"); printf(" 9. count users\n"); printf("10. quit\n"); - gets(in); - switch(atoi(in)) { + switch (atoi(getl("Command"))) { case 1: - printf("name?\n"); - add_user(id++, gets(in)); + add_user(id++, getl("Name (20 char max)")); break; case 2: - printf("id?\n"); - gets(in); - id = atoi(in); - printf("name?\n"); - add_user(id, gets(in)); + temp = atoi(getl("ID")); + add_user(temp, getl("Name (20 char max)")); break; case 3: - printf("id?\n"); - s = find_user(atoi(gets(in))); + s = find_user(atoi(getl("ID to find"))); printf("user: %s\n", s ? s->name : "unknown"); break; case 4: - printf("id?\n"); - s = find_user(atoi(gets(in))); + s = find_user(atoi(getl("ID to delete"))); if (s) { delete_user(s); } else { @@ -126,20 +124,20 @@ int main() delete_all(); break; case 6: - sort_by_name(); + HASH_SORT(users, by_name); break; case 7: - sort_by_id(); + HASH_SORT(users, by_id); break; case 8: print_users(); break; case 9: - num_users=HASH_COUNT(users); - printf("there are %u users\n", num_users); + temp = HASH_COUNT(users); + printf("there are %d users\n", temp); break; case 10: - running=0; + running = 0; break; } } diff --git a/tests/hashscan.c b/tests/hashscan.c index c487d9cee..d18b364ef 100644 --- a/tests/hashscan.c +++ b/tests/hashscan.c @@ -1,5 +1,5 @@ /* -Copyright (c) 2005-2018, Troy D. Hanson http://troydhanson.github.com/uthash/ +Copyright (c) 2005-2021, Troy D. Hanson http://troydhanson.github.io/uthash/ All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/tests/keystats b/tests/keystats index 9d4076278..9c6bf5b16 100755 --- a/tests/keystats +++ b/tests/keystats @@ -12,9 +12,11 @@ sub usage { usage if ((@ARGV == 0) or ($ARGV[0] eq '-h')); -my @exes = glob "$FindBin::Bin/keystat.???"; +my @exes = glob "'$FindBin::Bin/keystat.???'"; + my %stats; for my $exe (@exes) { + $exe =~ s/\ /\\ /g; $stats{$exe} = `$exe @ARGV`; delete $stats{$exe} if ($? != 0); # omit hash functions that fail to produce stats (nx) } diff --git a/tests/test10.c b/tests/test10.c index 64f8035e2..edf80d4a1 100644 --- a/tests/test10.c +++ b/tests/test10.c @@ -47,5 +47,8 @@ int main() HASH_FIND(alth,altusers,&i,sizeof(int),tmp); printf("%d %s in alth\n", i, (tmp != NULL) ? "found" : "not found"); + HASH_CLEAR(hh, users); + HASH_CLEAR(alth, altusers); + return 0; } diff --git a/tests/test6.c b/tests/test6.c index 55ce36bfb..919afa8e1 100644 --- a/tests/test6.c +++ b/tests/test6.c @@ -7,15 +7,16 @@ /* Set up macros for alternative malloc/free functions */ #undef uthash_malloc #undef uthash_free -#undef uthash_memcmp #undef uthash_strlen #undef uthash_bzero #define uthash_malloc(sz) alt_malloc(sz) #define uthash_free(ptr,sz) alt_free(ptr,sz) -#define uthash_memcmp(a,b,n) alt_memcmp(a,b,n) #define uthash_strlen(s) ..fail_to_compile.. #define uthash_bzero(a,n) alt_bzero(a,n) +#undef HASH_KEYCMP +#define HASH_KEYCMP(a,b,n) alt_keycmp(a,b,n) + typedef struct example_user_t { int id; int cookie; @@ -41,10 +42,10 @@ static void alt_free(void *ptr, size_t sz) free(ptr); } -static int alt_memcmp_count = 0; -static int alt_memcmp(const void *a, const void *b, size_t n) +static int alt_keycmp_count = 0; +static int alt_keycmp(const void *a, const void *b, size_t n) { - ++alt_memcmp_count; + ++alt_keycmp_count; return memcmp(a,b,n); } @@ -115,7 +116,7 @@ int main() #else assert(alt_bzero_count == 2); #endif - assert(alt_memcmp_count == 10); + assert(alt_keycmp_count == 10); assert(alt_malloc_balance == 0); return 0; } diff --git a/tests/test65.c b/tests/test65.c index c863d21db..0584fb1a0 100644 --- a/tests/test65.c +++ b/tests/test65.c @@ -3,7 +3,7 @@ #include "uthash.h" // this is an example of how to do a LRU cache in C using uthash -// http://troydhanson.github.com/uthash/ +// http://troydhanson.github.io/uthash/ // by Jehiah Czebotar 2011 - jehiah@gmail.com // this code is in the public domain http://unlicense.org/ diff --git a/tests/test76.c b/tests/test76.c index a18685cae..ee890f6a2 100644 --- a/tests/test76.c +++ b/tests/test76.c @@ -8,8 +8,8 @@ int main() char V_NeedleStr[] = "needle\0s";
long *V_KMP_Table;
long V_FindPos;
- size_t V_StartPos;
- size_t V_FindCnt;
+ size_t V_StartPos = 0;
+ size_t V_FindCnt = 0;
utstring_new(s);
@@ -24,9 +24,6 @@ int main() if (V_KMP_Table != NULL) {
_utstring_BuildTable(utstring_body(t), utstring_len(t), V_KMP_Table);
- V_FindCnt = 0;
- V_FindPos = 0;
- V_StartPos = 0;
do {
V_FindPos = _utstring_find(utstring_body(s) + V_StartPos,
utstring_len(s) - V_StartPos,
diff --git a/tests/test77.c b/tests/test77.c index 7ff97518e..dc55cb244 100644 --- a/tests/test77.c +++ b/tests/test77.c @@ -9,7 +9,7 @@ int main() long *V_KMP_Table;
long V_FindPos;
size_t V_StartPos;
- size_t V_FindCnt;
+ size_t V_FindCnt = 0;
utstring_new(s);
@@ -24,8 +24,6 @@ int main() if (V_KMP_Table != NULL) {
_utstring_BuildTableR(utstring_body(t), utstring_len(t), V_KMP_Table);
- V_FindCnt = 0;
- V_FindPos = 0;
V_StartPos = utstring_len(s) - 1;
do {
V_FindPos = _utstring_findR(utstring_body(s),
diff --git a/tests/test88.ans b/tests/test88.ans index 6f35d6e98..7d0129407 100644 --- a/tests/test88.ans +++ b/tests/test88.ans @@ -9,22 +9,22 @@ alt_strlen alt_strlen alt_strlen alt_strlen -alt_memcmp +alt_keycmp alt_strlen -alt_memcmp +alt_keycmp alt_strlen -alt_memcmp +alt_keycmp alt_strlen -alt_memcmp +alt_keycmp alt_strlen -alt_memcmp +alt_keycmp alt_strlen -alt_memcmp +alt_keycmp alt_strlen -alt_memcmp +alt_keycmp alt_strlen -alt_memcmp +alt_keycmp alt_strlen -alt_memcmp +alt_keycmp alt_strlen -alt_memcmp +alt_keycmp diff --git a/tests/test88.c b/tests/test88.c index 46f3ee76f..d7a454a0f 100644 --- a/tests/test88.c +++ b/tests/test88.c @@ -8,9 +8,9 @@ /* This is mostly a copy of test6.c. */ -#undef uthash_memcmp +#undef HASH_KEYCMP #undef uthash_strlen -#define uthash_memcmp(a,b,n) alt_memcmp(a,b,n) +#define HASH_KEYCMP(a,b,n) alt_keycmp(a,b,n) #define uthash_strlen(s) alt_strlen(s) typedef struct example_user_t { @@ -19,9 +19,9 @@ typedef struct example_user_t { UT_hash_handle hh; } example_user_t; -static int alt_memcmp(const void *a, const void *b, size_t n) +static int alt_keycmp(const void *a, const void *b, size_t n) { - puts("alt_memcmp"); + puts("alt_keycmp"); return memcmp(a,b,n); } diff --git a/tests/test93.c b/tests/test93.c index 4afe7d51e..81103a1a7 100644 --- a/tests/test93.c +++ b/tests/test93.c @@ -39,43 +39,39 @@ static void alt_fatal(char const * s) { longjmp(j_buf, 1); } -static example_user_t * init_user(int need_malloc_cnt) { - users = 0; +static void init_users(int need_malloc_cnt) { + users = NULL; example_user_t * user = (example_user_t*)malloc(sizeof(example_user_t)); user->id = user_id; is_fatal = 0; malloc_cnt = need_malloc_cnt; - /* printf("adding to hash...\n"); */ if (!setjmp(j_buf)) { HASH_ADD_INT(users, id, user); + } else { + free(user); } - return user; } int main() { + example_user_t *user; -#define init(a) do { \ -} while(0) - - example_user_t * user; - - user = init_user(3); /* bloom filter must fail */ + init_users(3); /* bloom filter must fail */ if (!is_fatal) { printf("fatal not called after bloom failure\n"); } - user = init_user(2); /* bucket creation must fail */ + init_users(2); /* bucket creation must fail */ if (!is_fatal) { printf("fatal not called after bucket creation failure\n"); } - user = init_user(1); /* table creation must fail */ + init_users(1); /* table creation must fail */ if (!is_fatal) { printf("fatal not called after table creation failure\n"); } - user = init_user(4); /* hash must create OK */ + init_users(4); /* hash must create OK */ if (is_fatal) { printf("fatal error when creating hash normally\n"); /* bad idea to continue running */ @@ -83,19 +79,20 @@ int main() } /* let's add users until expansion fails */ - users = 0; + users = NULL; malloc_cnt = 4; while (1) { - user = (example_user_t*)malloc(sizeof(example_user_t)); - user->id = user_id; if (user_id++ == 1000) { printf("there is no way 1000 iterations didn't require realloc\n"); break; } + user = (example_user_t*)malloc(sizeof(example_user_t)); + user->id = user_id; if (!setjmp(j_buf)) { HASH_ADD_INT(users, id, user); + } else { + free(user); } - malloc_cnt = 0; if (malloc_failed) { if (!is_fatal) { @@ -108,12 +105,12 @@ int main() /* we can't really do anything, the hash is not in consistent * state, so assume this is a success. */ break; - } + malloc_cnt = 0; } - printf("End\n"); + HASH_CLEAR(hh, users); + printf("End\n"); return 0; - } diff --git a/tests/test96.ans b/tests/test96.ans new file mode 100644 index 000000000..64556d9f8 --- /dev/null +++ b/tests/test96.ans @@ -0,0 +1,40 @@ +time 56 not found, inserting it +time 7 not found, inserting it +time 10 not found, inserting it +time 39 not found, inserting it +time 82 found with value 10 +time 15 found with value 39 +time 31 found with value 7 +time 26 not found, inserting it +time 51 found with value 39 +time 83 not found, inserting it +time 46 found with value 10 +time 92 found with value 56 +time 49 not found, inserting it +time 25 found with value 49 +time 80 found with value 56 +time 54 not found, inserting it +time 97 found with value 49 +time 9 not found, inserting it +time 34 found with value 10 +time 86 found with value 26 +time 87 found with value 39 +time 28 not found, inserting it +time 13 found with value 49 +time 91 found with value 7 +time 95 found with value 83 +time 63 found with value 39 +time 71 found with value 83 +time 100 found with value 28 +time 44 found with value 56 +time 42 found with value 54 +time 16 found with value 28 +time 32 found with value 56 +time 6 found with value 54 +time 85 found with value 49 +time 40 found with value 28 +time 20 found with value 56 +time 18 found with value 54 +time 99 found with value 39 +time 22 found with value 10 +time 1 found with value 49 diff --git a/tests/test96.c b/tests/test96.c new file mode 100644 index 000000000..700bdcf30 --- /dev/null +++ b/tests/test96.c @@ -0,0 +1,48 @@ +#include <stdio.h> +#include <stdlib.h> + +#define HASH_FUNCTION(a,n,hv) (hv = clockface_hash(*(const int*)(a))) +#define HASH_KEYCMP(a,b,n) clockface_neq(*(const int*)(a), *(const int*)(b)) + +#include "uthash.h" + +struct clockface { + int time; + UT_hash_handle hh; +}; + +int clockface_hash(int time) +{ + return (time % 4); +} + +int clockface_neq(int t1, int t2) +{ + return ((t1 % 12) != (t2 % 12)); +} + +int main() +{ + int random_data[] = { + 56, 7, 10, 39, 82, 15, 31, 26, 51, 83, + 46, 92, 49, 25, 80, 54, 97, 9, 34, 86, + 87, 28, 13, 91, 95, 63, 71, 100, 44, 42, + 16, 32, 6, 85, 40, 20, 18, 99, 22, 1 + }; + + struct clockface *times = NULL; + for (int i=0; i < 40; ++i) { + struct clockface *elt = (struct clockface *)malloc(sizeof(*elt)); + struct clockface *found = NULL; + elt->time = random_data[i]; + HASH_FIND_INT(times, &elt->time, found); + if (found) { + printf("time %d found with value %d\n", elt->time, found->time); + } else { + printf("time %d not found, inserting it\n", elt->time); + HASH_ADD_INT(times, time, elt); + } + } + + return 0; +} |