pax_global_header00006660000000000000000000000064126405156620014521gustar00rootroot0000000000000052 comment=d0961c339d43b2f15d2249d2c87ebd485a3c1692 uthash-1.9.9.1+git20151125/000077500000000000000000000000001264051566200145745ustar00rootroot00000000000000uthash-1.9.9.1+git20151125/LICENSE000066400000000000000000000021651264051566200156050ustar00rootroot00000000000000Copyright (c) 2005-2014, Troy D. Hanson http://troydhanson.github.com/uthash/ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. uthash-1.9.9.1+git20151125/README.md000066400000000000000000000001241264051566200160500ustar00rootroot00000000000000 Documentation for uthash is available at: http://troydhanson.github.com/uthash/ uthash-1.9.9.1+git20151125/doc/000077500000000000000000000000001264051566200153415ustar00rootroot00000000000000uthash-1.9.9.1+git20151125/doc/ChangeLog.html000066400000000000000000001045521264051566200200650ustar00rootroot00000000000000 uthash ChangeLog

Click to return to the uthash home page.

Note
uthash is no longer maintained as of 2015.

Version 1.9.9.1 (2014-11-18)

  • inclusion of experimental libut bundle with utvector in opt/

  • use shift in Bernstein hash instead of multiply (thanks, Jimmy Zhuo!)

  • switch ssize_t types in utarray/utstring to size_t (thanks, Hong Xu!)

  • fix utstring pointer math on >4GB strings (thanks, Thomas Bottesch!)

  • change FNV hash to FNV-1a varation (thanks, dwest1975!)

  • fix bug in HASH_REPLACE_STR (thanks, Ilya Kaliman!)

Version 1.9.9 (2014-02-25)

  • made HASH_ADD_STR compatible with char* or char[] (thanks, Samuel Thibault!)

  • fixed header inclusion of sys/types.h for ssize_t (thanks, Fernando Campos!)

  • added LL_COUNT/DL_COUNT/CDL_COUNT (thansk, Paul Praet!)

  • added LRU cache example in tests/lru_cache (thanks, Oliver Lorenz!)

  • fix LL_DELETE2 for VS2008 (thanks, Greg Davydouski!)

  • fix missing argument in HASH_REPLACE_STR (thanks, Alex!)

  • bump version number in source files to match docs (thanks, John Crow!)

  • add HASH_OVERHEAD macro to get overhead size for hash table

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 uthash on GitHub

  • there’s a uthash Google Group

  • uthash has been downloaded 29,000+ times since 2006 on SourceForge

Version 1.9.7 (2012-10-09)

  • utstring now supports substring search using utstring_find (thanks, Joe Wei!)

  • utlist now supports element prepend and replace (thanks, Zoltán Lajos Kis!)

  • utlist element prev/next fields can now have any names (thanks, Pawel S. Veselov!)

  • uthash cast quiets a clang warning (thanks, Roman Divacky and Baptiste Daroussin!)

  • uthash userguide example shows how to check key uniqueness (thanks, Richard Cook!)

  • uthash HASH_MUR compiles under MSVC++ 10 in C mode (thanks, Arun Kirthi Cherian!)

  • utstring_printf now supports format checking (thanks, Donald Carr!)

Version 1.9.6 (2012-04-28)

  • add utarray_prev (thanks, Ben Hiett!)

  • add parens/casts for greater compatibility (thanks, Atis, Debasis Ganguly, and Steve McClellan!)

  • added ifndef to uthash_malloc and related hooks (thanks, Holger Machens!)

  • edit examples so they do not leak memory (thanks, 任晶磊!)

Version 1.9.5 (2011-11-16)

  • added utarray_renew

  • fixed memory leak in uthash_clear when using Bloom filter (thanks, Jan Hättig!)

  • utarray now copies the UT_icd on array creation rather than storing a pointer

  • add parentheses to HASH_ADD to fix preprocessing of certain arguments (thanks, Aaron Rosen!)

  • more parenthesizations for greater macro argument flexibility

Version 1.9.4 (2011-06-05)

  • uthash now supports MurmurHash v3

  • utlist now includes concatenation macros (LL_CONCAT and DL_CONCAT)

  • utarray now supports binary search (utarray_find)

  • utstring now supports a new-or-clear-existing macro (utstring_renew)

  • documented technique for a multi-level hash table

  • clarified scope requirements for UT_icd in the utarray documentation

  • fixed termination when utstring_clear is followed by utstring_body

  • fixed utarray_inserta macro when used with complex arguments

  • on Visual Studio define missing type uint8_t

  • Debian/Ubuntu include uthash in the package uthash-dev.

  • uthash has been downloaded 16,211 times.

Thanks to Yu Feng, Richard Cook, Dino Ciuffetti, Chris Groer, and Arun Cherian for feedback and fixes in this release!

Version 1.9.3 (2010-10-31)

  • fix an ifdef for compatibility with Intel compiler (thanks, degski!)

  • fix HASH_ITER macro to satisfy C++ casting rules (thanks, Erik Bai!)

Version 1.9.2 (2010-10-04)

  • new HASH_ITER macro for more convenient deletion-safe iteration

  • hashscan can now run on FreeBSD 8.1 and later (thanks, Markus Gebert!)

  • More parens to evaluate complex macro arguments properly (thanks, ngg!)

  • Add sz parameter to the uthash_free hook for platforms that do their own memory management. Hopefully this minor API change doesn’t cause too much breakage for people. (thanks, Niall Douglas!)

  • uthash has been downloaded 12,294 times

Version 1.9.1 (2010-05-15)

  • Fix a redefinition warning when using uthash.h and utstring.h together

  • Fix a bug in utstring_init

  • Added HASH_FIND_PTR and HASH_ADD_PTR (thanks, Niall Douglas!)

Version 1.9 (2010-03-31)

  • uthash now supports Visual Studio 2008 and 2010 in C or C++ code!

  • new headers utarray.h and utstring.h are now included. These implement dynamic arrays and strings using macros

  • utlist.h now has deletion-safe iterators and search macros

  • the test suite now runs under Visual Studio (thanks again degski!)

  • special thanks for suggesting utarray and utlist features to Charalampos P.!

  • uthash has been downloaded 9,616 times

Version 1.8 (2009-09-08)

  • Added the hashscan utility that can report on the size and quality of hash tables in a running process (Linux-only)

  • Added Bloom filter support. This has the potential to speed up certain types of programs that look up non-existant keys in sufficient numbers.

  • Restored the MurmurHash, which can once again be used, if an additional symbol is defined. This is a "safety" by which the user declares they understand that -fno-strict-aliasing flag must be used if they are using MurmurHash under gcc with optimization.

  • Unified the bucket/table malloc hooks; now there is only one malloc hook

  • Re-organized the manual into a main section and advanced topics section

  • Fixed a bug in utlist.h where sorting a singly-linked list threw a compile-time error.

  • Fixed a bug in utlist.h where a doubly-linked list that is sorted did not maintain the special head->prev pointer back to the list tail.

Version 1.7 (2009-06-11)

  • The MurmurHash has been removed, and Jenkin’s hash is once again the default. While MurmurHash performed well, it’s unsafe with regard to the strict aliasing rule. This results in incorrect code when compiled with optimization. It’s not possible to enable -fno-strict-aliasing from within a header file.

  • The linked list macros in utlist.h now comply with the strict-aliasing rule so they generate correct code under high optimization levels (O2 or O3). The use of the __typeof__ extension, which was originally a GNU extension, may reduce portability to other compilers that do not support this extension. This extension is used in the singly-linked list macros and the sort macros.

Version 1.6 (2009-05-08)

Special thanks to Alfred Heisner for contributing several enhancements:

  • Support for two new hash functions:

    • the Paul Hsieh hash function (HASH_SFH)

    • Austin Appleby’s MurmurHash function (HASH_MUR)

  • Because of its excellent performance, MurmurHash is now the default hash function.

  • keystats now has much better elapsed time accuracy under Cygwin and MinGW

  • fixed casting in HASH_FNV, HASH_SAX and HASH_OAT for non-char keys

This release also includes:

  • a new HASH_CLEAR operation clears a hash table in one step.

  • a new HASH_SELECT operation inserts those elements from one hash that satisfy a given condition into another hash. The selected items have dual presence in both hash tables. For example a game could select the visible polygons from a hash of all polygons.

  • fixed a compile-time error which occurred if the final argument to HASH_ADD_KEYPTR was a pointer to an array member like &a[i]

  • added another test script tests/all_funcs which executes the test suite using every supported hash function

And lastly,

  • a new, separate header called utlist.h is included which provides linked list macros for C structures, similar in style to the uthash macros

Version 1.5 (2009-02-19)

  • now thread-safe for concurrent readers

  • use scratch variables on stack rather than in table (thanks, Petter Arvidsson!). This change made HASH_FIND about 13% faster and enabled reader concurrency.

  • made BSD license terms even more permissive

  • added PDF version of User Guide

  • added update news (RSS)

Version 1.4 (2008-09-23)

  • Add HASH_COUNT for counting items in the hash

  • Compatibility with C++. Satisfy additional casting requirements. Also in the tests/ directory, running make cplusplus now compiles all the test programs with the C++ compiler.

  • Eliminate elmt pointer from the UT_hash_handle. Calculate elmt from hash handle address by subtracting hho (hash handle offset).

  • Contributed by L.S.Chin: Cast void* to char* before pointer arithmetic to suppress compiler warnings. We assume compilers abide to C standards which impose requirement that sizeof(void*) == sizeof(char*).

  • Return meaningful exit status from do_tests per Tiago Cunha, so that package manager-based install can verify tests are successful

Version 1.3 (2008-07-27)

  • use integer-only math-- no floating point! Support FPU-less CPU’s.

  • eliminate hash_q metric, which measured the fraction of items with non-ideal chain positions. We only need to know if this fraction is below 0.5. This is now determined using fast bitwise tests.

  • when an item is added to the hash, calculate the key’s hash value upfront and store it, instead of recomputing it as needed. This hashv is stored in the hash handle. Potentially major speed benefit for bucket expansion algorithm. Deleting is marginally improved too.

  • fixed a minor bug in the calculation of the max ideal chain length; line 446 in v1.2 erroneously calculated a/b*2 instead of a/(b*2). The effect of this bug was that bucket expansion could occur more readily because the per-bucket max chain length multiplier factor (which delays bucket expansion when certain buckets are overused) was set to a lower, expansion-favoring value than intended.

  • improved source commenting and improved variable names in structures

  • remove HASH_JSW. Lengthy random number array made code less readable

  • add HASH_SRT(hh,hash,cmp) as a generalized HASH_SORT(hash,cmp). It was an omission in uthash 1.2 that there was no sort macro for hash handles with names other than hh.

  • Corrected HASH_FSCK so it works with any name for the hash handle.

  • behave properly in pathological HASH_DEL(a,a) case where the same variable references the head and the deletee (advancing the head then loses the correct reference to the deletee); fix by using scratch area in the hash table to store deletee hash handle.

  • made tests runnable on MinGW

  • 3000+ downloads since uthash-1.0

Version 1.2 (2006-11-22)

  • new HASH_SORT macro

  • Cygwin support

  • User Guide now features a clickable Table of Contents. (The technique for generating the TOC on the browser was contributed back to the AsciiDoc project and incorporated into AsciiDoc v8.1.0).

Version 1.1 (2006-06-28)

  • uthash-1.1 released

  • supports several built-in user-selectable hash functions

  • new keystats utility quantifies performance of hash functions

Version 1.0 (2006-06-02)

  • Initial release


uthash-1.9.9.1+git20151125/doc/ChangeLog.txt000066400000000000000000000272221264051566200177360ustar00rootroot00000000000000uthash ChangeLog ================ Click to return to the link:index.html[uthash home page]. NOTE: uthash is no longer maintained as of 2015. Version 1.9.9.1 (2014-11-18) -------------------------- * inclusion of experimental libut bundle with utvector in opt/ * use shift in Bernstein hash instead of multiply (thanks, Jimmy Zhuo!) * switch ssize_t types in utarray/utstring to size_t (thanks, Hong Xu!) * fix utstring pointer math on >4GB strings (thanks, Thomas Bottesch!) * change FNV hash to FNV-1a varation (thanks, dwest1975!) * fix bug in HASH_REPLACE_STR (thanks, Ilya Kaliman!) Version 1.9.9 (2014-02-25) -------------------------- * made HASH_ADD_STR compatible with char* or char[] (thanks, Samuel Thibault!) * fixed header inclusion of sys/types.h for ssize_t (thanks, Fernando Campos!) * added LL_COUNT/DL_COUNT/CDL_COUNT (thansk, Paul Praet!) * added LRU cache example in `tests/lru_cache` (thanks, Oliver Lorenz!) * fix LL_DELETE2 for VS2008 (thanks, Greg Davydouski!) * fix missing argument in `HASH_REPLACE_STR` (thanks, Alex!) * bump version number in source files to match docs (thanks, John Crow!) * add `HASH_OVERHEAD` macro to get overhead size for hash table 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] * there's a https://groups.google.com/d/forum/uthash[uthash Google Group] * uthash has been downloaded 29,000+ times since 2006 on SourceForge Version 1.9.7 (2012-10-09) -------------------------- * utstring now supports substring search using `utstring_find` (thanks, Joe Wei!) * utlist now supports element 'prepend' and 'replace' (thanks, Zoltán Lajos Kis!) * utlist element prev/next fields can now have any names (thanks, Pawel S. Veselov!) * uthash cast quiets a clang warning (thanks, Roman Divacky and Baptiste Daroussin!) * uthash userguide example shows how to check key uniqueness (thanks, Richard Cook!) * uthash HASH_MUR compiles under MSVC++ 10 in C mode (thanks, Arun Kirthi Cherian!) * `utstring_printf` now supports format checking (thanks, Donald Carr!) Version 1.9.6 (2012-04-28) -------------------------- * add utarray_prev (thanks, Ben Hiett!) * add parens/casts for greater compatibility (thanks, Atis, Debasis Ganguly, and Steve McClellan!) * added ifndef to uthash_malloc and related hooks (thanks, Holger Machens!) * edit examples so they do not leak memory (thanks, 任晶磊!) Version 1.9.5 (2011-11-16) -------------------------- * added `utarray_renew` * fixed memory leak in `uthash_clear` when using Bloom filter (thanks, Jan Hättig!) * utarray now copies the UT_icd on array creation rather than storing a pointer * add parentheses to `HASH_ADD` to fix preprocessing of certain arguments (thanks, Aaron Rosen!) * more parenthesizations for greater macro argument flexibility Version 1.9.4 (2011-06-05) -------------------------- * uthash now supports MurmurHash v3 * utlist now includes concatenation macros (`LL_CONCAT` and `DL_CONCAT`) * utarray now supports binary search (`utarray_find`) * utstring now supports a new-or-clear-existing macro (`utstring_renew`) * documented technique for a multi-level hash table * clarified scope requirements for `UT_icd` in the utarray documentation * fixed termination when `utstring_clear` is followed by `utstring_body` * fixed utarray_inserta macro when used with complex arguments * on Visual Studio define missing type `uint8_t` * Debian/Ubuntu include uthash in the package `uthash-dev`. * uthash has been downloaded 16,211 times. Thanks to Yu Feng, Richard Cook, Dino Ciuffetti, Chris Groer, and Arun Cherian for feedback and fixes in this release! Version 1.9.3 (2010-10-31) -------------------------- * fix an `ifdef` for compatibility with Intel compiler (thanks, degski!) * fix `HASH_ITER` macro to satisfy C++ casting rules (thanks, Erik Bai!) Version 1.9.2 (2010-10-04) -------------------------- * new `HASH_ITER` macro for more convenient deletion-safe iteration * `hashscan` can now run on FreeBSD 8.1 and later (thanks, Markus Gebert!) * More parens to evaluate complex macro arguments properly (thanks, ngg!) * Add sz parameter to the `uthash_free` hook for platforms that do their own memory management. Hopefully this minor API change doesn't cause too much breakage for people. (thanks, Niall Douglas!) * uthash has been downloaded 12,294 times Version 1.9.1 (2010-05-15) -------------------------- * Fix a redefinition warning when using `uthash.h` and `utstring.h` together * Fix a bug in `utstring_init` * Added `HASH_FIND_PTR` and `HASH_ADD_PTR` (thanks, Niall Douglas!) Version 1.9 (2010-03-31) -------------------------- * uthash now supports Visual Studio 2008 and 2010 in C or C++ code! * new headers link:utarray.html[utarray.h] and link:utstring.html[utstring.h] are now included. These implement dynamic arrays and strings using macros * link:utlist.html[utlist.h] now has deletion-safe iterators and search macros * the test suite now runs under Visual Studio (thanks again degski!) * special thanks for suggesting utarray and utlist features to Charalampos P.! * uthash has been downloaded 9,616 times Version 1.8 (2009-09-08) -------------------------- * Added the `hashscan` utility that can report on the size and quality of hash tables in a running process (Linux-only) * Added Bloom filter support. This has the potential to speed up certain types of programs that look up non-existant keys in sufficient numbers. * Restored the MurmurHash, which can once again be used, if an additional symbol is defined. This is a "safety" by which the user declares they understand that `-fno-strict-aliasing` flag must be used if they are using MurmurHash under gcc with optimization. * Unified the bucket/table malloc hooks; now there is only one malloc hook * Re-organized the manual into a main section and advanced topics section * Fixed a bug in `utlist.h` where sorting a singly-linked list threw a compile-time error. * Fixed a bug in `utlist.h` where a doubly-linked list that is sorted did not maintain the special `head->prev` pointer back to the list tail. Version 1.7 (2009-06-11) -------------------------- * The MurmurHash has been removed, and Jenkin's hash is once again the default. While MurmurHash performed well, it's unsafe with regard to the strict aliasing rule. This results in incorrect code when compiled with optimization. It's not possible to enable `-fno-strict-aliasing` from within a header file. * The linked list macros in `utlist.h` now comply with the strict-aliasing rule so they generate correct code under high optimization levels (O2 or O3). The use of the `__typeof__` extension, which was originally a GNU extension, may reduce portability to other compilers that do not support this extension. This extension is used in the singly-linked list macros and the sort macros. Version 1.6 (2009-05-08) -------------------------- Special thanks to Alfred Heisner for contributing several enhancements: * Support for two new hash functions: - the Paul Hsieh hash function (`HASH_SFH`) - Austin Appleby's MurmurHash function (`HASH_MUR`) * Because of its excellent performance, MurmurHash is now the default hash function. * `keystats` now has much better elapsed time accuracy under Cygwin and MinGW * fixed casting in `HASH_FNV`, `HASH_SAX` and `HASH_OAT` for non-char keys This release also includes: * a new `HASH_CLEAR` operation clears a hash table in one step. * a new `HASH_SELECT` operation inserts those elements from one hash that satisfy a given condition into another hash. The selected items have dual presence in both hash tables. For example a game could select the visible polygons from a hash of all polygons. * fixed a compile-time error which occurred if the final argument to `HASH_ADD_KEYPTR` was a pointer to an array member like `&a[i]` * added another test script `tests/all_funcs` which executes the test suite using every supported hash function And lastly, * a new, separate header called link:utlist.html[utlist.h] is included which provides 'linked list macros' for C structures, similar in style to the uthash macros Version 1.5 (2009-02-19) -------------------------- * now thread-safe for concurrent readers * use scratch variables on stack rather than in table (thanks, Petter Arvidsson!). This change made HASH_FIND about 13% faster and enabled reader concurrency. * made link:license.html[BSD license] terms even more permissive * added link:userguide.pdf[PDF version] of User Guide * added http://troydhanson.wordpress.com/feed/[update news] image:rss.png[(RSS)] Version 1.4 (2008-09-23) -------------------------- * Add `HASH_COUNT` for counting items in the hash * Compatibility with C\+\+. Satisfy additional casting requirements. Also in the `tests/` directory, running `make cplusplus` now compiles all the test programs with the C++ compiler. * Eliminate `elmt` pointer from the UT_hash_handle. Calculate elmt from hash handle address by subtracting `hho` (hash handle offset). * Contributed by L.S.Chin: Cast `void*` to char* before pointer arithmetic to suppress compiler warnings. We assume compilers abide to C standards which impose requirement that `sizeof(void*) == sizeof(char*)`. * Return meaningful exit status from do_tests per Tiago Cunha, so that package manager-based install can verify tests are successful Version 1.3 (2008-07-27) ------------------------ * use integer-only math-- no floating point! Support FPU-less CPU's. * eliminate `hash_q` metric, which measured the fraction of items with non-ideal chain positions. We only need to know if this fraction is below 0.5. This is now determined using fast bitwise tests. * when an item is added to the hash, calculate the key's hash value upfront and store it, instead of recomputing it as needed. This hashv is stored in the hash handle. Potentially major speed benefit for bucket expansion algorithm. Deleting is marginally improved too. * fixed a minor bug in the calculation of the max ideal chain length; line 446 in v1.2 erroneously calculated a/b*2 instead of a/(b*2). The effect of this bug was that bucket expansion could occur more readily because the per-bucket 'max chain length multiplier factor' (which delays bucket expansion when certain buckets are overused) was set to a lower, expansion-favoring value than intended. * improved source commenting and improved variable names in structures * remove `HASH_JSW`. Lengthy random number array made code less readable * add `HASH_SRT(hh,hash,cmp)` as a generalized `HASH_SORT(hash,cmp)`. It was an omission in uthash 1.2 that there was no sort macro for hash handles with names other than hh. * Corrected `HASH_FSCK` so it works with any name for the hash handle. * behave properly in pathological `HASH_DEL(a,a)` case where the same variable references the head and the deletee (advancing the head then loses the correct reference to the deletee); fix by using scratch area in the hash table to store deletee hash handle. * made tests runnable on MinGW * 3000+ downloads since uthash-1.0 Version 1.2 (2006-11-22) ------------------------ * new `HASH_SORT` macro * Cygwin support * User Guide now features a clickable Table of Contents. (The technique for generating the TOC on the browser was contributed back to the AsciiDoc project and incorporated into AsciiDoc v8.1.0). Version 1.1 (2006-06-28) ------------------------ * uthash-1.1 released * supports several built-in user-selectable hash functions * new keystats utility quantifies performance of hash functions Version 1.0 (2006-06-02) ------------------------ * Initial release // vim: set syntax=asciidoc: uthash-1.9.9.1+git20151125/doc/Makefile000066400000000000000000000005221264051566200170000ustar00rootroot00000000000000HTML=$(patsubst %.txt,%.html,$(wildcard *.txt)) all: $(HTML) # when each target of a multi-target rule has its own prereq # we use a static pattern rule. $(HTML): %.html: %.txt asciidoc -a toc2 $< TMP=/tmp/uthash-gh-pages stage: mkdir -p ${TMP} rm -if ${TMP}/* cp *.html *.css *.png ${TMP} .PHONY: clean clean: $(RM) $(HTML) uthash-1.9.9.1+git20151125/doc/banner.png000066400000000000000000000477751264051566200173400ustar00rootroot00000000000000PNG  IHDRzTcsRGBbKGD pHYs B(xtIME,i IDATxw^wp w]cF5j1(FL4c5v,( ~p;^cffwgQd>>Ӧ}[BLL4 ;aÆ ?U4U@6ɷz{lhpXMr%aÆ @oQ-r,6l'Dn\nl%aÆ =$~_/soذ^LWG^J6lذe4oO$"a^ zu3űc8{lذa^f'"waF/b0pVw;k%PIޛFG~>_<:O6lذaS(H^op\[%}^[ٰ W7S&@'O]~6lD /*/הȯP6p˹2~Ъ_+Ϥ>u|ZG?y]-g}6@FN<;ɗdNVX)Ȉ_~ZrĦӚkMl#-(Yב izkReq ``:u )LE3^L|*FDs='"H&uO*I8+nk͆ep -Ƿc3u#w3<u6Fz"p}my<x`U٣ҧyh6ɳ L( ѶM(fUm3\fˎhƁʧ/۫˺j{lFD~`Ujw^"'4jf֩mJf!pI0KDDI"T_@o!=V&~6l iN[sըQߪړu3Ŋ[b{l!zu3VJ mi=';~gu~,m/&w5UsihXlcgf|f[+哝{~۟ avQZk*s1.Wn0I $l ˔+oi6l=^Gs7,z#yf(iQRan_%w'TWƮ|j_hI-l<3I<ؼ6f*I ~(?jt[+eÆAf#BwJ8 ERP +X$xB1}P3o}Mh Tkq0S=wr#o:,Hf>6_|%CӖ3#u7HE핲a=9ZaO& Z+OQ{NUZ Q~=+=-V vN. &|6lxrLF/&78tWpJ6v(u3,4'o^~/#o2SLAޱmQ\&oM酓\)չ۰a#jh1]HoWȆ = Y_r>  󳹝c΀ĨNPH7õ9x6aPIuDLl 0_aO V1aaA@dպ",u k8UXHB06X3ٰe "\y9mpX]TR7^A$&Tf?΍'CY vh쫕I%}6yMi+aٰߠnd]C% ٰ^*iN{u~BVt>.@CKF`r4gJgGI*:khoDžYS ^J:D>_6zԄ؉>i(Pf{ڰߠ=gAO B p*?E BRBEpRN3G"*o;p kddҭou5}8"(&'1\kCvFC@&ݳɞ iW:6lmSC΀U6UbJڕgh 쳍~%,V {i&>xoN)y6 %p{]|38{ s06ꉏi"!8W O -XͤYGQi~1!$#cU .&;}1ƴO]c 5M)VæI6~D^Gw<ǡRj=O1ǀΨ&u&ѻ(Y!7?;Ɣ9(;.|P⍓GWGl)rT=jZZ Z5]n a2rzq'˽Xqq*%n7ZE\],{ 2 &f\$5IiJv{M}rxMEBdz1_s /.ϗ ~FcKBQQ4nbL*b5Ĺ/%FÅPH_ nl{yk*wUhɴxbZgf/1~Y;Nd ]HZ_y!~Mes lujh4MksIO#I_vA:NdzмΟ͞x[w(_ʃ7UWCԉ^ e"wzT%Yi2KxpąsJ6oPyY2g5>)-]$y=N=м_Ùl%l*ByHg )YiaiI#g 0^TOf HSd GR+ &ziɚ֠WHa*L ו@"{\wL>\ԁ()yym%.|h h5;ȌʅGS>ay55jB2"=njc|MjBM+ UICqi(qTPq|h{Pˆ\zܫLtz%9_N:3H55}8"J|~S:=Hw]lDiPNmߣ9kկ.*Ky z 4(( v 59n=k_|*/ϿWކ +sÊ}[_&fCV^L>x:"s#N8Ϗ/EWBb gI^)W䯻w)^^tUr'ӽ$KY%z'ѳX:!T^^}`%Ih%TTmt@e7yRn!bP7 މǁ#P{6TߜO Zo܊s}qB 1%JbIո!) 5{6s9_<}::k=}|;$6$fAIuՅOGħCZԠUm!yO')K&NŽ̀>q8ߙ ; }g?&]ʭ?@EM n6JRJ_rۦ$K)=!'Átt|e)_#>@- xMJb dn P*c0z"j?)B!Dp"08q"v+C̑R~Ѕ5\3VkZ={%(Tt!ɳRZr uks-XӎI|x3.x<{UV{2[/+EyԆ?l\sO O׳f2B`{;L. L*SdO7MOppVݧj0ԌB_qȅ{]ʝ=V&'%ujEPPf_ y?1kyQ#SG<΁Qң@ĦNDĤ<Λ6pBR\=CPs't;kYWB(ٓgߟ/|.BLRz;َ/0 X  ixqQ6ftG+ߘIB`1@Q?ff>fXB{ w| 6/3mg< $/TG87PD]h#_/n'I;ξO?8X !]$N3 nRJ"x8 4`Y fH5HRw]'c[+@1\'ce=)Bm B)8OJ)w5 _wս yF5BSR==Xe/T)  /vt/$hK!ćBB)eM_qwd]Ow59JCLłBw!yNҾ6\S 4e 5Pܗ jJ®%)q9$Uzȉ#c.EGT]8 ǽj:&zr g>C|5|++[ =L;Lb\#1!sAAMAI:]" U4/m}A]CF̶ΦƝ/' B#=b#5G4\p|m%az 6{7H_g`Q $ s1S]]`"EnY&tsz!ċ#RmC7jʴkU (| -]0w 63PTZHQipĂ[%z{j3`)NgRXd$Y uDB3e V(Q Y{*x'7z+/#Kw&kKS ʅYbHs7Eivw| /6͈LAm ^noJԬ(z'ƹh>/>WRzМHCs"*?h79kݡ!3<59Ŝtg=&zKyZ ł5SvTgt͞8Vmͪycy b8p ?%L$rد'!Kc>rBcYx}iϮ䝅gu:xpe}\p1N7/g/6[Q;4OKO# @s%?ls`su:ҪJrv\,&8 '65?S.!=tAoq5RCXry@pKn[! Eo I{q5ڇI)M> zVQ'Qs};#$hjFm CVT$Ϥ )2Sv$,;L~9~fV_7a;%?a83y]O>k)BQdkegfrl67 a^hT0HNq8OŁ6^g??tODgE} ʢ/#P?'Lܾi{0>_ !yC 2[}zϢq$R)RU !О,0<ǶBWH[c iƲBL荃`} %|:Oiiu5QkW3՞ѷ =o.8]SytM7'#s()H5icп h)i,(O}[sӦ~O mn+wXP˨c!4޽m+[W,_b ǒx|t!XʲM:sW6ENQlB׫#z'KOdڨo*7 ;Ԅtno˸ЪQ BnB3.ZYV4\AU}|rUX~}ʳ(E6"!GFQ`lî hHJ[c;c=q(i :rb CRU!6tOaН*?DŽ};;BAq*V) BDkސP~i~1z0I'0F!yY1t a\޳%z8/\Ldh`.He<S*Tc=tD6v S^q!_} w_K7W4 .A6_~+y:WD콯kSϟɣzN:4K$2t ΍J{?MA/ 'z!5b7xd~'J0$d:ݞl%Ga1#wA߭-_Y5wG%]cK˶ecNdۧ(-޾'{eX{v m< ݓ6|3*؞7aՏ;puv.+RR!\j_9Pmw > 5)C;J:PF]]^O:o{u\=_3LzˆUpL?F2ݍ~6iHϏ% 9~7"$=Z{BlS/]d/s' 16oNwAz7,0`q)5SFj0ds5YsYx&~wIC6U#4+{ ;{ἱaÆMlMׅXk66?vT 6 )D I1ѕ䦗qԘ6lrus;^>j׈Ң-XV % |YK#t9_.< VfI!,4t;=pT%z6lDMQ{c0C'yae1-{st-MWo߶nzi\7Z;5SOAqm MѧjvޥR EźZ@%')N!z]ơ&f!6G NoP?'vt|\t눝?Jh$Pf EڂRL,\'AuC6gݎ1Ma3$nuMѕ8Ѭ#`HIڶa&z6P4)h ]X~`kTu0׹0 >]n9'8X5J5Q5̺2wx|.^WT=ѧzdu\, s6#jPBޗ8]mJoc_WG%}CV՗Ֆ^Sq_pܸ/ht'bo-.mm $y## 6lg3xOW}g0eokC9:K3kKf R{#a"TeL+_tF]AzI3HÐI?S=>YKF;`speK{9cqI]_Uwg/q1c V355'Ł<*Hj᱋9bb|.RQ7  6lgcg|i%m)^zp Bs"_:pu%4:\DmlB$9ְ]g~ gʽC3XV_cN:8bPRީNͯ\98%-?l.ѳ&I)q{}dlg#O>k7CWi09 ^(҈?k@#'TDl9Ɉd/8aXn% Rx_x󧽅sI,ӈl(Gk(G!= Hw K#1\ǺjS_ӟ℉s|pԾq]TT\\DفJfL¼4; Krzj1P :SDoAϲx$~K)O~$pz֋RU'$:Қ)`Cm#Q46B_ΒEk4-.h #@:^#b"H}uIÿg#]k-T5v uMx|N> f-a3pv\^̹˦s /0+"f$"⺘2T((iPķ}1#WLmS}ϳa& &K)e^0*0XCw30< LBw.i_'`1ilgwx^yj͝ bU:Y 8IPLN8:D{,X@] !PY0͒i x7o# -,X}"bUtCwg zx,7o>瘱 k\k559%)%)7(ҋErQg=cYŽ[+nmSgT8'3Pu(|6lœ`f|B=eV)%B@6iBύ"BzS4M"P[*++ oÖz`)r$`*ԣ]FL^iRáUJVxj: ]x6|ߧ'ђ{Iנ{cQ6Y^A+WqV28g JVS\)9(PR:Mne8K9qO+! L1+kŨ3~xEknVx]=z8#lOs)w5u'.NrF`! 7FIB~g)_q * ]8rCHg[Jo:p0h{=rMsrH)B\n#w=yRrlm0$`00T Sa!.BhR"fu_$EZT; |HQ)"I)W? B』Y @&pcS1@Fԉ^'鏠Sc09H8Dv,IZT&7$4F{:|ޕfS09- =}iiͥ& <lBg#&d eL/!yZ[{NEI>l_]&-(%3yjX-5'3oqQ3>D|~ ߐ".>5ZCN@I.IF(`\Ir|uc gr9|G>pbH@ d\'EWnÂnQ]3#-s#fgφd2FJ9_1pbrFV)tQot#4kHCr7ǦTW *pl FdKNl4TV}^h~6S CSC`[TI-kEfgads%O=-1Az(wM\S4%Ʋ!$/v<}_ `{Bx7& H&נYj!Dn6WMrh&ί")e˳ך7TŁ9!i ~Jg0Hjc V+JjZKF:;PU$Fv@Z${ҔiB'zdL367>[\0hK"6>Mp"B'CS\ʃX\S5}A+brkB}-&zz c'l!'nUygșl2ȡwp/3v!Bq]%zQKn$ ^BEY>fg"t58y"5FIb `ԨQJnzjʰ|'Vڹ@qƒXz l[C(F{=ID5.4a|ETi4}n|CU+BԶƺ)*)FIBl K+mH&o_͢^$s[XG[ek`"XӐ/'O\IfVaQKw2cR2H!D*+]SX 1Hڛ=B \nkv _WHa՝gJT)NR"Átnxnb|*DLWĥ 6FmQQjƱ@3a/^ ]kdlf"h ,U  rzy[☥.\(!fTG&`%41^ر__#މ݋(*؂UHw"&O8bAJ|}Rht}Ct !ޓRZiYGP|Bz6!)btu6 >%06aIj%1BԦ9=ޠ\*caz !^G^utYHzwGIeBro7= %1fO!ы\%1 UGΨۂ3Ad'ɩdBH"$g K"?~d)PW^F]K07/_FR$!d@ZDP ^h${]!yG5:oMn"/#:bz̺aZ%Ft3ICK}Rh !J) bs!z\w _Opn4٥uB</"#$H)CmnF~!`+j56 !Rn7D Y>%:`'PRʀVD!ćC((B!\v%!Ĺf;D!DprT`Ye_tU]hRAk܍Q3-Iݏ?01N7Cz4I4F $}S+(b=S\1; '0IB,Q XJZw>@ٰc67u;3cg.B](/¤wT/X'#z͎푼0 DOw^ >G ">Cʋu=Mfj~ְ:=uVsgOm}RhB\Gotdp(7Gߡ۲ B@mH8`bA%4K7rCH)n!#ޫ[ U9c~B,6fߢǬpx_Jy!|(2%tuB_OkK atG Ijx-pbAD@ pkԉbˮ;v D5AI$.=U>_v<ݰ UW5{,JJ?dm BY()ᄉWh#{u-D L<,C+4L:԰@rF޵O_X #w<" u)lvR3ڴS'~.=?%?j9C-漩s\F}bn $[{(뷻&z6Nn \l5x2c@m' GsгZ_H6yG; ]__C4<]WJyb=M x =o4`6J!ī6n# :x<!FBΫMBlF1 , c3 4Hzck8cHxRnv^=|q89p86}ݗí/O;K7?0G%|=.VG+jc Zii;W2NϗKɞ~KmJ*:oܺjM*Tό 1a?l:=ew9ENR\k5f$&'U$:#:մMJfCׂ[G6>"_b0j80X`ŧu/wlmS2߭;iE6A$ ~q;KhAwfH"#yeҐe$6#Gķ ]U Xa -$hA@3%! _?~>Ǐ?Zr۽P$`nAv{"D'D6ڒ*iR%ߍ $/8䊉A'rչ\N۹_~2h>,=F?xTOjB-Iiah&$ jXyZHOo~"p uwo$r3 -l,¦B6RZC}s ͉4RWO^NF Xˡ3<=GaҼGKNOv^DذŅ?װf|~9|b(QgQ#Ô !<%JhԾ#vV_k 񹘻l:gZmI=`C`)Ȗio#f*źzh~MDCGQ[CGyNDxv ɟul= r{z=^װoɴQߠBI X$e3<|SsՉϛy IĠE͝ Gjx7Gh18Mow1!~5 _RA l]BM#g\_[Ս36cqH < @]g<8P3,=V/[NU}:IUHo/<&%nČ9G\R;H_^'z B -SBenlڍ$f擝.ӺJH^(DBI#xmԖ{9[91϶`pOwZC9i_{;Y(I9/R-E;^a4'\ִia֨<🬬7xKW"47݀C7޼ݙ,Mg=p6߽bQ{gygƬf`j\jH@%H hUJq (=RTRDӪ=ҔRU!Tp Q˘3 66^k;_صڳ:>ho}盙|9h١D Rl+~Q7hn n4l3c"ťe?tO>Hѽ j,ykYAs`97f#zzFwѺ7ѪYk^6l7hX;䦰̾!n4>4+9=˅>19%\ltl'rS4ޫ\CߦkT0帉V;iՌvyn򝖁_&" n*/ k_>hĝ~3''xކdg9`K`ӎuSG{MՋ_OA15Xm,6nʬOYKK*_żsvZ 4-F 斕p%}n}W{ưb-| VO?|:v3ٽW>W?xIZ4d|-ORsߋAu$?r'=:#p~稷Jb*ufr9LҲ2 9Rl~^T0䷧z1}wPVf4ӏiPU̚1nƎ`yMoYe+>~p D1}^1yټ^xw3+9za.y%<溌Hi64q )|Xyc4#gۺsruk$p,dr-aQ[nj)d8:HO!=ÅOK-)ƤQJ >g_؁dd'$A>zZ#)?튊K/:{8,_WH7PYwkfcZSѨq'7vlbz6,%d sA$MyTV/gOjo,p/9}ϭAf_nR{ 8t8hhqqZiⳮ菼T] K Ӂ}S^o8r}X!ŵx+{zOY=b;Ax㯱j?c5Vk B{h_:r}o3nuy0 {SBWRYR: EԴͧ3zK 9Yd8CR}.Qqu[[k ( WH;sȦ7o L W:H`bzȰyBp+XW( Vq1 O js Ӂr`cSFAxv5꬘C>#7D/"1 0 L@݆[uI> !Kr`qx q@pkUEơг~Âo!|A->;mUIƆ-cW1IENDB`uthash-1.9.9.1+git20151125/doc/banner.svg000066400000000000000000000442221264051566200173330ustar00rootroot00000000000000 image/svg+xml ut hash a hash tablefor C structures uthash-1.9.9.1+git20151125/doc/google315d692c9c632ed0.html000066400000000000000000000000651264051566200215650ustar00rootroot00000000000000google-site-verification: google315d692c9c632ed0.htmluthash-1.9.9.1+git20151125/doc/index.html000066400000000000000000000074401264051566200173430ustar00rootroot00000000000000 uthash: a hash table for C structures
GitHub page > uthash home

Any C structure can be stored in a hash table using uthash. Just add a UT_hash_handle to the structure and choose one or more fields in your structure to act as the key. Then use these macros to store, retrieve or delete items from the hash table.
Example 1. Adding an item to a hash.
#include "uthash.h"

struct my_struct {
    int id;            /* we'll use this field as the key */
    char name[10];             
    UT_hash_handle hh; /* makes this structure hashable */
};

struct my_struct *users = NULL;

void add_user(struct my_struct *s) {
    HASH_ADD_INT( users, id, s );    
}

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 );  
    return s;
}

Example 3. Deleting an item from a hash.
void delete_user(struct my_struct *user) {
    HASH_DEL( users, user);  
}

For more information and examples, please see the User Guide.

uthash-1.9.9.1+git20151125/doc/license.html000066400000000000000000000035371264051566200176610ustar00rootroot00000000000000 uthash: a hash table for C structures
uthash home > BSD license

Copyright (c) 2005-2015, Troy D. Hanson  http://troydhanson.github.com/uthash/
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

uthash-1.9.9.1+git20151125/doc/rss.png000066400000000000000000000012611264051566200166560ustar00rootroot00000000000000PNG  IHDRH-gAMA7tEXtSoftwareAdobe ImageReadyqe<CIDATxڌMHaδ1E"!HD*(PKtPnEХ:oAAHBRQ!%B]Y; ys4I@#֒Ps ZH sYLKDzzdR`TB ~;Ub# 4b^)uk)C2̝KhJlMlhim~&@eI25 K,M mGa<]ao% ޏ/q'Qʽbv[M)`q~fBYxaqd dg)BWM7H^lP@Qzz֦`H/7JeyJ%W\If m}XX\^+`_ǹ\,űX{+17j6+NDuZ(5]t6j.<&m+ARDž) ݬN GhȮ4ytPZ*k`r4M1MDC E2X$? GbIENDB`uthash-1.9.9.1+git20151125/doc/styles.css000066400000000000000000000041721264051566200174020ustar00rootroot00000000000000#banner { /* font-size: x-large; */ /* background: #ff00ff; */ /* height: 100px; */ } #topnav { /* background-image: url(img/grad_topnav.png); */ /* background-repeat: repeat-y; */ /* background-color: #af00af; */ /* height: 25px; */ margin-top: 5px; margin-bottom: 10px; padding: 3px; font-size: 9pt; font-family: sans-serif; /* border-style: solid; */ /* border-width: 1px; */ } #topnav a { padding: 8px; } h1,p { margin: 0; } /* non-0 margin on firefox */ #mid { /* background-image: url(img/grad_blue.png); */ background-repeat: repeat-y; /* background-color: #ffddaa; */ padding-top: 20px; padding-top: 20px; margin-bottom: 10px; } #mid img { padding-left: 10px; vertical-align: middle; } a img { border: 0 } .twitter-share-button { float: right; } .twitter-follow-button { padding: 5px; } #nav { background-color: #fff8f1; margin-left: 10px; margin-top: 20px; margin-right: 20px; float: left; padding: 10px; border-style: solid; border-width: 2px; font-family: sans-serif; } #nav h2 { font-weight: bold; font-size: 10pt; } #nav h3 { /* font-weight: bold; */ padding-left: 5px; /* font-style: oblique; */ font-family: sans-serif; font-size: 7pt; } #nav div { font-size: 9pt; padding-left: 15px; } #main { background: #ffffff; margin-top: 20px; margin-left: 170px; padding-left: 20px; height: 100%; } #main h1 { font-family: sans-serif; } .listing { margin: 20px; font-family: sans-serif; font-weight: bold; } .code { padding: 10px; margin: 10px; font-size: 8pt; font-weight: normal; background: #f3f3f3; width: 100%; border-style: solid; border-width: 1px; } #footer { /* background: #00ffff; */ margin-top: 5px; font-size: small; font-family: sans-serif; } hr { height: 0.04em; background: black; margin: 0 10% 0 0; } #footer { width: 90%; } #footer img { margin-right: 5px; float: right; } #footer #support { float: right; } body { width: 80%; } uthash-1.9.9.1+git20151125/doc/todo.txt000066400000000000000000000004001264051566200170410ustar00rootroot000000000000001. to minimize TLB churn, store hashv locally in chain 2. to reduce memory, make the insertion-order pointers optional 3. to improve optimization use function generators rather than void* 4. to reduce memory, eliminate hash handle, bookkeep in head object uthash-1.9.9.1+git20151125/doc/userguide.html000066400000000000000000003212021264051566200202230ustar00rootroot00000000000000 uthash User Guide
Note
As of 2015 uthash is unmaintained software.

To download uthash, follow this link back to the GitHub project page.

A hash in C

This document is written for C programmers. Since you’re reading this, chances are that you know a hash is used for looking up items using a key. In scripting languages, hashes or "dictionaries" are used all the time. In C, hashes don’t exist in the language itself. This software provides a hash table for C structures.

What can it do?

This software supports these operations on items in a hash table:

  1. add/replace

  2. find

  3. delete

  4. count

  5. iterate

  6. sort

Is it fast?

Add, find and delete are normally constant-time operations. This is influenced by your key domain and the hash function.

This hash aims to be minimalistic and efficient. It’s around 900 lines of C. It inlines automatically because it’s implemented as macros. It’s fast as long as the hash function is suited to your keys. You can use the default hash function, or easily compare performance and choose from among several other built-in hash functions.

Is it a library?

No, it’s just a single header file: uthash.h. All you need to do is copy the header file into your project, and:

#include "uthash.h"

Since uthash is a header file only, there is no library code to link against.

C/C++ and platforms

This software can be used in C and C++ programs. It has been tested on:

  • Linux

  • Mac OS X

  • Windows using Visual Studio 2008 and 2010

  • Solaris

  • OpenBSD

  • FreeBSD

Windows users: as of 2014 it’s been a few years since I had the environment to test uthash under Visual Studio.

Test suite

To run the test suite, enter the tests directory. Then,

  • on Unix platforms, run make

  • on Windows, run the "do_tests_win32.cmd" batch file. (You may edit the batch file if your Visual Studio is installed in a non-standard location).

BSD licensed

This software is made available under the revised BSD license. It is free and open source.

Download uthash

Follow the links on https://github.com/troydhanson/uthash to clone uthash or get a zip file.

Getting help

Please use the uthash Google Group to ask questions. You can email it at uthash@googlegroups.com. Please do not contact me directly. I can no longer answer any uthash questions or fix any bugs.

Contributing

You are welcome to fork uthash and make changes in your own repo. I have stopped maintaining uthash as of 2015.

Extras included

Three "extras" come with uthash. These provide lists, dynamic arrays and strings:

  • utlist.h provides linked list macros for C structures.

  • utarray.h implements dynamic arrays using macros.

  • utstring.h implements a basic dynamic string.

History

I wrote uthash in 2004-2006 for my own purposes. Originally it was hosted on SourceForge. Uthash was downloaded around 30,000 times between 2006-2013 then transitioned to GitHub. It’s been incorporated into commercial software, academic research, and into other open-source software. It has also been added to the native package repositories for a number of Unix-y distros.

When uthash was written, there were fewer options for doing generic hash tables in C than exist today. There are faster hash tables, more memory-efficient hash tables, with very different API’s today. But, like driving a minivan, uthash is convenient, and gets the job done for many purposes.

As of 2015 I have stopped maintaining uthash altogether.

Your structure

In uthash, a hash table is comprised of structures. Each structure represents a key-value association. One or more of the structure fields constitute the key. The structure pointer itself is the value.

Defining a structure that can be hashed
#include "uthash.h"

struct my_struct {
    int id;                    /* key */
    char name[10];
    UT_hash_handle hh;         /* makes this structure hashable */
};

Note that, in uthash, your structure will never be moved or copied into another location when you add it into a hash table. This means that you can keep other data structures that safely point to your structure-- regardless of whether you add or delete it from a hash table during your program’s lifetime.

The key

There are no restrictions on the data type or name of the key field. The key can also comprise multiple contiguous fields, having any names and data types.

Any data type… really?

Yes, your key and structure can have any data type. Unlike function calls with fixed prototypes, uthash consists of macros-- whose arguments are untyped-- and thus able to work with any type of structure or key.

Unique keys

As with any hash, every item must have a unique key. Your application must enforce key uniqueness. Before you add an item to the hash table, you must first know (if in doubt, check!) that the key is not already in use. You can check whether a key already exists in the hash table using HASH_FIND.

The hash handle

The UT_hash_handle field must be present in your structure. It is used for the internal bookkeeping that makes the hash work. It does not require initialization. It can be named anything, but you can simplify matters by naming it hh. This allows you to use the easier "convenience" macros to add, find and delete items.

A word about memory

Overhead

The hash handle consumes about 32 bytes per item on a 32-bit system, or 56 bytes per item on a 64-bit system. The other overhead costs-- the buckets and the table-- are negligible in comparison. You can use HASH_OVERHEAD to get the overhead size, in bytes, for a hash table. See Macro Reference.

How clean up occurs

Some have asked how uthash cleans up its internal memory. The answer is simple: when you delete the final item from a hash table, uthash releases all the internal memory associated with that hash table, and sets its pointer to NULL.

Hash operations

This section introduces the uthash macros by example. For a more succinct listing, see Macro Reference.

Convenience vs. general macros:

The uthash macros fall into two categories. The convenience macros can be used with integer, pointer or string keys (and require that you chose the conventional name hh for the UT_hash_handle field). The convenience macros take fewer arguments than the general macros, making their usage a bit simpler for these common types of keys.

The general macros can be used for any types of keys, or for multi-field keys, or when the UT_hash_handle has been named something other than hh. These macros take more arguments and offer greater flexibility in return. But if the convenience macros suit your needs, use them-- your code will be more readable.

Declare the hash

Your hash must be declared as a NULL-initialized pointer to your structure.

struct my_struct *users = NULL;    /* important! initialize to NULL */

Add item

Allocate and initialize your structure as you see fit. The only aspect of this that matters to uthash is that your key must be initialized to a unique value. Then call HASH_ADD. (Here we use the convenience macro HASH_ADD_INT, which offers simplified usage for keys of type int).

Add an item to a hash
void add_user(int user_id, char *name) {
    struct my_struct *s;

    s = malloc(sizeof(struct my_struct));
    s->id = user_id;
    strcpy(s->name, name);
    HASH_ADD_INT( users, id, s );  /* id: name of key field */
}

The first parameter to HASH_ADD_INT is the hash table, and the second parameter is the name of the key field. Here, this is id. The last parameter is a pointer to the structure being added.

Wait.. the field name is a parameter?

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 worry- the C preprocessor expands this to valid C code.

Key must not be modified while in-use

Once a structure has been added to the hash, do not change the value of its key. Instead, delete the item from the hash, change the key, and then re-add it.

Checking uniquness

In the example above, we didn’t check to see if user_id was already a key of some existing item in the hash. If there’s any chance that duplicate keys could be generated by your program, you must explicitly check the uniqueness before adding the key to the hash. If the key is already in the hash, you can simply modify the existing structure in the hash rather than adding the item. It is an error to add two items with the same key to the hash table.

Let’s rewrite the add_user function to check whether the id is in the hash. Only if the id is not present in the hash, do we create the item and add it. Otherwise we just modify the structure that already exists.

void add_user(int user_id, 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));
      s->id = user_id;
      HASH_ADD_INT( users, id, s );  /* id: name of key field */
    }
    strcpy(s->name, name);
}

Why doesn’t uthash check key uniqueness for you? It saves the cost of a hash lookup for those programs which don’t need it- for example, programs whose keys are generated by an incrementing, non-repeating counter.

However, if replacement is a common operation, it is possible to use the HASH_REPLACE macro. This macro, before adding the item, will try to find an item with the same key and delete it first. It also returns a pointer to the replaced item, so the user has a chance to de-allocate its memory.

Passing the hash pointer into functions

In the example above users is a global variable, but what if the caller wanted to pass the hash pointer into the add_user function? At first glance it would appear that you could simply pass users as an argument, but that won’t work right.

/* bad */
void add_user(struct my_struct *users, int user_id, char *name) {
  ...
  HASH_ADD_INT( users, id, s );
}

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 );
}

Note that we dereferenced the pointer in the HASH_ADD also.

The reason it’s necessary to deal with a pointer to the hash pointer is simple: the hash macros modify it (in other words, they modify the pointer itself not just what it points to).

Replace item

HASH_REPLACE macros are equivalent to HASH_ADD macros except they attempt to find and delete the item first. If it finds and deletes an item, it will also return that items pointer as an output parameter.

Find item

To look up a structure in a hash, you need its key. Then call HASH_FIND. (Here we use the convenience macro HASH_FIND_INT for keys of type int).

Find a structure using its key
struct my_struct *find_user(int user_id) {
    struct my_struct *s;

    HASH_FIND_INT( users, &user_id, s );  /* s: output pointer */
    return s;
}

Here, the hash table is users, and &user_id points to the key (an integer in this case). Last, s is the output variable of HASH_FIND_INT. The final result is that s points to the structure with the given key, or is NULL if the key wasn’t found in the hash.

Note
The middle argument is a pointer to the key. You can’t pass a literal key value to HASH_FIND. Instead assign the literal value to a variable, and pass a pointer to the variable.

Delete item

To delete a structure from a hash, you must have a pointer to it. (If you only have the key, first do a HASH_FIND to get the structure pointer).

Delete an item from a hash
void delete_user(struct my_struct *user) {
    HASH_DEL( users, user);  /* user: pointer to deletee */
    free(user);              /* optional; it's up to you! */
}

Here again, users is the hash table, and user is a pointer to the structure we want to remove from the hash.

uthash never frees your structure

Deleting a structure just removes it from the hash table-- it doesn’t free it. The choice of when to free your structure is entirely up to you; uthash will never free your structure. For example when using HASH_REPLACE macros, a replaced output argument is returned back, in order to make it possible for the user to de-allocate it.

Delete can change the pointer

The hash table pointer (which initially points to the first item added to the hash) can change in response to HASH_DEL (i.e. if you delete the first item in the hash table).

Iterative deletion

The HASH_ITER macro is a deletion-safe iteration construct which expands to a simple for loop.

Delete all items from a hash
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  */
  }
}

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);

Afterward, the list head (here, users) will be set to NULL.

Count items

The number of items in the hash table can be obtained using HASH_COUNT:

Count of items in the hash table
unsigned int num_users;
num_users = HASH_COUNT(users);
printf("there are %u users\n", num_users);

Incidentally, this works even the list (users, here) is NULL, in which case the count is 0.

Iterating and sorting

You can loop over the items in the hash by starting from the beginning and following the hh.next pointer.

Iterating over all the items in a hash
void print_users() {
    struct my_struct *s;

    for(s=users; s != NULL; s=s->hh.next) {
        printf("user id %d: name %s\n", s->id, s->name);
    }
}

There is also an hh.prev pointer you could use to iterate backwards through 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). 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 for-loop header. Here is how it could be used to rewrite the last example:

struct my_struct *s, *tmp;
HASH_ITER(hh, users, s, tmp) {
    printf("user id %d: name %s\n", s->id, s->name);
    /* ... it is safe to delete and free s here */
}
A hash is also a doubly-linked list.

Iterating backward and forward through the items in the hash is possible because of the hh.prev and hh.next fields. All the items in the hash can be reached by repeatedly following these pointers, thus the hash is also a 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.

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 );

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 less than zero, zero, or greater than zero, if the first item sorts before, equal to, or after the second item, respectively. (This is the same convention used by strcmp or qsort in the standard C library).

int sort_function(void *a, void *b) {
  /* compare a to b (cast a and b appropriately)
   * return (int) -1 if (a < b)
   * return (int)  0 if (a == b)
   * return (int)  1 if (a > b)
   */
}

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 id_sort(struct my_struct *a, 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);
}

When the items in the hash are sorted, the first item may change position. In the example above, users may point to a different structure after calling HASH_SORT.

A complete example

We’ll repeat all the code and embellish it with a main() function to form a working example.

If this code was placed in a file called example.c in the same directory as uthash.h, it could be compiled and run like this:

cc -o example example.c
./example

Follow the prompts to try the program.

A complete program
#include <stdio.h>   /* gets */
#include <stdlib.h>  /* atoi, malloc */
#include <string.h>  /* strcpy */
#include "uthash.h"

struct my_struct {
    int id;                    /* key */
    char name[10];
    UT_hash_handle hh;         /* makes this structure hashable */
};

struct my_struct *users = NULL;

void add_user(int user_id, 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));
      s->id = user_id;
      HASH_ADD_INT( users, id, s );  /* id: name of key field */
    }
    strcpy(s->name, name);
}

struct my_struct *find_user(int user_id) {
    struct my_struct *s;

    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 */
    free(user);
}

void delete_all() {
  struct my_struct *current_user, *tmp;

  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() {
    struct my_struct *s;

    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 id_sort(struct my_struct *a, 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);
}

int main(int argc, char *argv[]) {
    char in[10];
    int id=1, running=1;
    struct my_struct *s;
    unsigned num_users;

    while (running) {
        printf(" 1. add user\n");
        printf(" 2. add/rename user by id\n");
        printf(" 3. find user\n");
        printf(" 4. delete user\n");
        printf(" 5. delete all users\n");
        printf(" 6. sort items by name\n");
        printf(" 7. sort items by id\n");
        printf(" 8. print users\n");
        printf(" 9. count users\n");
        printf("10. quit\n");
        gets(in);
        switch(atoi(in)) {
            case 1:
                printf("name?\n");
                add_user(id++, gets(in));
                break;
            case 2:
                printf("id?\n");
                gets(in); id = atoi(in);
                printf("name?\n");
                add_user(id, gets(in));
                break;
            case 3:
                printf("id?\n");
                s = find_user(atoi(gets(in)));
                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");
                break;
            case 5:
                delete_all();
                break;
            case 6:
                sort_by_name();
                break;
            case 7:
                sort_by_id();
                break;
            case 8:
                print_users();
                break;
            case 9:
                num_users=HASH_COUNT(users);
                printf("there are %u users\n", num_users);
                break;
            case 10:
                running=0;
                break;
        }
    }

    delete_all();  /* free any structures */
    return 0;
}

This program is included in the distribution in tests/example.c. You can run make example in that directory to compile it easily.

Standard key types

This section goes into specifics of how to work with different kinds of keys. You can use nearly any type of key-- integers, strings, pointers, structures, etc.

Note
A note about float

You can use floating point keys. This comes with the same caveats as with any program that tests floating point equality. In other words, even the tiniest difference in two floating point numbers makes them distinct keys.

Integer keys

The preceding examples demonstrated use of integer keys. To recap, use the convenience macros HASH_ADD_INT and HASH_FIND_INT for structures with integer keys. (The other operations such as HASH_DELETE and HASH_SORT are the same for all types of keys).

String keys

If your structure has a string key, the operations to use depend on whether your structure points to the key (char *) or the string resides within the structure (char a[10]). This distinction is important. As we’ll see below, you need to use HASH_ADD_KEYPTR when your structure points to a key (that is, the key itself is outside of the structure); in contrast, use HASH_ADD_STR for a string key that is contained within your structure.

Note
char[ ] vs. char*

The string is within the structure in the first example below-- name is a char[10] field. In the second example, the key is outside of the structure-- name is a char *. So the first example uses HASH_ADD_STR but the second example uses HASH_ADD_KEYPTR. For information on this macro, see the Macro reference.

String within structure

A string-keyed hash (string within structure)
#include <string.h>  /* strcpy */
#include <stdlib.h>  /* malloc */
#include <stdio.h>   /* printf */
#include "uthash.h"

struct my_struct {
    char name[10];             /* key (string is WITHIN the structure) */
    int id;
    UT_hash_handle hh;         /* makes this structure hashable */
};


int main(int argc, char *argv[]) {
    const char **n, *names[] = { "joe", "bob", "betty", NULL };
    struct my_struct *s, *tmp, *users = NULL;
    int i=0;

    for (n = names; *n != NULL; n++) {
        s = (struct my_struct*)malloc(sizeof(struct my_struct));
        strncpy(s->name, *n,10);
        s->id = i++;
        HASH_ADD_STR( users, name, s );
    }

    HASH_FIND_STR( users, "betty", s);
    if (s) printf("betty's id is %d\n", s->id);

    /* free the hash table contents */
    HASH_ITER(hh, users, s, tmp) {
      HASH_DEL(users, s);
      free(s);
    }
    return 0;
}

This example is included in the distribution in tests/test15.c. It prints:

betty's id is 2

String pointer in structure

Now, here is the same example but using a char * key instead of char [ ]:

A string-keyed hash (structure points to string)
#include <string.h>  /* strcpy */
#include <stdlib.h>  /* malloc */
#include <stdio.h>   /* printf */
#include "uthash.h"

struct my_struct {
    const char *name;          /* key */
    int id;
    UT_hash_handle hh;         /* makes this structure hashable */
};


int main(int argc, char *argv[]) {
    const char **n, *names[] = { "joe", "bob", "betty", NULL };
    struct my_struct *s, *tmp, *users = NULL;
    int i=0;

    for (n = names; *n != NULL; n++) {
        s = (struct my_struct*)malloc(sizeof(struct my_struct));
        s->name = *n;
        s->id = i++;
        HASH_ADD_KEYPTR( hh, users, s->name, strlen(s->name), s );
    }

    HASH_FIND_STR( users, "betty", s);
    if (s) printf("betty's id is %d\n", s->id);

    /* free the hash table contents */
    HASH_ITER(hh, users, s, tmp) {
      HASH_DEL(users, s);
      free(s);
    }
    return 0;
}

This example is included in tests/test40.c.

Pointer keys

Your key can be a pointer. To be very clear, this means the pointer itself can be the key (in contrast, if the thing pointed to is the key, this is a different use case handled by HASH_ADD_KEYPTR).

Here is a simple example where a structure has a pointer member, called key.

A pointer key
#include <stdio.h>
#include <stdlib.h>
#include "uthash.h"

typedef struct {
  void *key;
  int i;
  UT_hash_handle hh;
} el_t;

el_t *hash = NULL;
char *someaddr = NULL;

int main() {
  el_t *d;
  el_t *e = (el_t*)malloc(sizeof(el_t));
  if (!e) return -1;
  e->key = (void*)someaddr;
  e->i = 1;
  HASH_ADD_PTR(hash,key,e);
  HASH_FIND_PTR(hash, &someaddr, d);
  if (d) printf("found\n");

  /* release memory */
  HASH_DEL(hash,e);
  free(e);
  return 0;
}

This example is included in tests/test57.c. Note that the end of the program deletes the element out of the hash, (and since no more elements remain in the hash), uthash releases its internal memory.

Structure keys

Your key field can have any data type. To uthash, it is just a sequence of bytes. Therefore, even a nested structure can be used as a key. We’ll use the general macros HASH_ADD and HASH_FIND to demonstrate.

Note
Structures contain padding (wasted internal space used to fulfill alignment requirements for the members of the structure). These padding bytes must be zeroed before adding an item to the hash or looking up an item. Therefore always zero the whole structure before setting the members of interest. The example below does this-- see the two calls to memset.
A key which is a structure
#include <stdlib.h>
#include <stdio.h>
#include "uthash.h"

typedef struct {
  char a;
  int b;
} record_key_t;

typedef struct {
    record_key_t key;
    /* ... other data ... */
    UT_hash_handle hh;
} record_t;

int main(int argc, char *argv[]) {
    record_t l, *p, *r, *tmp, *records = NULL;

    r = (record_t*)malloc( sizeof(record_t) );
    memset(r, 0, sizeof(record_t));
    r->key.a = 'a';
    r->key.b = 1;
    HASH_ADD(hh, records, key, sizeof(record_key_t), r);

    memset(&l, 0, sizeof(record_t));
    l.key.a = 'a';
    l.key.b = 1;
    HASH_FIND(hh, records, &l.key, sizeof(record_key_t), p);

    if (p) printf("found %c %d\n", p->key.a, p->key.b);

    HASH_ITER(hh, records, p, tmp) {
      HASH_DEL(records, p);
      free(p);
    }
    return 0;
}

This usage is nearly the same as use of a compound key explained below.

Note that the general macros require the name of the UT_hash_handle to be passed as the first argument (here, this is hh). The general macros are documented in Macro Reference.

Advanced Topics

Compound keys

Your key can even comprise multiple contiguous fields.

A multi-field key
#include <stdlib.h>    /* malloc       */
#include <stddef.h>    /* offsetof     */
#include <stdio.h>     /* printf       */
#include <string.h>    /* memset       */
#include "uthash.h"

#define UTF32 1

typedef struct {
  UT_hash_handle hh;
  int len;
  char encoding;      /* these two fields */
  int text[];         /* comprise the key */
} msg_t;

typedef struct {
    char encoding;
    int text[];
} lookup_key_t;

int main(int argc, char *argv[]) {
    unsigned keylen;
    msg_t *msg, *tmp, *msgs = NULL;
    lookup_key_t *lookup_key;

    int beijing[] = {0x5317, 0x4eac};   /* UTF-32LE for 北京 */

    /* allocate and initialize our structure */
    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;
    memcpy(msg->text, beijing, sizeof(beijing));

    /* calculate the key length including padding, using formula */
    keylen =   offsetof(msg_t, text)       /* offset of last key field */
             + sizeof(beijing)             /* size of last key field */
             - offsetof(msg_t, encoding);  /* offset of first key field */

    /* add our structure to the hash table */
    HASH_ADD( hh, msgs, encoding, keylen, msg);

    /* look it up to prove that it worked :-) */
    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 );
    if (msg) printf("found \n");
    free(lookup_key);

    HASH_ITER(hh, msgs, msg, tmp) {
      HASH_DEL(msgs, msg);
      free(msg);
    }
    return 0;
}

This example is included in the distribution in tests/test22.c.

If you use multi-field keys, recognize that the compiler pads adjacent fields (by inserting unused space between them) in order to fulfill the alignment requirement of each field. For example a structure containing a char followed by an int will normally have 3 "wasted" bytes of padding after the char, in order to make the int field start on a multiple-of-4 address (4 is the length of the int).

Calculating the length of a multi-field key:

To determine the key length when using a multi-field key, you must include any intervening structure padding the compiler adds for alignment purposes.

An easy way to calculate the key length is to use the offsetof macro from <stddef.h>. The formula is:

key length =   offsetof(last_key_field)
             + sizeof(last_key_field)
             - offsetof(first_key_field)

In the example above, the keylen variable is set using this formula.

When dealing with a multi-field key, you must zero-fill your structure before HASH_ADD'ing it to a hash table, or using its fields in a HASH_FIND key.

In the previous example, memset is used to initialize the structure by zero-filling it. This zeroes out any padding between the key fields. If we didn’t zero-fill the structure, this padding would contain random values. The random values would lead to HASH_FIND failures; as two "identical" keys will appear to mismatch if there are any differences within their padding.

Multi-level hash tables

A multi-level hash table arises when each element of a hash table contains its own secondary hash table. There can be any number of levels. In a scripting language you might see:

$items{bob}{age}=37

The C program below builds this example in uthash: the hash table is called items. It contains one element (bob) whose own hash table contains one element (age) with value 37. No special functions are necessary to build a multi-level hash table.

While this example represents both levels (bob and age) using the same structure, it would also be fine to use two different structure definitions. It would also be fine if there were three or more levels instead of two.

Multi-level hash table
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "uthash.h"

/* hash of hashes */
typedef struct item {
  char name[10];
  struct item *sub;
  int val;
  UT_hash_handle hh;
} item_t;

item_t *items=NULL;

int main(int argc, char *argvp[]) {
  item_t *item1, *item2, *tmp1, *tmp2;

  /* make initial element */
  item_t *i = malloc(sizeof(*i));
  strcpy(i->name, "bob");
  i->sub = NULL;
  i->val = 0;
  HASH_ADD_STR(items, name, i);

  /* add a sub hash table off this element */
  item_t *s = malloc(sizeof(*s));
  strcpy(s->name, "age");
  s->sub = NULL;
  s->val = 37;
  HASH_ADD_STR(i->sub, name, s);

  /* iterate over hash elements  */
  HASH_ITER(hh, items, item1, tmp1) {
    HASH_ITER(hh, item1->sub, item2, tmp2) {
      printf("$items{%s}{%s} = %d\n", item1->name, item2->name, item2->val);
    }
  }

  /* clean up both hash tables */
  HASH_ITER(hh, items, item1, tmp1) {
    HASH_ITER(hh, item1->sub, item2, tmp2) {
      HASH_DEL(item1->sub, item2);
      free(item2);
    }
    HASH_DEL(items, item1);
    free(item1);
  }

  return 0;
}

The example above is included in tests/test59.c.

Items in several hash tables

A structure can be added to more than one hash table. A few reasons you might do this include:

  • each hash table may use an alternative key;

  • each hash table may have its own sort order;

  • or you might simply use multiple hash tables for grouping purposes. E.g., you could have users in an admin_users and a users hash table.

Your structure needs to have a UT_hash_handle field for each hash table to which it might be added. You can name them anything. E.g.,

UT_hash_handle hh1, hh2;

Items with alternative keys

You might create a hash table keyed on an ID field, and another hash table keyed on username (if usernames are unique). You can add the same user structure to both hash tables (without duplication of the structure), allowing lookup of a user structure by their name or ID. The way to achieve this is to have a separate UT_hash_handle for each hash to which the structure may be added.

A structure with two alternative keys
struct my_struct {
    int id;                    /* usual key */
    char username[10];         /* alternative key */
    UT_hash_handle hh1;        /* handle for first hash table */
    UT_hash_handle hh2;        /* handle for second hash table */
};

In the example above, the structure can now be added to two separate hash tables. In one hash, id is its key, while in the other hash, username is its key. (There is no requirement that the two hashes have different key fields. They could both use the same key, such as id).

Notice the structure has two hash handles (hh1 and hh2). In the code below, notice that each hash handle is used exclusively with a particular hash table. (hh1 is always used with the users_by_id hash, while hh2 is always used with the users_by_name hash table).

Two keys on a structure
    struct my_struct *users_by_id = NULL, *users_by_name = NULL, *s;
    int i;
    char *name;

    s = malloc(sizeof(struct my_struct));
    s->id = 1;
    strcpy(s->username, "thanson");

    /* add the structure to both hash tables */
    HASH_ADD(hh1, users_by_id, id, sizeof(int), s);
    HASH_ADD(hh2, users_by_name, username, strlen(s->username), s);

    /* lookup user by ID in the "users_by_id" hash table */
    i=1;
    HASH_FIND(hh1, users_by_id, &i, sizeof(int), s);
    if (s) printf("found id %d: %s\n", i, s->username);

    /* lookup user by username in the "users_by_name" hash table */
    name = "thanson";
    HASH_FIND(hh2, users_by_name, name, strlen(name), s);
    if (s) printf("found user %s: %d\n", name, s->id);

Several sort orders

It comes as no suprise that two hash tables can have different sort orders, but this fact can also be used advantageously to sort the same items in several ways. This is based on the ability to store a structure in several hash tables.

Extending the previous example, suppose we have many users. We have added each user structure to the users_by_id hash table and the users_by_name hash table. (To reiterate, this is done without the need to have two copies of each structure). Now we can define two sort functions, then use HASH_SRT.

int sort_by_id(struct my_struct *a, struct my_struct *b) {
  if (a->id == b->id) return 0;
  return (a->id < b->id) ? -1 : 1;
}
int sort_by_name(struct my_struct *a, struct my_struct *b) {
  return strcmp(a->username,b->username);
}
HASH_SRT(hh1, users_by_id, sort_by_id);
HASH_SRT(hh2, users_by_name, sort_by_name);

Now iterating over the items in users_by_id will traverse them in id-order while, naturally, iterating over users_by_name will traverse them in name-order. The items are fully forward-and-backward linked in each order. So even for one set of users, we might store them in two hash tables to provide easy iteration in two different sort orders.

Bloom filter (faster misses)

Programs that generate a fair miss rate (HASH_FIND that result in NULL) may benefit from the built-in Bloom filter support. This is disabled by default, because programs that generate only hits would incur a slight penalty from it. Also, programs that do deletes should not use the Bloom filter. While the program would operate correctly, deletes diminish the benefit of the filter. To enable the Bloom filter, simply compile with -DHASH_BLOOM=n like:

-DHASH_BLOOM=27

where the number can be any value up to 32 which determines the amount of memory used by the filter, as shown below. Using more memory makes the filter more accurate and has the potential to speed up your program by making misses bail out faster.

Table 1. Bloom filter sizes for selected values of n
n Bloom filter size (per hash table)

16

8 kilobytes

20

128 kilobytes

24

2 megabytes

28

32 megabytes

32

512 megabytes

Bloom filters are only a performance feature; they do not change the results of hash operations in any way. The only way to gauge whether or not a Bloom filter is right for your program is to test it. Reasonable values for the size of the Bloom filter are 16-32 bits.

Select

An experimental select operation is provided that inserts those items from a source hash that satisfy a given condition into a destination hash. This insertion is done with somewhat more efficiency than if this were using HASH_ADD, namely because the hash function is not recalculated for keys of the selected items. This operation does not remove any items from the source hash. Rather the selected items obtain dual presence in both hashes. The destination hash may already have items in it; the selected items are added to it. In order for a structure to be usable with HASH_SELECT, it must have two or more hash handles. (As described 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 */
typedef struct {
    int id;
    UT_hash_handle hh;  /* handle for users hash */
    UT_hash_handle ah;  /* handle for admins hash */
} user_t;

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);

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 could just as well have used a function.

int is_admin(void *userv) {
  user_t *user = (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.

The two hash handles must differ. An example of using HASH_SELECT is included in tests/test36.c.

Built-in hash functions

Internally, a hash function transforms a key into a bucket number. You don’t have to take any action to use the default hash function, currently Jenkin’s.

Some programs may benefit from using another of the built-in hash functions. There is a simple analysis utility included with uthash to help you determine if another hash function will give you better performance.

You can use a different hash function by compiling your program with -DHASH_FUNCTION=HASH_xyz where xyz is one of the symbolic names listed below. E.g.,

cc -DHASH_FUNCTION=HASH_BER -o program program.c
Table 2. Built-in hash functions
Symbol Name

JEN

Jenkins (default)

BER

Bernstein

SAX

Shift-Add-Xor

OAT

One-at-a-time

FNV

Fowler/Noll/Vo

SFH

Paul Hsieh

MUR

MurmurHash v3 (see note)

Note
MurmurHash

A special symbol must be defined if you intend to use MurmurHash. To use it, add -DHASH_USING_NO_STRICT_ALIASING to your CFLAGS. And, if you are using the gcc compiler with optimization, add -fno-strict-aliasing to your CFLAGS.

Which hash function is best?

You can easily determine the best hash function for your key domain. To do so, you’ll need to run your program once in a data-collection pass, and then run the collected data through an included analysis utility.

First you must build the analysis utility. From the top-level directory,

cd tests/
make

We’ll use test14.c to demonstrate the data-collection and analysis steps (here using sh syntax to redirect file descriptor 3 to a file):

Using keystats
% cc -DHASH_EMIT_KEYS=3 -I../src -o test14 test14.c
% ./test14 3>test14.keys
% ./keystats test14.keys
fcn  ideal%     #items   #buckets  dup%  fl   add_usec  find_usec  del-all usec
---  ------ ---------- ---------- -----  -- ---------- ----------  ------------
SFH   91.6%       1219        256    0%  ok         92        131            25
FNV   90.3%       1219        512    0%  ok        107         97            31
SAX   88.7%       1219        512    0%  ok        111        109            32
OAT   87.2%       1219        256    0%  ok         99        138            26
JEN   86.7%       1219        256    0%  ok         87        130            27
BER   86.2%       1219        256    0%  ok        121        129            27
Note
The number 3 in -DHASH_EMIT_KEYS=3 is a file descriptor. Any file descriptor that your program doesn’t use for its own purposes can be used instead of 3. The data-collection mode enabled by -DHASH_EMIT_KEYS=x should not be used in production code.

Usually, you should just pick the first hash function that is listed. Here, this is SFH. This is the function that provides the most even distribution for your keys. If several have the same ideal%, then choose the fastest one according to the find_usec column.

keystats column reference

fcn

symbolic name of hash function

ideal%

The percentage of items in the hash table which can be looked up within an ideal number of steps. (Further explained below).

#items

the number of keys that were read in from the emitted key file

#buckets

the number of buckets in the hash after all the keys were added

dup%

the percent of duplicate keys encountered in the emitted key file. Duplicates keys are filtered out to maintain key uniqueness. (Duplicates are normal. For example, if the application adds an item to a hash, deletes it, then re-adds it, the key is written twice to the emitted file.)

flags

this is either ok, or nx (noexpand) if the expansion inhibited flag is set, described in Expansion internals. It is not recommended to use a hash function that has the noexpand flag set.

add_usec

the clock time in microseconds required to add all the keys to a hash

find_usec

the clock time in microseconds required to look up every key in the hash

del-all usec

the clock time in microseconds required to delete every item in the hash

ideal%

What is ideal%?

The n items in a hash are distributed into k buckets. Ideally each bucket would contain an equal share (n/k) of the items. In other words, the maximum linear position of any item in a bucket chain would be n/k if every bucket is equally used. If some buckets are overused and others are underused, the overused buckets will contain items whose linear position surpasses n/k. Such items are considered non-ideal.

As you might guess, ideal% is the percentage of ideal items in the hash. These items have favorable linear positions in their bucket chains. As ideal% approaches 100%, the hash table approaches constant-time lookup performance.

hashscan

Note
This utility is only available on Linux, and on FreeBSD (8.1 and up).

A utility called hashscan is included in the tests/ directory. It is built automatically when you run make in that directory. This tool examines a running process and reports on the uthash tables that it finds in that program’s memory. It can also save the keys from each table in a format that can be fed into keystats.

Here is an example of using hashscan. First ensure that it is built:

cd tests/
make

Since hashscan needs a running program to inspect, we’ll start up a simple program that makes a hash table and then sleeps as our test subject:

./test_sleep &
pid: 9711

Now that we have a test program, let’s run hashscan on it:

./hashscan 9711
Address            ideal    items  buckets mc fl bloom/sat fcn keys saved to
------------------ ----- -------- -------- -- -- --------- --- -------------
0x862e038            81%    10000     4096 11 ok 16    14% JEN

If we wanted to copy out all its keys for external analysis using keystats, add the -k flag:

./hashscan -k 9711
Address            ideal    items  buckets mc fl bloom/sat fcn keys saved to
------------------ ----- -------- -------- -- -- --------- --- -------------
0x862e038            81%    10000     4096 11 ok 16    14% JEN /tmp/9711-0.key

Now we could run ./keystats /tmp/9711-0.key to analyze which hash function has the best characteristics on this set of keys.

hashscan column reference

Address

virtual address of the hash table

ideal

The percentage of items in the table which can be looked up within an ideal number of steps. See [ideal] in the keystats section.

items

number of items in the hash table

buckets

number of buckets in the hash table

mc

the maximum chain length found in the hash table (uthash usually tries to keep fewer than 10 items in each bucket, or in some cases a multiple of 10)

fl

flags (either ok, or NX if the expansion-inhibited flag is set)

bloom/sat

if the hash table uses a Bloom filter, this is the size (as a power of two) of the filter (e.g. 16 means the filter is 2^16 bits in size). The second number is the "saturation" of the bits expressed as a percentage. The lower the percentage, the more potential benefit to identify cache misses quickly.

fcn

symbolic name of hash function

keys saved to

file to which keys were saved, if any

How hashscan works

When hashscan runs, it attaches itself to the target process, which suspends the target process momentarily. During this brief suspension, it scans the target’s virtual memory for the signature of a uthash hash table. It then checks if a valid hash table structure accompanies the signature and reports what it finds. When it detaches, the target process resumes running normally. The hashscan is performed "read-only"-- the target process is not modified. Since hashscan is analyzing a momentary snapshot of a running process, it may return different results from one run to another.

Expansion internals

Internally this hash manages the number of buckets, with the goal of having enough buckets so that each one contains only a small number of items.

Why does the number of buckets matter?

When looking up an item by its key, this hash scans linearly through the items in the appropriate bucket. In order for the linear scan to run in constant time, the number of items in each bucket must be bounded. This is accomplished by increasing the number of buckets as needed.

Normal expansion

This hash attempts to keep fewer than 10 items in each bucket. When an item is added that would cause a bucket to exceed this number, the number of buckets in the hash is doubled and the items are redistributed into the new buckets. In an ideal world, each bucket will then contain half as many items as it did before.

Bucket expansion occurs automatically and invisibly as needed. There is no need for the application to know when it occurs.

Per-bucket expansion threshold

Normally all buckets share the same threshold (10 items) at which point bucket expansion is triggered. During the process of bucket expansion, uthash can adjust this expansion-trigger threshold on a per-bucket basis if it sees that certain buckets are over-utilized.

When this threshold is adjusted, it goes from 10 to a multiple of 10 (for that particular bucket). The multiple is based on how many times greater the actual chain length is than the ideal length. It is a practical measure to reduce excess bucket expansion in the case where a hash function over-utilizes a few buckets but has good overall distribution. However, if the overall distribution gets too bad, uthash changes tactics.

Inhibited expansion

You usually don’t need to know or worry about this, particularly if you used the keystats utility during development to select a good hash for your keys.

A hash function may yield an uneven distribution of items across the buckets. In moderation this is not a problem. Normal bucket expansion takes place as the chain lengths grow. But when significant imbalance occurs (because the hash function is not well suited to the key domain), bucket expansion may be 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 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 inhibits expansion for that hash table. Once set, the bucket expansion inhibited flag remains in effect as long as the hash has items in it. Inhibited expansion may cause HASH_FIND to exhibit worse than constant-time performance.

Hooks

You don’t need to use these hooks- they are only here if you want to modify the behavior of uthash. Hooks can be used to change how uthash allocates memory, and to run code in response to certain internal events.

malloc/free

By default this hash implementation uses malloc and free to manage memory. If your application uses its own custom allocator, this hash can use them too.

Specifying alternate memory management functions
#include "uthash.h"

/* undefine the defaults */
#undef uthash_malloc
#undef uthash_free

/* re-define, specifying alternate functions */
#define uthash_malloc(sz) my_malloc(sz)
#define uthash_free(ptr,sz) my_free(ptr)

...

Notice that uthash_free receives two parameters. The sz parameter is for convenience on embedded platforms that manage their own memory.

Out of memory

If memory allocation fails (i.e., the malloc function returned NULL), the default behavior is to terminate the process by calling exit(-1). This can be modified by re-defining the uthash_fatal macro.

#undef uthash_fatal
#define uthash_fatal(msg) my_fatal_function(msg);

The fatal function should terminate the process or longjmp back to a safe place. Uthash does not support "returning a failure" if memory cannot be allocated.

Internal events

There is no need for the application to set these hooks or take action in response to these events. They are mainly for diagnostic purposes.

These two hooks are "notification" hooks which get executed if uthash is expanding buckets, or setting the bucket expansion inhibited flag. Normally both of these hooks are undefined and thus compile away to nothing.

Expansion

There is a hook for the bucket expansion event.

Bucket expansion hook
#include "uthash.h"

#undef uthash_expand_fyi
#define uthash_expand_fyi(tbl) printf("expanded to %d buckets\n", tbl->num_buckets)

...
Expansion-inhibition

This hook can be defined to code to execute in the event that uthash decides to set the bucket expansion inhibited flag.

Bucket expansion inhibited hook
#include "uthash.h"

#undef uthash_noexpand_fyi
#define uthash_noexpand_fyi printf("warning: bucket expansion inhibited\n");

...

Debug mode

If a program that uses this hash is compiled with -DHASH_DEBUG=1, a special internal consistency-checking mode is activated. In this mode, the integrity of the whole hash is checked following every add or delete operation. This is for debugging the uthash software only, not for use in production code.

In the tests/ directory, running make debug will run all the tests in this mode.

In this mode, any internal errors in the hash data structure will cause a message to be printed to stderr and the program to exit.

The UT_hash_handle data structure includes next, prev, hh_next and hh_prev fields. The former two fields determine the "application" ordering (that is, insertion order-- the order the items were added). The latter two fields determine the "bucket chain" order. These link the UT_hash_handles together in a doubly-linked list that is a bucket chain.

Checks performed in -DHASH_DEBUG=1 mode:

  • the hash is walked in its entirety twice: once in bucket order and a second time in application order

  • the total number of items encountered in both walks is checked against the stored number

  • during the walk in bucket order, each item’s hh_prev pointer is compared for equality with the last visited item

  • during the walk in application order, each item’s prev pointer is compared for equality with the last visited item

Macro debugging:

Sometimes it’s difficult to interpret a compiler warning on a line which contains a macro call. In the case of uthash, one macro can expand to dozens of lines. In this case, it is helpful to expand the macros and then recompile. By doing so, the warning message will refer to the exact line within the macro.

Here is an example of how to expand the macros and then recompile. This uses the test1.c program in the tests/ subdirectory.

gcc -E -I../src test1.c > /tmp/a.c
egrep -v '^#' /tmp/a.c > /tmp/b.c
indent /tmp/b.c
gcc -o /tmp/b /tmp/b.c

The last line compiles the original program (test1.c) with all macros expanded. If there was a warning, the referenced line number can be checked in /tmp/b.c.

Thread safety

You can use uthash in a threaded program. But you must do the locking. Use a read-write lock to protect against concurrent writes. It is ok to have 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");

Then, readers must acquire the read lock before doing any HASH_FIND calls or before iterating over the hash elements:

if (pthread_rwlock_rdlock(&lock) != 0) fatal("can't get rdlock");
HASH_FIND_INT(elts, &i, e);
pthread_rwlock_unlock(&lock);

Writers must acquire the exclusive write lock before doing any update. Add, delete, and sort are all updates that must be locked.

if (pthread_rwlock_wrlock(&lock) != 0) fatal("can't get wrlock");
HASH_DEL(elts, e);
pthread_rwlock_unlock(&lock);

If you prefer, you can use a mutex instead of a read-write lock, but this will reduce reader concurrency to a single thread at a time.

An example program using uthash with a read-write lock is included in tests/threads/test1.c.

Macro reference

Convenience macros

The convenience macros do the same thing as the generalized macros, but require fewer arguments.

In order to use the convenience macros,

  1. the structure’s UT_hash_handle field must be named hh, and

  2. for add or find, the key field must be of type int or char[] or pointer

Table 3. Convenience macros
macro arguments

HASH_ADD_INT

(head, keyfield_name, item_ptr)

HASH_REPLACE_INT

(head, keyfiled_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_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)

HASH_FIND_PTR

(head, key_ptr, item_ptr)

HASH_DEL

(head, item_ptr)

HASH_SORT

(head, cmp)

HASH_COUNT

(head)

General macros

These macros add, find, delete and sort the items in a hash. You need to use the general macros if your UT_hash_handle is named something other than hh, or if your key’s data type isn’t int or char[].

Table 4. General macros
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)

Note
HASH_ADD_KEYPTR is used when the structure contains a pointer to the key, rather than the key itself.

Argument descriptions

hh_name

name of the UT_hash_handle field in the structure. Conventionally called hh.

head

the structure pointer variable which acts as the "head" of the hash. So named because it initially points to the first item that is added to the hash.

keyfield_name

the name of the key field in the structure. (In the case of a multi-field key, this is the first field of the key). If you’re new to macros, it might seem strange to pass the name of a field as a parameter. See note.

key_len

the length of the key field in bytes. E.g. for an integer key, this is sizeof(int), while for a string key it’s strlen(key). (For a multi-field key, see the notes in this guide on calculating key length).

key_ptr

for HASH_FIND, this is a pointer to the key to look up in the hash (since it’s a pointer, you can’t directly pass a literal value here). For HASH_ADD_KEYPTR, this is the address of the key of the item being added.

item_ptr

pointer to the structure being added, deleted, or looked up, or the current pointer during iteration. This is an input parameter for HASH_ADD and HASH_DELETE macros, and an output parameter for HASH_FIND and HASH_ITER. (When using HASH_ITER to iterate, tmp_item_ptr is another variable of the same type as item_ptr, used internally).

replaced_item_ptr

used in HASH_REPLACE macros. This is an output parameter that is set to point to the replaced item (if no item is replaced it is set to NULL).

cmp

pointer to comparison function which accepts two arguments (pointers to items to compare) and returns an int specifying whether the first item should sort before, equal to, or after the second item (like strcmp).

condition

a function or macro which accepts a single argument-- a void pointer to a structure, which needs to be cast to the appropriate structure type. The function or macro should return (or evaluate to) a non-zero value if the structure should be "selected" for addition to the destination hash.


uthash-1.9.9.1+git20151125/doc/userguide.txt000066400000000000000000002025721264051566200201060ustar00rootroot00000000000000uthash User Guide ================= Troy D. Hanson v1.9.9, November 2014 NOTE: As of 2015 uthash is unmaintained software. To download uthash, follow this link back to the https://github.com/troydhanson/uthash[GitHub project page]. A hash in C ----------- This document is written for C programmers. Since you're reading this, chances are that you know a hash is used for looking up items using a key. In scripting languages, hashes or "dictionaries" are used all the time. In C, hashes don't exist in the language itself. This software provides a hash table for C structures. What can it do? ~~~~~~~~~~~~~~~~~ This software supports these operations on items in a hash table: 1. add/replace 2. find 3. delete 4. count 5. iterate 6. sort Is it fast? ~~~~~~~~~~~ Add, find and delete are normally constant-time operations. This is influenced by your key domain and the hash function. This hash aims to be minimalistic and efficient. It's around 900 lines of C. It inlines automatically because it's implemented as macros. It's fast as long as the hash function is suited to your keys. You can use the default hash function, or easily compare performance and choose from among several other <>. Is it a library? ~~~~~~~~~~~~~~~~ No, it's just a single header file: `uthash.h`. All you need to do is copy the header file into your project, and: #include "uthash.h" Since uthash is a header file only, there is no library code to link against. C/C++ and platforms ~~~~~~~~~~~~~~~~~~~ This software can be used in C and C++ programs. It has been tested on: * Linux * Mac OS X * Windows using Visual Studio 2008 and 2010 * Solaris * OpenBSD * FreeBSD Windows users: as of 2014 it's been a few years since I had the environment to test uthash under Visual Studio. Test suite ^^^^^^^^^^ To run the test suite, enter the `tests` directory. Then, * on Unix platforms, run `make` * on Windows, run the "do_tests_win32.cmd" batch file. (You may edit the batch file if your Visual Studio is installed in a non-standard location). BSD licensed ~~~~~~~~~~~~ This software is made available under the link:license.html[revised BSD license]. It is free and open source. Download uthash ~~~~~~~~~~~~~~~ Follow the links on https://github.com/troydhanson/uthash to clone uthash or get a zip file. Getting help ~~~~~~~~~~~~ Please use the https://groups.google.com/d/forum/uthash[uthash Google Group] to ask questions. You can email it at uthash@googlegroups.com. Please do not contact me directly. I can no longer answer any uthash questions or fix any bugs. Contributing ~~~~~~~~~~~~ You are welcome to fork uthash and make changes in your own repo. I have stopped maintaining uthash as of 2015. Extras included ~~~~~~~~~~~~~~~ Three "extras" come with uthash. These provide lists, dynamic arrays and strings: * link:utlist.html[utlist.h] provides linked list macros for C structures. * link:utarray.html[utarray.h] implements dynamic arrays using macros. * link:utstring.html[utstring.h] implements a basic dynamic string. History ~~~~~~~ I wrote uthash in 2004-2006 for my own purposes. Originally it was hosted on SourceForge. Uthash was downloaded around 30,000 times between 2006-2013 then transitioned to GitHub. It's been incorporated into commercial software, academic research, and into other open-source software. It has also been added to the native package repositories for a number of Unix-y distros. When uthash was written, there were fewer options for doing generic hash tables in C than exist today. There are faster hash tables, more memory-efficient hash tables, with very different API's today. But, like driving a minivan, uthash is convenient, and gets the job done for many purposes. As of 2015 I have stopped maintaining uthash altogether. Your structure -------------- In uthash, a hash table is comprised of structures. Each structure represents a key-value association. One or more of the structure fields constitute the key. The structure pointer itself is the value. .Defining a structure that can be hashed ---------------------------------------------------------------------- #include "uthash.h" struct my_struct { int id; /* key */ char name[10]; UT_hash_handle hh; /* makes this structure hashable */ }; ---------------------------------------------------------------------- Note that, in uthash, your structure will never be moved or copied into another location when you add it into a hash table. This means that you can keep other data structures that safely point to your structure-- regardless of whether you add or delete it from a hash table during your program's lifetime. The key ~~~~~~~ There are no restrictions on the data type or name of the key field. The key can also comprise multiple contiguous fields, having any names and data types. .Any data type... really? ***************************************************************************** Yes, your key and structure can have any data type. Unlike function calls with fixed prototypes, uthash consists of macros-- whose arguments are untyped-- and thus able to work with any type of structure or key. ***************************************************************************** Unique keys ^^^^^^^^^^^ As with any hash, every item must have a unique key. Your application must enforce key uniqueness. Before you add an item to the hash table, you must first know (if in doubt, check!) that the key is not already in use. You can check whether a key already exists in the hash table using `HASH_FIND`. The hash handle ~~~~~~~~~~~~~~~ The `UT_hash_handle` field must be present in your structure. It is used for the internal bookkeeping that makes the hash work. It does not require initialization. It can be named anything, but you can simplify matters by naming it `hh`. This allows you to use the easier "convenience" macros to add, find and delete items. A word about memory ~~~~~~~~~~~~~~~~~~~ Overhead ^^^^^^^^ The hash handle consumes about 32 bytes per item on a 32-bit system, or 56 bytes per item on a 64-bit system. The other overhead costs-- the buckets and the table-- are negligible in comparison. You can use `HASH_OVERHEAD` to get the overhead size, in bytes, for a hash table. See <>. How clean up occurs ^^^^^^^^^^^^^^^^^^^ Some have asked how uthash cleans up its internal memory. The answer is simple: 'when you delete the final item' from a hash table, uthash releases all the internal memory associated with that hash table, and sets its pointer to NULL. Hash operations --------------- This section introduces the uthash macros by example. For a more succinct listing, see <>. .Convenience vs. general macros: ***************************************************************************** The uthash macros fall into two categories. The 'convenience' macros can be used with integer, pointer or string keys (and require that you chose the conventional name `hh` for the `UT_hash_handle` field). The convenience macros take fewer arguments than the general macros, making their usage a bit simpler for these common types of keys. The 'general' macros can be used for any types of keys, or for multi-field keys, or when the `UT_hash_handle` has been named something other than `hh`. These macros take more arguments and offer greater flexibility in return. But if the convenience macros suit your needs, use them-- your code will be more readable. ***************************************************************************** Declare the hash ~~~~~~~~~~~~~~~~ Your hash must be declared as a `NULL`-initialized pointer to your structure. struct my_struct *users = NULL; /* important! initialize to NULL */ Add item ~~~~~~~~ Allocate and initialize your structure as you see fit. The only aspect of this that matters to uthash is that your key must be initialized to a unique value. Then call `HASH_ADD`. (Here we use the convenience macro `HASH_ADD_INT`, which offers simplified usage for keys of type `int`). .Add an item to a hash ---------------------------------------------------------------------- void add_user(int user_id, char *name) { struct my_struct *s; s = malloc(sizeof(struct my_struct)); s->id = user_id; strcpy(s->name, name); HASH_ADD_INT( users, id, s ); /* id: name of key field */ } ---------------------------------------------------------------------- The first parameter to `HASH_ADD_INT` is the hash table, and the 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? ******************************************************************************* 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 worry- the C preprocessor expands this to valid C code. ******************************************************************************* Key must not be modified while in-use ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Once a structure has been added to the hash, do not change the value of its key. Instead, delete the item from the hash, change the key, and then re-add it. Checking uniquness ^^^^^^^^^^^^^^^^^^ In the example above, we didn't check to see if `user_id` was already a key of some existing item in the hash. *If there's any chance that duplicate keys could be generated by your program, you must explicitly check the uniqueness* before adding the key to the hash. If the key is already in the hash, you can simply modify the existing structure in the hash rather than adding the item. 'It is an error to add two items with the same key to the hash table'. Let's rewrite the `add_user` function to check whether the id is in the hash. Only if the id is not present in the hash, do we create the item and add it. Otherwise we just modify the structure that already exists. void add_user(int user_id, 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)); s->id = user_id; HASH_ADD_INT( users, id, s ); /* id: name of key field */ } strcpy(s->name, name); } Why doesn't uthash check key uniqueness for you? It saves the cost of a hash lookup for those programs which don't need it- for example, programs whose keys are generated by an incrementing, non-repeating counter. However, if replacement is a common operation, it is possible to use the `HASH_REPLACE` macro. This macro, before adding the item, will try to find an item with the same key and delete it first. It also returns a pointer to the replaced item, so the user has a chance to de-allocate its memory. Passing the hash pointer into functions ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ In the example above `users` is a global variable, but what if the caller wanted to pass the hash pointer 'into' the `add_user` function? At first glance it would appear that you could simply pass `users` as an argument, but that won't work right. /* bad */ void add_user(struct my_struct *users, int user_id, char *name) { ... HASH_ADD_INT( users, id, s ); } 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 ); } Note that we dereferenced the pointer in the `HASH_ADD` also. The reason it's necessary to deal with a pointer to the hash pointer is simple: the hash macros modify it (in other words, they modify the 'pointer itself' not just what it points to). Replace item ~~~~~~~~~~~~ `HASH_REPLACE` macros are equivalent to HASH_ADD macros except they attempt to find and delete the item first. If it finds and deletes an item, it will also return that items pointer as an output parameter. Find item ~~~~~~~~~ To look up a structure in a hash, you need its key. Then call `HASH_FIND`. (Here we use the convenience macro `HASH_FIND_INT` for keys of type `int`). .Find a structure using its key ---------------------------------------------------------------------- struct my_struct *find_user(int user_id) { struct my_struct *s; HASH_FIND_INT( users, &user_id, s ); /* s: output pointer */ return s; } ---------------------------------------------------------------------- Here, the hash table is `users`, and `&user_id` points to the key (an integer in this case). Last, `s` is the 'output' variable of `HASH_FIND_INT`. The final result is that `s` points to the structure with the given key, or is `NULL` if the key wasn't found in the hash. [NOTE] The middle argument is a 'pointer' to the key. You can't pass a literal key value to `HASH_FIND`. Instead assign the literal value to a variable, and pass a pointer to the variable. Delete item ~~~~~~~~~~~ To delete a structure from a hash, you must have a pointer to it. (If you only have the key, first do a `HASH_FIND` to get the structure pointer). .Delete an item from a hash ---------------------------------------------------------------------- void delete_user(struct my_struct *user) { HASH_DEL( users, user); /* user: pointer to deletee */ free(user); /* optional; it's up to you! */ } ---------------------------------------------------------------------- Here again, `users` is the hash table, and `user` is a pointer to the structure we want to remove from the hash. uthash never frees your structure ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Deleting a structure just removes it from the hash table-- it doesn't `free` it. The choice of when to free your structure is entirely up to you; uthash will never free your structure. For example when using `HASH_REPLACE` macros, a replaced output argument is returned back, in order to make it possible for the user to de-allocate it. Delete can change the pointer ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The hash table pointer (which initially points to the first item added to the hash) can change in response to `HASH_DEL` (i.e. if you delete the first item in the hash table). Iterative deletion ^^^^^^^^^^^^^^^^^^ The `HASH_ITER` macro is a deletion-safe iteration construct which expands to a simple 'for' loop. .Delete all items from a hash ---------------------------------------------------------------------- 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 */ } } ---------------------------------------------------------------------- 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); Afterward, the list head (here, `users`) will be set to `NULL`. Count items ~~~~~~~~~~~ The number of items in the hash table can be obtained using `HASH_COUNT`: .Count of items in the hash table ---------------------------------------------------------------------- unsigned int num_users; num_users = HASH_COUNT(users); printf("there are %u users\n", num_users); ---------------------------------------------------------------------- Incidentally, this works even the list (`users`, here) is `NULL`, in which case the count is 0. Iterating and sorting ~~~~~~~~~~~~~~~~~~~~~ You can loop over the items in the hash by starting from the beginning and following the `hh.next` pointer. .Iterating over all the items in a hash ---------------------------------------------------------------------- void print_users() { struct my_struct *s; for(s=users; s != NULL; s=s->hh.next) { printf("user id %d: name %s\n", s->id, s->name); } } ---------------------------------------------------------------------- There is also an `hh.prev` pointer you could use to iterate backwards through the hash, starting from any known item. [[deletesafe]] 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). 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 `for`-loop header. Here is how it could be used to rewrite the last example: struct my_struct *s, *tmp; HASH_ITER(hh, users, s, tmp) { printf("user id %d: name %s\n", s->id, s->name); /* ... it is safe to delete and free s here */ } .A hash is also a doubly-linked list. ******************************************************************************* Iterating backward and forward through the items in the hash is possible because of the `hh.prev` and `hh.next` fields. All the items in the hash can be reached by repeatedly following these pointers, thus the hash is also a 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`. 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 ); 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 less than zero, zero, or greater than zero, if the first item sorts before, equal to, or after the second item, respectively. (This is the same convention used by `strcmp` or `qsort` in the standard C library). int sort_function(void *a, void *b) { /* compare a to b (cast a and b appropriately) * return (int) -1 if (a < b) * return (int) 0 if (a == b) * return (int) 1 if (a > b) */ } 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 id_sort(struct my_struct *a, 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); } ---------------------------------------------------------------------- When the items in the hash are sorted, the first item may change position. In the example above, `users` may point to a different structure after calling `HASH_SORT`. A complete example ~~~~~~~~~~~~~~~~~~ We'll repeat all the code and embellish it with a `main()` function to form a working example. If this code was placed in a file called `example.c` in the same directory as `uthash.h`, it could be compiled and run like this: cc -o example example.c ./example Follow the prompts to try the program. .A complete program ---------------------------------------------------------------------- #include /* gets */ #include /* atoi, malloc */ #include /* strcpy */ #include "uthash.h" struct my_struct { int id; /* key */ char name[10]; UT_hash_handle hh; /* makes this structure hashable */ }; struct my_struct *users = NULL; void add_user(int user_id, 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)); s->id = user_id; HASH_ADD_INT( users, id, s ); /* id: name of key field */ } strcpy(s->name, name); } struct my_struct *find_user(int user_id) { struct my_struct *s; 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 */ free(user); } void delete_all() { struct my_struct *current_user, *tmp; 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() { struct my_struct *s; 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 id_sort(struct my_struct *a, 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); } int main(int argc, char *argv[]) { char in[10]; int id=1, running=1; struct my_struct *s; unsigned num_users; while (running) { printf(" 1. add user\n"); printf(" 2. add/rename user by id\n"); printf(" 3. find user\n"); printf(" 4. delete user\n"); printf(" 5. delete all users\n"); printf(" 6. sort items by name\n"); printf(" 7. sort items by id\n"); printf(" 8. print users\n"); printf(" 9. count users\n"); printf("10. quit\n"); gets(in); switch(atoi(in)) { case 1: printf("name?\n"); add_user(id++, gets(in)); break; case 2: printf("id?\n"); gets(in); id = atoi(in); printf("name?\n"); add_user(id, gets(in)); break; case 3: printf("id?\n"); s = find_user(atoi(gets(in))); 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"); break; case 5: delete_all(); break; case 6: sort_by_name(); break; case 7: sort_by_id(); break; case 8: print_users(); break; case 9: num_users=HASH_COUNT(users); printf("there are %u users\n", num_users); break; case 10: running=0; break; } } delete_all(); /* free any structures */ return 0; } ---------------------------------------------------------------------- This program is included in the distribution in `tests/example.c`. You can run `make example` in that directory to compile it easily. Standard key types ------------------ This section goes into specifics of how to work with different kinds of keys. You can use nearly any type of key-- integers, strings, pointers, structures, etc. [NOTE] .A note about float ================================================================================ You can use floating point keys. This comes with the same caveats as with any program that tests floating point equality. In other words, even the tiniest difference in two floating point numbers makes them distinct keys. ================================================================================ Integer keys ~~~~~~~~~~~~ The preceding examples demonstrated use of integer keys. To recap, use the convenience macros `HASH_ADD_INT` and `HASH_FIND_INT` for structures with integer keys. (The other operations such as `HASH_DELETE` and `HASH_SORT` are the same for all types of keys). String keys ~~~~~~~~~~~ If your structure has a string key, the operations to use depend on whether your structure 'points to' the key (`char *`) or the string resides `within` the structure (`char a[10]`). *This distinction is important*. As we'll see below, you need to use `HASH_ADD_KEYPTR` when your structure 'points' to a key (that is, the key itself is 'outside' of the structure); in contrast, use `HASH_ADD_STR` for a string key that is contained *within* your structure. [NOTE] .char[ ] vs. char* ================================================================================ The string is 'within' the structure in the first example below-- `name` is a `char[10]` field. In the second example, the key is 'outside' of the structure-- `name` is a `char *`. So the first example uses `HASH_ADD_STR` but the second example uses `HASH_ADD_KEYPTR`. For information on this macro, see the <>. ================================================================================ String 'within' structure ^^^^^^^^^^^^^^^^^^^^^^^^^ .A string-keyed hash (string within structure) ---------------------------------------------------------------------- #include /* strcpy */ #include /* malloc */ #include /* printf */ #include "uthash.h" struct my_struct { char name[10]; /* key (string is WITHIN the structure) */ int id; UT_hash_handle hh; /* makes this structure hashable */ }; int main(int argc, char *argv[]) { const char **n, *names[] = { "joe", "bob", "betty", NULL }; struct my_struct *s, *tmp, *users = NULL; int i=0; for (n = names; *n != NULL; n++) { s = (struct my_struct*)malloc(sizeof(struct my_struct)); strncpy(s->name, *n,10); s->id = i++; HASH_ADD_STR( users, name, s ); } HASH_FIND_STR( users, "betty", s); if (s) printf("betty's id is %d\n", s->id); /* free the hash table contents */ HASH_ITER(hh, users, s, tmp) { HASH_DEL(users, s); free(s); } return 0; } ---------------------------------------------------------------------- This example is included in the distribution in `tests/test15.c`. It prints: betty's id is 2 String 'pointer' in structure ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Now, here is the same example but using a `char *` key instead of `char [ ]`: .A string-keyed hash (structure points to string) ---------------------------------------------------------------------- #include /* strcpy */ #include /* malloc */ #include /* printf */ #include "uthash.h" struct my_struct { const char *name; /* key */ int id; UT_hash_handle hh; /* makes this structure hashable */ }; int main(int argc, char *argv[]) { const char **n, *names[] = { "joe", "bob", "betty", NULL }; struct my_struct *s, *tmp, *users = NULL; int i=0; for (n = names; *n != NULL; n++) { s = (struct my_struct*)malloc(sizeof(struct my_struct)); s->name = *n; s->id = i++; HASH_ADD_KEYPTR( hh, users, s->name, strlen(s->name), s ); } HASH_FIND_STR( users, "betty", s); if (s) printf("betty's id is %d\n", s->id); /* free the hash table contents */ HASH_ITER(hh, users, s, tmp) { HASH_DEL(users, s); free(s); } return 0; } ---------------------------------------------------------------------- This example is included in `tests/test40.c`. Pointer keys ~~~~~~~~~~~~ Your key can be a pointer. To be very clear, this means the 'pointer itself' can be the key (in contrast, if the thing 'pointed to' is the key, this is a different use case handled by `HASH_ADD_KEYPTR`). Here is a simple example where a structure has a pointer member, called `key`. .A pointer key ---------------------------------------------------------------------- #include #include #include "uthash.h" typedef struct { void *key; int i; UT_hash_handle hh; } el_t; el_t *hash = NULL; char *someaddr = NULL; int main() { el_t *d; el_t *e = (el_t*)malloc(sizeof(el_t)); if (!e) return -1; e->key = (void*)someaddr; e->i = 1; HASH_ADD_PTR(hash,key,e); HASH_FIND_PTR(hash, &someaddr, d); if (d) printf("found\n"); /* release memory */ HASH_DEL(hash,e); free(e); return 0; } ---------------------------------------------------------------------- This example is included in `tests/test57.c`. Note that the end of the program deletes the element out of the hash, (and since no more elements remain in the hash), uthash releases its internal memory. Structure keys ~~~~~~~~~~~~~~ Your key field can have any data type. To uthash, it is just a sequence of bytes. Therefore, even a nested structure can be used as a key. We'll use the general macros `HASH_ADD` and `HASH_FIND` to demonstrate. NOTE: Structures contain padding (wasted internal space used to fulfill alignment requirements for the members of the structure). These padding bytes 'must be zeroed' before adding an item to the hash or looking up an item. Therefore always zero the whole structure before setting the members of interest. The example below does this-- see the two calls to `memset`. .A key which is a structure ---------------------------------------------------------------------- #include #include #include "uthash.h" typedef struct { char a; int b; } record_key_t; typedef struct { record_key_t key; /* ... other data ... */ UT_hash_handle hh; } record_t; int main(int argc, char *argv[]) { record_t l, *p, *r, *tmp, *records = NULL; r = (record_t*)malloc( sizeof(record_t) ); memset(r, 0, sizeof(record_t)); r->key.a = 'a'; r->key.b = 1; HASH_ADD(hh, records, key, sizeof(record_key_t), r); memset(&l, 0, sizeof(record_t)); l.key.a = 'a'; l.key.b = 1; HASH_FIND(hh, records, &l.key, sizeof(record_key_t), p); if (p) printf("found %c %d\n", p->key.a, p->key.b); HASH_ITER(hh, records, p, tmp) { HASH_DEL(records, p); free(p); } return 0; } ---------------------------------------------------------------------- This usage is nearly the same as use of a compound key explained below. Note that the general macros require the name of the `UT_hash_handle` to be passed as the first argument (here, this is `hh`). The general macros are documented in <>. Advanced Topics --------------- Compound keys ~~~~~~~~~~~~~ Your key can even comprise multiple contiguous fields. .A multi-field key ---------------------------------------------------------------------- #include /* malloc */ #include /* offsetof */ #include /* printf */ #include /* memset */ #include "uthash.h" #define UTF32 1 typedef struct { UT_hash_handle hh; int len; char encoding; /* these two fields */ int text[]; /* comprise the key */ } msg_t; typedef struct { char encoding; int text[]; } lookup_key_t; int main(int argc, char *argv[]) { unsigned keylen; msg_t *msg, *tmp, *msgs = NULL; lookup_key_t *lookup_key; int beijing[] = {0x5317, 0x4eac}; /* UTF-32LE for 北京 */ /* allocate and initialize our structure */ 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; memcpy(msg->text, beijing, sizeof(beijing)); /* calculate the key length including padding, using formula */ keylen = offsetof(msg_t, text) /* offset of last key field */ + sizeof(beijing) /* size of last key field */ - offsetof(msg_t, encoding); /* offset of first key field */ /* add our structure to the hash table */ HASH_ADD( hh, msgs, encoding, keylen, msg); /* look it up to prove that it worked :-) */ 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 ); if (msg) printf("found \n"); free(lookup_key); HASH_ITER(hh, msgs, msg, tmp) { HASH_DEL(msgs, msg); free(msg); } return 0; } ---------------------------------------------------------------------- This example is included in the distribution in `tests/test22.c`. If you use multi-field keys, recognize that the compiler pads adjacent fields (by inserting unused space between them) in order to fulfill the alignment requirement of each field. For example a structure containing a `char` followed by an `int` will normally have 3 "wasted" bytes of padding after the char, in order to make the `int` field start on a multiple-of-4 address (4 is the length of the int). .Calculating the length of a multi-field key: ******************************************************************************* To determine the key length when using a multi-field key, you must include any intervening structure padding the compiler adds for alignment purposes. An easy way to calculate the key length is to use the `offsetof` macro from ``. The formula is: key length = offsetof(last_key_field) + sizeof(last_key_field) - offsetof(first_key_field) In the example above, the `keylen` variable is set using this formula. ******************************************************************************* When dealing with a multi-field key, you must zero-fill your structure before `HASH_ADD`'ing it to a hash table, or using its fields in a `HASH_FIND` key. In the previous example, `memset` is used to initialize the structure by zero-filling it. This zeroes out any padding between the key fields. If we didn't zero-fill the structure, this padding would contain random values. The random values would lead to `HASH_FIND` failures; as two "identical" keys will appear to mismatch if there are any differences within their padding. [[multilevel]] Multi-level hash tables ~~~~~~~~~~~~~~~~~~~~~~~ A multi-level hash table arises when each element of a hash table contains its own secondary hash table. There can be any number of levels. In a scripting language you might see: $items{bob}{age}=37 The C program below builds this example in uthash: the hash table is called `items`. It contains one element (`bob`) whose own hash table contains one element (`age`) with value 37. No special functions are necessary to build a multi-level hash table. While this example represents both levels (`bob` and `age`) using the same structure, it would also be fine to use two different structure definitions. It would also be fine if there were three or more levels instead of two. .Multi-level hash table ---------------------------------------------------------------------- #include #include #include #include "uthash.h" /* hash of hashes */ typedef struct item { char name[10]; struct item *sub; int val; UT_hash_handle hh; } item_t; item_t *items=NULL; int main(int argc, char *argvp[]) { item_t *item1, *item2, *tmp1, *tmp2; /* make initial element */ item_t *i = malloc(sizeof(*i)); strcpy(i->name, "bob"); i->sub = NULL; i->val = 0; HASH_ADD_STR(items, name, i); /* add a sub hash table off this element */ item_t *s = malloc(sizeof(*s)); strcpy(s->name, "age"); s->sub = NULL; s->val = 37; HASH_ADD_STR(i->sub, name, s); /* iterate over hash elements */ HASH_ITER(hh, items, item1, tmp1) { HASH_ITER(hh, item1->sub, item2, tmp2) { printf("$items{%s}{%s} = %d\n", item1->name, item2->name, item2->val); } } /* clean up both hash tables */ HASH_ITER(hh, items, item1, tmp1) { HASH_ITER(hh, item1->sub, item2, tmp2) { HASH_DEL(item1->sub, item2); free(item2); } HASH_DEL(items, item1); free(item1); } return 0; } ---------------------------------------------------------------------- The example above is included in `tests/test59.c`. [[multihash]] Items in several hash tables ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A structure can be added to more than one hash table. A few reasons you might do this include: - each hash table may use an alternative key; - each hash table may have its own sort order; - or you might simply use multiple hash tables for grouping purposes. E.g., you could have users in an `admin_users` and a `users` hash table. Your structure needs to have a `UT_hash_handle` field for each hash table to which it might be added. You can name them anything. E.g., UT_hash_handle hh1, hh2; Items with alternative keys ~~~~~~~~~~~~~~~~~~~~~~~~~~~ You might create a hash table keyed on an ID field, and another hash table keyed on username (if usernames are unique). You can add the same user structure to both hash tables (without duplication of the structure), allowing lookup of a user structure by their name or ID. The way to achieve this is to have a separate `UT_hash_handle` for each hash to which the structure may be added. .A structure with two alternative keys ---------------------------------------------------------------------- struct my_struct { int id; /* usual key */ char username[10]; /* alternative key */ UT_hash_handle hh1; /* handle for first hash table */ UT_hash_handle hh2; /* handle for second hash table */ }; ---------------------------------------------------------------------- In the example above, the structure can now be added to two separate hash tables. In one hash, `id` is its key, while in the other hash, `username` is its key. (There is no requirement that the two hashes have different key fields. They could both use the same key, such as `id`). Notice the structure has two hash handles (`hh1` and `hh2`). In the code below, notice that each hash handle is used exclusively with a particular hash table. (`hh1` is always used with the `users_by_id` hash, while `hh2` is always used with the `users_by_name` hash table). .Two keys on a structure ---------------------------------------------------------------------- struct my_struct *users_by_id = NULL, *users_by_name = NULL, *s; int i; char *name; s = malloc(sizeof(struct my_struct)); s->id = 1; strcpy(s->username, "thanson"); /* add the structure to both hash tables */ HASH_ADD(hh1, users_by_id, id, sizeof(int), s); HASH_ADD(hh2, users_by_name, username, strlen(s->username), s); /* lookup user by ID in the "users_by_id" hash table */ i=1; HASH_FIND(hh1, users_by_id, &i, sizeof(int), s); if (s) printf("found id %d: %s\n", i, s->username); /* lookup user by username in the "users_by_name" hash table */ name = "thanson"; HASH_FIND(hh2, users_by_name, name, strlen(name), s); if (s) printf("found user %s: %d\n", name, s->id); ---------------------------------------------------------------------- Several sort orders ~~~~~~~~~~~~~~~~~~~ It comes as no suprise that two hash tables can have different sort orders, but this fact can also be used advantageously to sort the 'same items' in several ways. This is based on the ability to store a structure in several hash tables. Extending the previous example, suppose we have many users. We have added each user structure to the `users_by_id` hash table and the `users_by_name` hash table. (To reiterate, this is done without the need to have two copies of each structure). Now we can define two sort functions, then use `HASH_SRT`. int sort_by_id(struct my_struct *a, struct my_struct *b) { if (a->id == b->id) return 0; return (a->id < b->id) ? -1 : 1; } int sort_by_name(struct my_struct *a, struct my_struct *b) { return strcmp(a->username,b->username); } HASH_SRT(hh1, users_by_id, sort_by_id); HASH_SRT(hh2, users_by_name, sort_by_name); Now iterating over the items in `users_by_id` will traverse them in id-order while, naturally, iterating over `users_by_name` will traverse them in name-order. The items are fully forward-and-backward linked in each order. So even for one set of users, we might store them in two hash tables to provide easy iteration in two different sort orders. Bloom filter (faster misses) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Programs that generate a fair miss rate (`HASH_FIND` that result in `NULL`) may benefit from the built-in Bloom filter support. This is disabled by default, because programs that generate only hits would incur a slight penalty from it. Also, programs that do deletes should not use the Bloom filter. While the program would operate correctly, deletes diminish the benefit of the filter. To enable the Bloom filter, simply compile with `-DHASH_BLOOM=n` like: -DHASH_BLOOM=27 where the number can be any value up to 32 which determines the amount of memory used by the filter, as shown below. Using more memory makes the filter more accurate and has the potential to speed up your program by making misses bail out faster. .Bloom filter sizes for selected values of n [width="50%",cols="10m,30",grid="none",options="header"] |===================================================================== | n | Bloom filter size (per hash table) | 16 | 8 kilobytes | 20 | 128 kilobytes | 24 | 2 megabytes | 28 | 32 megabytes | 32 | 512 megabytes |===================================================================== Bloom filters are only a performance feature; they do not change the results of hash operations in any way. The only way to gauge whether or not a Bloom filter is right for your program is to test it. Reasonable values for the size of the Bloom filter are 16-32 bits. Select ~~~~~~ An experimental 'select' operation is provided that inserts those items from a source hash that satisfy a given condition into a destination hash. This insertion is done with somewhat more efficiency than if this were using `HASH_ADD`, namely because the hash function is not recalculated for keys of the selected items. This operation does not remove any items from the source hash. Rather the selected items obtain dual presence in both hashes. The destination hash may already have items in it; the selected items are added to it. In order for a structure to be usable with `HASH_SELECT`, it must have two or more hash handles. (As described <>, 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 */ typedef struct { int id; UT_hash_handle hh; /* handle for users hash */ UT_hash_handle ah; /* handle for admins hash */ } user_t; 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); 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 could just as well have used a function. int is_admin(void *userv) { user_t *user = (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. The two hash handles must differ. An example of using `HASH_SELECT` is included in `tests/test36.c`. [[hash_functions]] Built-in hash functions ~~~~~~~~~~~~~~~~~~~~~~~ Internally, a hash function transforms a key into a bucket number. You don't have to take any action to use the default hash function, currently Jenkin's. Some programs may benefit from using another of the built-in hash functions. There is a simple analysis utility included with uthash to help you determine if another hash function will give you better performance. You can use a different hash function by compiling your program with `-DHASH_FUNCTION=HASH_xyz` where `xyz` is one of the symbolic names listed below. E.g., cc -DHASH_FUNCTION=HASH_BER -o program program.c .Built-in hash functions [width="50%",cols="^5m,20",grid="none",options="header"] |=============================================================================== |Symbol | Name |JEN | Jenkins (default) |BER | Bernstein |SAX | Shift-Add-Xor |OAT | One-at-a-time |FNV | Fowler/Noll/Vo |SFH | Paul Hsieh |MUR | MurmurHash v3 (see note) |=============================================================================== [NOTE] .MurmurHash ================================================================================ A special symbol must be defined if you intend to use MurmurHash. To use it, add `-DHASH_USING_NO_STRICT_ALIASING` to your `CFLAGS`. And, if you are using the gcc compiler with optimization, add `-fno-strict-aliasing` to your `CFLAGS`. ================================================================================ Which hash function is best? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ You can easily determine the best hash function for your key domain. To do so, you'll need to run your program once in a data-collection pass, and then run the collected data through an included analysis utility. First you must build the analysis utility. From the top-level directory, cd tests/ make We'll use `test14.c` to demonstrate the data-collection and analysis steps (here using `sh` syntax to redirect file descriptor 3 to a file): .Using keystats -------------------------------------------------------------------------------- % cc -DHASH_EMIT_KEYS=3 -I../src -o test14 test14.c % ./test14 3>test14.keys % ./keystats test14.keys fcn ideal% #items #buckets dup% fl add_usec find_usec del-all usec --- ------ ---------- ---------- ----- -- ---------- ---------- ------------ SFH 91.6% 1219 256 0% ok 92 131 25 FNV 90.3% 1219 512 0% ok 107 97 31 SAX 88.7% 1219 512 0% ok 111 109 32 OAT 87.2% 1219 256 0% ok 99 138 26 JEN 86.7% 1219 256 0% ok 87 130 27 BER 86.2% 1219 256 0% ok 121 129 27 -------------------------------------------------------------------------------- [NOTE] The number 3 in `-DHASH_EMIT_KEYS=3` is a file descriptor. Any file descriptor that your program doesn't use for its own purposes can be used instead of 3. The data-collection mode enabled by `-DHASH_EMIT_KEYS=x` should not be used in production code. Usually, you should just pick the first hash function that is listed. Here, this is `SFH`. This is the function that provides the most even distribution for your keys. If several have the same `ideal%`, then choose the fastest one according to the `find_usec` column. keystats column reference ^^^^^^^^^^^^^^^^^^^^^^^^^ fcn:: symbolic name of hash function ideal%:: The percentage of items in the hash table which can be looked up within an ideal number of steps. (Further explained below). #items:: the number of keys that were read in from the emitted key file #buckets:: the number of buckets in the hash after all the keys were added dup%:: the percent of duplicate keys encountered in the emitted key file. Duplicates keys are filtered out to maintain key uniqueness. (Duplicates are normal. For example, if the application adds an item to a hash, deletes it, then re-adds it, the key is written twice to the emitted file.) flags:: this is either `ok`, or `nx` (noexpand) if the expansion inhibited flag is set, described in <>. It is not recommended to use a hash function that has the `noexpand` flag set. add_usec:: the clock time in microseconds required to add all the keys to a hash find_usec:: the clock time in microseconds required to look up every key in the hash del-all usec:: the clock time in microseconds required to delete every item in the hash [[ideal]] ideal% ^^^^^^ .What is ideal%? ***************************************************************************** The 'n' items in a hash are distributed into 'k' buckets. Ideally each bucket would contain an equal share '(n/k)' of the items. In other words, the maximum linear position of any item in a bucket chain would be 'n/k' if every bucket is equally used. If some buckets are overused and others are underused, the overused buckets will contain items whose linear position surpasses 'n/k'. Such items are considered non-ideal. As you might guess, `ideal%` is the percentage of ideal items in the hash. These items have favorable linear positions in their bucket chains. As `ideal%` approaches 100%, the hash table approaches constant-time lookup performance. ***************************************************************************** [[hashscan]] hashscan ~~~~~~~~ NOTE: This utility is only available on Linux, and on FreeBSD (8.1 and up). A utility called `hashscan` is included in the `tests/` directory. It is built automatically when you run `make` in that directory. This tool examines a running process and reports on the uthash tables that it finds in that program's memory. It can also save the keys from each table in a format that can be fed into `keystats`. Here is an example of using `hashscan`. First ensure that it is built: cd tests/ make Since `hashscan` needs a running program to inspect, we'll start up a simple program that makes a hash table and then sleeps as our test subject: ./test_sleep & pid: 9711 Now that we have a test program, let's run `hashscan` on it: ./hashscan 9711 Address ideal items buckets mc fl bloom/sat fcn keys saved to ------------------ ----- -------- -------- -- -- --------- --- ------------- 0x862e038 81% 10000 4096 11 ok 16 14% JEN If we wanted to copy out all its keys for external analysis using `keystats`, add the `-k` flag: ./hashscan -k 9711 Address ideal items buckets mc fl bloom/sat fcn keys saved to ------------------ ----- -------- -------- -- -- --------- --- ------------- 0x862e038 81% 10000 4096 11 ok 16 14% JEN /tmp/9711-0.key Now we could run `./keystats /tmp/9711-0.key` to analyze which hash function has the best characteristics on this set of keys. hashscan column reference ^^^^^^^^^^^^^^^^^^^^^^^^^ Address:: virtual address of the hash table ideal:: The percentage of items in the table which can be looked up within an ideal number of steps. See <> in the `keystats` section. items:: number of items in the hash table buckets:: number of buckets in the hash table mc:: the maximum chain length found in the hash table (uthash usually tries to keep fewer than 10 items in each bucket, or in some cases a multiple of 10) fl:: flags (either `ok`, or `NX` if the expansion-inhibited flag is set) bloom/sat:: if the hash table uses a Bloom filter, this is the size (as a power of two) of the filter (e.g. 16 means the filter is 2^16 bits in size). The second number is the "saturation" of the bits expressed as a percentage. The lower the percentage, the more potential benefit to identify cache misses quickly. fcn:: symbolic name of hash function keys saved to:: file to which keys were saved, if any .How hashscan works ***************************************************************************** When hashscan runs, it attaches itself to the target process, which suspends the target process momentarily. During this brief suspension, it scans the target's virtual memory for the signature of a uthash hash table. It then checks if a valid hash table structure accompanies the signature and reports what it finds. When it detaches, the target process resumes running normally. The hashscan is performed "read-only"-- the target process is not modified. Since hashscan is analyzing a momentary snapshot of a running process, it may return different results from one run to another. ***************************************************************************** [[expansion]] Expansion internals ~~~~~~~~~~~~~~~~~~~ Internally this hash manages the number of buckets, with the goal of having enough buckets so that each one contains only a small number of items. .Why does the number of buckets matter? ******************************************************************************** When looking up an item by its key, this hash scans linearly through the items in the appropriate bucket. In order for the linear scan to run in constant time, the number of items in each bucket must be bounded. This is accomplished by increasing the number of buckets as needed. ******************************************************************************** Normal expansion ^^^^^^^^^^^^^^^^ This hash attempts to keep fewer than 10 items in each bucket. When an item is added that would cause a bucket to exceed this number, the number of buckets in the hash is doubled and the items are redistributed into the new buckets. In an ideal world, each bucket will then contain half as many items as it did before. Bucket expansion occurs automatically and invisibly as needed. There is no need for the application to know when it occurs. Per-bucket expansion threshold ++++++++++++++++++++++++++++++ Normally all buckets share the same threshold (10 items) at which point bucket expansion is triggered. During the process of bucket expansion, uthash can adjust this expansion-trigger threshold on a per-bucket basis if it sees that certain buckets are over-utilized. When this threshold is adjusted, it goes from 10 to a multiple of 10 (for that particular bucket). The multiple is based on how many times greater the actual chain length is than the ideal length. It is a practical measure to reduce excess bucket expansion in the case where a hash function over-utilizes a few buckets but has good overall distribution. However, if the overall distribution gets too bad, uthash changes tactics. Inhibited expansion ^^^^^^^^^^^^^^^^^^^ You usually don't need to know or worry about this, particularly if you used the `keystats` utility during development to select a good hash for your keys. A hash function may yield an uneven distribution of items across the buckets. In moderation this is not a problem. Normal bucket expansion takes place as the chain lengths grow. But when significant imbalance occurs (because the hash function is not well suited to the key domain), bucket expansion may be 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 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 inhibits expansion for that hash table. Once set, the 'bucket expansion inhibited' flag remains in effect as long as the hash has items in it. Inhibited expansion may cause `HASH_FIND` to exhibit worse than constant-time performance. Hooks ~~~~~ You don't need to use these hooks- they are only here if you want to modify the behavior of uthash. Hooks can be used to change how uthash allocates memory, and to run code in response to certain internal events. malloc/free ^^^^^^^^^^^ By default this hash implementation uses `malloc` and `free` to manage memory. If your application uses its own custom allocator, this hash can use them too. .Specifying alternate memory management functions ---------------------------------------------------------------------------- #include "uthash.h" /* undefine the defaults */ #undef uthash_malloc #undef uthash_free /* re-define, specifying alternate functions */ #define uthash_malloc(sz) my_malloc(sz) #define uthash_free(ptr,sz) my_free(ptr) ... ---------------------------------------------------------------------------- Notice that `uthash_free` receives two parameters. The `sz` parameter is for convenience on embedded platforms that manage their own memory. Out of memory ^^^^^^^^^^^^^ If memory allocation fails (i.e., the malloc function returned `NULL`), the default behavior is to terminate the process by calling `exit(-1)`. This can be modified by re-defining the `uthash_fatal` macro. #undef uthash_fatal #define uthash_fatal(msg) my_fatal_function(msg); The fatal function should terminate the process or `longjmp` back to a safe place. Uthash does not support "returning a failure" if memory cannot be allocated. Internal events ^^^^^^^^^^^^^^^ There is no need for the application to set these hooks or take action in response to these events. They are mainly for diagnostic purposes. These two hooks are "notification" hooks which get executed if uthash is expanding buckets, or setting the 'bucket expansion inhibited' flag. Normally both of these hooks are undefined and thus compile away to nothing. Expansion +++++++++ There is a hook for the bucket expansion event. .Bucket expansion hook ---------------------------------------------------------------------------- #include "uthash.h" #undef uthash_expand_fyi #define uthash_expand_fyi(tbl) printf("expanded to %d buckets\n", tbl->num_buckets) ... ---------------------------------------------------------------------------- Expansion-inhibition ++++++++++++++++++++ This hook can be defined to code to execute in the event that uthash decides to set the 'bucket expansion inhibited' flag. .Bucket expansion inhibited hook ---------------------------------------------------------------------------- #include "uthash.h" #undef uthash_noexpand_fyi #define uthash_noexpand_fyi printf("warning: bucket expansion inhibited\n"); ... ---------------------------------------------------------------------------- Debug mode ~~~~~~~~~~ If a program that uses this hash is compiled with `-DHASH_DEBUG=1`, a special internal consistency-checking mode is activated. In this mode, the integrity of the whole hash is checked following every add or delete operation. This is for debugging the uthash software only, not for use in production code. In the `tests/` directory, running `make debug` will run all the tests in this mode. In this mode, any internal errors in the hash data structure will cause a message to be printed to `stderr` and the program to exit. The `UT_hash_handle` data structure includes `next`, `prev`, `hh_next` and `hh_prev` fields. The former two fields determine the "application" ordering (that is, insertion order-- the order the items were added). The latter two fields determine the "bucket chain" order. These link the `UT_hash_handles` together in a doubly-linked list that is a bucket chain. Checks performed in `-DHASH_DEBUG=1` mode: - the hash is walked in its entirety twice: once in 'bucket' order and a second time in 'application' order - the total number of items encountered in both walks is checked against the stored number - during the walk in 'bucket' order, each item's `hh_prev` pointer is compared for equality with the last visited item - during the walk in 'application' order, each item's `prev` pointer is compared for equality with the last visited item .Macro debugging: ******************************************************************************** Sometimes it's difficult to interpret a compiler warning on a line which contains a macro call. In the case of uthash, one macro can expand to dozens of lines. In this case, it is helpful to expand the macros and then recompile. By doing so, the warning message will refer to the exact line within the macro. Here is an example of how to expand the macros and then recompile. This uses the `test1.c` program in the `tests/` subdirectory. gcc -E -I../src test1.c > /tmp/a.c egrep -v '^#' /tmp/a.c > /tmp/b.c indent /tmp/b.c gcc -o /tmp/b /tmp/b.c The last line compiles the original program (test1.c) with all macros expanded. If there was a warning, the referenced line number can be checked in `/tmp/b.c`. ******************************************************************************** Thread safety ~~~~~~~~~~~~~ You can use uthash in a threaded program. But you must do the locking. Use a read-write lock to protect against concurrent writes. It is ok to have 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"); Then, readers must acquire the read lock before doing any `HASH_FIND` calls or before iterating over the hash elements: if (pthread_rwlock_rdlock(&lock) != 0) fatal("can't get rdlock"); HASH_FIND_INT(elts, &i, e); pthread_rwlock_unlock(&lock); Writers must acquire the exclusive write lock before doing any update. Add, delete, and sort are all updates that must be locked. if (pthread_rwlock_wrlock(&lock) != 0) fatal("can't get wrlock"); HASH_DEL(elts, e); pthread_rwlock_unlock(&lock); If you prefer, you can use a mutex instead of a read-write lock, but this will reduce reader concurrency to a single thread at a time. An example program using uthash with a read-write lock is included in `tests/threads/test1.c`. [[Macro_reference]] Macro reference --------------- Convenience macros ~~~~~~~~~~~~~~~~~~ The convenience macros do the same thing as the generalized macros, but require fewer arguments. In order to use the convenience macros, 1. the structure's `UT_hash_handle` field must be named `hh`, and 2. for add or find, the key field must be of type `int` or `char[]` or pointer .Convenience macros [width="90%",cols="10m,30m",grid="none",options="header"] |=============================================================================== |macro | arguments |HASH_ADD_INT | (head, keyfield_name, item_ptr) |HASH_REPLACE_INT | (head, keyfiled_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_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) |HASH_FIND_PTR | (head, key_ptr, item_ptr) |HASH_DEL | (head, item_ptr) |HASH_SORT | (head, cmp) |HASH_COUNT | (head) |=============================================================================== General macros ~~~~~~~~~~~~~~ These macros add, find, delete and sort the items in a hash. You need to use the general macros if your `UT_hash_handle` is named something other than `hh`, or if your key's data type isn't `int` or `char[]`. .General macros [width="90%",cols="10m,30m",grid="none",options="header"] |=============================================================================== |macro | arguments |HASH_ADD | (hh_name, head, keyfield_name, key_len, item_ptr) |HASH_ADD_KEYPTR| (hh_name, head, key_ptr, key_len, item_ptr) |HASH_REPLACE | (hh_name, head, keyfield_name, key_len, item_ptr, replaced_item_ptr) |HASH_FIND | (hh_name, head, key_ptr, key_len, item_ptr) |HASH_DELETE | (hh_name, head, item_ptr) |HASH_SRT | (hh_name, head, cmp) |HASH_CNT | (hh_name, head) |HASH_CLEAR | (hh_name, head) |HASH_SELECT | (dst_hh_name, dst_head, src_hh_name, src_head, condition) |HASH_ITER | (hh_name, head, item_ptr, tmp_item_ptr) |HASH_OVERHEAD | (hh_name, head) |=============================================================================== [NOTE] `HASH_ADD_KEYPTR` is used when the structure contains a pointer to the key, rather than the key itself. Argument descriptions ^^^^^^^^^^^^^^^^^^^^^ hh_name:: name of the `UT_hash_handle` field in the structure. Conventionally called `hh`. head:: the structure pointer variable which acts as the "head" of the hash. So named because it initially points to the first item that is added to the hash. keyfield_name:: the name of the key field in the structure. (In the case of a multi-field key, this is the first field of the key). If you're new to macros, it might seem strange to pass the name of a field as a parameter. See <>. key_len:: the length of the key field in bytes. E.g. for an integer key, this is `sizeof(int)`, while for a string key it's `strlen(key)`. (For a multi-field key, see the notes in this guide on calculating key length). key_ptr:: for `HASH_FIND`, this is a pointer to the key to look up in the hash (since it's a pointer, you can't directly pass a literal value here). For `HASH_ADD_KEYPTR`, this is the address of the key of the item being added. item_ptr:: pointer to the structure being added, deleted, or looked up, or the current pointer during iteration. This is an input parameter for `HASH_ADD` and `HASH_DELETE` macros, and an output parameter for `HASH_FIND` and `HASH_ITER`. (When using `HASH_ITER` to iterate, `tmp_item_ptr` is another variable of the same type as `item_ptr`, used internally). replaced_item_ptr:: used in HASH_REPLACE macros. This is an output parameter that is set to point to the replaced item (if no item is replaced it is set to NULL). cmp:: pointer to comparison function which accepts two arguments (pointers to items to compare) and returns an int specifying whether the first item should sort before, equal to, or after the second item (like `strcmp`). condition:: a function or macro which accepts a single argument-- a void pointer to a structure, which needs to be cast to the appropriate structure type. The function or macro should return (or evaluate to) a non-zero value if the structure should be "selected" for addition to the destination hash. // vim: set tw=80 wm=2 syntax=asciidoc: uthash-1.9.9.1+git20151125/doc/utarray.html000066400000000000000000001070461264051566200177260ustar00rootroot00000000000000 utarray: dynamic array macros for C

Here’s a link back to the GitHub project page.

Introduction

A set of general-purpose dynamic array macros for C structures are included with uthash in utarray.h. To use these macros in your own C program, just copy utarray.h into your source directory and use it in your programs.

#include "utarray.h"

The dynamic array supports basic operations such as push, pop, and erase on the array elements. These array elements can be any simple datatype or structure. The array operations are based loosely on the C++ STL vector methods.

Internally the dynamic array contains a contiguous memory region into which the elements are copied. This buffer is grown as needed using realloc to accomodate all the data that is pushed into it.

Download

To download the utarray.h header file, follow the links on https://github.com/troydhanson/uthash to clone uthash or get a zip file, then look in the src/ sub-directory.

BSD licensed

This software is made available under the revised BSD license. It is free and open source.

Platforms

The utarray macros have been tested on:

  • Linux,

  • Mac OS X,

  • Windows, using Visual Studio 2008 and Visual Studio 2010

Usage

Declaration

The array itself has the data type UT_array, regardless of the type of elements to be stored in it. It is declared like,

UT_array *nums;

New and free

The next step is to create the array using utarray_new. Later when you’re done with the array, utarray_free will free it and all its elements.

Push, pop, etc

The central features of the utarray involve putting elements into it, taking them out, and iterating over them. There are several operations to pick from that deal with either single elements or ranges of elements at a time. In the examples below we will use only the push operation to insert elements.

Elements

Support for dynamic arrays of integers or strings is especially easy. These are best shown by example:

Integers

This example makes a utarray of integers, pushes 0-9 into it, then prints it. Lastly it frees it.

Integer elements
#include <stdio.h>
#include "utarray.h"

int main() {
  UT_array *nums;
  int i, *p;

  utarray_new(nums,&ut_int_icd);
  for(i=0; i < 10; i++) utarray_push_back(nums,&i);

  for(p=(int*)utarray_front(nums);
      p!=NULL;
      p=(int*)utarray_next(nums,p)) {
    printf("%d\n",*p);
  }

  utarray_free(nums);

  return 0;
}

The second argument to utarray_push_back is always a pointer to the type (so a literal cannot be used). So for integers, it is an int*.

Strings

In this example we make a utarray of strings, push two strings into it, print it and free it.

String elements
#include <stdio.h>
#include "utarray.h"

int main() {
  UT_array *strs;
  char *s, **p;

  utarray_new(strs,&ut_str_icd);

  s = "hello"; utarray_push_back(strs, &s);
  s = "world"; utarray_push_back(strs, &s);
  p = NULL;
  while ( (p=(char**)utarray_next(strs,p))) {
    printf("%s\n",*p);
  }

  utarray_free(strs);

  return 0;
}

In this example, since the element is a char*, we pass a pointer to it (char**) as the second argument to utarray_push_back. Note that "push" makes a copy of the source string and pushes that copy into the array.

About UT_icd

Arrays be made of any type of element, not just integers and strings. The elements can be basic types or structures. Unless you’re dealing with integers and strings (which use pre-defined ut_int_icd and ut_str_icd), you’ll need to define a UT_icd helper structure. This structure contains everything that utarray needs to initialize, copy or destruct elements.

typedef struct {
    size_t sz;
    init_f *init;
    ctor_f *copy;
    dtor_f *dtor;
} UT_icd;

The three function pointers init, copy, and dtor have these prototypes:

typedef void (ctor_f)(void *dst, const void *src);
typedef void (dtor_f)(void *elt);
typedef void (init_f)(void *elt);

The sz is just the size of the element being stored in the array.

The init function will be invoked whenever utarray needs to initialize an empty element. This only happens as a byproduct of utarray_resize or utarray_extend_back. If init is NULL, it defaults to zero filling the new element using memset.

The copy function is used whenever an element is copied into the array. It is invoked during utarray_push_back, utarray_insert, utarray_inserta, or utarray_concat. If copy is NULL, it defaults to a bitwise copy using memcpy.

The dtor function is used to clean up an element that is being removed from the array. It may be invoked due to utarray_resize, utarray_pop_back, utarray_erase, utarray_clear, utarray_done or utarray_free. If the elements need no cleanup upon destruction, dtor may be NULL.

Scalar types

The next example uses UT_icd with all its defaults to make a utarray of long elements. This example pushes two longs, prints them, and frees the array.

long elements
#include <stdio.h>
#include "utarray.h"

UT_icd long_icd = {sizeof(long), NULL, NULL, NULL };

int main() {
  UT_array *nums;
  long l, *p;
  utarray_new(nums, &long_icd);

  l=1; utarray_push_back(nums, &l);
  l=2; utarray_push_back(nums, &l);

  p=NULL;
  while( (p=(long*)utarray_next(nums,p))) printf("%ld\n", *p);

  utarray_free(nums);
  return 0;
}

Structures

Structures can be used as utarray elements. If the structure requires no special effort to initialize, copy or destruct, we can use UT_icd with all its defaults. This example shows a structure that consists of two integers. Here we push two values, print them and free the array.

Structure (simple)
#include <stdio.h>
#include "utarray.h"

typedef struct {
    int a;
    int b;
} intpair_t;

UT_icd intpair_icd = {sizeof(intpair_t), NULL, NULL, NULL};

int main() {

  UT_array *pairs;
  intpair_t ip, *p;
  utarray_new(pairs,&intpair_icd);

  ip.a=1;  ip.b=2;  utarray_push_back(pairs, &ip);
  ip.a=10; ip.b=20; utarray_push_back(pairs, &ip);

  for(p=(intpair_t*)utarray_front(pairs);
      p!=NULL;
      p=(intpair_t*)utarray_next(pairs,p)) {
    printf("%d %d\n", p->a, p->b);
  }

  utarray_free(pairs);
  return 0;
}

The real utility of UT_icd is apparent when the elements of the utarray are structures that require special work to initialize, copy or destruct.

For example, when a structure contains pointers to related memory areas that need to be copied when the structure is copied (and freed when the structure is freed), we can use custom init, copy, and dtor members in the UT_icd.

Here we take an example of a structure that contains an integer and a string. When this element is copied (such as when an element is pushed into the array), we want to "deep copy" the s pointer (so the original element and the new element point to their own copies of s). When an element is destructed, we want to "deep free" its copy of s. Lastly, this example is written to work even if s has the value NULL.

Structure (complex)
#include <stdio.h>
#include <stdlib.h>
#include "utarray.h"

typedef struct {
    int a;
    char *s;
} intchar_t;

void intchar_copy(void *_dst, const void *_src) {
  intchar_t *dst = (intchar_t*)_dst, *src = (intchar_t*)_src;
  dst->a = src->a;
  dst->s = src->s ? strdup(src->s) : NULL;
}

void intchar_dtor(void *_elt) {
  intchar_t *elt = (intchar_t*)_elt;
  if (elt->s) free(elt->s);
}

UT_icd intchar_icd = {sizeof(intchar_t), NULL, intchar_copy, intchar_dtor};

int main() {
  UT_array *intchars;
  intchar_t ic, *p;
  utarray_new(intchars, &intchar_icd);

  ic.a=1; ic.s="hello"; utarray_push_back(intchars, &ic);
  ic.a=2; ic.s="world"; utarray_push_back(intchars, &ic);

  p=NULL;
  while( (p=(intchar_t*)utarray_next(intchars,p))) {
    printf("%d %s\n", p->a, (p->s ? p->s : "null"));
  }

  utarray_free(intchars);
  return 0;
}

Reference

This table lists all the utarray operations. These are loosely based on the C++ vector class.

Operations

utarray_new(UT_array *a, UT_icd *icd)

allocate a new array

utarray_free(UT_array *a)

free an allocated array

utarray_init(UT_array *a,UT_icd *icd)

init an array (non-alloc)

utarray_done(UT_array *a)

dispose of an array (non-allocd)

utarray_reserve(UT_array *a,int n)

ensure space available for n more elements

utarray_push_back(UT_array *a,void *p)

push element p onto a

utarray_pop_back(UT_array *a)

pop last element from a

utarray_extend_back(UT_array *a)

push empty element onto a

utarray_len(UT_array *a)

get length of a

utarray_eltptr(UT_array *a,int j)

get pointer of element from index

utarray_eltidx(UT_array *a,void *e)

get index of element from pointer

utarray_insert(UT_array *a,void *p, int j)

insert element p to index j

utarray_inserta(UT_array *a,UT_array *w, int j)

insert array w into array a at index j

utarray_resize(UT_array *dst,int num)

extend or shrink array to num elements

utarray_concat(UT_array *dst,UT_array *src)

copy src to end of dst array

utarray_erase(UT_array *a,int pos,int len)

remove len elements from a[pos]..a[pos+len-1]

utarray_clear(UT_array *a)

clear all elements from a, setting its length to zero

utarray_sort(UT_array *a,cmpfcn *cmp)

sort elements of a using comparison function

utarray_find(UT_array *a,void *v, cmpfcn *cmp)

find element v in utarray (must be sorted)

utarray_front(UT_array *a)

get first element of a

utarray_next(UT_array *a,void *e)

get element of a following e (front if e is NULL)

utarray_prev(UT_array *a,void *e)

get element of a before e (back if e is NULL)

utarray_back(UT_array *a)

get last element of a

Notes

  1. utarray_new and utarray_free are used to allocate a new array and free it, while utarray_init and utarray_done can be used if the UT_array is already allocated and just needs to be initialized or have its internal resources freed.

  2. utarray_reserve takes the "delta" of elements to reserve (not the total desired capacity of the array-- this differs from the C++ STL "reserve" notion)

  3. utarray_sort expects a comparison function having the usual strcmp -like convention where it accepts two elements (a and b) and returns a negative value if a precedes b, 0 if a and b sort equally, and positive if b precedes a. This is an example of a comparison function:

    int intsort(const void *a,const void*b) {
        int _a = *(int*)a;
        int _b = *(int*)b;
        return _a - _b;
    }
  4. utarray_find uses a binary search to locate an element having a certain value according to the given comparison function. The utarray must be first sorted using the same comparison function. An example of using utarray_find with a utarray of strings is included in tests/test61.c.

  5. A pointer to a particular element (obtained using utarray_eltptr or utarray_front, utarray_next, utarray_prev, utarray_back) becomes invalid whenever another element is inserted into the utarray. This is because the internal memory management may need to realloc the element storage to a new address. For this reason, it’s usually better to refer to an element by its integer index in code whose duration may include element insertion.


uthash-1.9.9.1+git20151125/doc/utarray.txt000066400000000000000000000306701264051566200175770ustar00rootroot00000000000000utarray: dynamic array macros for C =================================== Troy D. Hanson v1.9.9, November 2014 Here's a link back to the https://github.com/troydhanson/uthash[GitHub project page]. Introduction ------------ A set of general-purpose dynamic array macros for C structures are included with uthash in `utarray.h`. To use these macros in your own C program, just copy `utarray.h` into your source directory and use it in your programs. #include "utarray.h" The dynamic array supports basic operations such as push, pop, and erase on the array elements. These array elements can be any simple datatype or structure. The array <> are based loosely on the C++ STL vector methods. Internally the dynamic array contains a contiguous memory region into which the elements are copied. This buffer is grown as needed using `realloc` to accomodate all the data that is pushed into it. Download ~~~~~~~~ To download the `utarray.h` header file, follow the links on https://github.com/troydhanson/uthash to clone uthash or get a zip file, then look in the src/ sub-directory. BSD licensed ~~~~~~~~~~~~ This software is made available under the link:license.html[revised BSD license]. It is free and open source. Platforms ~~~~~~~~~ The 'utarray' macros have been tested on: * Linux, * Mac OS X, * Windows, using Visual Studio 2008 and Visual Studio 2010 Usage ----- Declaration ~~~~~~~~~~~ The array itself has the data type `UT_array`, regardless of the type of elements to be stored in it. It is declared like, UT_array *nums; New and free ~~~~~~~~~~~~ The next step is to create the array using `utarray_new`. Later when you're done with the array, `utarray_free` will free it and all its elements. Push, pop, etc ~~~~~~~~~~~~~~ The central features of the utarray involve putting elements into it, taking them out, and iterating over them. There are several <> to pick from that deal with either single elements or ranges of elements at a time. In the examples below we will use only the push operation to insert elements. Elements -------- Support for dynamic arrays of integers or strings is especially easy. These are best shown by example: Integers ~~~~~~~~ This example makes a utarray of integers, pushes 0-9 into it, then prints it. Lastly it frees it. .Integer elements ------------------------------------------------------------------------------- #include #include "utarray.h" int main() { UT_array *nums; int i, *p; utarray_new(nums,&ut_int_icd); for(i=0; i < 10; i++) utarray_push_back(nums,&i); for(p=(int*)utarray_front(nums); p!=NULL; p=(int*)utarray_next(nums,p)) { printf("%d\n",*p); } utarray_free(nums); return 0; } ------------------------------------------------------------------------------- The second argument to `utarray_push_back` is always a 'pointer' to the type (so a literal cannot be used). So for integers, it is an `int*`. Strings ~~~~~~~ In this example we make a utarray of strings, push two strings into it, print it and free it. .String elements ------------------------------------------------------------------------------- #include #include "utarray.h" int main() { UT_array *strs; char *s, **p; utarray_new(strs,&ut_str_icd); s = "hello"; utarray_push_back(strs, &s); s = "world"; utarray_push_back(strs, &s); p = NULL; while ( (p=(char**)utarray_next(strs,p))) { printf("%s\n",*p); } utarray_free(strs); return 0; } ------------------------------------------------------------------------------- In this example, since the element is a `char*`, we pass a pointer to it (`char**`) as the second argument to `utarray_push_back`. Note that "push" makes a copy of the source string and pushes that copy into the array. About UT_icd ~~~~~~~~~~~~ Arrays be made of any type of element, not just integers and strings. The elements can be basic types or structures. Unless you're dealing with integers and strings (which use pre-defined `ut_int_icd` and `ut_str_icd`), you'll need to define a `UT_icd` helper structure. This structure contains everything that utarray needs to initialize, copy or destruct elements. typedef struct { size_t sz; init_f *init; ctor_f *copy; dtor_f *dtor; } UT_icd; The three function pointers `init`, `copy`, and `dtor` have these prototypes: typedef void (ctor_f)(void *dst, const void *src); typedef void (dtor_f)(void *elt); typedef void (init_f)(void *elt); The `sz` is just the size of the element being stored in the array. The `init` function will be invoked whenever utarray needs to initialize an empty element. This only happens as a byproduct of `utarray_resize` or `utarray_extend_back`. If `init` is `NULL`, it defaults to zero filling the new element using memset. The `copy` function is used whenever an element is copied into the array. It is invoked during `utarray_push_back`, `utarray_insert`, `utarray_inserta`, or `utarray_concat`. If `copy` is `NULL`, it defaults to a bitwise copy using memcpy. The `dtor` function is used to clean up an element that is being removed from the array. It may be invoked due to `utarray_resize`, `utarray_pop_back`, `utarray_erase`, `utarray_clear`, `utarray_done` or `utarray_free`. If the elements need no cleanup upon destruction, `dtor` may be `NULL`. Scalar types ~~~~~~~~~~~~ The next example uses `UT_icd` with all its defaults to make a utarray of `long` elements. This example pushes two longs, prints them, and frees the array. .long elements ------------------------------------------------------------------------------- #include #include "utarray.h" UT_icd long_icd = {sizeof(long), NULL, NULL, NULL }; int main() { UT_array *nums; long l, *p; utarray_new(nums, &long_icd); l=1; utarray_push_back(nums, &l); l=2; utarray_push_back(nums, &l); p=NULL; while( (p=(long*)utarray_next(nums,p))) printf("%ld\n", *p); utarray_free(nums); return 0; } ------------------------------------------------------------------------------- Structures ~~~~~~~~~~ Structures can be used as utarray elements. If the structure requires no special effort to initialize, copy or destruct, we can use `UT_icd` with all its defaults. This example shows a structure that consists of two integers. Here we push two values, print them and free the array. .Structure (simple) ------------------------------------------------------------------------------- #include #include "utarray.h" typedef struct { int a; int b; } intpair_t; UT_icd intpair_icd = {sizeof(intpair_t), NULL, NULL, NULL}; int main() { UT_array *pairs; intpair_t ip, *p; utarray_new(pairs,&intpair_icd); ip.a=1; ip.b=2; utarray_push_back(pairs, &ip); ip.a=10; ip.b=20; utarray_push_back(pairs, &ip); for(p=(intpair_t*)utarray_front(pairs); p!=NULL; p=(intpair_t*)utarray_next(pairs,p)) { printf("%d %d\n", p->a, p->b); } utarray_free(pairs); return 0; } ------------------------------------------------------------------------------- The real utility of `UT_icd` is apparent when the elements of the utarray are structures that require special work to initialize, copy or destruct. For example, when a structure contains pointers to related memory areas that need to be copied when the structure is copied (and freed when the structure is freed), we can use custom `init`, `copy`, and `dtor` members in the `UT_icd`. Here we take an example of a structure that contains an integer and a string. When this element is copied (such as when an element is pushed into the array), we want to "deep copy" the `s` pointer (so the original element and the new element point to their own copies of `s`). When an element is destructed, we want to "deep free" its copy of `s`. Lastly, this example is written to work even if `s` has the value `NULL`. .Structure (complex) ------------------------------------------------------------------------------- #include #include #include "utarray.h" typedef struct { int a; char *s; } intchar_t; void intchar_copy(void *_dst, const void *_src) { intchar_t *dst = (intchar_t*)_dst, *src = (intchar_t*)_src; dst->a = src->a; dst->s = src->s ? strdup(src->s) : NULL; } void intchar_dtor(void *_elt) { intchar_t *elt = (intchar_t*)_elt; if (elt->s) free(elt->s); } UT_icd intchar_icd = {sizeof(intchar_t), NULL, intchar_copy, intchar_dtor}; int main() { UT_array *intchars; intchar_t ic, *p; utarray_new(intchars, &intchar_icd); ic.a=1; ic.s="hello"; utarray_push_back(intchars, &ic); ic.a=2; ic.s="world"; utarray_push_back(intchars, &ic); p=NULL; while( (p=(intchar_t*)utarray_next(intchars,p))) { printf("%d %s\n", p->a, (p->s ? p->s : "null")); } utarray_free(intchars); return 0; } ------------------------------------------------------------------------------- [[operations]] Reference --------- This table lists all the utarray operations. These are loosely based on the C++ vector class. Operations ~~~~~~~~~~ [width="100%",cols="50+ EyJExe$X |A:ҤMKHB&7ErQV/B3Aea)t@ ±?w'R]!f?AӅV[.đ%] Ǎag:^>~|hV/}Hu!4G-κQeq B ϻ:CYA14.2yQr3F-Wf m\BN3nQ2WlFގ8aϿP29>G~;o< oK ᑥiqped6頻 ܗtĊ;禨$M 2ؾIyYE!@ GaRi|҅ѯe>{I&%]-1^~s]9dm~V}e#Earu2sX)EOGf?3þor5s!-I,lyaoU! $"gt_vM1,Bն#n^J6hU!1\#btLY5{ۥPh ;ohoW2ڲzZ67\Nw|5OoJR^POG-gXXzkfma{ 5P Rs+^ld5:[\aSxpaQ/{jZxkoI|\pc'fR0+Ț_?C{=7/׿ц/.N6qlA (]GWOhDnr#%jK=MeSDŶʥ\]g^]{pC?~kԇR 44C!\/"B6ۚgpphD6/ǓEu"*Ms/#'p8𘫹ϟ?{mx9onv`)[Bc9U3In%ssS4߼uO=7ϛ@͎~_ޓjnW/W s7xA/M8Eل&)]4)L%R @hMSh:h Ss0aB!3rZ!k?'c[2 86:X]Лu=[<S$ l=l sw"Ba2S]^Z58t4V~HQE~~ D 4*˩/ .m[ÔF,($Iq~ IY./U6?gcgd~I 'q$-4ݖ"l&b=_rfΜٓlu߿azԲW88b,|6 ي 4uܺCu]?c} qUNCuë =U?$C(Y:33 ol{pO_C& qWt=v^C$8O>Pߔ?ln2dlV-]R [e:f$¼Tdf?Q":d*Rz,F4pe'O2oxГx HCw@EEey`A|gwܳmt &ǹ񺵴=_wpݤ";5z1_@)\.xkd]%zD"0dph4/0`~NK,>ןABA P+YLIJp7<`\ZnYNJ; d*zhHRo/W_`Lg3߹nj?B:,Yzmw/VgϏb =n3c&P(Tx2/Fܴu&?+“y{[A=nϥ8B˾5!G*l'#t*=-dۆNᅿ2xF%+n?Rk/gc,XiWN|± {Q0b JPh9c#2s!+R"%G@ G"U @  $KO>)68.Yi-!r T2sDzxc׵Zn^icU0$ \-_Z/A"b!sxIFd /!(Ic)+LX\]ϿJߙqbTBa%vBa'v IA8HHG) )7G0ҌK&IY-9=n e8IE*>H)q g4_JN* f ] 5G b~'ހILlltAm5󈧼C@қ+B=pѽ2mH_8sA!)/z+g|}TM?IENDB`uthash-1.9.9.1+git20151125/doc/uthash-mini.svg000066400000000000000000000302061264051566200203110ustar00rootroot00000000000000 image/svg+xml ut hash uthash-1.9.9.1+git20151125/doc/uthash.png000066400000000000000000000520161264051566200173470ustar00rootroot00000000000000PNG  IHDRWӷ@+iCCPICC ProfilexXwP;v{iJ/^T.E"K Aٰ U^EQ^ȗy/3;y䜜$'s'<<  p0%K{H^ 쬠)PDX>wC3+ܹjE  @7`0&vbH(~> &D89A|bM1G0trQMBG`7.B 4JsB #.'cLiƾOh[Q/Go9\9/7k=tͽA`76dܲXXX5Mjo ::q%>݁lmƹ̝wF@ZFXUQlxd#Vy-Z)nG[zu!~m%#;c YO6e532nޚF6.G'Vgk[-Ϲ=\{,}R}KnS@ }ԐЬjg#Ql"1t-l':&9ON1M58q&}utHNL?xZ#K8k-{8^ټ|Bɢ3q%gJˮ;RQXTpąًmr/ը\A]Z~v]v zM[:MgZ[tͺ*M8^=*kPX8_xZlOdK=!Jb^hXoy0s`՝:W4;10}Dyd]>~G?y—!ߌ~_n)M w]ص$,g]k+?W66=s7\+K6Kǜz\|PnQSm> Jg,%)4-̉6޺T']C~ +nOlLB#I|IoU%K!,6NFLPkΆ~GpJlxC?`P: N z'@#1Cj!GW("Pi4? Cˆc\1YgXf6NJ↘hL-n̗XY."X=Yhk6]*v<{ G:g Vbn~nxy? JUDE1Ubb[H[%%ofHHMIWo## /#$/$?pi{OT|TFJ ~Jjxu19˫'clA6j41a12 1v9k^cK렻Gƞ/})] m9OD$E F58.ŝM098t.!:֏?%-ƾhf&,S"s9GZVpx-|9gvVNf.V]]j->pNn&. 7w'ONuׅDDb-D QIȭ+Rۦefepy RDUE3%/R\*/TE44C;uuyFL+-l<[]<0qgҠ"})"uA>dh5#'bƉ,K&R?H;utwɞ 5<3gJJ W6V_p$yk1uW|9=[l_P#>BwD{7я|)0 4Z o!,o燇FZߕ&w#}~xx'g}_<~,{i 8l>qa»KKs?V+kk딟?6<̗~,FZLx_KhH~7|-ᯗ o2. _iQKC`%C1~j{>Ga!6V|Pļ&~#0ƐvSiFCM:P'+(%޿M'r> C!M-56$ޟ @?xх.h2Z M_m=[D:O{q˛kgEpTgB `3%^ t_zQIy9FA*Ag{ZRP:Yϙs}|OۇD}\xzl|inY$V>)R{I\*"F'iiojr {@J|CFq1>C[&9Z,"G{$8$sc v&Kl`׶-4 n~Uv~Wj?-`d|d`0Ek°(b<CfkM]4߾?*h];V,f?u|@'FnzN ` VzTPD!(oy}⣄D*zrdtJzUaS~|=߻p~=@}oGW,ց:~/GmCFR&Kd2## J@KwvG2 1I)U)%rpyoh;F-@K1Z:]+J.k ִg?Rԭ,~Sz$4ԭhi١9&ʐəJoc2SHu`g^—?`߬ll*RUkPN5 ,) ,?6Ѡn{^M=th|^Vg7}*ĔbR*٨ FZ1YYvdLN=;;:JWQ{ϑ)DsDH,W<kLFMOe@|;5^?m{eyb\Hm[E34Tyիo\tWLf j2&/e1PXdœ$R$ zNX a-g罯-cl~n͜jEA/9|JKI 0d&0$EsgzxaNrJR\t-K:5%2H.#;w9h5V*+jRj /MqEj"ס%a?i<:3ETMiXn)I ="aG%hbֵBf0T{z{H:tB"-rVuA'Prr^KbuXr :\ q~jߔ-b^*~%.QfkUFiSa* i t#z.s'j\@ò!,#Q . ٛLQxOAUݦCF4̄ɘ){sA2C(p* M>Yx>A/0tB=52s廠`m෿ZcX7Y (ַD^6NE1QH(dF,B$JZG13K:}kA"#iTB}Z_TAY( TkUA(j^Fa15[aWY<S-ٻ.xI$ 8D{,V9ھm:(Zp۶mY7[Q@(8j Mbo +rORW Mtt]a{0]W4w}%4X:$i1%[2b\&k9(R׺khwL`RgGˢa6G/Oho+;Vl!AKg)RB-;>seGQʭr3(g&t,>ð@@Y@]9^ԭd{at:`7,h $kS)hSGW; wjm;fO&9djrʋr5Lxm{ 5k$/| ɱD 4ҿqhq&J& tD`E y`4=YZ*Dg⭎բf KhQ9AU B(St?ztl1˔0ZGr*c9ɋ:;?\E'T^eĄoM '#j8hiѭ-5-bƃSg@e8e'FF`m (OymΞ ;m'0\sߔAGehBLslT[\tkT3[Ә^Ч1&'T&4v,LjhmjMjhK:VGGLƏ\.dz2?!6Lyeٝ:6M]:O$Ηh GZo1 KEF8 Pl\HřHe jz#\'UW:Jטfp  B_ G&r?+Ң' 0Of![[bCSINrS=psʐ\L\t N6ŤC-bbNK?qw=@ש"SOR5l XFG;PL!!, _޹.xwp8]J< ׊TW46ҟH #5LZCgfJ7/,ťqfO4WJ6;?Sn§|VTCODtDiN7  Q]xCC3,u}fYόo1_ Oߒ{4OdKٴ0c\.?K~YX+LJ#.~iسlBӉv4!ñX}rE;AOݓ(t겟_2ցŔP1̜6Y9#756JS0Ĥo4Dw 7c ~Le]s5sOZuFnйXgL+rV I@@CUC(8% 8ɴ$bLZa@ !@KMi Mx7}i|:ܘ8FX@r _zE'MbQR?ɯ] }}hvZR(Qid;);O VdX/xԁH깣`[sMhuϷ\4~潐%ŝaQ1ΒM.t˷m;Z:t8\i & >̱kŏZX;No]`ˇ;/8^7 >ƹФ]8WG#|t(K3Nr:~! CGuʎef L"%\~,)ݒPF8_W?> @ #d (7dME!g吊HNsN *.QE#o{jv - JȋA6ro\GVN/oμkڟo4T&qJ./>ٍS<ԄĤ@-FzOSf߇in2qdoTg9֣'$Z2[<,Umqޏ_xKNڳJjrA]".ꜚ%qm-.h7@۝pxF:0hLt>ZuѠi)߾?nju@]仏ꇈBNXMr"h:{ڪ .2(x<0$ $-G~q dyb ݴɑ(r#ϛ_,ivW`,-6“0JXa\R1X$&TduKc_|Q=4w'\YcVVa"y˟,.%o*{^}v瑱hPv%7M{1zv[36d(L?ZaRFs栞h[g,E ZYb)t_iBca嫟y3vd^>ycW&g˟8/A;,@=QvjЏqC~Rڴaі .-W_E4.( 8(CjZ7f0`Q:$axLw g&G_mqѷcY]geSJ|\-3/M͘Ha5Ws;.s/ѣJ肃ŒW \lnxit\mY򻰐kgu{ϙ>ѢaML!9T'\&|q[rM;Čajo34ɱL&ϤRtcnx=Ȁ3B-IaT sࡇ\y=78hÏJXtYsI:õXH*\ri YPJHIA9!< y=w}̩ZT /_~=dy NS{,K} |خO= Qf7ǏAԬ4f_AS|1[v~~_}_: ұbWGR0Bnu )u`!W_Dh ,9:=q^)K], ֛+n~1H]=jx!uxbq&yUm!y;^p˰z笟X{:qqR,r[Gn6bA,B 5(O * Q =%@wANN)aUlj޸?Z-@'j]@ §ko^{ߕS_jo eQdH ]I Q>ЉƦE:CUz9b1,vT "w0Z$$i eE&W'^lWϲɖV>\CL{ǀهO(t=%wr'kTBV At呡SnnR{窞]@jG>o^lvk ` IDATҲ[ZԼ H*F -a)49X>gخXyZjuZ d$'!yZ}gbzt~FrɘZɧF:chWyTz =B#f*@;9-߅MBTUp9m-u΄4k85b_ա$%\M<5Z1'bC`>̓._ML=EM .E.(%k\J|`ғuHNKsJCw},Q'eT}l̀qSmgsUTޔ`'%ФvqBgGuؕy8贊'ePrD^6oRb{v{'-7*gd\V{+ݸ#}3CQ5x*v{%ꚩ>x*PpՄdTb7GEbc,0ʓ'ڵ4> ɚu0qr4]Jt;:b倕ag띇nŊv|{9:^tiOtPjǔ]E=E'U { ܋){nFM~)U#]B[c3(&kX\Mq?}Zz¿r\RW5L #)d8יZ1c̺3mUm VUgϭok.?*kUc:#FD[Ozh ]'_[ c@0!}'_uleój8^ w3otk1vKڪLxrxgM-WOwU5Br"mYc y6stgu3"T w栘ZOZCi6.̒Oxf+)׸!f mB/|37o `8[^/c(VO8x0GoI^8~p NUS< E> 'Pus=vÂz:s>rkPDGN{˶U 5s1kRB~ӗ.0cG>/q.(p9Ƀ?ힲZ=kxl` 9|O'OИ?Y %fN~h݊m(^g4%~~>f$6a!g?a,rQ\! e!jyd̎#cwG/S`[u@yR8μ\:i@1c96e2CgeR#u].>9I>yFìlC 17f>j3_(]pRNQDp6ߤe*#*^QiXfr =2]ʺ#M罋،U<'EWv;C61{ ;M(sv'hX>)iNh<+z#EFX1gŎ1cg0a.nWFy ^P B#^TD `J(1b~{nldL~ 줒Al{zk=cJVqE [ˇt}䦵2;f6Qʴq{<6.D:mŦZѺNg/ZLæUтB8 GԤ-$7 =>qZNW\Cf/1Kb;L7=a%VN`UowdܫI:{F`bx%v=Dd20I6QYJcYUlƈ%X3@I>aLeg.rӈ?!1%tR6.vƇ>pK * PD q`CGt'QwocWjYc>캈Bl;U=fT`XU #ߢ-U! gMhp|yXkcR&eIYbb.۰>9)L-Å-y,Xj茉bS}>/J=S~P&O7 8gɑI**M0-[.Љ$\/ \q㇛ 6{ޟvOB^Gc"팳FДV:TbY# lf=&KM=exN xF3`txnX5ޜ{9=uoSO9䐡3_(#'tb,Mgi&Kȸu<2mG P-@9jI|}Z9ϨҌ#pd؄qT1cZ&R̲Ϩ3~Hvaώ[fМ]Ak19&Df`G;Lt7!9=񉆸ظOiHDNp|szb+ŘyG|O1B~;f"Y'P]bt?1ygMۢ*cLe q%s<"8:bRa C%$FϼA#*E*,hJ^2}0 2DP|(,kʈ)!e r֋)Lf%R5I| TI' iY**ʣI.v,=Ɯ{#{q4I跹:I` \HŲ"1\89z2b8Đb 881t zQRf2Y% J AbPHew~@[dfF-)Y*1gr<ә*^U }# VbM'qR:%J.v.16bl-ӎasҰҪIВZ-o5:}Uɞ'8(v՝dsԞgdy=WsGEò=hr$А%~\vA>(̬4@8\9ѕ]}A7VḅHO“0<"IgNzx/@7`͈Dw[ZF[:ܞQcdkT?iN tbr+섽@1pQ5)1W1\D@نS~ЉZoyJCNB Z$|Aɚ) nzp%hܸj|1e 㲖7#opsU%2/-E5"IfΑ!jnD`TȄAJ*R~ᜬ>D|&)ђy--+~6[FZ QuRl_ z:caunMz g2IpGs&}"ۻ*'פ Ѕe@O!$)x8I4=NFꄇIB pۍyL]{MzWoW Ј e5\7(gIA25I؇4J,ܹ%n O ZX ]$:E'o` V+K4CH6Z:"oX i,Gnv4͙<핹_(ݒt%l[,NRcu>;iezv`IĝJ=ioj@ $<Ӛ8+]$.zG<`(PChGDy1XBy.aTse*b&1STdT GC+-- O.;,gDح ub‰+O@ |2\Pؕ Kq턞DivUsgx2SOMᰉDz 7!&Lbl d-lLM5jNWɔ*M޽`j,_dVX2zu1lӢ_UvKx3Y/D%=9b5)ڴ7o bLO}V Z}<5'Z O^:u Cmݴڕ^.p!&3D- w禗i=KciJNN4}pxؤq$(`\(WxsX6)^I/JY)r ,)$,!7fW5q7T)X:v Q- eLYRVzOQru%4YG~M#P˓[t%Tgx+bR޻lN|xjwyrӚ'V.x_.,ܯx0ǯmdNb?8dOʅO(F"OC }}ɒ=6ɱݽzG56a 41z 3QWB~*J6t86^q"[ds8SRG\UyD+)Tr!`;$ KkR S8-&_ lrw{nSv+C6b^UMwC`I)CM5eݞs3}w K^0p}Fj0jX4D4;rȔ9L>1|AηϘ>aɝJk۞#ʆaѪ~u-HPX3߾CEXK4H¯07`v3]kG|_*ی: mO .V,? -`CQ C8G+\@LrPr6ϙ;sWVLޞ6bտ/7[/%0^ar\#vN~h! [s&󵗰z kj>^ɵN,TP6#q}-pQVzwsG߇*h'7g䝩+tIrO`n`NoM G&Ľ Āvys-g $5O0V፺˷ z}[%^ɣ}GtJ7{Ma@ἳ>Ŧ+SUHߧas1;B7S3N{j"zamC:iS3G.%\ C,IJVndL5Ӆe">8S쁪(pA}bC())Z  iW1<>#s(ladlheel/WN\;Wt[r'S;\9!vm9ߋh+Կ2, )LorhRsL59F2?qXb?tG?\sK$ѝיּmL_ˠYLKik ؁J4F)$цyX;pMԘ+(0W9Q}@I?0ք͉p%T p`OׯZ3{0r 2slDcsUyADhP82>MXq <5ʨs64c/Uxa1g`LCWI͕TJoAh-aCkoj=JⲋlN FFL C|57+q}|oi;f{fLbzN/}]ƾG}| 0X؆QsEXh_*;؝@ö@.yr_j|g /?jgTrXqnF{;6 [eٱ<ӷY~+lT0yd| ]UBNG2rBNʕeZӲɕze5GqpmEz-+?u>q;LbNe/|b{&`3^ ?,=祝OK{?㺙sVzDĤ!xE:7qX{@px+B2EDr9 7 ʇBOSwn"纽砓bkT"TԳwP5tRP>t+/?TpU7&@4cש~.mWir4rRiР>H `y;< 6_s2t#xB"ʾcv1/ iO(hjuMOxNlS~:DqWv՞rFKCo<؍OLk,yiTZ Gˎ5 vM&,'dy|{Ů{ap 4{L0hYtooٺOUűRviپ1H@I@\Pb4P eZ2RfBeM![#_`#f4݄ooL3\Lh>LZuVxs/sɆ$ ~fǫCs*6JC㾘 86{2`N89?o5Dh}o%:ɻ 6ZugqEڌѷnrNK3ߩx{~Q3HH`э| +8TzgfsRmAЦMnш9Hxc觫|鳻ժfWgO+cEVaG?x'Qt =-ء0~*HR=_{UHc~_J 2]gp e(2Y>g/ԆXg:&}dkSmb&&cLjCF^{rA[/t:v޺.χr)CuЭqHGTIDgv9_qS'mR[n 6T0b!%% ֥ ЙbNmlwF#@e Q[* *:Dۇhd6-8lU+Kf=3>HaA|uxd5r.H/]voR^yJKâ_Yv'N ;~% 1 ǘ|mcvw(@GO9̇(Ov`ɩfa4x11rKF5L-&A&԰#- =n,z[ռ:Q*vξxa]X>%W%i_rQB}wpMsKؒ:j`r@%qN˜1hxށBTQM| :bSbE6Mt^wHniO3qqIDATIadӈNaiJosE&_;6Q+E 6u>XA]eU$5b`ܭʺLxs] O Gڻ{5+e}:+F]=[sX]|#BȈI|[Wip@b@HIk‹, 5=n(9X6ͽ N0m~,9oelT;ʶX5yKkr> .A1jfwZsT-3t9+r2om_'`OԸ!2Y9!A ZS Vdj fdH,^{=tQw }kqwַ'IMGu:vlCc' jX3Oq8EDL$1< ${Q TKXP2fFԶX۰Q̜C'SjO»/͕kpNT䄊(?P)c$*2zx$o$ 5 9Ϛ7cpQO%?2B'8/oqJN3e߾:!.wO7 utlist: linked list macros for C structures

Here’s a link back to the GitHub project page.

Introduction

A set of general-purpose linked list macros for C structures are included with uthash in utlist.h. To use these macros in your own C program, just copy utlist.h into your source directory and use it in your programs.

#include "utlist.h"

These macros support the basic linked list operations: adding and deleting elements, sorting them and iterating over them.

Download

To download the utlist.h header file, follow the links on https://github.com/troydhanson/uthash to clone uthash or get a zip file, then look in the src/ sub-directory.

BSD licensed

This software is made available under the revised BSD license. It is free and open source.

Platforms

The utlist macros have been tested on:

  • Linux,

  • Mac OS X, and

  • Windows, using Visual Studio 2008, Visual Studio 2010, or Cygwin/MinGW.

Using utlist

Types of lists

Three types of linked lists are supported:

  • singly-linked lists,

  • doubly-linked lists, and

  • circular, doubly-linked lists

Efficiency

Prepending elements

Constant-time on all list types.

Appending

O(n) on singly-linked lists; constant-time on doubly-linked list. (The utlist implementation of the doubly-linked list keeps a tail pointer in head->prev so that append can be done in constant time).

Deleting elements

O(n) on singly-linked lists; constant-time on doubly-linked list.

Sorting

O(n log(n)) for all list types.

Iteration, counting and searching

O(n) for all list types.

List elements

You can use any structure with these macros, as long as the structure contains a next pointer. If you want to make a doubly-linked list, the element also needs to have a prev pointer.

typedef struct element {
    char *name;
    struct element *prev; /* needed for a doubly-linked list only */
    struct element *next; /* needed for singly- or doubly-linked lists */
} element;

You can name your structure anything. In the example above it is called element. Within a particular list, all elements must be of the same type.

Flexible prev/next naming

You can name your prev and next pointers something else. If you do, there is a family of macros that work identically but take these names as extra arguments.

List head

The list head is simply a pointer to your element structure. You can name it anything. It must be initialized to NULL.

element *head = NULL;

List operations

The lists support inserting or deleting elements, sorting the elements and iterating over them.

Singly-linked Doubly-linked Circular, doubly-linked

LL_PREPEND(head,add);

DL_PREPEND(head,add);

CDL_PREPEND(head,add;

LL_PREPEND_ELEM(head,elt,add)

DL_PREPEND_ELEM(head,elt,add)

CDL_PREPEND_ELEM(head,elt,add)

LL_REPLACE_ELEM(head,elt,add)

DL_REPLACE_ELEM(head,elt,add)

CDL_REPLACE_ELEM(head,elt,add)

LL_APPEND(head,add);

DL_APPEND(head,add);

LL_CONCAT(head1,head2);

DL_CONCAT(head1,head2);

LL_DELETE(head,del);

DL_DELETE(head,del);

CDL_DELETE(head,del);

LL_SORT(head,cmp);

DL_SORT(head,cmp);

CDL_SORT(head,cmp);

LL_FOREACH(head,elt) {…}

DL_FOREACH(head,elt) {…}

CDL_FOREACH(head,elt) {…}

LL_FOREACH_SAFE(head,elt,tmp) {…}

DL_FOREACH_SAFE(head,elt,tmp) {…}

CDL_FOREACH_SAFE(head,elt,tmp1,tmp2) {…}

LL_SEARCH_SCALAR(head,elt,mbr,val);

DL_SEARCH_SCALAR(head,elt,mbr,val);

CDL_SEARCH_SCALAR(head,elt,mbr,val);

LL_SEARCH(head,elt,like,cmp);

DL_SEARCH(head,elt,like,cmp);

CDL_SEARCH(head,elt,like,cmp);

LL_COUNT(head,elt,count);

DL_COUNT(head,elt,count);

CDL_COUNT(head,elt,count);

Prepend means to insert an element in front of the existing list head (if any), changing the list head to the new element. Append means to add an element at the end of the list, so it becomes the new tail element. Concatenate takes two properly constructed lists and appends the second list to the first. (Visual Studio 2008 does not support LL_CONCAT and DL_CONCAT, but VS2010 is ok.) To prepend before an arbitrary element instead of the list head, use the _PREPEND_ELEM macro family. To replace an arbitary list element with another element use the _REPLACE_ELEM family of macros.

The sort operation never moves the elements in memory; rather it only adjusts the list order by altering the prev and next pointers in each element. Also the sort operation can change the list head to point to a new element.

The foreach operation is for easy iteration over the list from the head to the tail. A usage example is shown below. You can of course just use the prev and next pointers directly instead of using the foreach macros. The foreach_safe operation should be used if you plan to delete any of the list elements while iterating.

The search operation is a shortcut for iteration in search of a particular element. It is not any faster than manually iterating and testing each element. There are two forms: the "scalar" version searches for an element using a simple equality test on a given structure member, while the general version takes an element to which all others in the list will be compared using a cmp function.

The count operation iterates over the list and increments a supplied counter.

The parameters shown in the table above are explained here:

head

The list head (a pointer to your list element structure).

add

A pointer to the list element structure you are adding to the list.

del

A pointer to the list element structure you are deleting from the list.

elt

A pointer that will be assigned to each list element in succession (see example) in the case of iteration macros; or, the output pointer from the search macros; or the element to be prepended to or replaced.

like

An element pointer, having the same type as elt, for which the search macro seeks a match (if found, the match is stored in elt). A match is determined by the given cmp function.

cmp

pointer to comparison function which accepts two arguments-- these are pointers to two element structures to be compared. The comparison function must return an int that is negative, zero, or positive, which specifies whether the first item should sort before, equal to, or after the second item, respectively. (In other words, the same convention that is used by strcmp). Note that under Visual Studio 2008 you may need to declare the two arguments as void * and then cast them back to their actual types.

tmp

A pointer of the same type as elt. Used internally. Need not be initialized.

mbr

In the scalar search macro, the name of a member within the elt structure which will be tested (using ==) for equality with the value val.

val

In the scalar search macro, specifies the value of (of structure member field) of the element being sought.

count

integer which will be set to the length of the list

Example

This example program reads names from a text file (one name per line), and appends each name to a doubly-linked list. Then it sorts and prints them.

A doubly-linked list
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "utlist.h"

#define BUFLEN 20

typedef struct el {
    char bname[BUFLEN];
    struct el *next, *prev;
} el;

int namecmp(el *a, el *b) {
    return strcmp(a->bname,b->bname);
}

el *head = NULL; /* important- initialize to NULL! */

int main(int argc, char *argv[]) {
    el *name, *elt, *tmp, etmp;

    char linebuf[BUFLEN];
    int count;
    FILE *file;

    if ( (file = fopen( "test11.dat", "r" )) == NULL ) {
        perror("can't open: ");
        exit(-1);
    }

    while (fgets(linebuf,BUFLEN,file) != NULL) {
        if ( (name = (el*)malloc(sizeof(el))) == NULL) exit(-1);
        strncpy(name->bname,linebuf,BUFLEN);
        DL_APPEND(head, name);
    }
    DL_SORT(head, namecmp);
    DL_FOREACH(head,elt) printf("%s", elt->bname);
    DL_COUNT(head, elt, count);
    printf("%d number of elements in list\n", count);

    memcpy(&etmp.bname, "WES\n", 5);
    DL_SEARCH(head,elt,&etmp,namecmp);
    if (elt) printf("found %s\n", elt->bname);

    /* now delete each element, use the safe iterator */
    DL_FOREACH_SAFE(head,elt,tmp) {
      DL_DELETE(head,elt);
    }

    fclose(file);

    return 0;
}

Other names for prev and next

If the prev and next fields are named something else, a separate group of macros must be used. These work the same as the regular macros, but take the field names as extra parameters.

These "flexible field name" macros are shown below. They all end with "2". Each operates the same as its counterpart without the 2, but they take the name of the prev and next fields (as applicable) as trailing arguments.

Flexible field name macros
LL_SORT2(list, cmp, next)
DL_SORT2(list, cmp, prev, next)
CDL_SORT2(list, cmp, prev, next)
LL_PREPEND2(head,add,next)
LL_CONCAT2(head1,head2,next)
LL_APPEND2(head,add,next)
LL_DELETE2(head,del,next)
LL_FOREACH2(head,el,next)
LL_FOREACH_SAFE2(head,el,tmp,next)
LL_SEARCH_SCALAR2(head,out,field,val,next)
LL_SEARCH2(head,out,elt,cmp,next)
LL_COUNT(head,el,count);
LL_COUNT2(head,el,count,next);
DL_PREPEND2(head,add,prev,next)
DL_APPEND2(head,add,prev,next)
DL_CONCAT2(head1,head2,prev,next)
DL_DELETE2(head,del,prev,next)
DL_FOREACH2(head,el,next)
DL_FOREACH_SAFE2(head,el,tmp,next)
DL_COUNT(head,el,count);
DL_COUNT2(head,el,count,next);
CDL_PREPEND2(head,add,prev,next)
CDL_DELETE2(head,del,prev,next)
CDL_FOREACH2(head,el,next)
CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next)
CDL_SEARCH_SCALAR2(head,out,field,val,next)
CDL_SEARCH2(head,out,elt,cmp,next)
CDL_COUNT(head,el,count);
CDL_COUNT2(head,el,count,next);

uthash-1.9.9.1+git20151125/doc/utlist.txt000066400000000000000000000246421264051566200174360ustar00rootroot00000000000000utlist: linked list macros for C structures =========================================== Troy D. Hanson v1.9.9, November 2014 Here's a link back to the https://github.com/troydhanson/uthash[GitHub project page]. Introduction ------------ A set of general-purpose 'linked list' macros for C structures are included with uthash in `utlist.h`. To use these macros in your own C program, just copy `utlist.h` into your source directory and use it in your programs. #include "utlist.h" These macros support the basic linked list operations: adding and deleting elements, sorting them and iterating over them. Download ~~~~~~~~ To download the `utlist.h` header file, follow the links on https://github.com/troydhanson/uthash to clone uthash or get a zip file, then look in the src/ sub-directory. BSD licensed ~~~~~~~~~~~~ This software is made available under the link:license.html[revised BSD license]. It is free and open source. Platforms ~~~~~~~~~ The 'utlist' macros have been tested on: * Linux, * Mac OS X, and * Windows, using Visual Studio 2008, Visual Studio 2010, or Cygwin/MinGW. Using utlist ------------ Types of lists ~~~~~~~~~~~~~~ Three types of linked lists are supported: - *singly-linked* lists, - *doubly-linked* lists, and - *circular, doubly-linked* lists Efficiency ^^^^^^^^^^ Prepending elements:: Constant-time on all list types. Appending:: 'O(n)' on singly-linked lists; constant-time on doubly-linked list. (The utlist implementation of the doubly-linked list keeps a tail pointer in `head->prev` so that append can be done in constant time). Deleting elements:: 'O(n)' on singly-linked lists; constant-time on doubly-linked list. Sorting:: 'O(n log(n))' for all list types. Iteration, counting and searching:: 'O(n)' for all list types. List elements ~~~~~~~~~~~~~ You can use any structure with these macros, as long as the structure contains a `next` pointer. If you want to make a doubly-linked list, the element also needs to have a `prev` pointer. typedef struct element { char *name; struct element *prev; /* needed for a doubly-linked list only */ struct element *next; /* needed for singly- or doubly-linked lists */ } element; You can name your structure anything. In the example above it is called `element`. Within a particular list, all elements must be of the same type. Flexible prev/next naming ^^^^^^^^^^^^^^^^^^^^^^^^^ You can name your `prev` and `next` pointers something else. If you do, there is a <> that work identically but take these names as extra arguments. List head ~~~~~~~~~ The list head is simply a pointer to your element structure. You can name it anything. *It must be initialized to `NULL`*. element *head = NULL; List operations ~~~~~~~~~~~~~~~ The lists support inserting or deleting elements, sorting the elements and iterating over them. [width="100%",cols="10 #include #include #include "utlist.h" #define BUFLEN 20 typedef struct el { char bname[BUFLEN]; struct el *next, *prev; } el; int namecmp(el *a, el *b) { return strcmp(a->bname,b->bname); } el *head = NULL; /* important- initialize to NULL! */ int main(int argc, char *argv[]) { el *name, *elt, *tmp, etmp; char linebuf[BUFLEN]; int count; FILE *file; if ( (file = fopen( "test11.dat", "r" )) == NULL ) { perror("can't open: "); exit(-1); } while (fgets(linebuf,BUFLEN,file) != NULL) { if ( (name = (el*)malloc(sizeof(el))) == NULL) exit(-1); strncpy(name->bname,linebuf,BUFLEN); DL_APPEND(head, name); } DL_SORT(head, namecmp); DL_FOREACH(head,elt) printf("%s", elt->bname); DL_COUNT(head, elt, count); printf("%d number of elements in list\n", count); memcpy(&etmp.bname, "WES\n", 5); DL_SEARCH(head,elt,&etmp,namecmp); if (elt) printf("found %s\n", elt->bname); /* now delete each element, use the safe iterator */ DL_FOREACH_SAFE(head,elt,tmp) { DL_DELETE(head,elt); free(elt); } fclose(file); return 0; } -------------------------------------------------------------------------------- [[flex_names]] Other names for prev and next ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If the `prev` and `next` fields are named something else, a separate group of macros must be used. These work the same as the regular macros, but take the field names as extra parameters. These "flexible field name" macros are shown below. They all end with "2". Each operates the same as its counterpart without the 2, but they take the name of the `prev` and `next` fields (as applicable) as trailing arguments. .Flexible field name macros LL_SORT2(list, cmp, next) DL_SORT2(list, cmp, prev, next) CDL_SORT2(list, cmp, prev, next) LL_PREPEND2(head,add,next) LL_CONCAT2(head1,head2,next) LL_APPEND2(head,add,next) LL_DELETE2(head,del,next) LL_FOREACH2(head,el,next) LL_FOREACH_SAFE2(head,el,tmp,next) LL_SEARCH_SCALAR2(head,out,field,val,next) LL_SEARCH2(head,out,elt,cmp,next) LL_COUNT(head,el,count); LL_COUNT2(head,el,count,next); DL_PREPEND2(head,add,prev,next) DL_APPEND2(head,add,prev,next) DL_CONCAT2(head1,head2,prev,next) DL_DELETE2(head,del,prev,next) DL_FOREACH2(head,el,next) DL_FOREACH_SAFE2(head,el,tmp,next) DL_COUNT(head,el,count); DL_COUNT2(head,el,count,next); CDL_PREPEND2(head,add,prev,next) CDL_DELETE2(head,del,prev,next) CDL_FOREACH2(head,el,next) CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next) CDL_SEARCH_SCALAR2(head,out,field,val,next) CDL_SEARCH2(head,out,elt,cmp,next) CDL_COUNT(head,el,count); CDL_COUNT2(head,el,count,next); // vim: set tw=80 wm=2 syntax=asciidoc: uthash-1.9.9.1+git20151125/doc/utringbuffer.html000066400000000000000000001056661264051566200207470ustar00rootroot00000000000000 utringbuffer: dynamic ring-buffer macros for C

Here’s a link back to the GitHub project page.

Introduction

The functions in utringbuffer.h are based on the general-purpose array macros provided in utarray.h, so before reading this page you should read that page first.

To use these macros in your own C program, copy both utarray.h and utringbuffer.h into your source directory and use utringbuffer.h in your program.

#include "utringbuffer.h"

The provided operations are based loosely on the C++ STL vector methods. The ring-buffer data type supports construction (with a specified capacity), destruction, iteration, and push, but not pop; once the ring-buffer reaches full capacity, pushing a new element automatically pops and destroys the oldest element. The elements contained in the ring-buffer can be any simple datatype or structure.

Internally the ring-buffer contains a pre-allocated memory region into which the elements are copied, starting at position 0. When the ring-buffer reaches full capacity, the next element to be pushed is pushed at position 0, overwriting the oldest element, and the internal index representing the "start" of the ring-buffer is incremented. A ring-buffer, once full, can never become un-full.

Download

To download the utringbuffer.h header file, follow the links on https://github.com/troydhanson/uthash to clone uthash or get a zip file, then look in the src/ sub-directory.

BSD licensed

This software is made available under the revised BSD license. It is free and open source.

Platforms

The utringbuffer macros have been tested on:

  • Linux,

  • Mac OS X,

  • Windows, using Visual Studio 2008 and Visual Studio 2010

Usage

Declaration

The ring-buffer itself has the data type UT_ringbuffer, regardless of the type of elements to be stored in it. It is declared like,

UT_ringbuffer *history;

New and free

The next step is to create the ring-buffer using utringbuffer_new. Later when you’re done with the ring-buffer, utringbuffer_free will free it and all its elements.

Push, etc

The central features of the ring-buffer involve putting elements into it and iterating over them. There are several operations that deal with either single elements or ranges of elements at a time. In the examples below we will use only the push operation to insert elements.

Elements

Support for dynamic arrays of integers or strings is especially easy. These are best shown by example:

Integers

This example makes a ring-buffer of integers, pushes 0-9 into it, then prints it two different ways. Lastly it frees it.

Integer elements
#include <stdio.h>
#include "utringbuffer.h"

int main() {
  UT_ringbuffer *history;
  int i, *p;

  utringbuffer_new(history, 7, &ut_int_icd);
  for(i=0; i < 10; i++) utringbuffer_push_back(history, &i);

  for (p = (int*)utringbuffer_front(history);
       p != NULL;
       p = (int*)utringbuffer_next(history, p)) {
    printf("%d\n", *p);  /* prints "3 4 5 6 7 8 9" */
  }

  for (i=0; i < utringbuffer_len(history); i++) {
    p = utringbuffer_eltptr(history, i);
    printf("%d\n", *p);  /* prints "3 4 5 6 7 8 9" */
  }

  utringbuffer_free(history);

  return 0;
}

The second argument to utringbuffer_push_back is always a pointer to the type (so a literal cannot be used). So for integers, it is an int*.

Strings

In this example we make a ring-buffer of strings, push two strings into it, print it and free it.

String elements
#include <stdio.h>
#include "utringbuffer.h"

int main() {
  UT_ringbuffer *strs;
  char *s, **p;

  utringbuffer_new(strs, 7, &ut_str_icd);

  s = "hello"; utringbuffer_push_back(strs, &s);
  s = "world"; utringbuffer_push_back(strs, &s);
  p = NULL;
  while ( (p=(char**)utringbuffer_next(strs,p))) {
    printf("%s\n",*p);
  }

  utringbuffer_free(strs);

  return 0;
}

In this example, since the element is a char*, we pass a pointer to it (char**) as the second argument to utringbuffer_push_back. Note that "push" makes a copy of the source string and pushes that copy into the array.

About UT_icd

Arrays can be made of any type of element, not just integers and strings. The elements can be basic types or structures. Unless you’re dealing with integers and strings (which use pre-defined ut_int_icd and ut_str_icd), you’ll need to define a UT_icd helper structure. This structure contains everything that utringbuffer (or utarray) needs to initialize, copy or destruct elements.

typedef struct {
    size_t sz;
    init_f *init;
    ctor_f *copy;
    dtor_f *dtor;
} UT_icd;

The three function pointers init, copy, and dtor have these prototypes:

typedef void (ctor_f)(void *dst, const void *src);
typedef void (dtor_f)(void *elt);
typedef void (init_f)(void *elt);

The sz is just the size of the element being stored in the array.

The init function is used by utarray but is never used by utringbuffer; you may safely set it to any value you want.

The copy function is used whenever an element is copied into the buffer. It is invoked during utringbuffer_push_back. If copy is NULL, it defaults to a bitwise copy using memcpy.

The dtor function is used to clean up an element that is being removed from the buffer. It may be invoked due to utringbuffer_push_back (on the oldest element in the buffer), utringbuffer_clear, utringbuffer_done, or utringbuffer_free. If the elements need no cleanup upon destruction, dtor may be NULL.

Scalar types

The next example uses UT_icd with all its defaults to make a ring-buffer of long elements. This example pushes two longs into a buffer of capacity 1, prints the contents of the buffer (which is to say, the most recent value pushed), and then frees the buffer.

long elements
#include <stdio.h>
#include "utringbuffer.h"

UT_icd long_icd = {sizeof(long), NULL, NULL, NULL };

int main() {
  UT_ringbuffer *nums;
  long l, *p;
  utringbuffer_new(nums, 1, &long_icd);

  l=1; utringbuffer_push_back(nums, &l);
  l=2; utringbuffer_push_back(nums, &l);

  p=NULL;
  while((p = (long*)utringbuffer_next(nums,p))) printf("%ld\n", *p);

  utringbuffer_free(nums);
  return 0;
}

Structures

Structures can be used as utringbuffer elements. If the structure requires no special effort to initialize, copy or destruct, we can use UT_icd with all its defaults. This example shows a structure that consists of two integers. Here we push two values, print them and free the buffer.

Structure (simple)
#include <stdio.h>
#include "utringbuffer.h"

typedef struct {
    int a;
    int b;
} intpair_t;

UT_icd intpair_icd = {sizeof(intpair_t), NULL, NULL, NULL};

int main() {

  UT_ringbuffer *pairs;
  intpair_t ip, *p;
  utringbuffer_new(pairs, 7, &intpair_icd);

  ip.a=1;  ip.b=2;  utringbuffer_push_back(pairs, &ip);
  ip.a=10; ip.b=20; utringbuffer_push_back(pairs, &ip);

  for(p=(intpair_t*)utringbuffer_front(pairs);
      p!=NULL;
      p=(intpair_t*)utringbuffer_next(pairs,p)) {
    printf("%d %d\n", p->a, p->b);
  }

  utringbuffer_free(pairs);
  return 0;
}

The real utility of UT_icd is apparent when the elements stored in the ring-buffer are structures that require special work to initialize, copy or destruct.

For example, when a structure contains pointers to related memory areas that need to be copied when the structure is copied (and freed when the structure is freed), we can use custom init, copy, and dtor members in the UT_icd.

Here we take an example of a structure that contains an integer and a string. When this element is copied (such as when an element is pushed), we want to "deep copy" the s pointer (so the original element and the new element point to their own copies of s). When an element is destructed, we want to "deep free" its copy of s. Lastly, this example is written to work even if s has the value NULL.

Structure (complex)
#include <stdio.h>
#include <stdlib.h>
#include "utringbuffer.h"

typedef struct {
    int a;
    char *s;
} intchar_t;

void intchar_copy(void *_dst, const void *_src) {
  intchar_t *dst = (intchar_t*)_dst, *src = (intchar_t*)_src;
  dst->a = src->a;
  dst->s = src->s ? strdup(src->s) : NULL;
}

void intchar_dtor(void *_elt) {
  intchar_t *elt = (intchar_t*)_elt;
  free(elt->s);
}

UT_icd intchar_icd = {sizeof(intchar_t), NULL, intchar_copy, intchar_dtor};

int main() {
  UT_ringbuffer *intchars;
  intchar_t ic, *p;
  utringbuffer_new(intchars, 2, &intchar_icd);

  ic.a=1; ic.s="hello"; utringbuffer_push_back(intchars, &ic);
  ic.a=2; ic.s="world"; utringbuffer_push_back(intchars, &ic);
  ic.a=3; ic.s="peace"; utringbuffer_push_back(intchars, &ic);

  p=NULL;
  while( (p=(intchar_t*)utringbuffer_next(intchars,p))) {
    printf("%d %s\n", p->a, (p->s ? p->s : "null"));
    /* prints "2 world 3 peace" */
  }

  utringbuffer_free(intchars);
  return 0;
}

Reference

This table lists all the utringbuffer operations. These are loosely based on the C++ vector class.

Operations

utringbuffer_new(UT_ringbuffer *a, int n, UT_icd *icd)

allocate a new ringbuffer

utringbuffer_free(UT_ringbuffer *a)

free an allocated ringbuffer

utringbuffer_init(UT_ringbuffer *a, int n, UT_icd *icd)

init a ringbuffer (non-alloc)

utringbuffer_done(UT_ringbuffer *a)

dispose of a ringbuffer (non-alloc)

utringbuffer_clear(UT_ringbuffer *a)

clear all elements from a, making it empty

utringbuffer_push_back(UT_ringbuffer *a, element *p)

push element p onto a

utringbuffer_len(UT_ringbuffer *a)

get length of a

utringbuffer_empty(UT_ringbuffer *a)

get whether a is empty

utringbuffer_full(UT_ringbuffer *a)

get whether a is full

utringbuffer_eltptr(UT_ringbuffer *a, int j)

get pointer of element from index

utringbuffer_eltidx(UT_ringbuffer *a, element *e)

get index of element from pointer

utringbuffer_front(UT_ringbuffer *a)

get oldest element of a

utringbuffer_next(UT_ringbuffer *a, element *e)

get element of a following e (front if e is NULL)

utringbuffer_prev(UT_ringbuffer *a, element *e)

get element of a before e (back if e is NULL)

utringbuffer_back(UT_ringbuffer *a)

get newest element of a

Notes

  1. utringbuffer_new and utringbuffer_free are used to allocate a new ring-buffer and to free it, while utringbuffer_init and utringbuffer_done can be used if the UT_ringbuffer is already allocated and just needs to be initialized or have its internal resources freed.

  2. Both utringbuffer_new and utringbuffer_init take a second parameter n indicating the capacity of the ring-buffer, that is, the size at which the ring-buffer is considered "full" and begins to overwrite old elements with newly pushed ones.

  3. Once a ring-buffer has become full, it will never again become un-full except by means of utringbuffer_clear. There is no way to "pop" a single old item from the front of the ring-buffer. You can simulate this ability by maintaining a separate integer count of the number of "logically popped elements", and starting your iteration with utringbuffer_eltptr(a, popped_count) instead of with utringbuffer_front(a).

  4. Pointers to elements (obtained using utringbuffer_eltptr, utringbuffer_front, utringbuffer_next, etc.) are not generally invalidated by utringbuffer_push_back, because utringbuffer does not perform reallocation; however, a pointer to the oldest element may suddenly turn into a pointer to the newest element if utringbuffer_push_back is called while the buffer is full.

  5. The elements of a ring-buffer are stored in contiguous memory, but once the ring-buffer has become full, it is no longer true that the elements are contiguously in order from oldest to newest; i.e., (element *)utringbuffer_front(a) + utringbuffer_len(a)-1 is not generally equal to (element *)utringbuffer_back(a).


uthash-1.9.9.1+git20151125/doc/utringbuffer.txt000066400000000000000000000323031264051566200206050ustar00rootroot00000000000000utringbuffer: dynamic ring-buffer macros for C ============================================== Arthur O'Dwyer v0.1, June 2015 Here's a link back to the https://github.com/troydhanson/uthash[GitHub project page]. Introduction ------------ The functions in `utringbuffer.h` are based on the general-purpose array macros provided in `utarray.h`, so before reading this page you should read link:utarray.html[that page] first. To use these macros in your own C program, copy both `utarray.h` and `utringbuffer.h` into your source directory and use `utringbuffer.h` in your program. #include "utringbuffer.h" The provided <> are based loosely on the C++ STL vector methods. The ring-buffer data type supports construction (with a specified capacity), destruction, iteration, and push, but not pop; once the ring-buffer reaches full capacity, pushing a new element automatically pops and destroys the oldest element. The elements contained in the ring-buffer can be any simple datatype or structure. Internally the ring-buffer contains a pre-allocated memory region into which the elements are copied, starting at position 0. When the ring-buffer reaches full capacity, the next element to be pushed is pushed at position 0, overwriting the oldest element, and the internal index representing the "start" of the ring-buffer is incremented. A ring-buffer, once full, can never become un-full. Download ~~~~~~~~ To download the `utringbuffer.h` header file, follow the links on https://github.com/troydhanson/uthash to clone uthash or get a zip file, then look in the src/ sub-directory. BSD licensed ~~~~~~~~~~~~ This software is made available under the link:license.html[revised BSD license]. It is free and open source. Platforms ~~~~~~~~~ The 'utringbuffer' macros have been tested on: * Linux, * Mac OS X, * Windows, using Visual Studio 2008 and Visual Studio 2010 Usage ----- Declaration ~~~~~~~~~~~ The ring-buffer itself has the data type `UT_ringbuffer`, regardless of the type of elements to be stored in it. It is declared like, UT_ringbuffer *history; New and free ~~~~~~~~~~~~ The next step is to create the ring-buffer using `utringbuffer_new`. Later when you're done with the ring-buffer, `utringbuffer_free` will free it and all its elements. Push, etc ~~~~~~~~~ The central features of the ring-buffer involve putting elements into it and iterating over them. There are several <> that deal with either single elements or ranges of elements at a time. In the examples below we will use only the push operation to insert elements. Elements -------- Support for dynamic arrays of integers or strings is especially easy. These are best shown by example: Integers ~~~~~~~~ This example makes a ring-buffer of integers, pushes 0-9 into it, then prints it two different ways. Lastly it frees it. .Integer elements ------------------------------------------------------------------------------- #include #include "utringbuffer.h" int main() { UT_ringbuffer *history; int i, *p; utringbuffer_new(history, 7, &ut_int_icd); for(i=0; i < 10; i++) utringbuffer_push_back(history, &i); for (p = (int*)utringbuffer_front(history); p != NULL; p = (int*)utringbuffer_next(history, p)) { printf("%d\n", *p); /* prints "3 4 5 6 7 8 9" */ } for (i=0; i < utringbuffer_len(history); i++) { p = utringbuffer_eltptr(history, i); printf("%d\n", *p); /* prints "3 4 5 6 7 8 9" */ } utringbuffer_free(history); return 0; } ------------------------------------------------------------------------------- The second argument to `utringbuffer_push_back` is always a 'pointer' to the type (so a literal cannot be used). So for integers, it is an `int*`. Strings ~~~~~~~ In this example we make a ring-buffer of strings, push two strings into it, print it and free it. .String elements ------------------------------------------------------------------------------- #include #include "utringbuffer.h" int main() { UT_ringbuffer *strs; char *s, **p; utringbuffer_new(strs, 7, &ut_str_icd); s = "hello"; utringbuffer_push_back(strs, &s); s = "world"; utringbuffer_push_back(strs, &s); p = NULL; while ( (p=(char**)utringbuffer_next(strs,p))) { printf("%s\n",*p); } utringbuffer_free(strs); return 0; } ------------------------------------------------------------------------------- In this example, since the element is a `char*`, we pass a pointer to it (`char**`) as the second argument to `utringbuffer_push_back`. Note that "push" makes a copy of the source string and pushes that copy into the array. About UT_icd ~~~~~~~~~~~~ Arrays can be made of any type of element, not just integers and strings. The elements can be basic types or structures. Unless you're dealing with integers and strings (which use pre-defined `ut_int_icd` and `ut_str_icd`), you'll need to define a `UT_icd` helper structure. This structure contains everything that utringbuffer (or utarray) needs to initialize, copy or destruct elements. typedef struct { size_t sz; init_f *init; ctor_f *copy; dtor_f *dtor; } UT_icd; The three function pointers `init`, `copy`, and `dtor` have these prototypes: typedef void (ctor_f)(void *dst, const void *src); typedef void (dtor_f)(void *elt); typedef void (init_f)(void *elt); The `sz` is just the size of the element being stored in the array. The `init` function is used by utarray but is never used by utringbuffer; you may safely set it to any value you want. The `copy` function is used whenever an element is copied into the buffer. It is invoked during `utringbuffer_push_back`. If `copy` is `NULL`, it defaults to a bitwise copy using memcpy. The `dtor` function is used to clean up an element that is being removed from the buffer. It may be invoked due to `utringbuffer_push_back` (on the oldest element in the buffer), `utringbuffer_clear`, `utringbuffer_done`, or `utringbuffer_free`. If the elements need no cleanup upon destruction, `dtor` may be `NULL`. Scalar types ~~~~~~~~~~~~ The next example uses `UT_icd` with all its defaults to make a ring-buffer of `long` elements. This example pushes two longs into a buffer of capacity 1, prints the contents of the buffer (which is to say, the most recent value pushed), and then frees the buffer. .long elements ------------------------------------------------------------------------------- #include #include "utringbuffer.h" UT_icd long_icd = {sizeof(long), NULL, NULL, NULL }; int main() { UT_ringbuffer *nums; long l, *p; utringbuffer_new(nums, 1, &long_icd); l=1; utringbuffer_push_back(nums, &l); l=2; utringbuffer_push_back(nums, &l); p=NULL; while((p = (long*)utringbuffer_next(nums,p))) printf("%ld\n", *p); utringbuffer_free(nums); return 0; } ------------------------------------------------------------------------------- Structures ~~~~~~~~~~ Structures can be used as utringbuffer elements. If the structure requires no special effort to initialize, copy or destruct, we can use `UT_icd` with all its defaults. This example shows a structure that consists of two integers. Here we push two values, print them and free the buffer. .Structure (simple) ------------------------------------------------------------------------------- #include #include "utringbuffer.h" typedef struct { int a; int b; } intpair_t; UT_icd intpair_icd = {sizeof(intpair_t), NULL, NULL, NULL}; int main() { UT_ringbuffer *pairs; intpair_t ip, *p; utringbuffer_new(pairs, 7, &intpair_icd); ip.a=1; ip.b=2; utringbuffer_push_back(pairs, &ip); ip.a=10; ip.b=20; utringbuffer_push_back(pairs, &ip); for(p=(intpair_t*)utringbuffer_front(pairs); p!=NULL; p=(intpair_t*)utringbuffer_next(pairs,p)) { printf("%d %d\n", p->a, p->b); } utringbuffer_free(pairs); return 0; } ------------------------------------------------------------------------------- The real utility of `UT_icd` is apparent when the elements stored in the ring-buffer are structures that require special work to initialize, copy or destruct. For example, when a structure contains pointers to related memory areas that need to be copied when the structure is copied (and freed when the structure is freed), we can use custom `init`, `copy`, and `dtor` members in the `UT_icd`. Here we take an example of a structure that contains an integer and a string. When this element is copied (such as when an element is pushed), we want to "deep copy" the `s` pointer (so the original element and the new element point to their own copies of `s`). When an element is destructed, we want to "deep free" its copy of `s`. Lastly, this example is written to work even if `s` has the value `NULL`. .Structure (complex) ------------------------------------------------------------------------------- #include #include #include "utringbuffer.h" typedef struct { int a; char *s; } intchar_t; void intchar_copy(void *_dst, const void *_src) { intchar_t *dst = (intchar_t*)_dst, *src = (intchar_t*)_src; dst->a = src->a; dst->s = src->s ? strdup(src->s) : NULL; } void intchar_dtor(void *_elt) { intchar_t *elt = (intchar_t*)_elt; free(elt->s); } UT_icd intchar_icd = {sizeof(intchar_t), NULL, intchar_copy, intchar_dtor}; int main() { UT_ringbuffer *intchars; intchar_t ic, *p; utringbuffer_new(intchars, 2, &intchar_icd); ic.a=1; ic.s="hello"; utringbuffer_push_back(intchars, &ic); ic.a=2; ic.s="world"; utringbuffer_push_back(intchars, &ic); ic.a=3; ic.s="peace"; utringbuffer_push_back(intchars, &ic); p=NULL; while( (p=(intchar_t*)utringbuffer_next(intchars,p))) { printf("%d %s\n", p->a, (p->s ? p->s : "null")); /* prints "2 world 3 peace" */ } utringbuffer_free(intchars); return 0; } ------------------------------------------------------------------------------- [[operations]] Reference --------- This table lists all the utringbuffer operations. These are loosely based on the C++ vector class. Operations ~~~~~~~~~~ [width="100%",cols="50 utstring: dynamic string macros for C

Here’s a link back to the GitHub project page.

Introduction

A set of basic dynamic string macros for C programs are included with uthash in utstring.h. To use these in your own C program, just copy utstring.h into your source directory and use it in your programs.

#include "utstring.h"

The dynamic string supports operations such as inserting data, concatenation, getting the length and content, substring search, and clear. It’s ok to put binary data into a utstring too. The string operations are listed below.

Some utstring operations are implemented as functions rather than macros.

Download

To download the utstring.h header file, follow the links on https://github.com/troydhanson/uthash to clone uthash or get a zip file, then look in the src/ sub-directory.

BSD licensed

This software is made available under the revised BSD license. It is free and open source.

Platforms

The utstring macros have been tested on:

  • Linux,

  • Windows, using Visual Studio 2008 and Visual Studio 2010

Usage

Declaration

The dynamic string itself has the data type UT_string. It is declared like,

UT_string *str;

New and free

The next step is to create the string using utstring_new. Later when you’re done with it, utstring_free will free it and all its content.

Manipulation

The utstring_printf or utstring_bincpy operations insert (copy) data into the string. To concatenate one utstring to another, use utstring_concat. To clear the content of the string, use utstring_clear. The length of the string is available from utstring_len, and its content from utstring_body. This evaluates to a char*. The buffer it points to is always null-terminated. So, it can be used directly with external functions that expect a string. This automatic null terminator is not counted in the length of the string.

Samples

These examples show how to use utstring.

Sample 1
#include <stdio.h>
#include "utstring.h"

int main() {
    UT_string *s;

    utstring_new(s);
    utstring_printf(s, "hello world!" );
    printf("%s\n", utstring_body(s));

    utstring_free(s);
    return 0;
}

The next example demonstrates that utstring_printf appends to the string. It also shows concatenation.

Sample 2
#include <stdio.h>
#include "utstring.h"

int main() {
    UT_string *s, *t;

    utstring_new(s);
    utstring_new(t);

    utstring_printf(s, "hello " );
    utstring_printf(s, "world " );

    utstring_printf(t, "hi " );
    utstring_printf(t, "there " );

    utstring_concat(s, t);
    printf("length: %u\n", utstring_len(s));
    printf("%s\n", utstring_body(s));

    utstring_free(s);
    utstring_free(t);
    return 0;
}

The next example shows how binary data can be inserted into the string. It also clears the string and prints new data into it.

Sample 3
#include <stdio.h>
#include "utstring.h"

int main() {
    UT_string *s;
    char binary[] = "\xff\xff";

    utstring_new(s);
    utstring_bincpy(s, binary, sizeof(binary));
    printf("length is %u\n", utstring_len(s));

    utstring_clear(s);
    utstring_printf(s,"number %d", 10);
    printf("%s\n", utstring_body(s));

    utstring_free(s);
    return 0;
}

Reference

These are the utstring operations.

Operations

utstring_new(s)

allocate a new utstring

utstring_renew(s)

allocate a new utstring (if s is NULL) otherwise clears it

utstring_free(s)

free an allocated utstring

utstring_init(s)

init a utstring (non-alloc)

utstring_done(s)

dispose of a utstring (non-allocd)

utstring_printf(s,fmt,…)

printf into a utstring (appends)

utstring_bincpy(s,bin,len)

insert binary data of length len (appends)

utstring_concat(dst,src)

concatenate src utstring to end of dst utstring

utstring_clear(s)

clear the content of s (setting its length to 0)

utstring_len(s)

obtain the length of s as an unsigned integer

utstring_body(s)

get char* to body of s (buffer is always null-terminated)

utstring_find(s,pos,str,len)

forward search from pos for a substring

utstring_findR(s,pos,str,len)

reverse search from pos a substring

New/free vs. init/done

Use utstring_new and utstring_free to allocate a new string or free it. If the UT_string is statically allocated, use utstring_init and utstring_done to initialize or free its internal memory.

Use utstring_find and utstring_findR to search for a substring in a utstring. It comes in forward and reverse varieties. The reverse search scans from the end of the string backward. These take a position to start searching from, measured from 0 (the start of the utstring). A negative position is counted from the end of the string, so, -1 is the last position. Note that in the reverse search, the initial position anchors to the end of the substring being searched for- e.g., the t in cat. The return value always refers to the offset where the substring starts in the utstring. When no substring match is found, -1 is returned.

For example if a utstring called s contains:

ABC ABCDAB ABCDABCDABDE

Then these forward and reverse substring searches for ABC produce these results:

utstring_find(  s, -9, "ABC", 3 ) = 15
utstring_find(  s,  3, "ABC", 3 ) =  4
utstring_find(  s, 16, "ABC", 3 ) = -1
utstring_findR( s, -9, "ABC", 3 ) = 11
utstring_findR( s, 12, "ABC", 3 ) =  4
utstring_findR( s,  2, "ABC", 3 ) =  0

The preceding examples show "single use" versions of substring matching, where the internal Knuth-Morris-Pratt (KMP) table is internally built and then freed after the search. If your program needs to run many searches for a given substring, it is more efficient to save the KMP table and reuse it.

To reuse the KMP table, build it manually and then pass it into the internal search functions. The functions involved are:

_utstring_BuildTable  (build the KMP table for a forward search)
_utstring_BuildTableR (build the KMP table for a reverse search)
_utstring_find        (forward search using a prebuilt KMP table)
_utstring_findR       (reverse search using a prebuilt KMP table)

This is an example of building a forward KMP table for the substring "ABC", and then using it in a search:

long *KPM_TABLE, offset;
KPM_TABLE = (long *)malloc( sizeof(long) * (strlen("ABC")) + 1));
_utstring_BuildTable("ABC", 3, KPM_TABLE);
offset = _utstring_find(utstring_body(s), utstring_len(s), "ABC", 3, KPM_TABLE );
free(KPM_TABLE);

Note that the internal _utstring_find has the length of the UT_string as its second argument, rather than the start position. You can emulate the position parameter by adding to the string start address and subtracting from its length.


uthash-1.9.9.1+git20151125/doc/utstring.txt000066400000000000000000000172651264051566200177740ustar00rootroot00000000000000utstring: dynamic string macros for C ===================================== Troy D. Hanson v1.9.9, November 2014 Here's a link back to the https://github.com/troydhanson/uthash[GitHub project page]. Introduction ------------ A set of basic dynamic string macros for C programs are included with uthash in `utstring.h`. To use these in your own C program, just copy `utstring.h` into your source directory and use it in your programs. #include "utstring.h" The dynamic string supports operations such as inserting data, concatenation, getting the length and content, substring search, and clear. It's ok to put binary data into a utstring too. The string <> are listed below. Some utstring operations are implemented as functions rather than macros. Download ~~~~~~~~ To download the `utstring.h` header file, follow the links on https://github.com/troydhanson/uthash to clone uthash or get a zip file, then look in the src/ sub-directory. BSD licensed ~~~~~~~~~~~~ This software is made available under the link:license.html[revised BSD license]. It is free and open source. Platforms ~~~~~~~~~ The 'utstring' macros have been tested on: * Linux, * Windows, using Visual Studio 2008 and Visual Studio 2010 Usage ----- Declaration ~~~~~~~~~~~ The dynamic string itself has the data type `UT_string`. It is declared like, UT_string *str; New and free ~~~~~~~~~~~~ The next step is to create the string using `utstring_new`. Later when you're done with it, `utstring_free` will free it and all its content. Manipulation ~~~~~~~~~~~~ The `utstring_printf` or `utstring_bincpy` operations insert (copy) data into the string. To concatenate one utstring to another, use `utstring_concat`. To clear the content of the string, use `utstring_clear`. The length of the string is available from `utstring_len`, and its content from `utstring_body`. This evaluates to a `char*`. The buffer it points to is always null-terminated. So, it can be used directly with external functions that expect a string. This automatic null terminator is not counted in the length of the string. Samples ~~~~~~~ These examples show how to use utstring. .Sample 1 ------------------------------------------------------------------------------- #include #include "utstring.h" int main() { UT_string *s; utstring_new(s); utstring_printf(s, "hello world!" ); printf("%s\n", utstring_body(s)); utstring_free(s); return 0; } ------------------------------------------------------------------------------- The next example demonstrates that `utstring_printf` 'appends' to the string. It also shows concatenation. .Sample 2 ------------------------------------------------------------------------------- #include #include "utstring.h" int main() { UT_string *s, *t; utstring_new(s); utstring_new(t); utstring_printf(s, "hello " ); utstring_printf(s, "world " ); utstring_printf(t, "hi " ); utstring_printf(t, "there " ); utstring_concat(s, t); printf("length: %u\n", utstring_len(s)); printf("%s\n", utstring_body(s)); utstring_free(s); utstring_free(t); return 0; } ------------------------------------------------------------------------------- The next example shows how binary data can be inserted into the string. It also clears the string and prints new data into it. .Sample 3 ------------------------------------------------------------------------------- #include #include "utstring.h" int main() { UT_string *s; char binary[] = "\xff\xff"; utstring_new(s); utstring_bincpy(s, binary, sizeof(binary)); printf("length is %u\n", utstring_len(s)); utstring_clear(s); utstring_printf(s,"number %d", 10); printf("%s\n", utstring_body(s)); utstring_free(s); return 0; } ------------------------------------------------------------------------------- [[operations]] Reference --------- These are the utstring operations. Operations ~~~~~~~~~~ [width="100%",cols="50u = r->i = r->o = 0; r->n = sz; done: return r; } void ringbuf_free(ringbuf* r) { free(r); } /* copy data in. fails if ringbuf has insuff space. */ #define MIN(a,b) (((a) < (b)) ? (a) : (b)) int ringbuf_put(ringbuf *r, const void *_data, size_t len) { char *data = (char*)_data; size_t a,b,c; if (r->i < r->o) { // available space is a contiguous buffer a = r->o - r->i; assert(a == r->n - r->u); if (len > a) return -1; memcpy(&r->d[r->i], data, len); } else { // available space wraps; it's two buffers b = r->n - r->i; // in-head to eob (receives leading input) c = r->o; // out-head to in-head (receives trailing input) a = b + c; // available space // the only ambiguous case is i==o, that's why u is needed if (r->i == r->o) a = r->n - r->u; assert(a == r->n - r->u); if (len > a) return -1; memcpy(&r->d[r->i], data, MIN(b, len)); if (len > b) memcpy(r->d, &data[b], len-b); } r->i = (r->i + len) % r->n; r->u += len; return 0; } size_t ringbuf_get_pending_size(ringbuf *r) { return r->u; } size_t ringbuf_get_next_chunk(ringbuf *r, char **data) { // in this case the next chunk is the whole pending buffer if (r->o < r->i) { assert(r->u == r->i - r->o); *data = &r->d[r->o]; return r->u; } // in this case (i==o) either the buffer is empty of full. // r->u tells distinguishes these cases. if ((r->o == r->i) && (r->u == 0)) { *data=NULL; return 0; } // if we're here, that means r->o > r->i. the pending // output is wrapped around the buffer. this function // returns the chunk prior to eob. the next call gets // the next chunk that's wrapped around the buffer. size_t b,c; b = r->n - r->o; // length of the part we're returning c = r->i; // wrapped part length- a sanity check assert(r->u == b + c); *data = &r->d[r->o]; return b; } void ringbuf_mark_consumed(ringbuf *r, size_t len) { assert(len <= r->u); r->o = (r->o + len ) % r->n; r->u -= len; } void ringbuf_clear(ringbuf *r) { r->u = r->i = r->o = 0; } uthash-1.9.9.1+git20151125/libut/src/utmm.c000066400000000000000000000044441264051566200176360ustar00rootroot00000000000000/* Copyright (c) 2003-2015, Troy D. Hanson http://troydhanson.github.com/uthash/ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* utmm * * low level memory primitives * */ #include "utmm.h" void *utmm_new(const UT_mm *mm, size_t n) { void *o = calloc(n, mm->sz); if (o) return o; fprintf(stderr,"oom"); exit(-1); } void utmm_init(const UT_mm *mm, void *_buf, size_t n) { char *buf = (char*)_buf; if (mm->init == NULL) { memset(buf,0,n*mm->sz); return; } while(n--) { mm->init(buf); buf += mm->sz; } } void utmm_fini(const UT_mm *mm, void *_buf, size_t n) { char *buf = (char*)_buf; if (mm->fini == NULL) return; while(n--) { mm->fini(buf); buf += mm->sz; } } void utmm_clear(const UT_mm *mm, void *_buf, size_t n) { char *buf = (char*)_buf; if (mm->clear == NULL) { memset(buf,0,n*mm->sz); return; } while(n--) { mm->clear(buf); buf += mm->sz; } } void utmm_copy(const UT_mm *mm, void *_dst, void *_src, size_t n) { char *dst = (char*)_dst; char *src = (char*)_src; if (mm->copy == NULL) { memcpy(dst,src,n*mm->sz); return; } while(n--) { mm->copy(dst,src); dst += mm->sz; src += mm->sz; } } /* convenient predefined utmm */ static UT_mm _utmm_int = {.sz = sizeof(int)}; UT_mm* utmm_int = &_utmm_int; uthash-1.9.9.1+git20151125/libut/src/utvector.c000066400000000000000000000113111264051566200205160ustar00rootroot00000000000000/* Copyright (c) 2003-2015, Troy D. Hanson http://troydhanson.github.com/uthash/ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "utvector.h" #define INITIAL_SIZE 16 /* utvector * * maintain a contiguous buffer of 'n' elements ('i' occupied) * the 'n' buffers are deep-inited at the time of allocation * the vector leaves popped slots as-is, clearing them on re-use * the memory management helper mm is used to define the size and * deep-init, deep-fini, deep-copy (into inited slots) and deep-clear. * deep-clear prepares a slot for re-use e.g. reset slot state. * */ void oom(void) { //fprintf(stderr,"out of memory\n"); exit(-1); } UT_vector *utvector_new(const UT_mm *mm) { UT_vector *v = malloc(sizeof(UT_vector)); if (!v) return NULL; utvector_init(v,mm); return v; } unsigned utvector_len(UT_vector *v) { return v->i; } void utvector_init(UT_vector *v, const UT_mm *mm) { v->mm = *mm; // struct copy v->i = v->n = 0; v->d = NULL; utvector_reserve(v, INITIAL_SIZE); // also inits them, sets v->n } void utvector_reserve(UT_vector *v, unsigned num) { if (v->n - v->i >= num) return; // space is big enough, return unsigned n = num - (v->n - v->i); // minimum we need to grow by if (n < (v->n * 2)) n = (v->n * 2); // grow by at least double current size char *d = realloc(v->d, (n + v->n) * v->mm.sz); if (!d) oom(); v->d = d; void *b = v->d + (v->n * v->mm.sz); // start of newly allocated area utmm_init(&v->mm,b,n); v->n = n + v->n; } void utvector_fini(UT_vector *v) { utmm_fini(&v->mm,v->d,v->n); free(v->d); v->d = NULL; v->i = v->n = 0; } UT_vector * utvector_clone(UT_vector *src) { UT_vector *v = utvector_new(&src->mm); utvector_copy(v, src); return v; } void utvector_clear(UT_vector *v) { v->i = 0; } void utvector_copy(UT_vector *dst, UT_vector *src) { /* dst, src both inited */ assert(dst->mm.sz == src->mm.sz); // double check that its inited utvector_clear(dst); utvector_reserve(dst, src->i); dst->i = src->i; utmm_clear(&dst->mm,dst->d,src->i); utmm_copy(&dst->mm, dst->d, src->d, src->i); } void utvector_free(UT_vector *v) { utvector_fini(v); free(v); } void *utvector_extend(UT_vector *v) { utvector_reserve(v,1); void *b = v->d + (v->i * v->mm.sz); utmm_clear(&v->mm,b,1); v->i++; return b; } void *utvector_next(UT_vector *v, void *cur) { if (cur == NULL) return v->i ? v->d : NULL; assert(cur >= (void*)(v->d)); // user pointer must be inside our data area char *n = (char*)cur + v->mm.sz; // next slot address if (n >= v->d + (v->i * v->mm.sz)) n=NULL; // only if next slot occupied return n; } void *utvector_head(UT_vector *v) { if (v->i == 0) return NULL; return v->d; } void *utvector_tail(UT_vector *v) { if (v->i == 0) return NULL; return v->d + ((v->i - 1) * v->mm.sz); } void *utvector_pop(UT_vector *v) { if (v->i == 0) return NULL; return v->d + (--(v->i) * v->mm.sz); } void *utvector_elt(UT_vector *v, unsigned i) { if (i >= v->i) return NULL; return v->d + (i * v->mm.sz); } /* shifting is not very efficient. we end up throwing away/fini'ing the * head of the vector, then doing a memmove, then having to init a new slot. * we don't return the shifted item because its been fini'd, and we have * no caller memory to copy it into anyway. a cpy_shift maybe handy */ void utvector_shift(UT_vector *v) { assert (v->i); utmm_fini(&v->mm,v->d,1); v->i--; memmove(v->d, v->d + v->mm.sz, (v->n-1)*v->mm.sz); char *b = v->d + ((v->n-1) * v->mm.sz); utmm_init(&v->mm,b,1); } void *utvector_push(UT_vector *v, void *e) { void *b = utvector_extend(v); utmm_copy(&v->mm, b, e, 1); return v->d + ((v->i - 1) * v->mm.sz); } uthash-1.9.9.1+git20151125/libut/tests/000077500000000000000000000000001264051566200170555ustar00rootroot00000000000000uthash-1.9.9.1+git20151125/libut/tests/Makefile000066400000000000000000000010711264051566200205140ustar00rootroot00000000000000PROGS=test1 test2 test3 test4 test5 test6 test7 test8 test9 test10 test11 test12 \ test13 test14 test15 test16 OBJS=$(patsubst %,%.o,$(PROGS)) CFLAGS += -I../include CFLAGS += -g CFLAGS += -Wall -Wextra LDFLAGS += -L.. -lut TEST_TARGET=run_tests TESTS=./do_tests all: $(OBJS) $(PROGS) $(TEST_TARGET) # static pattern rule: multiple targets $(OBJS): %.o: %.c $(CC) -c $(CPPFLAGS) $(CFLAGS) $< $(PROGS): %: %.o $(CC) -o $@ $(CPPFLAGS) $(CFLAGS) $< $(LDFLAGS) run_tests: $(PROGS) perl $(TESTS) .PHONY: clean clean: rm -f $(PROGS) $(OBJS) test*.out uthash-1.9.9.1+git20151125/libut/tests/README000066400000000000000000000011621264051566200177350ustar00rootroot00000000000000test1: test utvector init/fini test2: test utvector of int, push, next test3: test utvector push, pop, extend test4: test utvector_copy test5: test utvector of utstring test6: test utvector of utstring more ops test7: test utvector of utstring even more ops test8: test utextend past initial size int test9: test utextend past initial size utstring test10: test utvector_pop on empty list (int) test11: test utvector_pop on empty list (utstring) test12: test utvector head/tail (int) test13: test utvector head/tail (utstring) test14: test utvector_shift (int) test15: test utvector_shift (utstring) test16: test utvector_elt uthash-1.9.9.1+git20151125/libut/tests/do_tests000077500000000000000000000005571264051566200206360ustar00rootroot00000000000000#!/usr/bin/perl use strict; use warnings; my @tests; for (glob "test*[0-9]") { push @tests, $_ if -e "$_.ans"; } my $num_failed=0; for my $test (@tests) { `./$test > $test.out`; `diff $test.out $test.ans`; print "$test failed\n" if $?; $num_failed++ if $?; } print scalar @tests . " tests conducted, $num_failed failed.\n"; exit $num_failed; uthash-1.9.9.1+git20151125/libut/tests/test1.ans000066400000000000000000000000001264051566200206060ustar00rootroot00000000000000uthash-1.9.9.1+git20151125/libut/tests/test1.c000066400000000000000000000001651264051566200202630ustar00rootroot00000000000000#include "utvector.h" int main() { UT_vector v; utvector_init(&v, utmm_int); utvector_fini(&v); return 0; } uthash-1.9.9.1+git20151125/libut/tests/test10.ans000066400000000000000000000000711264051566200206760ustar00rootroot00000000000000extend 1000 pop result: non-null 1000 pop result: null 0 uthash-1.9.9.1+git20151125/libut/tests/test10.c000066400000000000000000000010061264051566200203360ustar00rootroot00000000000000#include #include "utvector.h" int main() { int *p; UT_vector v; utvector_init(&v, utmm_int); printf("extend\n"); p = (int*)utvector_extend(&v); *p = 1000; p=NULL; while ( (p=(int*)utvector_next(&v,p))) printf("%d\n",*p); printf("pop\n"); p = (int*)utvector_pop(&v); printf("result: %s %d\n", p ? "non-null" : "null", p ? *p : 0); printf("pop\n"); p = (int*)utvector_pop(&v); printf("result: %s %d\n", p ? "non-null" : "null", p ? *p : 0); utvector_fini(&v); return 0; } uthash-1.9.9.1+git20151125/libut/tests/test11.ans000066400000000000000000000000721264051566200207000ustar00rootroot00000000000000extend iterate hello pop hello iterate pop (null) iterate uthash-1.9.9.1+git20151125/libut/tests/test11.c000066400000000000000000000014351264051566200203450ustar00rootroot00000000000000#include #include "libut.h" int main() { UT_string *s; UT_vector v; utvector_init(&v, utstring_mm); printf("extend\n"); s = (UT_string*)utvector_extend(&v); utstring_printf(s,"hello"); printf("iterate\n"); s=NULL; while ( (s=(UT_string*)utvector_next(&v,s))) printf("%s\n",utstring_body(s)); printf("pop\n"); s=(UT_string*)utvector_pop(&v); printf("%s\n", s ? utstring_body(s) : "(null)"); printf("iterate\n"); s=NULL; while ( (s=(UT_string*)utvector_next(&v,s))) printf("%s\n",utstring_body(s)); printf("pop\n"); s=(UT_string*)utvector_pop(&v); printf("%s\n", s ? utstring_body(s) : "(null)"); printf("iterate\n"); s=NULL; while ( (s=(UT_string*)utvector_next(&v,s))) printf("%s\n",utstring_body(s)); utvector_fini(&v); return 0; } uthash-1.9.9.1+git20151125/libut/tests/test12.ans000066400000000000000000000001151264051566200206770ustar00rootroot000000000000000 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 head: (non-null) 0 tail: (non-null) 15 uthash-1.9.9.1+git20151125/libut/tests/test12.c000066400000000000000000000007011264051566200203410ustar00rootroot00000000000000#include #include "utvector.h" int main() { int i,*p=NULL; UT_vector v; utvector_init(&v, utmm_int); for(i=0; i<16; i++) utvector_push(&v, &i); p=NULL; while ( (p=(int*)utvector_next(&v,p))) printf("%d\n",*p); p = (int*)utvector_head(&v); printf("head: (%s) %d\n", p?"non-null":"null", p?*p:0); p = (int*)utvector_tail(&v); printf("tail: (%s) %d\n", p?"non-null":"null", p?*p:0); utvector_fini(&v); return 0; } uthash-1.9.9.1+git20151125/libut/tests/test13.ans000066400000000000000000000006441264051566200207070ustar00rootroot00000000000000len: 16 . .. ... .... ..... ...... ....... ........ ......... .......... ........... ............ ............. .............. ............... ................ head: non-null . tail: non-null ................ extend len: 17 . .. ... .... ..... ...... ....... ........ ......... .......... ........... ............ ............. .............. ............... ................ hello head: non-null . tail: non-null hello uthash-1.9.9.1+git20151125/libut/tests/test13.c000066400000000000000000000020061264051566200203420ustar00rootroot00000000000000#include #include "libut.h" void dump(UT_vector *v) { printf("len: %d\n", utvector_len(v)); UT_string *p=NULL; while ( (p=(UT_string*)utvector_next(v,p))) printf("%s\n",utstring_body(p)); } int main() { int i; UT_string *t; UT_vector v; utvector_init(&v, utstring_mm); UT_string s; utstring_init(&s); for(i=0; i<16; i++) { utstring_printf(&s, "."); utvector_push(&v, &s); } dump(&v); t = (UT_string*)utvector_head(&v); printf("head: %s %s\n", t?"non-null":"null", t?utstring_body(t):"-"); t = (UT_string*)utvector_tail(&v); printf("tail: %s %s\n", t?"non-null":"null", t?utstring_body(t):"-"); printf("extend\n"); t = (UT_string*)utvector_extend(&v); utstring_bincpy(t, "hello", 5); dump(&v); t = (UT_string*)utvector_head(&v); printf("head: %s %s\n", t?"non-null":"null", t?utstring_body(t):"-"); t = (UT_string*)utvector_tail(&v); printf("tail: %s %s\n", t?"non-null":"null", t?utstring_body(t):"-"); utvector_fini(&v); utstring_done(&s); return 0; } uthash-1.9.9.1+git20151125/libut/tests/test14.ans000066400000000000000000000002031264051566200206770ustar00rootroot000000000000000 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 head: (non-null) 0 tail: (non-null) 15 len: 16 shift len: 15 head: (non-null) 1 clear len: 0 uthash-1.9.9.1+git20151125/libut/tests/test14.c000066400000000000000000000013561264051566200203520ustar00rootroot00000000000000#include #include "utvector.h" int main() { int i,*p=NULL; UT_vector v; utvector_init(&v, utmm_int); for(i=0; i<16; i++) utvector_push(&v, &i); p=NULL; while ( (p=(int*)utvector_next(&v,p))) printf("%d\n",*p); p = (int*)utvector_head(&v); printf("head: (%s) %d\n", p?"non-null":"null", p?*p:0); p = (int*)utvector_tail(&v); printf("tail: (%s) %d\n", p?"non-null":"null", p?*p:0); printf("len: %d\n", utvector_len(&v)); printf("shift\n"); utvector_shift(&v); printf("len: %d\n", utvector_len(&v)); p = (int*)utvector_head(&v); printf("head: (%s) %d\n", p?"non-null":"null", p?*p:0); printf("clear\n"); utvector_clear(&v); printf("len: %d\n", utvector_len(&v)); utvector_fini(&v); return 0; } uthash-1.9.9.1+git20151125/libut/tests/test15.ans000066400000000000000000000015421264051566200207070ustar00rootroot00000000000000len: 16 . .. ... .... ..... ...... ....... ........ ......... .......... ........... ............ ............. .............. ............... ................ head: non-null . tail: non-null ................ shift len: 15, head: non-null .. shift len: 14, head: non-null ... shift len: 13, head: non-null .... shift len: 12, head: non-null ..... shift len: 11, head: non-null ...... shift len: 10, head: non-null ....... shift len: 9, head: non-null ........ shift len: 8, head: non-null ......... shift len: 7, head: non-null .......... shift len: 6, head: non-null ........... shift len: 5, head: non-null ............ shift len: 4, head: non-null ............. shift len: 3, head: non-null .............. shift len: 2, head: non-null ............... shift len: 1, head: non-null ................ shift len: 0, head: null - extend len: 1, head: non-null extended uthash-1.9.9.1+git20151125/libut/tests/test15.c000066400000000000000000000021741264051566200203520ustar00rootroot00000000000000#include #include "libut.h" void dump(UT_vector *v) { printf("len: %d\n", utvector_len(v)); UT_string *p=NULL; while ( (p=(UT_string*)utvector_next(v,p))) printf("%s\n",utstring_body(p)); } int main() { int i; UT_string *t; UT_vector v; utvector_init(&v, utstring_mm); UT_string s; utstring_init(&s); for(i=0; i<16; i++) { utstring_printf(&s, "."); utvector_push(&v, &s); } dump(&v); t = (UT_string*)utvector_head(&v); printf("head: %s %s\n", t?"non-null":"null", t?utstring_body(t):"-"); t = (UT_string*)utvector_tail(&v); printf("tail: %s %s\n", t?"non-null":"null", t?utstring_body(t):"-"); for(i=0; i<16; i++) { printf("shift\n"); utvector_shift(&v); t = (UT_string*)utvector_head(&v); printf("len: %d, head: %s %s\n", utvector_len(&v), t?"non-null":"null", t?utstring_body(t):"-"); } printf("extend\n"); t= (UT_string*)utvector_extend(&v); utstring_printf(t,"extended"); t = (UT_string*)utvector_head(&v); printf("len: %d, head: %s %s\n", utvector_len(&v), t?"non-null":"null", t?utstring_body(t):"-"); utvector_fini(&v); utstring_done(&s); return 0; } uthash-1.9.9.1+git20151125/libut/tests/test16.ans000066400000000000000000000001701264051566200207040ustar00rootroot000000000000000 1 2 3 4 5 6 7 8 9 elt 0: 0 elt 1: 1 elt 2: 2 elt 3: 3 elt 4: 4 elt 5: 5 elt 6: 6 elt 7: 7 elt 8: 8 elt 9: 9 p is null uthash-1.9.9.1+git20151125/libut/tests/test16.c000066400000000000000000000007721264051566200203550ustar00rootroot00000000000000#include #include "utvector.h" int main() { int i,*p=NULL; UT_vector v,*k; utvector_init(&v, utmm_int); for(i=0; i<10; i++) utvector_push(&v, &i); k = utvector_clone(&v); while ( (p=(int*)utvector_next(k,p))) printf("%d\n",*p); for(i=0; i<10; i++) { p = (int*)utvector_elt(&v, i); printf("elt %d: %d\n", i, *p); } /* expect null */ p = (int*)utvector_elt(&v, 11); printf("p is %snull\n", p ? "not " : ""); utvector_fini(&v); utvector_free(k); return 0; } uthash-1.9.9.1+git20151125/libut/tests/test2.ans000066400000000000000000000000241264051566200206150ustar00rootroot000000000000000 1 2 3 4 5 6 7 8 9 uthash-1.9.9.1+git20151125/libut/tests/test2.c000066400000000000000000000004021264051566200202560ustar00rootroot00000000000000#include #include "utvector.h" int main() { int i,*p=NULL; UT_vector v; utvector_init(&v, utmm_int); for(i=0; i<10; i++) utvector_push(&v, &i); while ( (p=(int*)utvector_next(&v,p))) printf("%d\n",*p); utvector_fini(&v); return 0; } uthash-1.9.9.1+git20151125/libut/tests/test3.ans000066400000000000000000000000571264051566200206240ustar00rootroot00000000000000len 10 len 9 0 1 2 3 4 5 6 7 8 11 len 10 len 0 uthash-1.9.9.1+git20151125/libut/tests/test3.c000066400000000000000000000010051264051566200202570ustar00rootroot00000000000000#include #include "utvector.h" int main() { int i,*p=NULL; UT_vector v; utvector_init(&v, utmm_int); for(i=0; i<10; i++) utvector_push(&v, &i); printf("len %d\n", utvector_len(&v)); utvector_pop(&v); printf("len %d\n", utvector_len(&v)); p = (int*)utvector_extend(&v); *p = 11; p=NULL; while ( (p=(int*)utvector_next(&v,p))) printf("%d\n",*p); printf("len %d\n", utvector_len(&v)); utvector_clear(&v); printf("len %d\n", utvector_len(&v)); utvector_fini(&v); return 0; } uthash-1.9.9.1+git20151125/libut/tests/test4.ans000066400000000000000000000000241264051566200206170ustar00rootroot000000000000000 1 2 3 4 5 6 7 8 9 uthash-1.9.9.1+git20151125/libut/tests/test4.c000066400000000000000000000004641264051566200202700ustar00rootroot00000000000000#include #include "utvector.h" int main() { int i,*p=NULL; UT_vector v,*k; utvector_init(&v, utmm_int); for(i=0; i<10; i++) utvector_push(&v, &i); k = utvector_clone(&v); while ( (p=(int*)utvector_next(k,p))) printf("%d\n",*p); utvector_fini(&v); utvector_free(k); return 0; } uthash-1.9.9.1+git20151125/libut/tests/test5.ans000066400000000000000000000001011264051566200206140ustar00rootroot00000000000000. .. ... .... ..... ...... ....... ........ ......... .......... uthash-1.9.9.1+git20151125/libut/tests/test5.c000066400000000000000000000006041264051566200202650ustar00rootroot00000000000000#include #include "libut.h" int main() { int i; UT_string *p; UT_vector v; utvector_init(&v, utstring_mm); UT_string s; utstring_init(&s); for(i=0; i<10; i++) { utstring_printf(&s, "."); utvector_push(&v, &s); } p=NULL; while ( (p=(UT_string*)utvector_next(&v,p))) printf("%s\n",utstring_body(p)); utvector_fini(&v); utstring_done(&s); return 0; } uthash-1.9.9.1+git20151125/libut/tests/test6.ans000066400000000000000000000004571264051566200206330ustar00rootroot00000000000000len: 10 . .. ... .... ..... ...... ....... ........ ......... .......... extend len: 11 . .. ... .... ..... ...... ....... ........ ......... .......... extended element pop len: 10 . .. ... .... ..... ...... ....... ........ ......... .......... clear len: 0 push len: 1 allocated utstring done1 done2 uthash-1.9.9.1+git20151125/libut/tests/test6.c000066400000000000000000000015471264051566200202750ustar00rootroot00000000000000#include #include "libut.h" void dump(UT_vector *v) { printf("len: %d\n", utvector_len(v)); UT_string *p=NULL; while ( (p=(UT_string*)utvector_next(v,p))) printf("%s\n",utstring_body(p)); } int main() { int i; UT_string *p; UT_vector v; utvector_init(&v, utstring_mm); UT_string s; utstring_init(&s); for(i=0; i<10; i++) { utstring_printf(&s, "."); utvector_push(&v, &s); } dump(&v); printf("extend\n"); p = utvector_extend(&v); utstring_printf(p,"extended element"); dump(&v); printf("pop\n"); utvector_pop(&v); dump(&v); printf("clear\n"); utvector_clear(&v); dump(&v); printf("push\n"); utstring_new(p); utstring_printf(p,"allocated utstring"); utvector_push(&v, p); utstring_free(p); dump(&v); printf("done1\n"); utvector_fini(&v); printf("done2\n"); utstring_done(&s); return 0; } uthash-1.9.9.1+git20151125/libut/tests/test7.ans000066400000000000000000000002301264051566200206210ustar00rootroot00000000000000len: 10 . .. ... .... ..... ...... ....... ........ ......... .......... clone len: 10 . .. ... .... ..... ...... ....... ........ ......... .......... uthash-1.9.9.1+git20151125/libut/tests/test7.c000066400000000000000000000010611264051566200202650ustar00rootroot00000000000000#include #include "libut.h" void dump(UT_vector *v) { printf("len: %d\n", utvector_len(v)); UT_string *p=NULL; while ( (p=(UT_string*)utvector_next(v,p))) printf("%s\n",utstring_body(p)); } int main() { int i; UT_vector v; utvector_init(&v, utstring_mm); UT_vector *k; UT_string s; utstring_init(&s); for(i=0; i<10; i++) { utstring_printf(&s, "."); utvector_push(&v, &s); } dump(&v); printf("clone\n"); k = utvector_clone(&v); dump(k); utvector_fini(&v); utvector_free(k); utstring_done(&s); return 0; } uthash-1.9.9.1+git20151125/libut/tests/test8.ans000066400000000000000000000000531264051566200206250ustar00rootroot000000000000000 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 1000 uthash-1.9.9.1+git20151125/libut/tests/test8.c000066400000000000000000000004641264051566200202740ustar00rootroot00000000000000#include #include "utvector.h" int main() { int i,*p=NULL; UT_vector v; utvector_init(&v, utmm_int); for(i=0; i<16; i++) utvector_push(&v, &i); p = utvector_extend(&v); *p = 1000; p=NULL; while ( (p=(int*)utvector_next(&v,p))) printf("%d\n",*p); utvector_fini(&v); return 0; } uthash-1.9.9.1+git20151125/libut/tests/test9.ans000066400000000000000000000005151264051566200206310ustar00rootroot00000000000000len: 16 . .. ... .... ..... ...... ....... ........ ......... .......... ........... ............ ............. .............. ............... ................ extend len: 17 . .. ... .... ..... ...... ....... ........ ......... .......... ........... ............ ............. .............. ............... ................ hello uthash-1.9.9.1+git20151125/libut/tests/test9.c000066400000000000000000000011161264051566200202700ustar00rootroot00000000000000#include #include "libut.h" void dump(UT_vector *v) { printf("len: %d\n", utvector_len(v)); UT_string *p=NULL; while ( (p=(UT_string*)utvector_next(v,p))) printf("%s\n",utstring_body(p)); } int main() { int i; UT_string *t; UT_vector v; utvector_init(&v, utstring_mm); UT_string s; utstring_init(&s); for(i=0; i<16; i++) { utstring_printf(&s, "."); utvector_push(&v, &s); } dump(&v); printf("extend\n"); t = (UT_string*)utvector_extend(&v); utstring_bincpy(t, "hello", 5); dump(&v); utvector_fini(&v); utstring_done(&s); return 0; } uthash-1.9.9.1+git20151125/package.json000066400000000000000000000005501264051566200170620ustar00rootroot00000000000000{ "description": "C macros for hash tables and more", "keywords": [ "array", "data", "hash", "list", "macro", "string", "structure", "uthash" ], "name": "uthash", "repo": "troydhanson/uthash", "src": [ "src/utarray.h", "src/uthash.h", "src/utlist.h", "src/utstring.h" ], "version": "1.9.9" } uthash-1.9.9.1+git20151125/src/000077500000000000000000000000001264051566200153635ustar00rootroot00000000000000uthash-1.9.9.1+git20151125/src/libut.h000066400000000000000000000004061264051566200166530ustar00rootroot00000000000000#ifndef __LIBUT_H_ #define __LIBUT_H_ /* libut is a container around other sources */ #include "utmm.h" #include "utvector.h" #include "utstring.h" #include "utarray.h" #include "uthash.h" #include "utringbuffer.h" #include "utlist.h" #endif /* __LIBUT_H_ */ uthash-1.9.9.1+git20151125/src/ringbuf.h000066400000000000000000000012441264051566200171710ustar00rootroot00000000000000#ifndef _RINGBUF_H_ #define _RINGBUF_H_ #include #include #include #include /* simple ring buffer */ typedef struct _ringbuf { size_t n; /* allocd size */ size_t u; /* used space */ size_t i; /* input pos */ size_t o; /* output pos */ char d[]; /* C99 flexible array member */ } ringbuf; ringbuf *ringbuf_new(size_t sz); int ringbuf_put(ringbuf *, const void *data, size_t len); size_t ringbuf_get_pending_size(ringbuf *); size_t ringbuf_get_next_chunk(ringbuf *, char **data); void ringbuf_mark_consumed(ringbuf *, size_t); void ringbuf_free(ringbuf*); void ringbuf_clear(ringbuf*); #endif /* _RINGBUF_H_ */ uthash-1.9.9.1+git20151125/src/utarray.h000066400000000000000000000307731264051566200172350ustar00rootroot00000000000000/* Copyright (c) 2008-2014, Troy D. Hanson http://troydhanson.github.com/uthash/ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* a dynamic array implementation using macros */ #ifndef UTARRAY_H #define UTARRAY_H #define UTARRAY_VERSION 1.9.9 #ifdef __GNUC__ #define _UNUSED_ __attribute__ ((__unused__)) #else #define _UNUSED_ #endif #include /* size_t */ #include /* memset, etc */ #include /* exit */ #ifndef oom #define oom() exit(-1) #endif typedef void (ctor_f)(void *dst, const void *src); typedef void (dtor_f)(void *elt); typedef void (init_f)(void *elt); typedef struct { size_t sz; init_f *init; ctor_f *copy; dtor_f *dtor; } UT_icd; typedef struct { unsigned i,n;/* i: index of next available slot, n: num slots */ UT_icd icd; /* initializer, copy and destructor functions */ char *d; /* n slots of size icd->sz*/ } UT_array; #define utarray_init(a,_icd) do { \ memset(a,0,sizeof(UT_array)); \ (a)->icd=*_icd; \ } while(0) #define utarray_done(a) do { \ if ((a)->n) { \ if ((a)->icd.dtor) { \ size_t _ut_i; \ for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \ (a)->icd.dtor(utarray_eltptr(a,_ut_i)); \ } \ } \ free((a)->d); \ } \ (a)->n=0; \ } while(0) #define utarray_new(a,_icd) do { \ a=(UT_array*)malloc(sizeof(UT_array)); \ utarray_init(a,_icd); \ } while(0) #define utarray_free(a) do { \ utarray_done(a); \ free(a); \ } while(0) #define utarray_reserve(a,by) do { \ if (((a)->i+(by)) > ((a)->n)) { \ char *utarray_tmp; \ while(((a)->i+(by)) > ((a)->n)) { (a)->n = ((a)->n ? (2*(a)->n) : 8); } \ utarray_tmp=(char*)realloc((a)->d, (a)->n*(a)->icd.sz); \ if (utarray_tmp == NULL) oom(); \ (a)->d=utarray_tmp; \ } \ } while(0) #define utarray_push_back(a,p) do { \ utarray_reserve(a,1); \ if ((a)->icd.copy) { (a)->icd.copy( _utarray_eltptr(a,(a)->i++), p); } \ else { memcpy(_utarray_eltptr(a,(a)->i++), p, (a)->icd.sz); }; \ } while(0) #define utarray_pop_back(a) do { \ if ((a)->icd.dtor) { (a)->icd.dtor( _utarray_eltptr(a,--((a)->i))); } \ else { (a)->i--; } \ } while(0) #define utarray_extend_back(a) do { \ utarray_reserve(a,1); \ if ((a)->icd.init) { (a)->icd.init(_utarray_eltptr(a,(a)->i)); } \ else { memset(_utarray_eltptr(a,(a)->i),0,(a)->icd.sz); } \ (a)->i++; \ } while(0) #define utarray_len(a) ((a)->i) #define utarray_eltptr(a,j) (((j) < (a)->i) ? _utarray_eltptr(a,j) : NULL) #define _utarray_eltptr(a,j) ((char*)((a)->d + ((a)->icd.sz*(j) ))) #define utarray_insert(a,p,j) do { \ if (j > (a)->i) utarray_resize(a,j); \ utarray_reserve(a,1); \ if ((j) < (a)->i) { \ memmove( _utarray_eltptr(a,(j)+1), _utarray_eltptr(a,j), \ ((a)->i - (j))*((a)->icd.sz)); \ } \ if ((a)->icd.copy) { (a)->icd.copy( _utarray_eltptr(a,j), p); } \ else { memcpy(_utarray_eltptr(a,j), p, (a)->icd.sz); }; \ (a)->i++; \ } while(0) #define utarray_inserta(a,w,j) do { \ if (utarray_len(w) == 0) break; \ if (j > (a)->i) utarray_resize(a,j); \ utarray_reserve(a,utarray_len(w)); \ if ((j) < (a)->i) { \ memmove(_utarray_eltptr(a,(j)+utarray_len(w)), \ _utarray_eltptr(a,j), \ ((a)->i - (j))*((a)->icd.sz)); \ } \ if ((a)->icd.copy) { \ size_t _ut_i; \ for(_ut_i=0;_ut_i<(w)->i;_ut_i++) { \ (a)->icd.copy(_utarray_eltptr(a,j+_ut_i), _utarray_eltptr(w,_ut_i)); \ } \ } else { \ memcpy(_utarray_eltptr(a,j), _utarray_eltptr(w,0), \ utarray_len(w)*((a)->icd.sz)); \ } \ (a)->i += utarray_len(w); \ } while(0) #define utarray_resize(dst,num) do { \ size_t _ut_i; \ if (dst->i > (size_t)(num)) { \ if ((dst)->icd.dtor) { \ for(_ut_i=num; _ut_i < dst->i; _ut_i++) { \ (dst)->icd.dtor(utarray_eltptr(dst,_ut_i)); \ } \ } \ } else if (dst->i < (size_t)(num)) { \ utarray_reserve(dst,num-dst->i); \ if ((dst)->icd.init) { \ for(_ut_i=dst->i; _ut_i < num; _ut_i++) { \ (dst)->icd.init(utarray_eltptr(dst,_ut_i)); \ } \ } else { \ memset(_utarray_eltptr(dst,dst->i),0,(dst)->icd.sz*(num-dst->i)); \ } \ } \ dst->i = num; \ } while(0) #define utarray_concat(dst,src) do { \ utarray_inserta((dst),(src),utarray_len(dst)); \ } while(0) #define utarray_erase(a,pos,len) do { \ if ((a)->icd.dtor) { \ size_t _ut_i; \ for(_ut_i=0; _ut_i < len; _ut_i++) { \ (a)->icd.dtor(utarray_eltptr((a),pos+_ut_i)); \ } \ } \ if ((a)->i > (pos+len)) { \ memmove( _utarray_eltptr((a),pos), _utarray_eltptr((a),pos+len), \ (((a)->i)-(pos+len))*((a)->icd.sz)); \ } \ (a)->i -= (len); \ } while(0) #define utarray_renew(a,u) do { \ if (a) utarray_clear(a); \ else utarray_new((a),(u)); \ } while(0) #define utarray_clear(a) do { \ if ((a)->i > 0) { \ if ((a)->icd.dtor) { \ size_t _ut_i; \ for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \ (a)->icd.dtor(utarray_eltptr(a,_ut_i)); \ } \ } \ (a)->i = 0; \ } \ } while(0) #define utarray_sort(a,cmp) do { \ qsort((a)->d, (a)->i, (a)->icd.sz, cmp); \ } while(0) #define utarray_find(a,v,cmp) bsearch((v),(a)->d,(a)->i,(a)->icd.sz,cmp) #define utarray_front(a) (((a)->i) ? (_utarray_eltptr(a,0)) : NULL) #define utarray_next(a,e) (((e)==NULL) ? utarray_front(a) : ((((a)->i) > (utarray_eltidx(a,e)+1)) ? _utarray_eltptr(a,utarray_eltidx(a,e)+1) : NULL)) #define utarray_prev(a,e) (((e)==NULL) ? utarray_back(a) : ((utarray_eltidx(a,e) > 0) ? _utarray_eltptr(a,utarray_eltidx(a,e)-1) : NULL)) #define utarray_back(a) (((a)->i) ? (_utarray_eltptr(a,(a)->i-1)) : NULL) #define utarray_eltidx(a,e) (((char*)(e) >= (char*)((a)->d)) ? (((char*)(e) - (char*)((a)->d))/(size_t)(a)->icd.sz) : -1) /* 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); } static void utarray_str_dtor(void *elt) { char **eltc = (char**)elt; if (*eltc) free(*eltc); } static const UT_icd ut_str_icd _UNUSED_ = {sizeof(char*),NULL,utarray_str_cpy,utarray_str_dtor}; static const UT_icd ut_int_icd _UNUSED_ = {sizeof(int),NULL,NULL,NULL}; static const UT_icd ut_ptr_icd _UNUSED_ = {sizeof(void*),NULL,NULL,NULL}; #endif /* UTARRAY_H */ uthash-1.9.9.1+git20151125/src/uthash.h000066400000000000000000001714201264051566200170350ustar00rootroot00000000000000/* Copyright (c) 2003-2014, Troy D. Hanson http://troydhanson.github.com/uthash/ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef UTHASH_H #define UTHASH_H #include /* memcmp,strlen */ #include /* ptrdiff_t */ #include /* exit() */ /* 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 or, for VS2008 where neither is available, uses casting workarounds. */ #if defined(_MSC_VER) /* MS compiler */ #if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ #define DECLTYPE(x) (decltype(x)) #else /* VS2008 or older (or VS2010 in C mode) */ #define NO_DECLTYPE #define DECLTYPE(x) #endif #elif defined(__BORLANDC__) || defined(__LCC__) || defined(__WATCOMC__) #define NO_DECLTYPE #define DECLTYPE(x) #else /* GNU, Sun and other compilers */ #define DECLTYPE(x) (__typeof(x)) #endif #ifdef NO_DECLTYPE #define DECLTYPE_ASSIGN(dst,src) \ do { \ char **_da_dst = (char**)(&(dst)); \ *_da_dst = (char*)(src); \ } while(0) #else #define DECLTYPE_ASSIGN(dst,src) \ do { \ (dst) = DECLTYPE(dst)(src); \ } 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 #elif defined(__WATCOMC__) || defined(__MINGW32__) || defined(__CYGWIN__) #include #else typedef unsigned int uint32_t; typedef unsigned char uint8_t; #endif #elif defined(__GNUC__) && !defined(__VXWORKS__) #include #else typedef unsigned int uint32_t; typedef unsigned char uint8_t; #endif #define UTHASH_VERSION 1.9.9 #ifndef uthash_fatal #define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */ #endif #ifndef uthash_malloc #define uthash_malloc(sz) malloc(sz) /* malloc fcn */ #endif #ifndef uthash_free #define uthash_free(ptr,sz) free(ptr) /* free fcn */ #endif #ifndef uthash_noexpand_fyi #define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ #endif #ifndef uthash_expand_fyi #define uthash_expand_fyi(tbl) /* can be defined to log expands */ #endif /* initial number of buckets */ #define HASH_INITIAL_NUM_BUCKETS 32U /* initial number of buckets */ #define HASH_INITIAL_NUM_BUCKETS_LOG2 5U /* lg2 of initial number of buckets */ #define HASH_BKT_CAPACITY_THRESH 10U /* expand when bucket count reaches */ /* calculate the element whose hash handle address is hhe */ #define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho))) #define HASH_FIND(hh,head,keyptr,keylen,out) \ do { \ out=NULL; \ if (head != NULL) { \ unsigned _hf_bkt,_hf_hashv; \ HASH_FCN(keyptr,keylen, (head)->hh.tbl->num_buckets, _hf_hashv, _hf_bkt); \ 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) #ifdef HASH_BLOOM #define HASH_BLOOM_BITLEN (1UL << HASH_BLOOM) #define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8UL) + (((HASH_BLOOM_BITLEN%8UL)!=0UL) ? 1UL : 0UL) #define HASH_BLOOM_MAKE(tbl) \ do { \ (tbl)->bloom_nbits = HASH_BLOOM; \ (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \ if (!((tbl)->bloom_bv)) { uthash_fatal( "out of memory"); } \ memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN); \ (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ } while (0) #define HASH_BLOOM_FREE(tbl) \ do { \ uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ } while (0) #define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8U] |= (1U << ((idx)%8U))) #define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8U] & (1U << ((idx)%8U))) #define HASH_BLOOM_ADD(tbl,hashv) \ HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1U))) #define HASH_BLOOM_TEST(tbl,hashv) \ HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1U))) #else #define HASH_BLOOM_MAKE(tbl) #define HASH_BLOOM_FREE(tbl) #define HASH_BLOOM_ADD(tbl,hashv) #define HASH_BLOOM_TEST(tbl,hashv) (1) #define HASH_BLOOM_BYTELEN 0U #endif #define HASH_MAKE_TABLE(hh,head) \ do { \ (head)->hh.tbl = (UT_hash_table*)uthash_malloc( \ sizeof(UT_hash_table)); \ if (!((head)->hh.tbl)) { uthash_fatal( "out of memory"); } \ memset((head)->hh.tbl, 0, sizeof(UT_hash_table)); \ (head)->hh.tbl->tail = &((head)->hh); \ (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \ (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \ HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); } \ memset((head)->hh.tbl->buckets, 0, \ HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ HASH_BLOOM_MAKE((head)->hh.tbl); \ (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_REPLACE(hh,head,fieldname,keylen_in,add,replaced) \ do { \ replaced=NULL; \ HASH_FIND(hh,head,&((add)->fieldname),keylen_in,replaced); \ if (replaced!=NULL) { \ HASH_DELETE(hh,head,replaced); \ } \ HASH_ADD(hh,head,fieldname,keylen_in,add); \ } while(0) #define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,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, (head)->hh.tbl->num_buckets, \ (add)->hh.hashv, _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_TO_BKT( hashv, num_bkts, bkt ) \ do { \ bkt = ((hashv) & ((num_bkts) - 1U)); \ } while(0) /* delete "delptr" from the hash table. * "the usual" patch-up process for the app-order doubly-linked-list. * The use of _hd_hh_del below deserves special explanation. * These used to be expressed using (delptr) but that led to a bug * if someone used the same symbol for the head and deletee, like * HASH_DELETE(hh,users,users); * We want that to work, but by changing the head (users) below * we were forfeiting our ability to further refer to the deletee (users) * in the patch-up process. Solution: use scratch space to * copy the deletee pointer, then the latter references are via that * scratch pointer rather than through the repointed (users) symbol. */ #define HASH_DELETE(hh,head,delptr) \ do { \ struct UT_hash_handle *_hd_hh_del; \ if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) ) { \ uthash_free((head)->hh.tbl->buckets, \ (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ HASH_BLOOM_FREE((head)->hh.tbl); \ uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ head = NULL; \ } else { \ unsigned _hd_bkt; \ _hd_hh_del = &((delptr)->hh); \ if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) { \ (head)->hh.tbl->tail = \ (UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \ (head)->hh.tbl->hho); \ } \ if ((delptr)->hh.prev != NULL) { \ ((UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \ (head)->hh.tbl->hho))->next = (delptr)->hh.next; \ } else { \ DECLTYPE_ASSIGN(head,(delptr)->hh.next); \ } \ if (_hd_hh_del->next != NULL) { \ ((UT_hash_handle*)((ptrdiff_t)_hd_hh_del->next + \ (head)->hh.tbl->hho))->prev = \ _hd_hh_del->prev; \ } \ HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ (head)->hh.tbl->num_items--; \ } \ HASH_FSCK(hh,head); \ } while (0) /* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ #define HASH_FIND_STR(head,findstr,out) \ HASH_FIND(hh,head,findstr,(unsigned)strlen(findstr),out) #define HASH_ADD_STR(head,strfield,add) \ HASH_ADD(hh,head,strfield[0],(unsigned int)strlen(add->strfield),add) #define HASH_REPLACE_STR(head,strfield,add,replaced) \ HASH_REPLACE(hh,head,strfield[0],(unsigned)strlen(add->strfield),add,replaced) #define HASH_FIND_INT(head,findint,out) \ HASH_FIND(hh,head,findint,sizeof(int),out) #define HASH_ADD_INT(head,intfield,add) \ HASH_ADD(hh,head,intfield,sizeof(int),add) #define HASH_REPLACE_INT(head,intfield,add,replaced) \ HASH_REPLACE(hh,head,intfield,sizeof(int),add,replaced) #define HASH_FIND_PTR(head,findptr,out) \ HASH_FIND(hh,head,findptr,sizeof(void *),out) #define HASH_ADD_PTR(head,ptrfield,add) \ HASH_ADD(hh,head,ptrfield,sizeof(void *),add) #define HASH_REPLACE_PTR(head,ptrfield,add,replaced) \ HASH_REPLACE(hh,head,ptrfield,sizeof(void *),add,replaced) #define HASH_DEL(head,delptr) \ HASH_DELETE(hh,head,delptr) /* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. */ #ifdef HASH_DEBUG #define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0) #define HASH_FSCK(hh,head) \ do { \ struct UT_hash_handle *_thh; \ if (head) { \ unsigned _bkt_i; \ unsigned _count; \ char *_prev; \ _count = 0; \ for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) { \ unsigned _bkt_count = 0; \ _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ _prev = NULL; \ while (_thh) { \ if (_prev != (char*)(_thh->hh_prev)) { \ HASH_OOPS("invalid hh_prev %p, actual %p\n", \ _thh->hh_prev, _prev ); \ } \ _bkt_count++; \ _prev = (char*)(_thh); \ _thh = _thh->hh_next; \ } \ _count += _bkt_count; \ if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ HASH_OOPS("invalid bucket count %u, actual %u\n", \ (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ } \ } \ if (_count != (head)->hh.tbl->num_items) { \ HASH_OOPS("invalid hh item count %u, actual %u\n", \ (head)->hh.tbl->num_items, _count ); \ } \ /* traverse hh in app order; check next/prev integrity, count */ \ _count = 0; \ _prev = NULL; \ _thh = &(head)->hh; \ while (_thh) { \ _count++; \ if (_prev !=(char*)(_thh->prev)) { \ HASH_OOPS("invalid prev %p, actual %p\n", \ _thh->prev, _prev ); \ } \ _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ _thh = ( _thh->next ? (UT_hash_handle*)((char*)(_thh->next) + \ (head)->hh.tbl->hho) : NULL ); \ } \ if (_count != (head)->hh.tbl->num_items) { \ HASH_OOPS("invalid app item count %u, actual %u\n", \ (head)->hh.tbl->num_items, _count ); \ } \ } \ } while (0) #else #define HASH_FSCK(hh,head) #endif /* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to * the descriptor to which this macro is defined for tuning the hash function. * The app can #include to get the prototype for write(2). */ #ifdef HASH_EMIT_KEYS #define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ do { \ unsigned _klen = fieldlen; \ write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ write(HASH_EMIT_KEYS, keyptr, (unsigned long)fieldlen); \ } while (0) #else #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,num_bkts,hashv,bkt) \ do { \ unsigned _hb_keylen=(unsigned)keylen; \ const unsigned char *_hb_key=(const unsigned char*)(key); \ (hashv) = 0; \ while (_hb_keylen-- != 0U) { \ (hashv) = (((hashv) << 5) + (hashv)) + *_hb_key++; \ } \ bkt = (hashv) & (num_bkts-1U); \ } while (0) /* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */ #define HASH_SAX(key,keylen,num_bkts,hashv,bkt) \ do { \ unsigned _sx_i; \ const unsigned char *_hs_key=(const unsigned char*)(key); \ hashv = 0; \ for(_sx_i=0; _sx_i < keylen; _sx_i++) { \ hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ } \ bkt = hashv & (num_bkts-1U); \ } while (0) /* FNV-1a variation */ #define HASH_FNV(key,keylen,num_bkts,hashv,bkt) \ do { \ unsigned _fn_i; \ const unsigned char *_hf_key=(const unsigned char*)(key); \ hashv = 2166136261U; \ for(_fn_i=0; _fn_i < keylen; _fn_i++) { \ hashv = hashv ^ _hf_key[_fn_i]; \ hashv = hashv * 16777619U; \ } \ bkt = hashv & (num_bkts-1U); \ } while(0) #define HASH_OAT(key,keylen,num_bkts,hashv,bkt) \ do { \ unsigned _ho_i; \ const unsigned char *_ho_key=(const unsigned char*)(key); \ hashv = 0; \ for(_ho_i=0; _ho_i < keylen; _ho_i++) { \ hashv += _ho_key[_ho_i]; \ hashv += (hashv << 10); \ hashv ^= (hashv >> 6); \ } \ hashv += (hashv << 3); \ hashv ^= (hashv >> 11); \ hashv += (hashv << 15); \ bkt = hashv & (num_bkts-1U); \ } while(0) #define HASH_JEN_MIX(a,b,c) \ do { \ a -= b; a -= c; a ^= ( c >> 13 ); \ b -= c; b -= a; b ^= ( a << 8 ); \ c -= a; c -= b; c ^= ( b >> 13 ); \ a -= b; a -= c; a ^= ( c >> 12 ); \ b -= c; b -= a; b ^= ( a << 16 ); \ c -= a; c -= b; c ^= ( b >> 5 ); \ a -= b; a -= c; a ^= ( c >> 3 ); \ b -= c; b -= a; b ^= ( a << 10 ); \ c -= a; c -= b; c ^= ( b >> 15 ); \ } while (0) #define HASH_JEN(key,keylen,num_bkts,hashv,bkt) \ do { \ unsigned _hj_i,_hj_j,_hj_k; \ unsigned const char *_hj_key=(unsigned const char*)(key); \ hashv = 0xfeedbeefu; \ _hj_i = _hj_j = 0x9e3779b9u; \ _hj_k = (unsigned)(keylen); \ while (_hj_k >= 12U) { \ _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \ + ( (unsigned)_hj_key[2] << 16 ) \ + ( (unsigned)_hj_key[3] << 24 ) ); \ _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \ + ( (unsigned)_hj_key[6] << 16 ) \ + ( (unsigned)_hj_key[7] << 24 ) ); \ hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \ + ( (unsigned)_hj_key[10] << 16 ) \ + ( (unsigned)_hj_key[11] << 24 ) ); \ \ HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ \ _hj_key += 12; \ _hj_k -= 12U; \ } \ hashv += (unsigned)(keylen); \ switch ( _hj_k ) { \ case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); /* FALLTHROUGH */ \ case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); /* FALLTHROUGH */ \ case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); /* FALLTHROUGH */ \ case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); /* FALLTHROUGH */ \ case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); /* FALLTHROUGH */ \ case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); /* FALLTHROUGH */ \ case 5: _hj_j += _hj_key[4]; /* FALLTHROUGH */ \ 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]; \ } \ HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ bkt = hashv & (num_bkts-1U); \ } while(0) /* The Paul Hsieh hash function */ #undef get16bits #if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) #define get16bits(d) (*((const uint16_t *) (d))) #endif #if !defined (get16bits) #define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \ +(uint32_t)(((const uint8_t *)(d))[0]) ) #endif #define HASH_SFH(key,keylen,num_bkts,hashv,bkt) \ do { \ unsigned const char *_sfh_key=(unsigned const char*)(key); \ uint32_t _sfh_tmp, _sfh_len = (uint32_t)keylen; \ \ unsigned _sfh_rem = _sfh_len & 3U; \ _sfh_len >>= 2; \ hashv = 0xcafebabeu; \ \ /* Main loop */ \ for (;_sfh_len > 0U; _sfh_len--) { \ hashv += get16bits (_sfh_key); \ _sfh_tmp = ((uint32_t)(get16bits (_sfh_key+2)) << 11) ^ hashv; \ hashv = (hashv << 16) ^ _sfh_tmp; \ _sfh_key += 2U*sizeof (uint16_t); \ hashv += hashv >> 11; \ } \ \ /* Handle end cases */ \ switch (_sfh_rem) { \ case 3: hashv += get16bits (_sfh_key); \ hashv ^= hashv << 16; \ hashv ^= (uint32_t)(_sfh_key[sizeof (uint16_t)]) << 18; \ hashv += hashv >> 11; \ break; \ case 2: hashv += get16bits (_sfh_key); \ hashv ^= hashv << 11; \ hashv += hashv >> 17; \ break; \ case 1: hashv += *_sfh_key; \ hashv ^= hashv << 10; \ hashv += hashv >> 1; \ } \ \ /* Force "avalanching" of final 127 bits */ \ hashv ^= hashv << 3; \ hashv += hashv >> 5; \ hashv ^= hashv << 4; \ hashv += hashv >> 17; \ hashv ^= hashv << 25; \ hashv += hashv >> 6; \ bkt = hashv & (num_bkts-1U); \ } while(0) #ifdef HASH_USING_NO_STRICT_ALIASING /* The MurmurHash exploits some CPU's (x86,x86_64) tolerance for unaligned reads. * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error. * MurmurHash uses the faster approach only on CPU's where we know it's safe. * * Note the preprocessor built-in defines can be emitted using: * * gcc -m64 -dM -E - < /dev/null (on gcc) * cc -## a.c (where a.c is a simple test file) (Sun Studio) */ #if (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86)) #define MUR_GETBLOCK(p,i) p[i] #else /* non intel */ #define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 3UL) == 0UL) #define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 3UL) == 1UL) #define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 3UL) == 2UL) #define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 3UL) == 3UL) #define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL)) #if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__)) #define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24)) #define MUR_TWO_TWO(p) ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16)) #define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >> 8)) #else /* assume little endian non-intel */ #define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24)) #define MUR_TWO_TWO(p) ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16)) #define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) << 8)) #endif #define MUR_GETBLOCK(p,i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) : \ (MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : \ (MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) : \ MUR_ONE_THREE(p)))) #endif #define MUR_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) #define MUR_FMIX(_h) \ do { \ _h ^= _h >> 16; \ _h *= 0x85ebca6bu; \ _h ^= _h >> 13; \ _h *= 0xc2b2ae35u; \ _h ^= _h >> 16; \ } while(0) #define HASH_MUR(key,keylen,num_bkts,hashv,bkt) \ do { \ const uint8_t *_mur_data = (const uint8_t*)(key); \ const int _mur_nblocks = (int)(keylen) / 4; \ uint32_t _mur_h1 = 0xf88D5353u; \ uint32_t _mur_c1 = 0xcc9e2d51u; \ uint32_t _mur_c2 = 0x1b873593u; \ uint32_t _mur_k1 = 0; \ const uint8_t *_mur_tail; \ const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+(_mur_nblocks*4)); \ int _mur_i; \ for(_mur_i = -_mur_nblocks; _mur_i!=0; _mur_i++) { \ _mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i); \ _mur_k1 *= _mur_c1; \ _mur_k1 = MUR_ROTL32(_mur_k1,15); \ _mur_k1 *= _mur_c2; \ \ _mur_h1 ^= _mur_k1; \ _mur_h1 = MUR_ROTL32(_mur_h1,13); \ _mur_h1 = (_mur_h1*5U) + 0xe6546b64u; \ } \ _mur_tail = (const uint8_t*)(_mur_data + (_mur_nblocks*4)); \ _mur_k1=0; \ switch((keylen) & 3U) { \ case 3: _mur_k1 ^= (uint32_t)_mur_tail[2] << 16; /* FALLTHROUGH */ \ case 2: _mur_k1 ^= (uint32_t)_mur_tail[1] << 8; /* FALLTHROUGH */ \ case 1: _mur_k1 ^= (uint32_t)_mur_tail[0]; \ _mur_k1 *= _mur_c1; \ _mur_k1 = MUR_ROTL32(_mur_k1,15); \ _mur_k1 *= _mur_c2; \ _mur_h1 ^= _mur_k1; \ } \ _mur_h1 ^= (uint32_t)(keylen); \ MUR_FMIX(_mur_h1); \ hashv = _mur_h1; \ bkt = hashv & (num_bkts-1U); \ } while(0) #endif /* HASH_USING_NO_STRICT_ALIASING */ /* key comparison function; return 0 if keys equal */ #define HASH_KEYCMP(a,b,len) memcmp(a,b,(unsigned long)(len)) /* iterate over items in a known bucket to find desired item */ #define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,out) \ do { \ if (head.hh_head != NULL) { DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,head.hh_head)); } \ else { out=NULL; } \ while (out != NULL) { \ if ((out)->hh.keylen == (keylen_in)) { \ if ((HASH_KEYCMP((out)->hh.key,keyptr,keylen_in)) == 0) { break; } \ } \ if ((out)->hh.hh_next != NULL) { DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,(out)->hh.hh_next)); } \ else { out = NULL; } \ } \ } while(0) /* add an item to a bucket */ #define HASH_ADD_TO_BKT(head,addhh) \ do { \ head.count++; \ (addhh)->hh_next = head.hh_head; \ (addhh)->hh_prev = NULL; \ if (head.hh_head != NULL) { (head).hh_head->hh_prev = (addhh); } \ (head).hh_head=addhh; \ if ((head.count >= ((head.expand_mult+1U) * HASH_BKT_CAPACITY_THRESH)) \ && ((addhh)->tbl->noexpand != 1U)) { \ HASH_EXPAND_BUCKETS((addhh)->tbl); \ } \ } while(0) /* remove an item from a given bucket */ #define HASH_DEL_IN_BKT(hh,head,hh_del) \ (head).count--; \ if ((head).hh_head == hh_del) { \ (head).hh_head = hh_del->hh_next; \ } \ if (hh_del->hh_prev) { \ hh_del->hh_prev->hh_next = hh_del->hh_next; \ } \ if (hh_del->hh_next) { \ hh_del->hh_next->hh_prev = hh_del->hh_prev; \ } /* Bucket expansion has the effect of doubling the number of buckets * and redistributing the items into the new buckets. Ideally the * items will distribute more or less evenly into the new buckets * (the extent to which this is true is a measure of the quality of * the hash function as it applies to the key domain). * * With the items distributed into more buckets, the chain length * (item count) in each bucket is reduced. Thus by expanding buckets * the hash keeps a bound on the chain length. This bounded chain * length is the essence of how a hash provides constant time lookup. * * The calculation of tbl->ideal_chain_maxlen below deserves some * explanation. First, keep in mind that we're calculating the ideal * maximum chain length based on the *new* (doubled) bucket count. * In fractions this is just n/b (n=number of items,b=new num buckets). * Since the ideal chain length is an integer, we want to calculate * ceil(n/b). We don't depend on floating point arithmetic in this * hash, so to calculate ceil(n/b) with integers we could write * * ceil(n/b) = (n/b) + ((n%b)?1:0) * * and in fact a previous version of this hash did just that. * But now we have improved things a bit by recognizing that b is * always a power of two. We keep its base 2 log handy (call it lb), * so now we can write this with a bit shift and logical AND: * * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) * */ #define HASH_EXPAND_BUCKETS(tbl) \ do { \ unsigned _he_bkt; \ unsigned _he_bkt_i; \ 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)); \ if (!_he_new_buckets) { uthash_fatal( "out of memory"); } \ memset(_he_new_buckets, 0, \ 2UL * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ tbl->ideal_chain_maxlen = \ (tbl->num_items >> (tbl->log2_num_buckets+1U)) + \ (((tbl->num_items & ((tbl->num_buckets*2U)-1U)) != 0U) ? 1U : 0U); \ tbl->nonideal_items = 0; \ for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++) \ { \ _he_thh = tbl->buckets[ _he_bkt_i ].hh_head; \ while (_he_thh != NULL) { \ _he_hh_nxt = _he_thh->hh_next; \ HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2U, _he_bkt); \ _he_newbkt = &(_he_new_buckets[ _he_bkt ]); \ if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) { \ tbl->nonideal_items++; \ _he_newbkt->expand_mult = _he_newbkt->count / \ tbl->ideal_chain_maxlen; \ } \ _he_thh->hh_prev = NULL; \ _he_thh->hh_next = _he_newbkt->hh_head; \ if (_he_newbkt->hh_head != NULL) { _he_newbkt->hh_head->hh_prev = \ _he_thh; } \ _he_newbkt->hh_head = _he_thh; \ _he_thh = _he_hh_nxt; \ } \ } \ uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ tbl->num_buckets *= 2U; \ tbl->log2_num_buckets++; \ tbl->buckets = _he_new_buckets; \ tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ? \ (tbl->ineff_expands+1U) : 0U; \ if (tbl->ineff_expands > 1U) { \ tbl->noexpand=1; \ uthash_noexpand_fyi(tbl); \ } \ uthash_expand_fyi(tbl); \ } while(0) /* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ /* Note that HASH_SORT assumes the hash handle name to be hh. * HASH_SRT was added to allow the hash handle name to be passed in. */ #define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) #define HASH_SRT(hh,head,cmpfcn) \ do { \ unsigned _hs_i; \ unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \ struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ if (head != NULL) { \ _hs_insize = 1; \ _hs_looping = 1; \ _hs_list = &((head)->hh); \ while (_hs_looping != 0U) { \ _hs_p = _hs_list; \ _hs_list = NULL; \ _hs_tail = NULL; \ _hs_nmerges = 0; \ while (_hs_p != NULL) { \ _hs_nmerges++; \ _hs_q = _hs_p; \ _hs_psize = 0; \ for ( _hs_i = 0; _hs_i < _hs_insize; _hs_i++ ) { \ _hs_psize++; \ _hs_q = (UT_hash_handle*)((_hs_q->next != NULL) ? \ ((void*)((char*)(_hs_q->next) + \ (head)->hh.tbl->hho)) : NULL); \ if (! (_hs_q) ) { break; } \ } \ _hs_qsize = _hs_insize; \ while ((_hs_psize > 0U) || ((_hs_qsize > 0U) && (_hs_q != NULL))) {\ if (_hs_psize == 0U) { \ _hs_e = _hs_q; \ _hs_q = (UT_hash_handle*)((_hs_q->next != NULL) ? \ ((void*)((char*)(_hs_q->next) + \ (head)->hh.tbl->hho)) : NULL); \ _hs_qsize--; \ } else if ( (_hs_qsize == 0U) || (_hs_q == NULL) ) { \ _hs_e = _hs_p; \ if (_hs_p != NULL){ \ _hs_p = (UT_hash_handle*)((_hs_p->next != NULL) ? \ ((void*)((char*)(_hs_p->next) + \ (head)->hh.tbl->hho)) : NULL); \ } \ _hs_psize--; \ } else if (( \ cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \ DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \ ) <= 0) { \ _hs_e = _hs_p; \ if (_hs_p != NULL){ \ _hs_p = (UT_hash_handle*)((_hs_p->next != NULL) ? \ ((void*)((char*)(_hs_p->next) + \ (head)->hh.tbl->hho)) : NULL); \ } \ _hs_psize--; \ } else { \ _hs_e = _hs_q; \ _hs_q = (UT_hash_handle*)((_hs_q->next != NULL) ? \ ((void*)((char*)(_hs_q->next) + \ (head)->hh.tbl->hho)) : NULL); \ _hs_qsize--; \ } \ if ( _hs_tail != NULL ) { \ _hs_tail->next = ((_hs_e != NULL) ? \ ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL); \ } else { \ _hs_list = _hs_e; \ } \ if (_hs_e != NULL) { \ _hs_e->prev = ((_hs_tail != NULL) ? \ ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL); \ } \ _hs_tail = _hs_e; \ } \ _hs_p = _hs_q; \ } \ if (_hs_tail != NULL){ \ _hs_tail->next = NULL; \ } \ if ( _hs_nmerges <= 1U ) { \ _hs_looping=0; \ (head)->hh.tbl->tail = _hs_tail; \ DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ } \ _hs_insize *= 2U; \ } \ HASH_FSCK(hh,head); \ } \ } while (0) /* This function selects items from one hash into another hash. * The end result is that the selected items have dual presence * in both hashes. There is no copy of the items made; rather * they are added into the new hash through a secondary hash * hash handle that must be present in the structure. */ #define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ do { \ unsigned _src_bkt, _dst_bkt; \ void *_last_elt=NULL, *_elt; \ UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ if (src != NULL) { \ for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \ for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ _src_hh != NULL; \ _src_hh = _src_hh->hh_next) { \ _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ if (cond(_elt)) { \ _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \ _dst_hh->key = _src_hh->key; \ _dst_hh->keylen = _src_hh->keylen; \ _dst_hh->hashv = _src_hh->hashv; \ _dst_hh->prev = _last_elt; \ _dst_hh->next = NULL; \ if (_last_elt_hh != NULL) { _last_elt_hh->next = _elt; } \ if (dst == NULL) { \ DECLTYPE_ASSIGN(dst,_elt); \ HASH_MAKE_TABLE(hh_dst,dst); \ } else { \ _dst_hh->tbl = (dst)->hh_dst.tbl; \ } \ HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh); \ (dst)->hh_dst.tbl->num_items++; \ _last_elt = _elt; \ _last_elt_hh = _dst_hh; \ } \ } \ } \ } \ HASH_FSCK(hh_dst,dst); \ } while (0) #define HASH_CLEAR(hh,head) \ do { \ if (head != NULL) { \ uthash_free((head)->hh.tbl->buckets, \ (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \ HASH_BLOOM_FREE((head)->hh.tbl); \ uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ (head)=NULL; \ } \ } while(0) #define HASH_OVERHEAD(hh,head) \ ((head != NULL) ? ( \ (size_t)(((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \ ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \ sizeof(UT_hash_table) + \ (HASH_BLOOM_BYTELEN))) : 0U) #ifdef NO_DECLTYPE #define HASH_ITER(hh,head,el,tmp) \ for(((el)=(head)), ((*(char**)(&(tmp)))=(char*)((head!=NULL)?(head)->hh.next:NULL)); \ (el) != NULL; ((el)=(tmp)), ((*(char**)(&(tmp)))=(char*)((tmp!=NULL)?(tmp)->hh.next:NULL))) #else #define HASH_ITER(hh,head,el,tmp) \ for(((el)=(head)), ((tmp)=DECLTYPE(el)((head!=NULL)?(head)->hh.next:NULL)); \ (el) != NULL; ((el)=(tmp)), ((tmp)=DECLTYPE(el)((tmp!=NULL)?(tmp)->hh.next:NULL))) #endif /* obtain a count of items in the hash */ #define HASH_COUNT(head) HASH_CNT(hh,head) #define HASH_CNT(hh,head) ((head != NULL)?((head)->hh.tbl->num_items):0U) typedef struct UT_hash_bucket { struct UT_hash_handle *hh_head; unsigned count; /* expand_mult is normally set to 0. In this situation, the max chain length * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If * the bucket's chain exceeds this length, bucket expansion is triggered). * However, setting expand_mult to a non-zero value delays bucket expansion * (that would be triggered by additions to this particular bucket) * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. * (The multiplier is simply expand_mult+1). The whole idea of this * multiplier is to reduce bucket expansions, since they are expensive, in * situations where we know that a particular bucket tends to be overused. * It is better to let its chain length grow to a longer yet-still-bounded * value, than to do an O(n) bucket expansion too often. */ unsigned expand_mult; } UT_hash_bucket; /* random signature used only to find hash tables in external analysis */ #define HASH_SIGNATURE 0xa0111fe1u #define HASH_BLOOM_SIGNATURE 0xb12220f2u typedef struct UT_hash_table { UT_hash_bucket *buckets; unsigned num_buckets, log2_num_buckets; unsigned num_items; struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ /* in an ideal situation (all buckets used equally), no bucket would have * more than ceil(#items/#buckets) items. that's the ideal chain length. */ unsigned ideal_chain_maxlen; /* nonideal_items is the number of items in the hash whose chain position * exceeds the ideal chain maxlen. these items pay the penalty for an uneven * hash distribution; reaching them in a chain traversal takes >ideal steps */ unsigned nonideal_items; /* ineffective expands occur when a bucket doubling was performed, but * afterward, more than half the items in the hash had nonideal chain * positions. If this happens on two consecutive expansions we inhibit any * further expansion, as it's not helping; this happens when the hash * function isn't a good fit for the key domain. When expansion is inhibited * the hash will still work, albeit no longer in constant time. */ unsigned ineff_expands, noexpand; uint32_t signature; /* used only to find hash tables in external analysis */ #ifdef HASH_BLOOM uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ uint8_t *bloom_bv; uint8_t bloom_nbits; #endif } UT_hash_table; typedef struct UT_hash_handle { struct UT_hash_table *tbl; void *prev; /* prev element in app order */ 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 */ unsigned keylen; /* enclosing struct's key len */ unsigned hashv; /* result of hash-fcn(key) */ } UT_hash_handle; #endif /* UTHASH_H */ uthash-1.9.9.1+git20151125/src/utlist.h000066400000000000000000001551161264051566200170710ustar00rootroot00000000000000/* Copyright (c) 2007-2014, Troy D. Hanson http://troydhanson.github.com/uthash/ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef UTLIST_H #define UTLIST_H #define UTLIST_VERSION 1.9.9 #include /* * This file contains macros to manipulate singly and doubly-linked lists. * * 1. LL_ macros: singly-linked lists. * 2. DL_ macros: doubly-linked lists. * 3. CDL_ macros: circular doubly-linked lists. * * To use singly-linked lists, your structure must have a "next" pointer. * To use doubly-linked lists, your structure must "prev" and "next" pointers. * Either way, the pointer to the head of the list must be initialized to NULL. * * ----------------.EXAMPLE ------------------------- * struct item { * int id; * struct item *prev, *next; * } * * struct item *list = NULL: * * int main() { * struct item *item; * ... allocate and populate item ... * DL_APPEND(list, item); * } * -------------------------------------------------- * * For doubly-linked lists, the append and delete macros are O(1) * For singly-linked lists, append and delete are O(n) but prepend is O(1) * The sort macro is O(n log(n)) for all types of single/double/circular lists. */ /* 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++ code), this code uses whatever method is needed or, for VS2008 where neither is available, uses casting workarounds. */ #ifdef _MSC_VER /* MS compiler */ #if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ #define LDECLTYPE(x) decltype(x) #else /* VS2008 or older (or VS2010 in C mode) */ #define NO_DECLTYPE #define LDECLTYPE(x) char* #endif #elif defined(__ICCARM__) #define NO_DECLTYPE #define LDECLTYPE(x) char* #else /* GNU, Sun and other compilers */ #define LDECLTYPE(x) __typeof(x) #endif /* for VS2008 we use some workarounds to get around the lack of decltype, * namely, we always reassign our tmp variable to the list head if we need * to dereference its prev/next pointers, and save/restore the real head.*/ #ifdef NO_DECLTYPE #define _SV(elt,list) _tmp = (char*)(list); {char **_alias = (char**)&(list); *_alias = (elt); } #define _NEXT(elt,list,next) ((char*)((list)->next)) #define _NEXTASGN(elt,list,to,next) { char **_alias = (char**)&((list)->next); *_alias=(char*)(to); } /* #define _PREV(elt,list,prev) ((char*)((list)->prev)) */ #define _PREVASGN(elt,list,to,prev) { char **_alias = (char**)&((list)->prev); *_alias=(char*)(to); } #define _RS(list) { char **_alias = (char**)&(list); *_alias=_tmp; } #define _CASTASGN(a,b) { char **_alias = (char**)&(a); *_alias=(char*)(b); } #else #define _SV(elt,list) #define _NEXT(elt,list,next) ((elt)->next) #define _NEXTASGN(elt,list,to,next) ((elt)->next)=(to) /* #define _PREV(elt,list,prev) ((elt)->prev) */ #define _PREVASGN(elt,list,to,prev) ((elt)->prev)=(to) #define _RS(list) #define _CASTASGN(a,b) (a)=(b) #endif /****************************************************************************** * The sort macro is an adaptation of Simon Tatham's O(n log(n)) mergesort * * Unwieldy variable names used here to avoid shadowing passed-in variables. * *****************************************************************************/ #define LL_SORT(list, cmp) \ LL_SORT2(list, cmp, next) #define LL_SORT2(list, cmp, next) \ do { \ LDECLTYPE(list) _ls_p; \ LDECLTYPE(list) _ls_q; \ LDECLTYPE(list) _ls_e; \ LDECLTYPE(list) _ls_tail; \ int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ if (list) { \ _ls_insize = 1; \ _ls_looping = 1; \ while (_ls_looping) { \ _CASTASGN(_ls_p,list); \ list = NULL; \ _ls_tail = NULL; \ _ls_nmerges = 0; \ while (_ls_p) { \ _ls_nmerges++; \ _ls_q = _ls_p; \ _ls_psize = 0; \ for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ _ls_psize++; \ _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list); \ if (!_ls_q) break; \ } \ _ls_qsize = _ls_insize; \ while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ if (_ls_psize == 0) { \ _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ } else if (_ls_qsize == 0 || !_ls_q) { \ _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ } else if (cmp(_ls_p,_ls_q) <= 0) { \ _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ } else { \ _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ } \ if (_ls_tail) { \ _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \ } else { \ _CASTASGN(list,_ls_e); \ } \ _ls_tail = _ls_e; \ } \ _ls_p = _ls_q; \ } \ if (_ls_tail) { \ _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list); \ } \ if (_ls_nmerges <= 1) { \ _ls_looping=0; \ } \ _ls_insize *= 2; \ } \ } \ } while (0) #define DL_SORT(list, cmp) \ DL_SORT2(list, cmp, prev, next) #define DL_SORT2(list, cmp, prev, next) \ do { \ LDECLTYPE(list) _ls_p; \ LDECLTYPE(list) _ls_q; \ LDECLTYPE(list) _ls_e; \ LDECLTYPE(list) _ls_tail; \ int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ if (list) { \ _ls_insize = 1; \ _ls_looping = 1; \ while (_ls_looping) { \ _CASTASGN(_ls_p,list); \ list = NULL; \ _ls_tail = NULL; \ _ls_nmerges = 0; \ while (_ls_p) { \ _ls_nmerges++; \ _ls_q = _ls_p; \ _ls_psize = 0; \ for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ _ls_psize++; \ _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list); \ if (!_ls_q) break; \ } \ _ls_qsize = _ls_insize; \ while ((_ls_psize > 0) || ((_ls_qsize > 0) && _ls_q)) { \ if (_ls_psize == 0) { \ _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ } else if ((_ls_qsize == 0) || (!_ls_q)) { \ _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ } else if (cmp(_ls_p,_ls_q) <= 0) { \ _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ } else { \ _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ } \ if (_ls_tail) { \ _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \ } else { \ _CASTASGN(list,_ls_e); \ } \ _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list); \ _ls_tail = _ls_e; \ } \ _ls_p = _ls_q; \ } \ _CASTASGN(list->prev, _ls_tail); \ _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list); \ if (_ls_nmerges <= 1) { \ _ls_looping=0; \ } \ _ls_insize *= 2; \ } \ } \ } while (0) #define CDL_SORT(list, cmp) \ CDL_SORT2(list, cmp, prev, next) #define CDL_SORT2(list, cmp, prev, next) \ do { \ LDECLTYPE(list) _ls_p; \ LDECLTYPE(list) _ls_q; \ LDECLTYPE(list) _ls_e; \ LDECLTYPE(list) _ls_tail; \ LDECLTYPE(list) _ls_oldhead; \ LDECLTYPE(list) _tmp; \ int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ if (list) { \ _ls_insize = 1; \ _ls_looping = 1; \ while (_ls_looping) { \ _CASTASGN(_ls_p,list); \ _CASTASGN(_ls_oldhead,list); \ list = NULL; \ _ls_tail = NULL; \ _ls_nmerges = 0; \ while (_ls_p) { \ _ls_nmerges++; \ _ls_q = _ls_p; \ _ls_psize = 0; \ for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ _ls_psize++; \ _SV(_ls_q,list); \ if (_NEXT(_ls_q,list,next) == _ls_oldhead) { \ _ls_q = NULL; \ } else { \ _ls_q = _NEXT(_ls_q,list,next); \ } \ _RS(list); \ if (!_ls_q) break; \ } \ _ls_qsize = _ls_insize; \ while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ if (_ls_psize == 0) { \ _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ } else if (_ls_qsize == 0 || !_ls_q) { \ _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ } else if (cmp(_ls_p,_ls_q) <= 0) { \ _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ } else { \ _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ } \ if (_ls_tail) { \ _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \ } else { \ _CASTASGN(list,_ls_e); \ } \ _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list); \ _ls_tail = _ls_e; \ } \ _ls_p = _ls_q; \ } \ _CASTASGN(list->prev,_ls_tail); \ _CASTASGN(_tmp,list); \ _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_tmp,next); _RS(list); \ if (_ls_nmerges <= 1) { \ _ls_looping=0; \ } \ _ls_insize *= 2; \ } \ } \ } while (0) /****************************************************************************** * singly linked list macros (non-circular) * *****************************************************************************/ #define LL_PREPEND(head,add) \ LL_PREPEND2(head,add,next) #define LL_PREPEND2(head,add,next) \ do { \ (add)->next = head; \ head = add; \ } while (0) #define LL_CONCAT(head1,head2) \ LL_CONCAT2(head1,head2,next) #define LL_CONCAT2(head1,head2,next) \ do { \ LDECLTYPE(head1) _tmp; \ if (head1) { \ _tmp = head1; \ while (_tmp->next) { _tmp = _tmp->next; } \ _tmp->next=(head2); \ } else { \ (head1)=(head2); \ } \ } while (0) #define LL_APPEND(head,add) \ LL_APPEND2(head,add,next) #define LL_APPEND2(head,add,next) \ do { \ LDECLTYPE(head) _tmp; \ (add)->next=NULL; \ if (head) { \ _tmp = head; \ while (_tmp->next) { _tmp = _tmp->next; } \ _tmp->next=(add); \ } else { \ (head)=(add); \ } \ } while (0) #define LL_DELETE(head,del) \ LL_DELETE2(head,del,next) #define LL_DELETE2(head,del,next) \ do { \ LDECLTYPE(head) _tmp; \ if ((head) == (del)) { \ (head)=(head)->next; \ } else { \ _tmp = head; \ while (_tmp->next && (_tmp->next != (del))) { \ _tmp = _tmp->next; \ } \ if (_tmp->next) { \ _tmp->next = ((del)->next); \ } \ } \ } while (0) /* Here are VS2008 replacements for LL_APPEND and LL_DELETE */ #define LL_APPEND_VS2008(head,add) \ LL_APPEND2_VS2008(head,add,next) #define LL_APPEND2_VS2008(head,add,next) \ do { \ if (head) { \ (add)->next = head; /* use add->next as a temp variable */ \ while ((add)->next->next) { (add)->next = (add)->next->next; } \ (add)->next->next=(add); \ } else { \ (head)=(add); \ } \ (add)->next=NULL; \ } while (0) #define LL_DELETE_VS2008(head,del) \ LL_DELETE2_VS2008(head,del,next) #define LL_DELETE2_VS2008(head,del,next) \ do { \ if ((head) == (del)) { \ (head)=(head)->next; \ } else { \ char *_tmp = (char*)(head); \ while ((head)->next && ((head)->next != (del))) { \ head = (head)->next; \ } \ if ((head)->next) { \ (head)->next = ((del)->next); \ } \ { \ char **_head_alias = (char**)&(head); \ *_head_alias = _tmp; \ } \ } \ } while (0) #ifdef NO_DECLTYPE #undef LL_APPEND #define LL_APPEND LL_APPEND_VS2008 #undef LL_DELETE #define LL_DELETE LL_DELETE_VS2008 #undef LL_DELETE2 #define LL_DELETE2 LL_DELETE2_VS2008 #undef LL_APPEND2 #define LL_APPEND2 LL_APPEND2_VS2008 #undef LL_CONCAT /* no LL_CONCAT_VS2008 */ #undef DL_CONCAT /* no DL_CONCAT_VS2008 */ #endif /* end VS2008 replacements */ #define LL_COUNT(head,el,counter) \ LL_COUNT2(head,el,counter,next) \ #define LL_COUNT2(head,el,counter,next) \ { \ counter = 0; \ LL_FOREACH2(head,el,next){ ++counter; } \ } #define LL_FOREACH(head,el) \ LL_FOREACH2(head,el,next) #define LL_FOREACH2(head,el,next) \ for(el=head;el;el=(el)->next) #define LL_FOREACH_SAFE(head,el,tmp) \ LL_FOREACH_SAFE2(head,el,tmp,next) #define LL_FOREACH_SAFE2(head,el,tmp,next) \ for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp) #define LL_SEARCH_SCALAR(head,out,field,val) \ LL_SEARCH_SCALAR2(head,out,field,val,next) #define LL_SEARCH_SCALAR2(head,out,field,val,next) \ do { \ LL_FOREACH2(head,out,next) { \ if ((out)->field == (val)) break; \ } \ } while(0) #define LL_SEARCH(head,out,elt,cmp) \ LL_SEARCH2(head,out,elt,cmp,next) #define LL_SEARCH2(head,out,elt,cmp,next) \ do { \ LL_FOREACH2(head,out,next) { \ if ((cmp(out,elt))==0) break; \ } \ } while(0) #define LL_REPLACE_ELEM(head, el, add) \ do { \ LDECLTYPE(head) _tmp; \ assert(head != NULL); \ assert(el != NULL); \ assert(add != NULL); \ (add)->next = (el)->next; \ if ((head) == (el)) { \ (head) = (add); \ } else { \ _tmp = head; \ while (_tmp->next && (_tmp->next != (el))) { \ _tmp = _tmp->next; \ } \ if (_tmp->next) { \ _tmp->next = (add); \ } \ } \ } while (0) #define LL_PREPEND_ELEM(head, el, add) \ do { \ LDECLTYPE(head) _tmp; \ assert(head != NULL); \ assert(el != NULL); \ assert(add != NULL); \ (add)->next = (el); \ if ((head) == (el)) { \ (head) = (add); \ } else { \ _tmp = head; \ while (_tmp->next && (_tmp->next != (el))) { \ _tmp = _tmp->next; \ } \ if (_tmp->next) { \ _tmp->next = (add); \ } \ } \ } while (0) \ /****************************************************************************** * doubly linked list macros (non-circular) * *****************************************************************************/ #define DL_PREPEND(head,add) \ DL_PREPEND2(head,add,prev,next) #define DL_PREPEND2(head,add,prev,next) \ do { \ (add)->next = head; \ if (head) { \ (add)->prev = (head)->prev; \ (head)->prev = (add); \ } else { \ (add)->prev = (add); \ } \ (head) = (add); \ } while (0) #define DL_APPEND(head,add) \ DL_APPEND2(head,add,prev,next) #define DL_APPEND2(head,add,prev,next) \ do { \ if (head) { \ (add)->prev = (head)->prev; \ (head)->prev->next = (add); \ (head)->prev = (add); \ (add)->next = NULL; \ } else { \ (head)=(add); \ (head)->prev = (head); \ (head)->next = NULL; \ } \ } while (0) #define DL_CONCAT(head1,head2) \ DL_CONCAT2(head1,head2,prev,next) #define DL_CONCAT2(head1,head2,prev,next) \ do { \ LDECLTYPE(head1) _tmp; \ if (head2) { \ if (head1) { \ _tmp = (head2)->prev; \ (head2)->prev = (head1)->prev; \ (head1)->prev->next = (head2); \ (head1)->prev = _tmp; \ } else { \ (head1)=(head2); \ } \ } \ } while (0) #define DL_DELETE(head,del) \ DL_DELETE2(head,del,prev,next) #define DL_DELETE2(head,del,prev,next) \ do { \ assert((del)->prev != NULL); \ if ((del)->prev == (del)) { \ (head)=NULL; \ } else if ((del)==(head)) { \ (del)->next->prev = (del)->prev; \ (head) = (del)->next; \ } else { \ (del)->prev->next = (del)->next; \ if ((del)->next) { \ (del)->next->prev = (del)->prev; \ } else { \ (head)->prev = (del)->prev; \ } \ } \ } while (0) #define DL_COUNT(head,el,counter) \ DL_COUNT2(head,el,counter,next) \ #define DL_COUNT2(head,el,counter,next) \ { \ counter = 0; \ DL_FOREACH2(head,el,next){ ++counter; } \ } #define DL_FOREACH(head,el) \ DL_FOREACH2(head,el,next) #define DL_FOREACH2(head,el,next) \ for(el=head;el;el=(el)->next) /* this version is safe for deleting the elements during iteration */ #define DL_FOREACH_SAFE(head,el,tmp) \ DL_FOREACH_SAFE2(head,el,tmp,next) #define DL_FOREACH_SAFE2(head,el,tmp,next) \ for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp) /* these are identical to their singly-linked list counterparts */ #define DL_SEARCH_SCALAR LL_SEARCH_SCALAR #define DL_SEARCH LL_SEARCH #define DL_SEARCH_SCALAR2 LL_SEARCH_SCALAR2 #define DL_SEARCH2 LL_SEARCH2 #define DL_REPLACE_ELEM(head, el, add) \ do { \ assert(head != NULL); \ assert(el != NULL); \ assert(add != NULL); \ if ((head) == (el)) { \ (head) = (add); \ (add)->next = (el)->next; \ if ((el)->next == NULL) { \ (add)->prev = (add); \ } else { \ (add)->prev = (el)->prev; \ (add)->next->prev = (add); \ } \ } else { \ (add)->next = (el)->next; \ (add)->prev = (el)->prev; \ (add)->prev->next = (add); \ if ((el)->next == NULL) { \ (head)->prev = (add); \ } else { \ (add)->next->prev = (add); \ } \ } \ } while (0) #define DL_PREPEND_ELEM(head, el, add) \ do { \ assert(head != NULL); \ assert(el != NULL); \ assert(add != NULL); \ (add)->next = (el); \ (add)->prev = (el)->prev; \ (el)->prev = (add); \ if ((head) == (el)) { \ (head) = (add); \ } else { \ (add)->prev->next = (add); \ } \ } while (0) \ /****************************************************************************** * circular doubly linked list macros * *****************************************************************************/ #define CDL_PREPEND(head,add) \ CDL_PREPEND2(head,add,prev,next) #define CDL_PREPEND2(head,add,prev,next) \ do { \ if (head) { \ (add)->prev = (head)->prev; \ (add)->next = (head); \ (head)->prev = (add); \ (add)->prev->next = (add); \ } else { \ (add)->prev = (add); \ (add)->next = (add); \ } \ (head)=(add); \ } while (0) #define CDL_DELETE(head,del) \ CDL_DELETE2(head,del,prev,next) #define CDL_DELETE2(head,del,prev,next) \ do { \ if ( ((head)==(del)) && ((head)->next == (head))) { \ (head) = NULL; \ } else { \ (del)->next->prev = (del)->prev; \ (del)->prev->next = (del)->next; \ if ((del) == (head)) (head)=(del)->next; \ } \ } while (0) #define CDL_COUNT(head,el,counter) \ CDL_COUNT2(head,el,counter,next) \ #define CDL_COUNT2(head, el, counter,next) \ { \ counter = 0; \ CDL_FOREACH2(head,el,next){ ++counter; } \ } #define CDL_FOREACH(head,el) \ CDL_FOREACH2(head,el,next) #define CDL_FOREACH2(head,el,next) \ for(el=head;el;el=(((el)->next==head) ? 0L : (el)->next)) #define CDL_FOREACH_SAFE(head,el,tmp1,tmp2) \ CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next) #define CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next) \ for((el)=(head), ((tmp1)=(head)?((head)->prev):NULL); \ (el) && ((tmp2)=(el)->next, 1); \ ((el) = (((el)==(tmp1)) ? 0L : (tmp2)))) #define CDL_SEARCH_SCALAR(head,out,field,val) \ CDL_SEARCH_SCALAR2(head,out,field,val,next) #define CDL_SEARCH_SCALAR2(head,out,field,val,next) \ do { \ CDL_FOREACH2(head,out,next) { \ if ((out)->field == (val)) break; \ } \ } while(0) #define CDL_SEARCH(head,out,elt,cmp) \ CDL_SEARCH2(head,out,elt,cmp,next) #define CDL_SEARCH2(head,out,elt,cmp,next) \ do { \ CDL_FOREACH2(head,out,next) { \ if ((cmp(out,elt))==0) break; \ } \ } while(0) #define CDL_REPLACE_ELEM(head, el, add) \ do { \ assert(head != NULL); \ assert(el != NULL); \ assert(add != NULL); \ if ((el)->next == (el)) { \ (add)->next = (add); \ (add)->prev = (add); \ (head) = (add); \ } else { \ (add)->next = (el)->next; \ (add)->prev = (el)->prev; \ (add)->next->prev = (add); \ (add)->prev->next = (add); \ if ((head) == (el)) { \ (head) = (add); \ } \ } \ } while (0) #define CDL_PREPEND_ELEM(head, el, add) \ do { \ assert(head != NULL); \ assert(el != NULL); \ assert(add != NULL); \ (add)->next = (el); \ (add)->prev = (el)->prev; \ (el)->prev = (add); \ (add)->prev->next = (add); \ if ((head) == (el)) { \ (head) = (add); \ } \ } while (0) \ #endif /* UTLIST_H */ uthash-1.9.9.1+git20151125/src/utmm.h000066400000000000000000000036401264051566200165210ustar00rootroot00000000000000#include #include #include /* Copyright (c) 2003-2015, Troy D. Hanson http://troydhanson.github.com/uthash/ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* utmm * * low level memory primitives * */ #ifndef __UTMM_H_ #define __UTMM_H_ typedef struct { size_t sz; void (*init)(void *buf); //-> utstring-init void (*fini)(void *buf); //-> utstring-done void (*copy)(void *dst, void *src); //-> ustring_concat void (*clear)(void *buf); //-> utstring-clear } UT_mm; void *utmm_new(const UT_mm *mm, size_t n); void utmm_init(const UT_mm *mm, void *buf, size_t n); void utmm_fini(const UT_mm *mm, void *buf, size_t n); void utmm_clear(const UT_mm *mm, void *buf, size_t n); void utmm_copy(const UT_mm *mm, void *dst, void *src, size_t n); /* convenient predefined mm */ extern UT_mm* utmm_int; extern UT_mm* utstring_mm; #endif /* __UTMM_H_ */ uthash-1.9.9.1+git20151125/src/utringbuffer.h000066400000000000000000000126651264051566200202500ustar00rootroot00000000000000/* Copyright (c) 2008-2014, Troy D. Hanson http://troydhanson.github.com/uthash/ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* a ring-buffer implementation using macros */ #ifndef UTRINGBUFFER_H #define UTRINGBUFFER_H #include #include #include "utarray.h" // for "UT_icd" typedef struct { unsigned i; /* index of next available slot; wraps at n */ unsigned n; /* capacity */ unsigned char f; /* full */ UT_icd icd; /* initializer, copy and destructor functions */ char *d; /* n slots of size icd->sz */ } UT_ringbuffer; #define utringbuffer_init(a, _n, _icd) do { \ memset(a, 0, sizeof(UT_ringbuffer)); \ (a)->icd = *(_icd); \ (a)->n = (_n); \ if ((a)->n) { (a)->d = malloc((a)->n * (_icd)->sz); } \ } while(0) #define utringbuffer_clear(a) do { \ if ((a)->icd.dtor) { \ if ((a)->f) { \ for (unsigned _ut_i=0; _ut_i < (a)->n; _ut_i++) { \ (a)->icd.dtor(utringbuffer_eltptr(a, _ut_i)); \ } \ } else { \ for (unsigned _ut_i=0; _ut_i < (a)->i; _ut_i++) { \ (a)->icd.dtor(utringbuffer_eltptr(a, _ut_i)); \ } \ } \ } \ (a)->i = 0; \ (a)->f = 0; \ } while(0) #define utringbuffer_done(a) do { \ utringbuffer_clear(a); \ free((a)->d); (a)->d = NULL; \ (a)->n = 0; \ } while(0) #define utringbuffer_new(a,n,_icd) do { \ a = (UT_ringbuffer*)malloc(sizeof(UT_ringbuffer)); \ utringbuffer_init(a, n, _icd); \ } while(0) #define utringbuffer_free(a) do { \ utringbuffer_done(a); \ free(a); \ } while(0) #define utringbuffer_push_back(a,p) do { \ if ((a)->icd.dtor && (a)->f) { (a)->icd.dtor(_utringbuffer_internalptr(a,(a)->i)); } \ if ((a)->icd.copy) { (a)->icd.copy( _utringbuffer_internalptr(a,(a)->i), p); } \ else { memcpy(_utringbuffer_internalptr(a,(a)->i), p, (a)->icd.sz); }; \ if (++(a)->i == (a)->n) { (a)->i = 0; (a)->f = 1; } \ } while(0) #define utringbuffer_len(a) ((a)->f ? (a)->n : (a)->i) #define utringbuffer_empty(a) ((a)->i == 0 && !(a)->f) #define utringbuffer_full(a) ((a)->f != 0) #define _utringbuffer_real_idx(a,j) ((a)->f ? ((j) + (a)->i) % (a)->n : (j)) #define _utringbuffer_internalptr(a,j) ((void*)((char*)((a)->d + ((a)->icd.sz * (j))))) #define utringbuffer_eltptr(a,j) ((0 <= (j) && (j) < utringbuffer_len(a)) ? _utringbuffer_internalptr(a,_utringbuffer_real_idx(a,j)) : NULL) #define _utringbuffer_fake_idx(a,j) ((a)->f ? ((j) + (a)->n - (a)->i) % (a)->n : (j)) #define _utringbuffer_internalidx(a,e) (((char*)(e) >= (char*)(a)->d) ? (((char*)(e) - (char*)(a)->d)/(size_t)(a)->icd.sz) : -1) #define utringbuffer_eltidx(a,e) _utringbuffer_fake_idx(a, _utringbuffer_internalidx(a,e)) #define utringbuffer_front(a) utringbuffer_eltptr(a,0) #define utringbuffer_next(a,e) ((e)==NULL ? utringbuffer_front(a) : utringbuffer_eltptr(a, utringbuffer_eltidx(a,e)+1)) #define utringbuffer_prev(a,e) ((e)==NULL ? utringbuffer_back(a) : utringbuffer_eltptr(a, utringbuffer_eltidx(a,e)-1)) #define utringbuffer_back(a) (utringbuffer_empty(a) ? NULL : utringbuffer_eltptr(a, utringbuffer_len(a) - 1)) #endif /* UTRINGBUFFER_H */ uthash-1.9.9.1+git20151125/src/utstring.h000066400000000000000000000266571264051566200174330ustar00rootroot00000000000000/* Copyright (c) 2008-2014, Troy D. Hanson http://troydhanson.github.com/uthash/ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* a dynamic string implementation using macros */ #ifndef UTSTRING_H #define UTSTRING_H #define UTSTRING_VERSION 1.9.9 #ifdef __GNUC__ #define _UNUSED_ __attribute__ ((__unused__)) #else #define _UNUSED_ #endif #include #include #include #include #ifndef oom #define oom() exit(-1) #endif typedef struct { char *d; size_t n; /* allocd size */ size_t i; /* index of first unused byte */ } UT_string; #define utstring_reserve(s,amt) \ do { \ if (((s)->n - (s)->i) < (size_t)(amt)) { \ char *utstring_tmp = (char*)realloc( \ (s)->d, (s)->n + (amt)); \ if (utstring_tmp == NULL) oom(); \ (s)->d = utstring_tmp; \ (s)->n += (amt); \ } \ } while(0) #define utstring_init(s) \ do { \ (s)->n = 0; (s)->i = 0; (s)->d = NULL; \ utstring_reserve(s,100); \ (s)->d[0] = '\0'; \ } while(0) #define utstring_done(s) \ do { \ if ((s)->d != NULL) free((s)->d); \ (s)->n = 0; \ } while(0) #define utstring_free(s) \ do { \ utstring_done(s); \ free(s); \ } while(0) #define utstring_new(s) \ do { \ s = (UT_string*)calloc(sizeof(UT_string),1); \ if (!s) oom(); \ utstring_init(s); \ } while(0) #define utstring_renew(s) \ do { \ if (s) { \ utstring_clear(s); \ } else { \ utstring_new(s); \ } \ } while(0) #define utstring_clear(s) \ do { \ (s)->i = 0; \ (s)->d[0] = '\0'; \ } while(0) #define utstring_bincpy(s,b,l) \ do { \ utstring_reserve((s),(l)+1); \ if (l) memcpy(&(s)->d[(s)->i], b, l); \ (s)->i += (l); \ (s)->d[(s)->i]='\0'; \ } while(0) #define utstring_concat(dst,src) \ do { \ utstring_reserve((dst),((src)->i)+1); \ if ((src)->i) memcpy(&(dst)->d[(dst)->i], (src)->d, (src)->i); \ (dst)->i += (src)->i; \ (dst)->d[(dst)->i]='\0'; \ } while(0) #define utstring_len(s) ((unsigned)((s)->i)) #define utstring_body(s) ((s)->d) _UNUSED_ static void utstring_printf_va(UT_string *s, const char *fmt, va_list ap) { int n; va_list cp; while (1) { #ifdef _WIN32 cp = ap; #else va_copy(cp, ap); #endif n = vsnprintf (&s->d[s->i], s->n-s->i, fmt, cp); va_end(cp); if ((n > -1) && ((size_t) n < (s->n-s->i))) { s->i += n; return; } /* Else try again with more space. */ if (n > -1) utstring_reserve(s,n+1); /* exact */ else utstring_reserve(s,(s->n)*2); /* 2x */ } } #ifdef __GNUC__ /* support printf format checking (2=the format string, 3=start of varargs) */ static void utstring_printf(UT_string *s, const char *fmt, ...) __attribute__ (( format( printf, 2, 3) )); #endif _UNUSED_ static void utstring_printf(UT_string *s, const char *fmt, ...) { va_list ap; va_start(ap,fmt); utstring_printf_va(s,fmt,ap); va_end(ap); } /******************************************************************************* * begin substring search functions * ******************************************************************************/ /* Build KMP table from left to right. */ _UNUSED_ static void _utstring_BuildTable( const char *P_Needle, size_t P_NeedleLen, long *P_KMP_Table) { long i, j; i = 0; j = i - 1; P_KMP_Table[i] = j; while (i < (long) P_NeedleLen) { while ( (j > -1) && (P_Needle[i] != P_Needle[j]) ) { j = P_KMP_Table[j]; } i++; j++; if (i < (long) P_NeedleLen) { if (P_Needle[i] == P_Needle[j]) { P_KMP_Table[i] = P_KMP_Table[j]; } else { P_KMP_Table[i] = j; } } else { P_KMP_Table[i] = j; } } return; } /* Build KMP table from right to left. */ _UNUSED_ static void _utstring_BuildTableR( const char *P_Needle, size_t P_NeedleLen, long *P_KMP_Table) { long i, j; i = P_NeedleLen - 1; j = i + 1; P_KMP_Table[i + 1] = j; while (i >= 0) { while ( (j < (long) P_NeedleLen) && (P_Needle[i] != P_Needle[j]) ) { j = P_KMP_Table[j + 1]; } i--; j--; if (i >= 0) { if (P_Needle[i] == P_Needle[j]) { P_KMP_Table[i + 1] = P_KMP_Table[j + 1]; } else { P_KMP_Table[i + 1] = j; } } else { P_KMP_Table[i + 1] = j; } } return; } /* Search data from left to right. ( Multiple search mode. ) */ _UNUSED_ static long _utstring_find( const char *P_Haystack, size_t P_HaystackLen, const char *P_Needle, size_t P_NeedleLen, long *P_KMP_Table) { long i, j; long V_FindPosition = -1; /* Search from left to right. */ i = j = 0; while ( (j < (int)P_HaystackLen) && (((P_HaystackLen - j) + i) >= P_NeedleLen) ) { while ( (i > -1) && (P_Needle[i] != P_Haystack[j]) ) { i = P_KMP_Table[i]; } i++; j++; if (i >= (int)P_NeedleLen) { /* Found. */ V_FindPosition = j - i; break; } } return V_FindPosition; } /* Search data from right to left. ( Multiple search mode. ) */ _UNUSED_ static long _utstring_findR( const char *P_Haystack, size_t P_HaystackLen, const char *P_Needle, size_t P_NeedleLen, long *P_KMP_Table) { long i, j; long V_FindPosition = -1; /* Search from right to left. */ j = (P_HaystackLen - 1); i = (P_NeedleLen - 1); while ( (j >= 0) && (j >= i) ) { while ( (i < (int)P_NeedleLen) && (P_Needle[i] != P_Haystack[j]) ) { i = P_KMP_Table[i + 1]; } i--; j--; if (i < 0) { /* Found. */ V_FindPosition = j + 1; break; } } return V_FindPosition; } /* Search data from left to right. ( One time search mode. ) */ _UNUSED_ static long utstring_find( UT_string *s, long P_StartPosition, /* Start from 0. -1 means last position. */ const char *P_Needle, size_t P_NeedleLen) { long V_StartPosition; long V_HaystackLen; long *V_KMP_Table; long V_FindPosition = -1; if (P_StartPosition < 0) { V_StartPosition = s->i + P_StartPosition; } else { V_StartPosition = P_StartPosition; } V_HaystackLen = s->i - V_StartPosition; if ( (V_HaystackLen >= (long) P_NeedleLen) && (P_NeedleLen > 0) ) { V_KMP_Table = (long *)malloc(sizeof(long) * (P_NeedleLen + 1)); if (V_KMP_Table != NULL) { _utstring_BuildTable(P_Needle, P_NeedleLen, V_KMP_Table); V_FindPosition = _utstring_find(s->d + V_StartPosition, V_HaystackLen, P_Needle, P_NeedleLen, V_KMP_Table); if (V_FindPosition >= 0) { V_FindPosition += V_StartPosition; } free(V_KMP_Table); } } return V_FindPosition; } /* Search data from right to left. ( One time search mode. ) */ _UNUSED_ static long utstring_findR( UT_string *s, long P_StartPosition, /* Start from 0. -1 means last position. */ const char *P_Needle, size_t P_NeedleLen) { long V_StartPosition; long V_HaystackLen; long *V_KMP_Table; long V_FindPosition = -1; if (P_StartPosition < 0) { V_StartPosition = s->i + P_StartPosition; } else { V_StartPosition = P_StartPosition; } V_HaystackLen = V_StartPosition + 1; if ( (V_HaystackLen >= (long) P_NeedleLen) && (P_NeedleLen > 0) ) { V_KMP_Table = (long *)malloc(sizeof(long) * (P_NeedleLen + 1)); if (V_KMP_Table != NULL) { _utstring_BuildTableR(P_Needle, P_NeedleLen, V_KMP_Table); V_FindPosition = _utstring_findR(s->d, V_HaystackLen, P_Needle, P_NeedleLen, V_KMP_Table); free(V_KMP_Table); } } return V_FindPosition; } /******************************************************************************* * end substring search functions * ******************************************************************************/ #endif /* UTSTRING_H */ uthash-1.9.9.1+git20151125/src/utvector.h000066400000000000000000000052171264051566200174140ustar00rootroot00000000000000/* Copyright (c) 2003-2015, Troy D. Hanson http://troydhanson.github.com/uthash/ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* utvector * * maintain a contiguous buffer of 'n' elements ('i' occupied) * the 'n' buffers are deep-inited at the time of allocation * the vector leaves popped slots as-is, clearing them on re-use * the memory management helper mm is used to define the size and * deep-init, deep-fini, deep-copy (into inited slots) and deep-clear. * deep-clear prepares a slot for re-use e.g. reset slot state. * */ #ifndef __UTVECTOR_H_ #define __UTVECTOR_H_ #include "utmm.h" /* typical usage e.g. a vector of utstring would have * .sz = sizeof(UT_string) .init = utstring-init .fini = utstring-done .copy = ustring_concat .clear= utstring-clear */ typedef struct _UT_vector { UT_mm mm; unsigned i,n;/* i: index of next available slot, n: num slots */ char *d; /* n slots of size icd->sz*/ } UT_vector; UT_vector *utvector_new(const UT_mm *mm); void utvector_init(UT_vector *v, const UT_mm *mm); void utvector_reserve(UT_vector *v, unsigned num); void utvector_fini(UT_vector *v); UT_vector * utvector_clone(UT_vector *src); void utvector_clear(UT_vector *v); void utvector_copy(UT_vector *dst, UT_vector *src); void utvector_free(UT_vector *v); void *utvector_extend(UT_vector *v); void *utvector_head(UT_vector *v); void *utvector_tail(UT_vector *v); void *utvector_next(UT_vector *v, void *cur); void *utvector_pop(UT_vector *v); void *utvector_elt(UT_vector *v, unsigned i); void utvector_shift(UT_vector *v); void *utvector_push(UT_vector *v, void *e); unsigned utvector_len(UT_vector *v); #endif /* __UTVECTOR_H_ */ uthash-1.9.9.1+git20151125/tests/000077500000000000000000000000001264051566200157365ustar00rootroot00000000000000uthash-1.9.9.1+git20151125/tests/Makefile000066400000000000000000000061271264051566200174040ustar00rootroot00000000000000#CC=clang HASHDIR = ../src FUNCS = BER SAX FNV OAT JEN SFH SPECIAL_FUNCS = MUR UTILS = emit_keys PROGS = test1 test2 test3 test4 test5 test6 test7 test8 test9 \ test10 test11 test12 test13 test14 test15 test16 test17 \ test18 test19 test20 test21 test22 test23 test24 test25 \ test26 test27 test28 test29 test30 test31 test32 test33 \ test34 test35 test36 test37 test38 test39 test40 test41 \ test42 test43 test44 test45 test46 test47 test48 test49 \ test50 test51 test52 test53 test54 test55 test56 test57 \ 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 CFLAGS += -I$(HASHDIR) #CFLAGS += -DHASH_BLOOM=16 #CFLAGS += -O2 CFLAGS += -g #CFLAGS += -Wstrict-aliasing=2 CFLAGS += -Wall #CFLAGS += -Wextra #CFLAGS += -std=c89 CFLAGS += ${EXTRA_CFLAGS} ifeq ($(HASH_DEBUG),1) CFLAGS += -DHASH_DEBUG=1 endif ifeq ($(HASH_PEDANTIC),1) CFLAGS += -pedantic endif TEST_TARGET=run_tests TESTS=./do_tests MUR_CFLAGS = -DHASH_USING_NO_STRICT_ALIASING -fno-strict-aliasing # On GNU we use -fno-strict-aliasing when using the Murmurhash ifneq ($(strip $(shell $(CC) -v 2>&1 |egrep "gcc")),) ifeq ($(HASH_FUNCTION),"HASH_MUR") CFLAGS += $(MUR_CFLAGS) endif endif # detect Cygwin ifneq ($(strip $(shell $(CC) -v 2>&1 |grep "cygwin")),) TESTS=./do_tests.cygwin endif # detect MinGW ifneq ($(strip $(shell $(CC) -v 2>&1 |grep "mingw")),) TEST_TARGET=run_tests_mingw TESTS=./do_tests.mingw endif #detect Linux (platform specific utilities) ifneq ($(strip $(shell $(CC) -v 2>&1 |grep "linux")),) PLAT_UTILS = hashscan sleep_test endif #detect FreeBSD (platform specific utilities) ifeq ($(strip $(shell uname -s)), FreeBSD) ifeq ($(shell if [ `sysctl -n kern.osreldate` -ge 0801000 ]; then echo "ok"; fi), ok) PLAT_UTILS = hashscan sleep_test endif endif all: $(PROGS) $(UTILS) $(PLAT_UTILS) $(FUNCS) $(SPECIAL_FUNCS) $(TEST_TARGET) tests_only: $(PROGS) $(TEST_TARGET) debug: $(MAKE) all HASH_DEBUG=1 pedantic: $(MAKE) all HASH_PEDANTIC=1 cplusplus: CC=$(CXX) $(MAKE) all example: example.c $(HASHDIR)/uthash.h $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $(@).c $(PROGS) $(UTILS) : $(HASHDIR)/uthash.h $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $(@).c hashscan : $(HASHDIR)/uthash.h $(CC) $(CPPFLAGS) $(CFLAGS) $(MUR_CFLAGS) $(LDFLAGS) -o $@ $(@).c sleep_test : $(HASHDIR)/uthash.h $(CC) $(CPPFLAGS) $(CFLAGS) -DHASH_BLOOM=16 $(LDFLAGS) -o $@ $(@).c $(FUNCS) : $(HASHDIR)/uthash.h $(CC) $(CPPFLAGS) $(CFLAGS) -DHASH_FUNCTION=HASH_$@ \ $(LDFLAGS) -o keystat.$@ keystat.c $(SPECIAL_FUNCS) : $(HASHDIR)/uthash.h $(CC) $(CPPFLAGS) $(CFLAGS) $(MUR_CFLAGS) -DHASH_FUNCTION=HASH_$@ \ $(LDFLAGS) -o keystat.$@ keystat.c run_tests: $(PROGS) perl $(TESTS) run_tests_mingw: $(PROGS) /bin/bash do_tests.mingw astyle: astyle -n --style=kr --indent-switches --add-brackets *.c .PHONY: clean astyle clean: rm -f $(UTILS) $(PLAT_UTILS) $(PROGS) test*.out keystat.??? example *.exe rm -rf *.dSYM uthash-1.9.9.1+git20151125/tests/README000066400000000000000000000127451264051566200166270ustar00rootroot00000000000000Automated tests for uthash ============================================================================== Run "make" in this directory to build the tests and run them. test1: make 10-item hash, iterate and print each one 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 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 test10: dual-hash handle test, bucket expansion on one and not the other test11: read dat file of names into hash, sort them and print test12: create hash with string keys, add 10 items, lookup each item test13: make 10-item hash, delete items with even keys, reverse print others test14: read dat file of names into hash, read file again and lookup each one test15: build string-keyed hash of 3 items, lookup one item (c.f. test40.c) test16: hash on aggregate key, iterate, lookup, using generalized macros test17: sort, add more items, sort again test18: test pathological HASH_DEL(a,a) scenario (single head,deletee variable) test19: sort two hash tables with shared elements using HASH_SRT test20: test a 5-byte "binary" key test21: test a structure key (userguide) test22: test multi-field key using flexible array member (userguide utf32) test23: test whether delete in iteration works test24: make 10-item hash and confirm item count (HASH_COUNT) test25: CDL / DL / LL tests test26: test the linked list sort macros in utlist.h test27: LL_APPEND, SORT test28: CDL / DL / LL tests test29: DL_APPEND, SORT test30: CDL_PREPEND, SORT test31: CDL_PREPEND, SORT test32: DL_PREPEND test33: LL_PREPEND test34: CDL_PREPEND test35: CDL_PREPEND test36: HASH_SELECT test37: HASH_CLEAR test38: find-or-add test on integer keys in short loop test39: HASH_ADD_KEYPTR then HASH_FIND using array element as key pointer test40: HASH_ADD_KEYPTR on string keys; pointer equivalent to test15.c test41: test LL_FOREACH_SAFE,DL_FOREACH_SAFE,CDL_FOREACH_SAFE test42: test LL_SEARCH, LL_SEARCH_SCALAR, and DL and CDL counterparts test43: test utarray with intpair objects test44: test utarray with int objects test45: test utarray with int objects test46: test utarray with char* objects test47: test utstring test48: test utarray of int test49: test utarray of str test50: test utarray of long test51: test utarray of intpair test52: test utarray of intchar test53: test utstring test54: test utstring test55: test utstring test56: test uthash, utlist and utstring together for #define conflicts etc test57: test uthash HASH_ADD_PTR and HASH_FIND_PTR test58: test HASH_ITER macro test59: sample of multi-level hash test60: sample of multi-level hash that also does HASH_DEL and free test61: test utarray_find test62: test macros used in safe unaligned reads on non-Intel type platforms test63: LL_CONCAT test test64: DL_CONCAT test test65: LRU cache example courtesy of jehiah.cz with modifications test66: test example where output variable to HASH_FIND needs extra parens test67: test utarray_prev test68: test DL_REPLACE_ELEM (Zoltán Lajos Kis) test69: test DL_PREPEND_ELEM (Zoltán Lajos Kis) test70: test LL_REPLACE_ELEM (Zoltán Lajos Kis) test71: test LL_PREPEND_ELEM (Zoltán Lajos Kis) test72: test CDL_REPLACE_ELEM (Zoltán Lajos Kis) test73: test CDL_PREPEND_ELEM (Zoltán Lajos Kis) test74: test utstring with utstring_find (Joe Wei) test75: test utstring with utstring_findR (Joe Wei) test76: test utstring with _utstring_find (Joe Wei) test77: test utstring with _utstring_findR (Joe Wei) test78: test utlist "2" family with flexible Prev/Next naming eg. DL_DELETE2 test79: test HASH_REPLACE test80: test utarray_insert past end of array test81: test utarray_insert past end of array test82: test utarray_inserta past end of array 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 Other Make targets ================================================================================ pedantic: makes the tests with extra CFLAGS for pedantic compiling cplusplus: compiles all the C tests using the C++ compiler to test compatibility debug: makes the tests with debugging symbols and no optimization example: builds the 'example' program from the user guide ================================================================================ Testing a specific hash function -------------------------------- Set EXTRA_CFLAGS with this Makefile to use a specific hash function: EXTRA_CFLAGS=-DHASH_FUNCTION=HASH_BER make Other files ================================================================================ keystats: key statistics analyzer. See the uthash User Guide. emit_keys: reads a data file of unique strings, emits as keys w/HASH_EMIT_KEYS=1 all_funcs: a script which executes the test suite with every hash function win32tests:builds and runs the test suite under Microsoft Visual Studio LINUX/FREEBSD ------------- hashscan: tool to examine a running process and get info on its hash tables test_sleep:used as a subject for inspection by hashscan Manual performance testing ================================================================================ # test performance characteristics on keys that are English dictionary words emit_keys /usr/share/dict/words > words.keys ./keystats words.keys uthash-1.9.9.1+git20151125/tests/all_funcs000077500000000000000000000011371264051566200176340ustar00rootroot00000000000000#!/bin/bash function proceed { read -p "proceed ? [n] " response if [ "$response" != "y" ]; then exit -1; fi } make clean tests_only EXTRA_CFLAGS='-DHASH_FUNCTION=HASH_BER'; proceed make clean tests_only EXTRA_CFLAGS='-DHASH_FUNCTION=HASH_SAX'; proceed make clean tests_only EXTRA_CFLAGS='-DHASH_FUNCTION=HASH_FNV'; proceed make clean tests_only EXTRA_CFLAGS='-DHASH_FUNCTION=HASH_OAT'; proceed make clean tests_only EXTRA_CFLAGS='-DHASH_FUNCTION=HASH_JEN'; proceed make clean tests_only EXTRA_CFLAGS='-DHASH_FUNCTION=HASH_MUR'; proceed make clean tests_only EXTRA_CFLAGS='-DHASH_FUNCTION=HASH_SFH'; uthash-1.9.9.1+git20151125/tests/bloom_perf.c000066400000000000000000000041251264051566200202300ustar00rootroot00000000000000#include /* malloc */ #include /* gettimeofday */ #include /* perror */ #include /* printf */ #include "uthash.h" #define BUFLEN 20 #if 0 #undef uthash_expand_fyi #define uthash_expand_fyi(tbl) printf("expanding to %d buckets\n", tbl->num_buckets) #endif typedef struct name_rec { char boy_name[BUFLEN]; UT_hash_handle hh; } name_rec; int main(int argc,char *argv[]) { name_rec *name, *names=NULL; char linebuf[BUFLEN]; FILE *file; int i=0,j,nloops=3,loopnum=0,miss; struct timeval tv1,tv2; long elapsed_usec; if (argc > 1) { nloops = atoi(argv[1]); } if ( (file = fopen( "test14.dat", "r" )) == NULL ) { perror("can't open: "); exit(-1); } while (fgets(linebuf,BUFLEN,file) != NULL) { i++; if ( (name = (name_rec*)malloc(sizeof(name_rec))) == NULL) { exit(-1); } strncpy(name->boy_name,linebuf,BUFLEN); HASH_ADD_STR(names,boy_name,name); } again: if (fseek(file,0,SEEK_SET) == -1) { fprintf(stderr,"fseek failed: %s\n", strerror(errno)); } j=0; if (gettimeofday(&tv1,NULL) == -1) { perror("gettimeofday: "); } while (fgets(linebuf,BUFLEN,file) != NULL) { /* if we do 10 loops, the first has a 0% miss rate, * the second has a 10% miss rate, etc */ miss = ((rand()*1.0/RAND_MAX) < (loopnum*1.0/nloops)) ? 1 : 0; /* generate a miss if we want one */ if (miss) { linebuf[0]++; if (linebuf[1] != '\0') { linebuf[1]++; } } HASH_FIND_STR(names,linebuf,name); if (name) { j++; } } if (gettimeofday(&tv2,NULL) == -1) { perror("gettimeofday: "); } elapsed_usec = ((tv2.tv_sec - tv1.tv_sec) * 1000000) + (tv2.tv_usec - tv1.tv_usec); printf("lookup on %d of %d (%.2f%%) names succeeded (%.2f usec)\n", j, i, j*100.0/i, (double)(elapsed_usec)); if (++loopnum < nloops) { goto again; } fclose(file); return 0; } uthash-1.9.9.1+git20151125/tests/bloom_perf.sh000077500000000000000000000004471264051566200204260ustar00rootroot00000000000000#!/bin/bash BITS="16" cc -I../src -O3 -Wall -m64 bloom_perf.c -o bloom_perf.none for bits in $BITS do cc -I../src -DHASH_BLOOM=$bits -O3 -Wall -m64 bloom_perf.c -o bloom_perf.$bits done for bits in none $BITS do echo echo "using $bits-bit filter:" ./bloom_perf.$bits 10 done uthash-1.9.9.1+git20151125/tests/do_tests000077500000000000000000000005571264051566200175170ustar00rootroot00000000000000#!/usr/bin/perl use strict; use warnings; my @tests; for (glob "test*[0-9]") { push @tests, $_ if -e "$_.ans"; } my $num_failed=0; for my $test (@tests) { `./$test > $test.out`; `diff $test.out $test.ans`; print "$test failed\n" if $?; $num_failed++ if $?; } print scalar @tests . " tests conducted, $num_failed failed.\n"; exit $num_failed; uthash-1.9.9.1+git20151125/tests/do_tests.cygwin000077500000000000000000000006651264051566200210160ustar00rootroot00000000000000#!/usr/bin/perl use strict; use warnings; my @tests; for (glob "test*[0-9].exe") { push @tests, "$_" if -e substr($_, 0, - 4).".ans"; } my $num_failed=0; for my $test (@tests) { `./$test > $test.out`; my $ansfile = substr($test, 0, - 4).".ans"; `diff $test.out $ansfile`; print "$test failed\n" if $?; $num_failed++ if $?; } print scalar @tests . " tests conducted, $num_failed failed.\n"; exit $num_failed; uthash-1.9.9.1+git20151125/tests/do_tests.mingw000066400000000000000000000004471264051566200206320ustar00rootroot00000000000000#!/bin/bash echo "MinGW test script starting" for f in test*.exe do t=`echo $f | sed s/.exe//` `$f > $t.out` diff -qb "$t.out" "$t.ans" if [ $? -eq 1 ] then echo "$f failed" else true # can't have empty else #echo "$f passed" fi done echo echo "All tests complete" uthash-1.9.9.1+git20151125/tests/do_tests_win32.cmd000066400000000000000000000013161264051566200212720ustar00rootroot00000000000000:: this compiles and runs the test suite under Visual Studio 2008 ::@echo off call "C:\Program Files\Microsoft Visual Studio 9.0\VC\bin\vcvars32.bat" > vc.out ::call "C:\Program Files\Microsoft Visual Studio 10.0\VC\bin\vcvars32.bat" > vc.out set "COMPILE=cl.exe /I ..\src /EHsc /nologo" echo compiling... %COMPILE% tdiff.cpp > compile.out ::for %%f in (test*.c) do %COMPILE% /Tp %%f >> compile.out for %%f in (test*.c) do %COMPILE% /Tc %%f >> compile.out echo running tests... for %%f in (test*.exe) do %%f > %%~nf.out echo scanning for failures... for %%f in (test*.out) do tdiff %%f %%~nf.ans echo tests completed ::for %%f in (test*.out test*.obj test*.exe vc.out compile.out tdiff.obj tdiff.exe) do del %%f pause uthash-1.9.9.1+git20151125/tests/emit_keys.c000066400000000000000000000020111264051566200200650ustar00rootroot00000000000000#include /* malloc */ #include /* perror */ #include /* printf */ #include /* write */ /* this define must precede uthash.h */ #define HASH_EMIT_KEYS 1 #include "uthash.h" #define BUFLEN 30 typedef struct name_rec { char boy_name[BUFLEN]; UT_hash_handle hh; } name_rec; int main(int argc,char *argv[]) { name_rec *name, *names=NULL; char linebuf[BUFLEN]; FILE *file; int i=0; if (argc != 2) { fprintf(stderr,"usage: %s file\n", argv[0]); exit(-1); } if ( (file = fopen( argv[1], "r" )) == NULL ) { perror("can't open: "); exit(-1); } while (fgets(linebuf,BUFLEN,file) != NULL) { name = (name_rec*)malloc(sizeof(name_rec)); if (name == NULL) { exit(-1); } strncpy(name->boy_name,linebuf,sizeof(name->boy_name)); HASH_ADD_STR(names,boy_name,name); i++; } fprintf(stderr,"%d keys emitted.\n", i); fclose(file); return 0; } uthash-1.9.9.1+git20151125/tests/example.c000066400000000000000000000070351264051566200175420ustar00rootroot00000000000000#include /* gets */ #include /* atoi, malloc */ #include /* strcpy */ #include "uthash.h" struct my_struct { int id; /* key */ char name[10]; UT_hash_handle hh; /* makes this structure hashable */ }; struct my_struct *users = NULL; void add_user(int user_id, 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)); s->id = user_id; HASH_ADD_INT( users, id, s ); /* id: name of key field */ } strcpy(s->name, name); } struct my_struct *find_user(int user_id) { struct my_struct *s; 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 */ free(user); } void delete_all() { struct my_struct *current_user, *tmp; 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() { struct my_struct *s; 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 id_sort(struct my_struct *a, 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); } int main(int argc, char *argv[]) { char in[10]; int id=1, running=1; struct my_struct *s; unsigned num_users; while (running) { printf(" 1. add user\n"); printf(" 2. add/rename user by id\n"); printf(" 3. find user\n"); printf(" 4. delete user\n"); printf(" 5. delete all users\n"); printf(" 6. sort items by name\n"); printf(" 7. sort items by id\n"); printf(" 8. print users\n"); printf(" 9. count users\n"); printf("10. quit\n"); gets(in); switch(atoi(in)) { case 1: printf("name?\n"); add_user(id++, gets(in)); break; case 2: printf("id?\n"); gets(in); id = atoi(in); printf("name?\n"); add_user(id, gets(in)); break; case 3: printf("id?\n"); s = find_user(atoi(gets(in))); 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"); } break; case 5: delete_all(); break; case 6: sort_by_name(); break; case 7: sort_by_id(); break; case 8: print_users(); break; case 9: num_users=HASH_COUNT(users); printf("there are %u users\n", num_users); break; case 10: running=0; break; } } delete_all(); /* free any structures */ return 0; } uthash-1.9.9.1+git20151125/tests/hashscan.c000066400000000000000000000522721264051566200177020ustar00rootroot00000000000000/* Copyright (c) 2005-2014, Troy D. Hanson http://troydhanson.github.com/uthash/ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __FreeBSD__ #include /* MAXPATHLEN */ #include /* VM_PROT_* flags */ #endif /* need this defined so offsetof can give us bloom offsets in UT_hash_table */ #define HASH_BLOOM 16 #include "uthash.h" #ifdef __FreeBSD__ typedef struct { void *start; void *end; } vma_t; #else typedef struct { off_t start; off_t end; char perms[4]; /* rwxp */ char device[5]; /* fd:01 or 00:00 */ } vma_t; #endif const uint32_t sig = HASH_SIGNATURE; int verbose=0; int getkeys=0; #define vv(...) do {if (verbose>0) printf(__VA_ARGS__);} while(0) #define vvv(...) do {if (verbose>1) printf(__VA_ARGS__);} while(0) /* these id's are arbitrary, only meaningful within this file */ #define JEN 1 #define BER 2 #define SFH 3 #define SAX 4 #define FNV 5 #define OAT 6 #define MUR 7 #define NUM_HASH_FUNCS 8 /* includes id 0, the non-function */ char *hash_fcns[] = {"???","JEN","BER","SFH","SAX","FNV","OAT","MUR"}; /* given a peer key/len/hashv, reverse engineer its hash function */ static int infer_hash_function(char *key, size_t keylen, uint32_t hashv) { uint32_t obkt, ohashv, num_bkts=0x01000000; /* anything ok */ /* BER SAX FNV OAT JEN SFH */ HASH_JEN(key,keylen,num_bkts,ohashv,obkt); if (ohashv == hashv) { return JEN; } HASH_BER(key,keylen,num_bkts,ohashv,obkt); if (ohashv == hashv) { return BER; } HASH_SFH(key,keylen,num_bkts,ohashv,obkt); if (ohashv == hashv) { return SFH; } HASH_SAX(key,keylen,num_bkts,ohashv,obkt); if (ohashv == hashv) { return SAX; } HASH_FNV(key,keylen,num_bkts,ohashv,obkt); if (ohashv == hashv) { return FNV; } HASH_OAT(key,keylen,num_bkts,ohashv,obkt); if (ohashv == hashv) { return OAT; } HASH_MUR(key,keylen,num_bkts,ohashv,obkt); if (ohashv == hashv) { return MUR; } obkt++; // this quiets an unused variable warning. yes, this is a ugly hack return 0; } /* read peer's memory from addr for len bytes, store into our dst */ #ifdef __FreeBSD__ static int read_mem(void *dst, pid_t pid, void *start, size_t len) { struct ptrace_io_desc io_desc; int ret; io_desc.piod_op = PIOD_READ_D; io_desc.piod_offs = start; io_desc.piod_addr = dst; io_desc.piod_len = len; ret = ptrace(PT_IO, pid, (void *) &io_desc, 0); if (ret) { vv("read_mem: ptrace failed: %s\n", strerror(errno)); return -1; } else if (io_desc.piod_len != len) { vv("read_mem: short read!\n"); return -1; } return 0; } #else static int read_mem(void *dst, int fd, off_t start, size_t len) { int rc; size_t bytes_read=0; if (lseek(fd, start, SEEK_SET) == (off_t)-1) { fprintf(stderr, "lseek failed: %s\n", strerror(errno)); return -1; } while ( len && ((rc=read(fd, (char*)dst+bytes_read, len)) > 0)) { len -= rc; bytes_read += rc; } if (rc==-1) { vv("read_mem failed (%s)\n",strerror(errno)); } if ((len != 0 && rc >= 0)) { vv("INTERNAL ERROR\n"); } return (rc == -1) ? -1 : 0; } #endif /* later compensate for possible presence of bloom filter */ static char *tbl_from_sig_addr(char *sig) { return (sig - offsetof(UT_hash_table,signature)); } #define HS_BIT_TEST(v,i) (v[i/8] & (1U << (i%8))) static void found(int fd, char* peer_sig, pid_t pid) { UT_hash_table *tbl=NULL; UT_hash_bucket *bkts=NULL; UT_hash_handle hh; size_t i, bloom_len, bloom_bitlen, bloom_on_bits=0,bloom_off_bits=0; char *peer_tbl, *peer_bloom_sig, *peer_bloom_nbits, *peer_bloombv_ptr, *peer_bloombv, *peer_bkts, *peer_key, *peer_hh, *key=NULL, *hash_fcn=NULL, sat[10]; unsigned char *bloombv=NULL; static int fileno=0; char keyfile[50]; unsigned char bloom_nbits=0; int keyfd=-1, mode=S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, hash_fcn_hits[NUM_HASH_FUNCS], hash_fcn_winner; unsigned max_chain=0; uint32_t bloomsig; double bloom_sat=0; snprintf(sat,sizeof(sat)," "); for(i=0; i < NUM_HASH_FUNCS; i++) { hash_fcn_hits[i]=0; } if (getkeys) { snprintf(keyfile, sizeof(keyfile), "/tmp/%u-%u.key", (unsigned)pid,fileno++); if ( (keyfd = open(keyfile, O_WRONLY|O_CREAT|O_TRUNC, mode)) == -1) { fprintf(stderr, "can't open %s: %s\n", keyfile, strerror(errno)); exit(-1); } } vv("found signature at peer %p\n", peer_sig); peer_tbl = tbl_from_sig_addr(peer_sig); vvv("reading table at peer %p\n", peer_tbl); if ( (tbl = (UT_hash_table*)malloc(sizeof(UT_hash_table))) == NULL) { fprintf(stderr, "out of memory\n"); exit(-1); } #ifdef __FreeBSD__ if (read_mem(tbl, pid, (void *)peer_tbl, sizeof(UT_hash_table)) != 0) { #else if (read_mem(tbl, fd, (off_t)peer_tbl, sizeof(UT_hash_table)) != 0) { #endif fprintf(stderr, "failed to read peer memory\n"); goto done; } /* got the table. how about the buckets */ peer_bkts = (char*)tbl->buckets; vvv("reading buckets at peer %p\n", peer_bkts); bkts = (UT_hash_bucket*)malloc(sizeof(UT_hash_bucket)*tbl->num_buckets); if (bkts == NULL) { fprintf(stderr, "out of memory\n"); exit(-1); } #ifdef __FreeBSD__ if (read_mem(bkts, pid, (void *)peer_bkts, sizeof(UT_hash_bucket)*tbl->num_buckets) != 0) { #else if (read_mem(bkts, fd, (off_t)peer_bkts, sizeof(UT_hash_bucket)*tbl->num_buckets) != 0) { #endif fprintf(stderr, "failed to read peer memory\n"); goto done; } vvv("scanning %u peer buckets\n", tbl->num_buckets); for(i=0; i < tbl->num_buckets; i++) { vvv("bucket %u has %u items\n", (unsigned)i, (unsigned)(bkts[i].count)); if (bkts[i].count > max_chain) { max_chain = bkts[i].count; } if (bkts[i].expand_mult) { vvv(" bucket %u has expand_mult %u\n", (unsigned)i, (unsigned)(bkts[i].expand_mult)); } vvv("scanning bucket %u chain:\n", (unsigned)i); peer_hh = (char*)bkts[i].hh_head; while(peer_hh) { #ifdef __FreeBSD__ if (read_mem(&hh, pid, (void *)peer_hh, sizeof(hh)) != 0) { #else if (read_mem(&hh, fd, (off_t)peer_hh, sizeof(hh)) != 0) { #endif fprintf(stderr, "failed to read peer memory\n"); goto done; } if ((char*)hh.tbl != peer_tbl) { goto done; } peer_hh = (char*)hh.hh_next; peer_key = (char*)(hh.key); /* malloc space to read the key, and read it */ if ( (key = (char*)malloc(sizeof(hh.keylen))) == NULL) { fprintf(stderr, "out of memory\n"); exit(-1); } #ifdef __FreeBSD__ if (read_mem(key, pid, (void*)peer_key, hh.keylen) != 0) { #else if (read_mem(key, fd, (off_t)peer_key, hh.keylen) != 0) { #endif fprintf(stderr, "failed to read peer memory\n"); goto done; } hash_fcn_hits[infer_hash_function(key,hh.keylen,hh.hashv)]++; /* write the key if requested */ if (getkeys) { write(keyfd, &hh.keylen, sizeof(unsigned)); write(keyfd, key, hh.keylen); } free(key); key=NULL; } } /* does it have a bloom filter? */ peer_bloom_sig = peer_tbl + offsetof(UT_hash_table, bloom_sig); peer_bloombv_ptr = peer_tbl + offsetof(UT_hash_table, bloom_bv); peer_bloom_nbits = peer_tbl + offsetof(UT_hash_table, bloom_nbits); vvv("looking for bloom signature at peer %p\n", peer_bloom_sig); #ifdef __FreeBSD__ if ((read_mem(&bloomsig, pid, (void *)peer_bloom_sig, sizeof(uint32_t)) == 0) && (bloomsig == HASH_BLOOM_SIGNATURE)) { #else if ((read_mem(&bloomsig, fd, (off_t)peer_bloom_sig, sizeof(uint32_t)) == 0) && (bloomsig == HASH_BLOOM_SIGNATURE)) { #endif vvv("bloom signature (%x) found\n",bloomsig); /* bloom found. get at bv, nbits */ #ifdef __FreeBSD__ if (read_mem(&bloom_nbits, pid, (void *)peer_bloom_nbits, sizeof(char)) == 0) { #else if (read_mem(&bloom_nbits, fd, (off_t)peer_bloom_nbits, sizeof(char)) == 0) { #endif /* scan bloom filter, calculate saturation */ bloom_bitlen = (1ULL << bloom_nbits); bloom_len = (bloom_bitlen / 8) + ((bloom_bitlen % 8) ? 1 : 0); vvv("bloom bitlen is %u, bloom_bytelen is %u\n", (unsigned)bloom_bitlen, (unsigned)bloom_len); if ( (bloombv = (unsigned char*)malloc(bloom_len)) == NULL) { fprintf(stderr, "out of memory\n"); exit(-1); } /* read the address of the bitvector in the peer, then read the bv itself */ #ifdef __FreeBSD__ if ((read_mem(&peer_bloombv, pid, (void *)peer_bloombv_ptr, sizeof(void*)) == 0) && (read_mem(bloombv, pid, (void *)peer_bloombv, bloom_len) == 0)) { #else if ((read_mem(&peer_bloombv, fd, (off_t)peer_bloombv_ptr, sizeof(void*)) == 0) && (read_mem(bloombv, fd, (off_t)peer_bloombv, bloom_len) == 0)) { #endif /* calculate saturation */ vvv("read peer bloom bitvector from %p (%u bytes)\n", peer_bloombv, (unsigned)bloom_len); for(i=0; i < bloom_bitlen; i++) { if (HS_BIT_TEST(bloombv,(unsigned)i)) { /* vvv("bit %u set\n",(unsigned)i); */ bloom_on_bits++; } else { bloom_off_bits++; } } vvv("there were %u on_bits among %u total bits\n", (unsigned)bloom_on_bits, (unsigned)bloom_bitlen); bloom_sat = bloom_on_bits * 100.0 / bloom_bitlen; snprintf(sat,sizeof(sat),"%2u %5.0f%%", bloom_nbits, bloom_sat); } } } /* choose apparent hash function */ hash_fcn_winner=0; for(i=0; i hash_fcn_hits[hash_fcn_winner]) { hash_fcn_winner=i; } } hash_fcn = hash_fcns[hash_fcn_winner]; /* Address items ideal buckets mxch/<10 fl bloom/sat fcn keys saved to ------------------ -------- ----- -------- -------- -- --------- --- ------------- 0x0123456789abcdef 10000000 98% 32000000 10 100% ok BER /tmp/9110-0.key 0x0123456789abcdef 10000000 100% 32000000 9 90% NX 27/0.010% BER /tmp/9110-1.key */ printf("Address ideal items buckets mc fl bloom/sat fcn keys saved to\n"); printf("------------------ ----- -------- -------- -- -- --------- --- -------------\n"); printf("%-18p %4.0f%% %8u %8u %2u %s %s %s %s\n", (void*)peer_tbl, (tbl->num_items - tbl->nonideal_items) * 100.0 / tbl->num_items, tbl->num_items, tbl->num_buckets, max_chain, tbl->noexpand ? "NX" : "ok", sat, hash_fcn, (getkeys ? keyfile : "")); #if 0 printf("read peer tbl:\n"); printf("num_buckets: %u\n", tbl->num_buckets); printf("num_items: %u\n", tbl->num_items); printf("nonideal_items: %u (%.2f%%)\n", tbl->nonideal_items, tbl->nonideal_items*100.0/tbl->num_items); printf("expand: %s\n", tbl->noexpand ? "inhibited": "normal"); if (getkeys) { printf("keys written to %s\n", keyfile); } #endif done: if (bkts) { free(bkts); } if (tbl) { free(tbl); } if (key) { free(key); } if (keyfd != -1) { close(keyfd); } if (bloombv) { free(bloombv); } } #ifdef __FreeBSD__ static void sigscan(pid_t pid, void *start, void *end, uint32_t sig) { struct ptrace_io_desc io_desc; int page_size = getpagesize(); char *buf; char *pos; /* make sure page_size is a multiple of the signature size, code below assumes this */ assert(page_size % sizeof(sig) == 0); buf = malloc(page_size); if (buf == NULL) { fprintf(stderr, "malloc failed in sigscan()\n"); return; } io_desc.piod_op = PIOD_READ_D; io_desc.piod_offs = start; io_desc.piod_addr = buf; io_desc.piod_len = page_size; /* read in one page after another and search sig */ while(!ptrace(PT_IO, pid, (void *) &io_desc, 0)) { if (io_desc.piod_len != page_size) { fprintf(stderr, "PT_IO returned less than page size in sigscan()\n"); return; } /* iterate over the the page using the signature size and look for the sig */ for (pos = buf; pos < (buf + page_size); pos += sizeof(sig)) { if (*(uint32_t *) pos == sig) { found(pid, (char *) io_desc.piod_offs + (pos - buf), pid); } } /* * 'end' is inclusive (the address of the last valid byte), so if the current offset * plus a page is beyond 'end', we're already done. since all vm map entries consist * of entire pages and 'end' is inclusive, current offset plus one page should point * exactly one byte beyond 'end'. this is assert()ed below to be on the safe side. */ if (io_desc.piod_offs + page_size > end) { assert(io_desc.piod_offs + page_size == (end + 1)); break; } /* advance to the next page */ io_desc.piod_offs += page_size; } } #else static void sigscan(int fd, off_t start, off_t end, uint32_t sig, pid_t pid) { int rlen; uint32_t u; off_t at=0; if (lseek(fd, start, SEEK_SET) == (off_t)-1) { fprintf(stderr, "lseek failed: %s\n", strerror(errno)); return; } while ( (rlen = read(fd,&u,sizeof(u))) == sizeof(u)) { if (!memcmp(&u,&sig,sizeof(u))) { found(fd, (char*)(start+at),pid); } at += sizeof(u); if ((off_t)(at + sizeof(u)) > end-start) { break; } } if (rlen == -1) { //fprintf(stderr,"read failed: %s\n", strerror(errno)); //exit(-1); } } #endif #ifdef __FreeBSD__ static int scan(pid_t pid) { vma_t *vmas=NULL, vma; unsigned i, num_vmas = 0; int ret; struct ptrace_vm_entry vm_entry; char path[MAXPATHLEN]; vv("attaching to peer\n"); if (ptrace(PT_ATTACH,pid,NULL,0) == -1) { fprintf(stderr,"failed to attach to %u: %s\n", (unsigned)pid, strerror(errno)); exit(EXIT_FAILURE); } vv("waiting for peer to suspend temporarily\n"); if (waitpid(pid,NULL,0) != pid) { fprintf(stderr,"failed to wait for pid %u: %s\n",(unsigned)pid, strerror(errno)); goto die; } /* read memory map using ptrace */ vv("listing peer virtual memory areas\n"); vm_entry.pve_entry = 0; vm_entry.pve_path = path; /* not used but required to make vm_entry.pve_pathlen work */ while(1) { /* set pve_pathlen every turn, it gets overwritten by ptrace */ vm_entry.pve_pathlen = MAXPATHLEN; errno = 0; ret = ptrace(PT_VM_ENTRY, pid, (void *) &vm_entry, 0); if (ret) { if (errno == ENOENT) { /* we've reached the last entry */ break; } fprintf(stderr, "fetching vm map entry failed: %s (%i)\n", strerror(errno), errno); goto die; } vvv("vmmap entry: start: %p, end: %p", (void *) vm_entry.pve_start, (void *) vm_entry.pve_end); /* skip unreadable or vnode-backed entries */ if (!(vm_entry.pve_prot & VM_PROT_READ) || vm_entry.pve_pathlen > 0) { vvv(" -> skipped (not readable or vnode-backed)\n"); vm_entry.pve_path[0] = 0; continue; } /* useful entry, add to list */ vvv(" -> will be scanned\n"); vma.start = (void *)vm_entry.pve_start; vma.end = (void *)vm_entry.pve_end; vmas = (vma_t *) realloc(vmas, (num_vmas + 1) * sizeof(vma_t)); if (vmas == NULL) { exit(-1); } vmas[num_vmas++] = vma; } vv("peer has %u virtual memory areas\n", num_vmas); /* look for the hash signature */ vv("scanning peer memory for hash table signatures\n"); for(i=0; i\n", prog); exit(-1); } int main(int argc, char *argv[]) { pid_t pid; int opt; while ( (opt = getopt(argc, argv, "kv")) != -1) { switch (opt) { case 'v': verbose++; break; case 'k': getkeys++; break; default: usage(argv[0]); break; } } if (optind < argc) { pid=atoi(argv[optind++]); } else { usage(argv[0]); } return scan(pid); } uthash-1.9.9.1+git20151125/tests/keystat.c000066400000000000000000000201451264051566200175700ustar00rootroot00000000000000#include /* for 'open' */ #include /* for 'open' */ #include /* for 'open' */ #include /* for 'malloc' */ #include /* for 'printf' */ #include /* for 'read' */ #include /* for 'sterror' */ #include /* for 'gettimeofday' */ #include "uthash.h" #undef uthash_noexpand_fyi #define uthash_noexpand_fyi(t) die() #define UNALIGNED_KEYS 0 static void die() { fprintf(stderr,"expansion inhibited\n"); exit(-1); } /* Windows doesn't have gettimeofday. While Cygwin and some * versions of MinGW supply one, it is very coarse. This substitute * gives much more accurate elapsed times under Windows. */ #if (( defined __CYGWIN__ ) || ( defined __MINGW32__ )) #include static void win_gettimeofday(struct timeval* p, void* tz /* IGNORED */) { LARGE_INTEGER q; static long long freq; static long long cyg_timer; QueryPerformanceFrequency(&q); freq = q.QuadPart; QueryPerformanceCounter(&q); cyg_timer = q.QuadPart; p->tv_sec = (long)(cyg_timer / freq); p->tv_usec = (long)(((cyg_timer % freq) * 1000000) / freq); } #define gettimeofday win_gettimeofday #define MODE (O_RDONLY|O_BINARY) #else #define MODE (O_RDONLY) #endif #ifndef timersub #define timersub(a, b, result) \ do { \ (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ if ((result)->tv_usec < 0) { \ --(result)->tv_sec; \ (result)->tv_usec += 1000000; \ } \ } while (0) #endif typedef struct stat_key { char *key; unsigned len; UT_hash_handle hh, hh2; } stat_key; #define CHAIN_0 0 #define CHAIN_5 1 #define CHAIN_10 2 #define CHAIN_20 3 #define CHAIN_100 4 #define CHAIN_MAX 5 static void hash_chain_len_histogram(const UT_hash_table *tbl) { unsigned i, bkt_hist[CHAIN_MAX+1]; double pct = 100.0/(double)tbl->num_buckets; memset(bkt_hist,0,sizeof(bkt_hist)); for(i=0; i < tbl->num_buckets; i++) { unsigned count = tbl->buckets[i].count; if (count == 0U) { bkt_hist[CHAIN_0]++; } else if (count < 5U) { bkt_hist[CHAIN_5]++; } else if (count < 10U) { bkt_hist[CHAIN_10]++; } else if (count < 20U) { bkt_hist[CHAIN_20]++; } else if (count < 100U) { bkt_hist[CHAIN_100]++; } else { bkt_hist[CHAIN_MAX]++; } } fprintf(stderr, "Buckets with 0 items: %.1f%%\n", (double)bkt_hist[CHAIN_0 ]*pct); fprintf(stderr, "Buckets with < 5 items: %.1f%%\n", (double)bkt_hist[CHAIN_5 ]*pct); fprintf(stderr, "Buckets with < 10 items: %.1f%%\n", (double)bkt_hist[CHAIN_10]*pct); fprintf(stderr, "Buckets with < 20 items: %.1f%%\n", (double)bkt_hist[CHAIN_20]*pct); fprintf(stderr, "Buckets with < 100 items: %.1f%%\n", (double)bkt_hist[CHAIN_100]*pct); fprintf(stderr, "Buckets with > 100 items: %.1f%%\n", (double)bkt_hist[CHAIN_MAX]*pct); } int main(int argc, char *argv[]) { int dups=0, rc, fd, done=0, err=0, want, i, padding=0, v=1, percent=100; unsigned keylen, max_keylen=0, verbose=0; const char *filename = "/dev/stdin"; char *dst; stat_key *keyt, *keytmp, *keys=NULL, *keys2=NULL; struct timeval start_tm, end_tm, elapsed_tm, elapsed_tm2, elapsed_tm3; if ((argc >= 3) && (strcmp(argv[1],"-p") == 0)) { percent = atoi(argv[2]); v = 3; } if ((argc >= v) && (strcmp(argv[v],"-v") == 0)) { verbose=1; v++; } if (argc >= v) { filename=argv[v]; } fd=open(filename,MODE); if ( fd == -1 ) { fprintf(stderr,"open failed %s: %s\n", filename, strerror(errno)); return -1; } for(i=0; done==0; i++) { want = sizeof(int); dst = (char*)&keylen; readmore1: rc = read(fd,dst,want); if (rc != want) { if (rc == 0) { done=1; } else if (rc == -1) { fprintf(stderr,"read failed: %s\n", strerror(errno)); err=1; } else if (rc > 0) { want -= rc; dst += rc; goto readmore1; } } if (done || err) { break; } if (keylen > max_keylen) { max_keylen=keylen; } keyt = (stat_key*)malloc(sizeof(stat_key)); if (keyt == NULL) { fprintf(stderr,"out of memory\n"); exit(-1); } /* read key */ #ifdef UNALIGNED_KEYS padding = i%8; #endif keyt->key = (char*)malloc(padding+keylen); if (keyt->key == NULL) { fprintf(stderr,"out of memory\n"); exit(-1); } keyt->key += padding; /* forcibly alter the alignment of key */ keyt->len = keylen; want = keylen; dst = keyt->key; readmore2: rc = read(fd,dst,want); if (rc != want) { if (rc == -1) { fprintf(stderr,"read failed: %s\n", strerror(errno)); err=1; } else if (rc == 0) { fprintf(stderr,"incomplete file\n"); err=1; } else if (rc >= 0) { want -= rc; dst += rc; goto readmore2; } } if (err != 0) { break; } /* if percent was set to something less than 100%, skip some keys*/ if (((rand()*1.0) / RAND_MAX) > ((percent*1.0)/100)) { free(keyt->key-padding); free(keyt); continue; } /* eliminate dups */ HASH_FIND(hh,keys,keyt->key,keylen,keytmp); if (keytmp != NULL) { dups++; free(keyt->key - padding); free(keyt); } else { HASH_ADD_KEYPTR(hh,keys,keyt->key,keylen,keyt); } } if (verbose != 0) { unsigned key_count = HASH_COUNT(keys); fprintf(stderr,"max key length: %u\n", max_keylen); fprintf(stderr,"number unique keys: %u\n", key_count); fprintf(stderr,"keystats memory: %u\n", (unsigned)((sizeof(stat_key)+max_keylen)*key_count)); hash_chain_len_histogram(keys->hh.tbl); } /* add all keys to a new hash, so we can measure add time w/o malloc */ gettimeofday(&start_tm,NULL); for(keyt = keys; keyt != NULL; keyt=(stat_key*)keyt->hh.next) { HASH_ADD_KEYPTR(hh2,keys2,keyt->key,keyt->len,keyt); } gettimeofday(&end_tm,NULL); timersub(&end_tm, &start_tm, &elapsed_tm); /* now look up all keys in the new hash, again measuring elapsed time */ gettimeofday(&start_tm,NULL); for(keyt = keys; keyt != NULL; keyt=(stat_key*)keyt->hh.next) { HASH_FIND(hh2,keys2,keyt->key,keyt->len,keytmp); if (keytmp == NULL) { fprintf(stderr,"internal error, key not found\n"); } } gettimeofday(&end_tm,NULL); timersub(&end_tm, &start_tm, &elapsed_tm2); /* now delete all items in the new hash, measuring elapsed time */ gettimeofday(&start_tm,NULL); while (keys2 != NULL) { keytmp = keys2; HASH_DELETE(hh2,keys2,keytmp); } gettimeofday(&end_tm,NULL); timersub(&end_tm, &start_tm, &elapsed_tm3); if (err == 0) { printf("%.3f,%u,%u,%d,%s,%ld,%ld,%ld\n", 1-(1.0*keys->hh.tbl->nonideal_items/keys->hh.tbl->num_items), keys->hh.tbl->num_items, keys->hh.tbl->num_buckets, dups, (keys->hh.tbl->noexpand != 0U) ? "nx" : "ok", (elapsed_tm.tv_sec * 1000000) + elapsed_tm.tv_usec, (elapsed_tm2.tv_sec * 1000000) + elapsed_tm2.tv_usec, (elapsed_tm3.tv_sec * 1000000) + elapsed_tm3.tv_usec ); } return 0; } uthash-1.9.9.1+git20151125/tests/keystats000077500000000000000000000023121264051566200175310ustar00rootroot00000000000000#!/usr/bin/perl use strict; use FindBin; sub usage { print "usage: keystats [-v] keyfile\n"; print "usage: keystats [-p [-v]] keyfile\n"; exit -1; } usage if ((@ARGV == 0) or ($ARGV[0] eq '-h')); my @exes = glob "$FindBin::Bin/keystat.???"; my %stats; for my $exe (@exes) { $stats{$exe} = `$exe @ARGV`; delete $stats{$exe} if ($? != 0); # omit hash functions that fail to produce stats (nx) } print( "fcn ideal% #items #buckets dup% fl add_usec find_usec del-all usec\n"); printf("--- ------ ---------- ---------- ----- -- ---------- ---------- ------------\n"); for my $exe (sort statsort keys %stats) { my ($ideal,$items,$bkts,$dups,$ok,$add,$find,$del) = split /,/, $stats{$exe}; # convert 0-1 values to percentages $dups = $items ? (100.0 * $dups / $items) : 0.0; $ideal = 100.0 * $ideal; printf("%3s %5.1f%% %10d %10d %4.0f%% %2s %10d %10d %12d\n", substr($exe,-3,3), $ideal,$items,$bkts,$dups,$ok,$add,$find,$del); } # sort on hash_q (desc) then by find_usec (asc) sub statsort { my @a_stats = split /,/, $stats{$a}; my @b_stats = split /,/, $stats{$b}; return ($b_stats[0] <=> $a_stats[0]) || ($a_stats[-1] <=> $b_stats[-1]); } uthash-1.9.9.1+git20151125/tests/lru_cache/000077500000000000000000000000001264051566200176635ustar00rootroot00000000000000uthash-1.9.9.1+git20151125/tests/lru_cache/Makefile000066400000000000000000000007021264051566200213220ustar00rootroot00000000000000CC=gcc CFLAGS+=-W -Werror -Wall -Wextra -std=c99 \ -D_FORTIFY_SOURCE=2 -fstack-protector -g \ -Wformat=2 -pedantic -pedantic-errors \ -D_GNU_SOURCE=1 -D_BSD_SOURCE=1 \ -I../../src LDFLAGS+=-pthread cache: main.o cache.o $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) main.o cache.o -o cache main.o: main.c $(CC) $(CPPFLAGS) $(CFLAGS) -c main.c -o main.o cache.o: cache.c $(CC) $(CPPFLAGS) $(CFLAGS) -c cache.c -o cache.o clean: rm -f cache *.o uthash-1.9.9.1+git20151125/tests/lru_cache/cache.c000066400000000000000000000116211264051566200210730ustar00rootroot00000000000000/* * ===================================================================================== * * Filename: cache.c * * Description: A simple cache * * Version: 1.0 * Created: 04/11/2013 02:31:02 PM * Revision: none * Compiler: gcc * * Author: Oliver Lorenz (ol), olli@olorenz.org * Company: https://olorenz.org * License: This is licensed under the same terms as uthash itself * * ===================================================================================== */ #include #include #include #include "cache.h" #include "uthash.h" /** * A cache entry */ struct foo_cache_entry { char *key; /**cache_lock), NULL)) != 0) goto err_out; new->max_entries = capacity; new->entries = NULL; new->free_cb = free_cb; *dst = new; return 0; err_out: if (new) free(new); return rv; } /** Frees an allocated cache object @param cache The cache object to free @param keep_data Whether to free contained data or just delete references to it @return EINVAL if cache is NULL, 0 otherwise */ int foo_cache_delete(struct foo_cache *cache, int keep_data) { struct foo_cache_entry *entry, *tmp; int rv; if (!cache) return EINVAL; rv = pthread_rwlock_wrlock(&(cache->cache_lock)); if (rv) return rv; if (keep_data) { HASH_CLEAR(hh, cache->entries); } else { HASH_ITER(hh, cache->entries, entry, tmp) { HASH_DEL(cache->entries, entry); if (cache->free_cb) cache->free_cb(entry->data); free(entry); } } (void)pthread_rwlock_unlock(&(cache->cache_lock)); (void)pthread_rwlock_destroy(&(cache->cache_lock)); free(cache); cache = NULL; return 0; } /** Checks if a given key is in the cache @param cache The cache object @param key The key to look-up @param result Where to store the result if key is found. A warning: Even though result is just a pointer, you have to call this function with a **ptr, otherwise this will blow up in your face. @return EINVAL if cache is NULL, 0 otherwise */ int foo_cache_lookup(struct foo_cache *cache, char *key, void *result) { int rv; struct foo_cache_entry *tmp = NULL; char **dirty_hack = result; if (!cache || !key || !result) return EINVAL; rv = pthread_rwlock_wrlock(&(cache->cache_lock)); if (rv) return rv; HASH_FIND_STR(cache->entries, key, tmp); if (tmp) { size_t key_len = strnlen(tmp->key, KEY_MAX_LENGTH); HASH_DELETE(hh, cache->entries, tmp); HASH_ADD_KEYPTR(hh, cache->entries, tmp->key, key_len, tmp); *dirty_hack = tmp->data; } else { *dirty_hack = result = NULL; } rv = pthread_rwlock_unlock(&(cache->cache_lock)); return rv; } /** Inserts a given pair into the cache @param cache The cache object @param key The key that identifies @param data Data associated with @return EINVAL if cache is NULL, ENOMEM if malloc fails, 0 otherwise */ int foo_cache_insert(struct foo_cache *cache, char *key, void *data) { struct foo_cache_entry *entry = NULL; struct foo_cache_entry *tmp_entry = NULL; size_t key_len = 0; int rv; if (!cache || !data) return EINVAL; if ((entry = malloc(sizeof(*entry))) == NULL) return ENOMEM; if ((rv = pthread_rwlock_wrlock(&(cache->cache_lock))) != 0) goto err_out; entry->key = key; entry->data = data; key_len = strnlen(entry->key, KEY_MAX_LENGTH); HASH_ADD_KEYPTR(hh, cache->entries, entry->key, key_len, entry); if (HASH_COUNT(cache->entries) >= cache->max_entries) { HASH_ITER(hh, cache->entries, entry, tmp_entry) { HASH_DELETE(hh, cache->entries, entry); if (cache->free_cb) cache->free_cb(entry->data); else free(entry->data); /* free(key->key) if data has been copied */ free(entry); break; } } rv = pthread_rwlock_unlock(&(cache->cache_lock)); return rv; err_out: if (entry) free(entry); (void)pthread_rwlock_unlock(&(cache->cache_lock)); return rv; } uthash-1.9.9.1+git20151125/tests/lru_cache/cache.h000066400000000000000000000016711264051566200211040ustar00rootroot00000000000000/* * ===================================================================================== * * Filename: cache.h * * Description: A simple cache * * Version: 1.0 * Created: 04/11/2013 02:30:46 PM * Revision: none * Compiler: gcc * * Author: Oliver Lorenz (ol), olli@olorenz.org * Company: https://olorenz.org * License: This is licensed under the same terms as uthash itself * * ===================================================================================== */ #ifndef _CACHE_ #define _CACHE_ struct foo_cache; extern int foo_cache_create(struct foo_cache **dst, const size_t capacity, void (*free_cb) (void *element)); extern int foo_cache_delete(struct foo_cache *cache, int keep_data); extern int foo_cache_lookup(struct foo_cache *cache, char *key, void *result); extern int foo_cache_insert(struct foo_cache *cache, char *key, void *data); #endif uthash-1.9.9.1+git20151125/tests/lru_cache/main.c000066400000000000000000000067651264051566200207710ustar00rootroot00000000000000#include #include #include #include #include #include #include "cache.h" #define MAX_RANDOM_ENTRIES 32 struct key_record { char *key; char *value; }; int generate_random_entry(struct key_record **entry); int generate_random_string(char **dst, const size_t len); void free_random_entry(void *entry); void *producer(void *arg) { struct foo_cache *cache = arg; int i; for (i = 0; i < MAX_RANDOM_ENTRIES; i++) { struct key_record *entry = NULL; if (generate_random_entry(&entry)) { fprintf(stderr, "generate_random_entry() failed\n"); continue; } #if defined(DEBUG) printf("Random Entry:\n"); printf(" key: %s\n", entry->key); printf(" Key: %s\n", entry->value); #else printf("inserted %s (%d)\n", entry->key, (int)strlen(entry->key)); #endif if (foo_cache_insert(cache, entry->key, entry)) { fprintf(stderr, "foo_cache_insert() failed\n"); continue; } } pthread_exit(NULL); } void *consumer(void *arg) { struct foo_cache *cache = arg; struct key_record *result = NULL; char *buffer = malloc(64); char key[33]; int stop = 0; if (!buffer) goto out; /* give producer time to populate the cache */ sleep(2); printf("\n\n"); do { memset(key, 0, 64); result = NULL; printf("Enter key for lookup: "); fgets(buffer, sizeof(key), stdin); sscanf(buffer, "%s\n", key); /* read '\n' from stdin */ getchar(); if (strncmp(key, "exit", 4) == 0) { stop = 1; continue; } printf("Got key %s (%d)\n", key, (int)strlen(key)); if (foo_cache_lookup(cache, key, &result)) { fprintf(stderr, "Could not retrieve key %s\n", key); continue; } if (!result) { printf("MISS\n"); continue; } printf("HIT\n"); printf("key: %s\n", result->key); printf("key : %s\n", result->value); } while (!stop); out: if (buffer) free(buffer); pthread_exit(NULL); } int main(void) { int rv; struct foo_cache *cache = NULL; pthread_t workers[2]; rv = foo_cache_create(&cache, MAX_RANDOM_ENTRIES / 2, free_random_entry); if (rv) { fprintf(stderr, "Could not create cache\n"); exit(1); } (void)pthread_create(&workers[0], NULL, producer, (void *)cache); (void)pthread_create(&workers[1], NULL, consumer, (void *)cache); pthread_join(workers[0], NULL); pthread_join(workers[1], NULL); (void)foo_cache_delete(cache, 0); return 0; } int generate_random_entry(struct key_record **entry) { struct key_record *new = NULL; char *key = NULL; char *value = NULL; int rv; if (!entry) return EINVAL; rv = generate_random_string(&key, 33); if (rv) return rv; rv = generate_random_string(&value, 129); if (rv) return rv; if ((new = malloc(sizeof(*new))) == NULL) { free(key); free(value); return ENOMEM; } new->key = key; new->value = value; *entry = new; return 0; } int generate_random_string(char **dst, const size_t len) { static const char alphanum[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; size_t i; char *s; if (!dst || len == 0) return EINVAL; if ((s = malloc(len)) == NULL) return ENOMEM; for (i = 0; i < len - 1; i++) { s[i] = alphanum[rand() % (sizeof(alphanum) - 1)]; } s[len - 1] = '\0'; *dst = s; return 0; } void free_random_entry(void *entry) { #if defined(DEBUG) fprintf(stderr, "In %s: entry @ %p\n", __func__, entry); #endif struct key_record *record = entry; if (!record) return; if (record->key) free(record->key); if (record->value) free(record->value); free(record); record = NULL; } uthash-1.9.9.1+git20151125/tests/mexpand000077500000000000000000000005571264051566200173270ustar00rootroot00000000000000#!/bin/bash # utility to macro-expand a test program CC=gcc #CPPFLAGS=-DHASH_DEBUG=1 #CC=g++ CPPFLAGS="-m64 -O3" CFLAGS="-O3 -m64 -pedantic -Wall" ${CC} ${CPPFLAGS} -E -I../src $1 | egrep -v '^#' > /tmp/$1 indent /tmp/$1 ${CC} ${CFLAGS} -o /tmp/$1.$$ /tmp/$1 rm -f /tmp/$1.$$ read -p "open /tmp/$1 ? [n] " response if [ "$response" = "y" ] then vi /tmp/$1 fi uthash-1.9.9.1+git20151125/tests/simkeys.pl000077500000000000000000000014541264051566200177660ustar00rootroot00000000000000#!/usr/bin/perl # This program generates a simkey10.dat (100, 1000, etc) each # containing 100 random keys of length 10 (100, 1000, etc). # These files can then be fed into keystats to observe that # the time to add or find the keys is directly proportional to # keylength n [in other words, O(n)]. # # The conclusion is that really long keys (e.g. 100k) are not # efficient. TDH 23Jan07 use strict; use warnings; #for my $len (10,100,1000,10000,100000,1000000) { for my $len (100) { open OUTFILE, ">simkeys$len.dat" or die "can't open: $!\n"; # we'll do 100 keys of $len print "keylen $len\n"; for my $i (0..99) { my $key = pack "I", $len; $key .= pack "C", (int(rand(256))) for (1..$len); print OUTFILE $key; } close OUTFILE; } uthash-1.9.9.1+git20151125/tests/sleep_test.c000066400000000000000000000014011264051566200202450ustar00rootroot00000000000000#include "uthash.h" #include /* malloc */ #include /* printf */ #include /* getpid */ typedef struct example_user_t { int id; int cookie; UT_hash_handle hh; } example_user_t; int main(int argc,char *argv[]) { int i; example_user_t *user, *users=NULL; /* create elements */ for(i=0; i<10000; i++) { if ( (user = (example_user_t*)malloc(sizeof(example_user_t))) == NULL) { exit(-1); } user->id = i; user->cookie = i*i; HASH_ADD_INT(users,id,user); } printf("pid: %u\n", (unsigned)getpid()); /* printf("sig: %p\n", &users->hh.tbl->signature); */ /* printf("bbv: %p\n", &users->hh.tbl->bloom_bv); */ sleep(60*10); return 0; } uthash-1.9.9.1+git20151125/tests/tdiff.cpp000066400000000000000000000015621264051566200175420ustar00rootroot00000000000000// Windows does not have unix diff so this is a simple replacement #include #include using namespace std; int main(int argc, char *argv[] ) { int rc=-1; if (argc != 3) { cout << "usage: " << argv[0] << " file1 file2\n"; return -1; } char *file1 = argv[1]; char *file2 = argv[2]; ifstream is1(file1, ios::in); ifstream is2(file2, ios::in); if (is1.fail()) {cerr << "failed to open " << file1 << "\n"; goto done;} if (is2.fail()) {cerr << "failed to open " << file2 << "\n"; goto done;} char d1[256], d2[256]; do { is1.read(d1,sizeof(d1)); is2.read(d2,sizeof(d2)); if ((is1.gcount() != is2.gcount()) || memcmp(d1,d2,is1.gcount())) { cout << file1 << " and " << file2 << " differ\n"; goto done; } } while (!is1.eof() && !is2.eof()); rc=0; done: is1.close(); is2.close(); return rc; } uthash-1.9.9.1+git20151125/tests/test1.ans000066400000000000000000000002601264051566200174770ustar00rootroot00000000000000user 0, cookie 0 user 1, cookie 1 user 2, cookie 4 user 3, cookie 9 user 4, cookie 16 user 5, cookie 25 user 6, cookie 36 user 7, cookie 49 user 8, cookie 64 user 9, cookie 81 uthash-1.9.9.1+git20151125/tests/test1.c000066400000000000000000000013051264051566200171410ustar00rootroot00000000000000#include "uthash.h" #include /* malloc */ #include /* printf */ typedef struct example_user_t { int id; int cookie; UT_hash_handle hh; } example_user_t; int main(int argc,char *argv[]) { int i; example_user_t *user, *users=NULL; /* create elements */ for(i=0; i<10; i++) { user = (example_user_t*)malloc(sizeof(example_user_t)); if (user == NULL) { exit(-1); } user->id = i; user->cookie = i*i; HASH_ADD_INT(users,id,user); } for(user=users; user != NULL; user=(example_user_t*)(user->hh.next)) { printf("user %d, cookie %d\n", user->id, user->cookie); } return 0; } uthash-1.9.9.1+git20151125/tests/test10.ans000066400000000000000000000001021264051566200175520ustar00rootroot000000000000009 found in hh 9 found in alth 10 not found in hh 10 found in alth uthash-1.9.9.1+git20151125/tests/test10.c000066400000000000000000000026141264051566200172250ustar00rootroot00000000000000#include "uthash.h" #include /* malloc */ #include /* printf */ typedef struct example_user_t { int id; int cookie; UT_hash_handle hh; UT_hash_handle alth; } example_user_t; int main(int argc,char *argv[]) { int i; example_user_t *user, *tmp, *users=NULL, *altusers=NULL; /* create elements */ for(i=0; i<1000; i++) { user = (example_user_t*)malloc(sizeof(example_user_t)); if (user == NULL) { exit(-1); } user->id = i; user->cookie = i*i; if (i<10) { HASH_ADD_INT(users,id,user); } HASH_ADD(alth,altusers,id,sizeof(int),user); } /* printf("hh items: %d, alth items: %d\n", users->hh.tbl->num_items, users->alth.tbl->num_items); printf("hh buckets: %d, alth buckets: %d\n", users->hh.tbl->num_buckets, users->alth.tbl->num_buckets); */ i=9; HASH_FIND_INT(users,&i,tmp); printf("%d %s in hh\n", i, (tmp != NULL) ? "found" : "not found"); HASH_FIND(alth,altusers,&i,sizeof(int),tmp); printf("%d %s in alth\n", i, (tmp != NULL) ? "found" : "not found"); i=10; HASH_FIND_INT(users,&i,tmp); printf("%d %s in hh\n", i, (tmp != NULL) ? "found" : "not found"); HASH_FIND(alth,altusers,&i,sizeof(int),tmp); printf("%d %s in alth\n", i, (tmp != NULL) ? "found" : "not found"); return 0; } uthash-1.9.9.1+git20151125/tests/test11.ans000066400000000000000000000005321264051566200175620ustar00rootroot00000000000000ADRIAN ARNOLDO CARROLL CARY CHONG CLIFTON CODY COLTON CORNELL DAMON DANNIE DARIO DONN DOUG DOUGLAS FREDERICK FRITZ GERALD GUS HARVEY IRVING ISAIAH JARVIS JOHN KENTON LAURENCE LESTER LINCOLN LOWELL NELSON NEVILLE NIGEL NORMAND ODIS OMAR ORLANDO RAYMUNDO REX ROLANDO RON SHANE TONEY TRINIDAD WALTER WARNER WARREN WES WILLARD WILLIAM WINFRED XAVIER uthash-1.9.9.1+git20151125/tests/test11.c000066400000000000000000000024371264051566200172310ustar00rootroot00000000000000#include "uthash.h" #include /* malloc */ #include /* perror */ #include /* printf */ #define BUFLEN 20 #if 0 /* Print a message if the hash's no-expand flag is set. */ #undef uthash_noexpand_fyi #undef uthash_expand_fyi #define uthash_noexpand_fyi(tbl) printf("noexpand set\n"); #define uthash_expand_fyi(tbl) printf("hash expanded\n"); #endif typedef struct name_rec { char boy_name[BUFLEN]; UT_hash_handle hh; } name_rec; static int namecmp(void *_a, void *_b) { name_rec *a = (name_rec*)_a; name_rec *b = (name_rec*)_b; return strcmp(a->boy_name,b->boy_name); } int main(int argc,char *argv[]) { name_rec *name, *names=NULL; char linebuf[BUFLEN]; FILE *file; file = fopen( "test11.dat", "r" ); if (file == NULL) { perror("can't open: "); exit(-1); } while (fgets(linebuf,BUFLEN,file) != NULL) { name = (name_rec*)malloc(sizeof(name_rec)); if (name == NULL) { exit(-1); } strncpy(name->boy_name,linebuf,sizeof(name->boy_name)); HASH_ADD_STR(names,boy_name,name); } fclose(file); HASH_SORT(names,namecmp); for(name=names; name!=NULL; name=(name_rec*)(name->hh.next)) { printf("%s",name->boy_name); } return 0; } uthash-1.9.9.1+git20151125/tests/test11.dat000066400000000000000000000005321264051566200175510ustar00rootroot00000000000000JOHN WILLIAM WALTER DOUGLAS GERALD FREDERICK WARREN SHANE LESTER RON HARVEY ADRIAN CODY NELSON CLIFTON WILLARD DOUG ORLANDO REX OMAR DAMON LOWELL IRVING CARROLL LAURENCE ROLANDO CARY XAVIER ISAIAH GUS JARVIS WINFRED RAYMUNDO LINCOLN CORNELL NIGEL NORMAND FRITZ DONN TRINIDAD ODIS DANNIE DARIO KENTON CHONG NEVILLE TONEY WARNER WES COLTON ARNOLDO uthash-1.9.9.1+git20151125/tests/test12.ans000066400000000000000000000005301264051566200175610ustar00rootroot00000000000000added bob (id 0) added jack (id 1) added gary (id 2) added ty (id 3) added bo (id 4) added phil (id 5) added art (id 6) added gil (id 7) added buck (id 8) added ted (id 9) found bob (id 0) found jack (id 1) found gary (id 2) found ty (id 3) found bo (id 4) found phil (id 5) found art (id 6) found gil (id 7) found buck (id 8) found ted (id 9) uthash-1.9.9.1+git20151125/tests/test12.c000066400000000000000000000021141264051566200172220ustar00rootroot00000000000000#include "uthash.h" #include #include /* malloc */ typedef struct person_t { char first_name[10]; int id; UT_hash_handle hh; } person_t; int main(int argc, char*argv[]) { person_t *people=NULL, *person; const char **name; const char * names[] = { "bob", "jack", "gary", "ty", "bo", "phil", "art", "gil", "buck", "ted", NULL }; int id=0; for(name=names; *name != NULL; name++) { person = (person_t*)malloc(sizeof(person_t)); if (person == NULL) { exit(-1); } strncpy(person->first_name, *name,10UL); person->id = id++; HASH_ADD_STR(people,first_name,person); printf("added %s (id %d)\n", person->first_name, person->id); } for(name=names; *name != NULL; name++) { HASH_FIND_STR(people,*name,person); if (person != NULL) { printf("found %s (id %d)\n", person->first_name, person->id); } else { printf("failed to find %s\n", *name); } } return 0; } uthash-1.9.9.1+git20151125/tests/test13.ans000066400000000000000000000001701264051566200175620ustar00rootroot00000000000000id 9, following prev... id 7, following prev... id 5, following prev... id 3, following prev... id 1, following prev... uthash-1.9.9.1+git20151125/tests/test13.c000066400000000000000000000021241264051566200172240ustar00rootroot00000000000000#include "uthash.h" #include /* malloc */ #include /* printf */ typedef struct example_user_t { int id; int cookie; UT_hash_handle hh; } example_user_t; int main(int argc,char *argv[]) { int i; example_user_t *user, *tmp, *users=NULL; /* create elements */ for(i=0; i<10; i++) { user = (example_user_t*)malloc(sizeof(example_user_t)); if (user == NULL) { exit(-1); } user->id = i; user->cookie = i*i; HASH_ADD_INT(users,id,user); } /* delete each even ID */ for(i=0; i<10; i+=2) { HASH_FIND_INT(users,&i,tmp); if (tmp != NULL) { HASH_DEL(users,tmp); free(tmp); } else { printf("user id %d not found\n", i); } } i=9; HASH_FIND_INT(users,&i,tmp); if (tmp != NULL) { while (tmp != NULL) { printf("id %d, following prev...\n", tmp->id); tmp = (example_user_t*)tmp->hh.prev; } } else { printf("user id %d not found\n", i); } return 0; } uthash-1.9.9.1+git20151125/tests/test14.ans000066400000000000000000000000471264051566200175660ustar00rootroot00000000000000lookup on 1219 of 1219 names succeeded uthash-1.9.9.1+git20151125/tests/test14.c000066400000000000000000000023161264051566200172300ustar00rootroot00000000000000#include "uthash.h" #include /* malloc */ #include /* perror */ #include /* printf */ #define BUFLEN 20 #if 0 #undef uthash_expand_fyi #define uthash_expand_fyi(tbl) printf("expanding to %d buckets\n", tbl->num_buckets) #endif typedef struct name_rec { char boy_name[BUFLEN]; UT_hash_handle hh; } name_rec; int main(int argc,char *argv[]) { name_rec *name, *names=NULL; char linebuf[BUFLEN]; FILE *file; int i=0,j=0; file = fopen( "test14.dat", "r" ); if (file == NULL ) { perror("can't open: "); exit(-1); } while (fgets(linebuf,BUFLEN,file) != NULL) { i++; name = (name_rec*)malloc(sizeof(name_rec)); if (name == NULL) { exit(-1); } strncpy(name->boy_name,linebuf,sizeof(name->boy_name)); HASH_ADD_STR(names,boy_name,name); } fseek(file,0L,SEEK_SET); while (fgets(linebuf,BUFLEN,file) != NULL) { HASH_FIND_STR(names,linebuf,name); if (!name) { printf("failed to find: %s", linebuf); } else { j++; } } fclose(file); printf("lookup on %d of %d names succeeded\n", j, i); return 0; } uthash-1.9.9.1+git20151125/tests/test14.dat000066400000000000000000000200011264051566200175450ustar00rootroot00000000000000JAMES JOHN ROBERT MICHAEL WILLIAM DAVID RICHARD CHARLES JOSEPH THOMAS CHRISTOPHER DANIEL PAUL MARK DONALD GEORGE KENNETH STEVEN EDWARD BRIAN RONALD ANTHONY KEVIN JASON MATTHEW GARY TIMOTHY JOSE LARRY JEFFREY FRANK SCOTT ERIC STEPHEN ANDREW RAYMOND GREGORY JOSHUA JERRY DENNIS WALTER PATRICK PETER HAROLD DOUGLAS HENRY CARL ARTHUR RYAN ROGER JOE JUAN JACK ALBERT JONATHAN JUSTIN TERRY GERALD KEITH SAMUEL WILLIE RALPH LAWRENCE NICHOLAS ROY BENJAMIN BRUCE BRANDON ADAM HARRY FRED WAYNE BILLY STEVE LOUIS JEREMY AARON RANDY HOWARD EUGENE CARLOS RUSSELL BOBBY VICTOR MARTIN ERNEST PHILLIP TODD JESSE CRAIG ALAN SHAWN CLARENCE SEAN PHILIP CHRIS JOHNNY EARL JIMMY ANTONIO DANNY BRYAN TONY LUIS MIKE STANLEY LEONARD NATHAN DALE MANUEL RODNEY CURTIS NORMAN ALLEN MARVIN VINCENT GLENN JEFFERY TRAVIS JEFF CHAD JACOB LEE MELVIN ALFRED KYLE FRANCIS BRADLEY JESUS HERBERT FREDERICK RAY JOEL EDWIN DON EDDIE RICKY TROY RANDALL BARRY ALEXANDER BERNARD MARIO LEROY FRANCISCO MARCUS MICHEAL THEODORE CLIFFORD MIGUEL OSCAR JAY JIM TOM CALVIN ALEX JON RONNIE BILL LLOYD TOMMY LEON DEREK WARREN DARRELL JEROME FLOYD LEO ALVIN TIM WESLEY GORDON DEAN GREG JORGE DUSTIN PEDRO DERRICK DAN LEWIS ZACHARY COREY HERMAN MAURICE VERNON ROBERTO CLYDE GLEN HECTOR SHANE RICARDO SAM RICK LESTER BRENT RAMON CHARLIE TYLER GILBERT GENE MARC REGINALD RUBEN BRETT ANGEL NATHANIEL RAFAEL LESLIE EDGAR MILTON RAUL BEN CHESTER CECIL DUANE FRANKLIN ANDRE ELMER BRAD GABRIEL RON MITCHELL ROLAND ARNOLD HARVEY JARED ADRIAN KARL CORY CLAUDE ERIK DARRYL JAMIE NEIL JESSIE CHRISTIAN JAVIER FERNANDO CLINTON TED MATHEW TYRONE DARREN LONNIE LANCE CODY JULIO KELLY KURT ALLAN NELSON GUY CLAYTON HUGH MAX DWAYNE DWIGHT ARMANDO FELIX JIMMIE EVERETT JORDAN IAN WALLACE KEN BOB JAIME CASEY ALFREDO ALBERTO DAVE IVAN JOHNNIE SIDNEY BYRON JULIAN ISAAC MORRIS CLIFTON WILLARD DARYL ROSS VIRGIL ANDY MARSHALL SALVADOR PERRY KIRK SERGIO MARION TRACY SETH KENT TERRANCE RENE EDUARDO TERRENCE ENRIQUE FREDDIE WADE AUSTIN STUART FREDRICK ARTURO ALEJANDRO JACKIE JOEY NICK LUTHER WENDELL JEREMIAH EVAN JULIUS DANA DONNIE OTIS SHANNON TREVOR OLIVER LUKE HOMER GERARD DOUG KENNY HUBERT ANGELO SHAUN LYLE MATT LYNN ALFONSO ORLANDO REX CARLTON ERNESTO CAMERON NEAL PABLO LORENZO OMAR WILBUR BLAKE GRANT HORACE RODERICK KERRY ABRAHAM WILLIS RICKEY JEAN IRA ANDRES CESAR JOHNATHAN MALCOLM RUDOLPH DAMON KELVIN RUDY PRESTON ALTON ARCHIE MARCO WM PETE RANDOLPH GARRY GEOFFREY JONATHON FELIPE BENNIE GERARDO ED DOMINIC ROBIN LOREN DELBERT COLIN GUILLERMO EARNEST LUCAS BENNY NOEL SPENCER RODOLFO MYRON EDMUND GARRETT SALVATORE CEDRIC LOWELL GREGG SHERMAN WILSON DEVIN SYLVESTER KIM ROOSEVELT ISRAEL JERMAINE FORREST WILBERT LELAND SIMON GUADALUPE CLARK IRVING CARROLL BRYANT OWEN RUFUS WOODROW SAMMY KRISTOPHER MACK LEVI MARCOS GUSTAVO JAKE LIONEL MARTY TAYLOR ELLIS DALLAS GILBERTO CLINT NICOLAS LAURENCE ISMAEL ORVILLE DREW JODY ERVIN DEWEY AL WILFRED JOSH HUGO IGNACIO CALEB TOMAS SHELDON ERICK FRANKIE STEWART DOYLE DARREL ROGELIO TERENCE SANTIAGO ALONZO ELIAS BERT ELBERT RAMIRO CONRAD PAT NOAH GRADY PHIL CORNELIUS LAMAR ROLANDO CLAY PERCY DEXTER BRADFORD MERLE DARIN AMOS TERRELL MOSES IRVIN SAUL ROMAN DARNELL RANDAL TOMMIE TIMMY DARRIN WINSTON BRENDAN TOBY VAN ABEL DOMINICK BOYD COURTNEY JAN EMILIO ELIJAH CARY DOMINGO SANTOS AUBREY EMMETT MARLON EMANUEL JERALD EDMOND EMIL DEWAYNE WILL OTTO TEDDY REYNALDO BRET MORGAN JESS TRENT HUMBERTO EMMANUEL STEPHAN LOUIE VICENTE LAMONT STACY GARLAND MILES MICAH EFRAIN BILLIE LOGAN HEATH RODGER HARLEY DEMETRIUS ETHAN ELDON ROCKY PIERRE JUNIOR FREDDY ELI BRYCE ANTOINE ROBBIE KENDALL ROYCE STERLING MICKEY CHASE GROVER ELTON CLEVELAND DYLAN CHUCK DAMIAN REUBEN STAN AUGUST LEONARDO JASPER RUSSEL ERWIN BENITO HANS MONTE BLAINE ERNIE CURT QUENTIN AGUSTIN MURRAY JAMAL DEVON ADOLFO HARRISON TYSON BURTON BRADY ELLIOTT WILFREDO BART JARROD VANCE DENIS DAMIEN JOAQUIN HARLAN DESMOND ELLIOT DARWIN ASHLEY GREGORIO BUDDY XAVIER KERMIT ROSCOE ESTEBAN ANTON SOLOMON SCOTTY NORBERT ELVIN WILLIAMS NOLAN CAREY ROD QUINTON HAL BRAIN ROB ELWOOD KENDRICK DARIUS MOISES SON MARLIN FIDEL THADDEUS CLIFF MARCEL ALI JACKSON RAPHAEL BRYON ARMAND ALVARO JEFFRY DANE JOESPH THURMAN NED SAMMIE RUSTY MICHEL MONTY RORY FABIAN REGGIE MASON GRAHAM KRIS ISAIAH VAUGHN GUS AVERY LOYD DIEGO ALEXIS ADOLPH NORRIS MILLARD ROCCO GONZALO DERICK RODRIGO GERRY STACEY CARMEN WILEY RIGOBERTO ALPHONSO TY SHELBY RICKIE NOE VERN BOBBIE REED JEFFERSON ELVIS BERNARDO MAURICIO HIRAM DONOVAN BASIL RILEY OLLIE NICKOLAS MAYNARD SCOT VINCE QUINCY EDDY SEBASTIAN FEDERICO ULYSSES HERIBERTO DONNELL COLE DENNY DAVIS GAVIN EMERY WARD ROMEO JAYSON DION DANTE CLEMENT COY ODELL MAXWELL JARVIS BRUNO ISSAC MARY DUDLEY BROCK SANFORD COLBY CARMELO BARNEY NESTOR HOLLIS STEFAN DONNY ART LINWOOD BEAU WELDON GALEN ISIDRO TRUMAN DELMAR JOHNATHON SILAS FREDERIC DICK KIRBY IRWIN CRUZ MERLIN MERRILL CHARLEY MARCELINO LANE HARRIS CLEO CARLO TRENTON KURTIS HUNTER AURELIO WINFRED VITO COLLIN DENVER CARTER LEONEL EMORY PASQUALE MOHAMMAD MARIANO DANIAL BLAIR LANDON DIRK BRANDEN ADAN NUMBERS CLAIR BUFORD GERMAN BERNIE WILMER JOAN EMERSON ZACHERY FLETCHER JACQUES ERROL DALTON MONROE JOSUE DOMINIQUE EDWARDO BOOKER WILFORD SONNY SHELTON CARSON THERON RAYMUNDO DAREN TRISTAN HOUSTON ROBBY LINCOLN JAME GENARO GALE BENNETT OCTAVIO CORNELL LAVERNE HUNG ARRON ANTONY HERSCHEL ALVA GIOVANNI GARTH CYRUS CYRIL RONNY STEVIE LON FREEMAN ERIN DUNCAN KENNITH CARMINE AUGUSTINE YOUNG ERICH CHADWICK WILBURN RUSS REID MYLES ANDERSON MORTON JONAS FOREST MITCHEL MERVIN ZANE RICH JAMEL LAZARO ALPHONSE RANDELL MAJOR JOHNIE JARRETT BROOKS ARIEL ABDUL DUSTY LUCIANO LINDSEY TRACEY SEYMOUR SCOTTIE EUGENIO MOHAMMED SANDY VALENTIN CHANCE ARNULFO LUCIEN FERDINAND THAD EZRA SYDNEY ALDO RUBIN ROYAL MITCH EARLE ABE WYATT MARQUIS LANNY KAREEM JAMAR BORIS ISIAH EMILE ELMO ARON LEOPOLDO EVERETTE JOSEF GAIL ELOY DORIAN RODRICK REINALDO LUCIO JERROD WESTON HERSHEL BARTON PARKER LEMUEL LAVERN BURT JULES GIL ELISEO AHMAD NIGEL EFREN ANTWAN ALDEN MARGARITO COLEMAN REFUGIO DINO OSVALDO LES DEANDRE NORMAND KIETH IVORY ANDREA TREY NORBERTO NAPOLEON JEROLD FRITZ ROSENDO MILFORD SANG DEON CHRISTOPER ALFONZO LYMAN JOSIAH BRANT WILTON RICO JAMAAL DEWITT CAROL BRENTON YONG OLIN FOSTER FAUSTINO CLAUDIO JUDSON GINO EDGARDO BERRY ALEC TANNER JARRED DONN TRINIDAD TAD SHIRLEY PRINCE PORFIRIO ODIS MARIA LENARD CHAUNCEY CHANG TOD MEL MARCELO KORY AUGUSTUS KEVEN HILARIO BUD SAL ROSARIO ORVAL MAURO DANNIE ZACHARIAH OLEN ANIBAL MILO JED FRANCES THANH DILLON AMADO NEWTON CONNIE LENNY TORY RICHIE LUPE HORACIO BRICE MOHAMED DELMER DARIO REYES DEE MAC JONAH JERROLD ROBT HANK SUNG RUPERT ROLLAND KENTON DAMION CHI ANTONE WALDO FREDRIC BRADLY QUINN KIP BURL WALKER TYREE JEFFEREY AHMED WILLY STANFORD OREN NOBLE MOSHE MIKEL ENOCH BRENDON QUINTIN JAMISON FLORENCIO DARRICK TOBIAS MINH HASSAN GIUSEPPE DEMARCUS CLETUS TYRELL LYNDON KEENAN WERNER THEO GERALDO LOU COLUMBUS CHET BERTRAM MARKUS HUEY HILTON DWAIN DONTE TYRON OMER ISAIAS HIPOLITO FERMIN CHUNG ADALBERTO VALENTINE JAMEY BO BARRETT WHITNEY TEODORO MCKINLEY MAXIMO GARFIELD SOL RALEIGH LAWERENCE ABRAM RASHAD KING EMMITT DARON CHONG SAMUAL PARIS OTHA MIQUEL LACY EUSEBIO DONG DOMENIC DARRON BUSTER ANTONIA WILBER RENATO JC HOYT HAYWOOD EZEKIEL CHAS FLORENTINO ELROY CLEMENTE ARDEN NEVILLE KELLEY EDISON DESHAWN CARROL SHAYNE NATHANIAL JORDON DANILO CLAUD VAL SHERWOOD RAYMON RAYFORD CRISTOBAL AMBROSE TITUS HYMAN FELTON EZEQUIEL ERASMO STANTON LONNY LEN IKE MILAN LINO JAROD HERB ANDREAS WALTON RHETT PALMER JUDE DOUGLASS CORDELL OSWALDO ELLSWORTH VIRGILIO TONEY NATHANAEL DEL BRITT BENEDICT MOSE HONG LEIGH JOHNSON ISREAL GAYLE GARRET FAUSTO ASA ARLEN ZACK WARNER MODESTO FRANCESCO MANUAL JAE GAYLORD GASTON FILIBERTO DEANGELO MICHALE GRANVILLE WES MALIK ZACKARY TUAN NICKY ELDRIDGE CRISTOPHER CORTEZ ANTIONE MALCOM LONG KOREY JOSPEH COLTON WAYLON VON HOSEA SHAD SANTO RUDOLF ROLF REY RENALDO MARCELLUS LUCIUS LESLEY KRISTOFER BOYCE BENTON MAN KASEY JEWELL HAYDEN HARLAND ARNOLDO RUEBEN LEANDRO KRAIG JERRELL JEROMY HOBERT CEDRICK ARLIE WINFORD WALLY PATRICIA LUIGI KENETH JACINTO GRAIG FRANKLYN EDMUNDO SID PORTER LEIF LAUREN JERAMY ELISHA BUCK WILLIAN VINCENZO SHON MICHAL LYNWOOD LINDSAY JEWEL JERE HAI ELDEN DORSEY DARELL BRODERICK ALONSO uthash-1.9.9.1+git20151125/tests/test15.ans000066400000000000000000000000201264051566200175560ustar00rootroot00000000000000betty's id is 2 uthash-1.9.9.1+git20151125/tests/test15.c000066400000000000000000000016571264051566200172400ustar00rootroot00000000000000#include /* strcpy */ #include /* malloc */ #include /* printf */ #include "uthash.h" struct my_struct { char name[10]; /* key */ int id; UT_hash_handle hh; /* makes this structure hashable */ }; int main(int argc, char *argv[]) { const char **n, *names[] = { "joe", "bob", "betty", NULL }; struct my_struct *s, *tmp, *users = NULL; int i=0; for (n = names; *n != NULL; n++) { s = (struct my_struct*)malloc(sizeof(struct my_struct)); if (s == NULL) { exit(-1); } strncpy(s->name, *n,10UL); s->id = i++; HASH_ADD_STR( users, name, s ); } HASH_FIND_STR( users, "betty", s); if (s != NULL) { printf("betty's id is %d\n", s->id); } /* free the hash table contents */ HASH_ITER(hh, users, s, tmp) { HASH_DEL(users, s); free(s); } return 0; } uthash-1.9.9.1+git20151125/tests/test16.ans000066400000000000000000000000431264051566200175640ustar00rootroot00000000000000found: user 5, unix time 157680000 uthash-1.9.9.1+git20151125/tests/test16.c000066400000000000000000000026471264051566200172410ustar00rootroot00000000000000#include /* malloc */ #include /* offsetof */ #include /* printf */ #include /* memset */ #include "uthash.h" struct inner { int a; int b; }; struct my_event { struct inner is; /* key is aggregate of this field */ char event_code; /* and this field. */ int user_id; UT_hash_handle hh; /* makes this structure hashable */ }; int main(int argc, char *argv[]) { struct my_event *e, ev, *events = NULL; unsigned keylen; int i; keylen = offsetof(struct my_event, event_code) + sizeof(char) - offsetof(struct my_event, is); for(i = 0; i < 10; i++) { e = (struct my_event*)malloc(sizeof(struct my_event)); if (e == NULL) { exit(-1); } memset(e,0,sizeof(struct my_event)); e->is.a = i * (60*60*24*365); /* i years (sec)*/ e->is.b = 0; e->event_code = 'a'+(i%2); /* meaningless */ e->user_id = i; HASH_ADD( hh, events, is, keylen, e); } /* look for one specific event */ memset(&ev,0,sizeof(struct my_event)); ev.is.a = 5 * (60*60*24*365); ev.is.b = 0; ev.event_code = 'b'; HASH_FIND( hh, events, &ev.is, keylen , e); if (e != NULL) { printf("found: user %d, unix time %d\n", e->user_id, e->is.a); } return 0; } uthash-1.9.9.1+git20151125/tests/test17.ans000066400000000000000000000050551264051566200175750ustar00rootroot00000000000000user 9, cookie 81 user 8, cookie 64 user 7, cookie 49 user 6, cookie 36 user 5, cookie 25 user 4, cookie 16 user 3, cookie 9 user 2, cookie 4 user 1, cookie 1 user 0, cookie 0 sorting called for a:9, b:8 called for a:7, b:6 called for a:5, b:4 called for a:3, b:2 called for a:1, b:0 called for a:8, b:6 called for a:8, b:7 called for a:4, b:2 called for a:4, b:3 called for a:6, b:2 called for a:6, b:3 called for a:6, b:4 called for a:6, b:5 called for a:2, b:0 called for a:2, b:1 user 0, cookie 0 user 1, cookie 1 user 2, cookie 4 user 3, cookie 9 user 4, cookie 16 user 5, cookie 25 user 6, cookie 36 user 7, cookie 49 user 8, cookie 64 user 9, cookie 81 adding 10-20 user 0, cookie 0 user 1, cookie 1 user 2, cookie 4 user 3, cookie 9 user 4, cookie 16 user 5, cookie 25 user 6, cookie 36 user 7, cookie 49 user 8, cookie 64 user 9, cookie 81 user 20, cookie 400 user 19, cookie 361 user 18, cookie 324 user 17, cookie 289 user 16, cookie 256 user 15, cookie 225 user 14, cookie 196 user 13, cookie 169 user 12, cookie 144 user 11, cookie 121 user 10, cookie 100 sorting called for a:0, b:1 called for a:2, b:3 called for a:4, b:5 called for a:6, b:7 called for a:8, b:9 called for a:20, b:19 called for a:18, b:17 called for a:16, b:15 called for a:14, b:13 called for a:12, b:11 called for a:0, b:2 called for a:1, b:2 called for a:4, b:6 called for a:5, b:6 called for a:8, b:19 called for a:9, b:19 called for a:17, b:15 called for a:17, b:16 called for a:13, b:11 called for a:13, b:12 called for a:0, b:4 called for a:1, b:4 called for a:2, b:4 called for a:3, b:4 called for a:8, b:15 called for a:9, b:15 called for a:19, b:15 called for a:19, b:16 called for a:19, b:17 called for a:19, b:18 called for a:11, b:10 called for a:0, b:8 called for a:1, b:8 called for a:2, b:8 called for a:3, b:8 called for a:4, b:8 called for a:5, b:8 called for a:6, b:8 called for a:7, b:8 called for a:0, b:10 called for a:1, b:10 called for a:2, b:10 called for a:3, b:10 called for a:4, b:10 called for a:5, b:10 called for a:6, b:10 called for a:7, b:10 called for a:8, b:10 called for a:9, b:10 called for a:15, b:10 called for a:15, b:11 called for a:15, b:12 called for a:15, b:13 called for a:15, b:14 user 0, cookie 0 user 1, cookie 1 user 2, cookie 4 user 3, cookie 9 user 4, cookie 16 user 5, cookie 25 user 6, cookie 36 user 7, cookie 49 user 8, cookie 64 user 9, cookie 81 user 10, cookie 100 user 11, cookie 121 user 12, cookie 144 user 13, cookie 169 user 14, cookie 196 user 15, cookie 225 user 16, cookie 256 user 17, cookie 289 user 18, cookie 324 user 19, cookie 361 user 20, cookie 400 uthash-1.9.9.1+git20151125/tests/test17.c000066400000000000000000000032741264051566200172370ustar00rootroot00000000000000#include "uthash.h" #include /* malloc */ #include /* printf */ typedef struct example_user_t { int id; int cookie; UT_hash_handle hh; } example_user_t; static int rev(void *_a, void *_b) { example_user_t *a = (example_user_t*)_a; example_user_t *b = (example_user_t*)_b; printf("called for a:%d, b:%d\n",a->id, b->id); return (a->id - b->id); } int main(int argc,char *argv[]) { int i; example_user_t *user, *users=NULL; /* create elements */ for(i=9; i>=0; i--) { user = (example_user_t*)malloc(sizeof(example_user_t)); if (user == NULL) { exit(-1); } user->id = i; user->cookie = i*i; HASH_ADD_INT(users,id,user); } for(user=users; user != NULL; user=(example_user_t*)user->hh.next) { printf("user %d, cookie %d\n", user->id, user->cookie); } printf("sorting\n"); HASH_SORT(users,rev); for(user=users; user != NULL; user=(example_user_t*)user->hh.next) { printf("user %d, cookie %d\n", user->id, user->cookie); } printf("adding 10-20\n"); for(i=20; i>=10; i--) { user = (example_user_t*)malloc(sizeof(example_user_t)); if (user == NULL) { exit(-1); } user->id = i; user->cookie = i*i; HASH_ADD_INT(users,id,user); } for(user=users; user != NULL; user=(example_user_t*)user->hh.next) { printf("user %d, cookie %d\n", user->id, user->cookie); } printf("sorting\n"); HASH_SORT(users,rev); for(user=users; user != NULL; user=(example_user_t*)user->hh.next) { printf("user %d, cookie %d\n", user->id, user->cookie); } return 0; } uthash-1.9.9.1+git20151125/tests/test18.ans000066400000000000000000000004741264051566200175760ustar00rootroot00000000000000user 0, cookie 0 user 1, cookie 1 user 2, cookie 4 user 3, cookie 9 user 4, cookie 16 user 5, cookie 25 user 6, cookie 36 user 7, cookie 49 user 8, cookie 64 user 9, cookie 81 deleting id 0 deleting id 1 deleting id 2 deleting id 3 deleting id 4 deleting id 5 deleting id 6 deleting id 7 deleting id 8 deleting id 9 uthash-1.9.9.1+git20151125/tests/test18.c000066400000000000000000000015741264051566200172410ustar00rootroot00000000000000#include "uthash.h" #include /* malloc */ #include /* printf */ typedef struct example_user_t { int id; int cookie; UT_hash_handle hh; } example_user_t; int main(int argc,char *argv[]) { int i; example_user_t *user, *users=NULL; /* create elements */ for(i=0; i<10; i++) { user = (example_user_t*)malloc(sizeof(example_user_t)); if (user == NULL) { exit(-1); } user->id = i; user->cookie = i*i; HASH_ADD_INT(users,id,user); } for(user=users; user != NULL; user=(example_user_t*)user->hh.next) { printf("user %d, cookie %d\n", user->id, user->cookie); } /* delete them all, pathologically */ while(users != NULL) { printf("deleting id %i\n", users->id); HASH_DEL(users,users); /* single head/deletee var! */ } return 0; } uthash-1.9.9.1+git20151125/tests/test19.ans000066400000000000000000000273541264051566200176050ustar00rootroot00000000000000sorting users ascending user 0 user 1 user 2 user 3 user 4 user 5 user 6 user 7 user 8 user 9 sorting altusers descending altuser 999 altuser 998 altuser 997 altuser 996 altuser 995 altuser 994 altuser 993 altuser 992 altuser 991 altuser 990 altuser 989 altuser 988 altuser 987 altuser 986 altuser 985 altuser 984 altuser 983 altuser 982 altuser 981 altuser 980 altuser 979 altuser 978 altuser 977 altuser 976 altuser 975 altuser 974 altuser 973 altuser 972 altuser 971 altuser 970 altuser 969 altuser 968 altuser 967 altuser 966 altuser 965 altuser 964 altuser 963 altuser 962 altuser 961 altuser 960 altuser 959 altuser 958 altuser 957 altuser 956 altuser 955 altuser 954 altuser 953 altuser 952 altuser 951 altuser 950 altuser 949 altuser 948 altuser 947 altuser 946 altuser 945 altuser 944 altuser 943 altuser 942 altuser 941 altuser 940 altuser 939 altuser 938 altuser 937 altuser 936 altuser 935 altuser 934 altuser 933 altuser 932 altuser 931 altuser 930 altuser 929 altuser 928 altuser 927 altuser 926 altuser 925 altuser 924 altuser 923 altuser 922 altuser 921 altuser 920 altuser 919 altuser 918 altuser 917 altuser 916 altuser 915 altuser 914 altuser 913 altuser 912 altuser 911 altuser 910 altuser 909 altuser 908 altuser 907 altuser 906 altuser 905 altuser 904 altuser 903 altuser 902 altuser 901 altuser 900 altuser 899 altuser 898 altuser 897 altuser 896 altuser 895 altuser 894 altuser 893 altuser 892 altuser 891 altuser 890 altuser 889 altuser 888 altuser 887 altuser 886 altuser 885 altuser 884 altuser 883 altuser 882 altuser 881 altuser 880 altuser 879 altuser 878 altuser 877 altuser 876 altuser 875 altuser 874 altuser 873 altuser 872 altuser 871 altuser 870 altuser 869 altuser 868 altuser 867 altuser 866 altuser 865 altuser 864 altuser 863 altuser 862 altuser 861 altuser 860 altuser 859 altuser 858 altuser 857 altuser 856 altuser 855 altuser 854 altuser 853 altuser 852 altuser 851 altuser 850 altuser 849 altuser 848 altuser 847 altuser 846 altuser 845 altuser 844 altuser 843 altuser 842 altuser 841 altuser 840 altuser 839 altuser 838 altuser 837 altuser 836 altuser 835 altuser 834 altuser 833 altuser 832 altuser 831 altuser 830 altuser 829 altuser 828 altuser 827 altuser 826 altuser 825 altuser 824 altuser 823 altuser 822 altuser 821 altuser 820 altuser 819 altuser 818 altuser 817 altuser 816 altuser 815 altuser 814 altuser 813 altuser 812 altuser 811 altuser 810 altuser 809 altuser 808 altuser 807 altuser 806 altuser 805 altuser 804 altuser 803 altuser 802 altuser 801 altuser 800 altuser 799 altuser 798 altuser 797 altuser 796 altuser 795 altuser 794 altuser 793 altuser 792 altuser 791 altuser 790 altuser 789 altuser 788 altuser 787 altuser 786 altuser 785 altuser 784 altuser 783 altuser 782 altuser 781 altuser 780 altuser 779 altuser 778 altuser 777 altuser 776 altuser 775 altuser 774 altuser 773 altuser 772 altuser 771 altuser 770 altuser 769 altuser 768 altuser 767 altuser 766 altuser 765 altuser 764 altuser 763 altuser 762 altuser 761 altuser 760 altuser 759 altuser 758 altuser 757 altuser 756 altuser 755 altuser 754 altuser 753 altuser 752 altuser 751 altuser 750 altuser 749 altuser 748 altuser 747 altuser 746 altuser 745 altuser 744 altuser 743 altuser 742 altuser 741 altuser 740 altuser 739 altuser 738 altuser 737 altuser 736 altuser 735 altuser 734 altuser 733 altuser 732 altuser 731 altuser 730 altuser 729 altuser 728 altuser 727 altuser 726 altuser 725 altuser 724 altuser 723 altuser 722 altuser 721 altuser 720 altuser 719 altuser 718 altuser 717 altuser 716 altuser 715 altuser 714 altuser 713 altuser 712 altuser 711 altuser 710 altuser 709 altuser 708 altuser 707 altuser 706 altuser 705 altuser 704 altuser 703 altuser 702 altuser 701 altuser 700 altuser 699 altuser 698 altuser 697 altuser 696 altuser 695 altuser 694 altuser 693 altuser 692 altuser 691 altuser 690 altuser 689 altuser 688 altuser 687 altuser 686 altuser 685 altuser 684 altuser 683 altuser 682 altuser 681 altuser 680 altuser 679 altuser 678 altuser 677 altuser 676 altuser 675 altuser 674 altuser 673 altuser 672 altuser 671 altuser 670 altuser 669 altuser 668 altuser 667 altuser 666 altuser 665 altuser 664 altuser 663 altuser 662 altuser 661 altuser 660 altuser 659 altuser 658 altuser 657 altuser 656 altuser 655 altuser 654 altuser 653 altuser 652 altuser 651 altuser 650 altuser 649 altuser 648 altuser 647 altuser 646 altuser 645 altuser 644 altuser 643 altuser 642 altuser 641 altuser 640 altuser 639 altuser 638 altuser 637 altuser 636 altuser 635 altuser 634 altuser 633 altuser 632 altuser 631 altuser 630 altuser 629 altuser 628 altuser 627 altuser 626 altuser 625 altuser 624 altuser 623 altuser 622 altuser 621 altuser 620 altuser 619 altuser 618 altuser 617 altuser 616 altuser 615 altuser 614 altuser 613 altuser 612 altuser 611 altuser 610 altuser 609 altuser 608 altuser 607 altuser 606 altuser 605 altuser 604 altuser 603 altuser 602 altuser 601 altuser 600 altuser 599 altuser 598 altuser 597 altuser 596 altuser 595 altuser 594 altuser 593 altuser 592 altuser 591 altuser 590 altuser 589 altuser 588 altuser 587 altuser 586 altuser 585 altuser 584 altuser 583 altuser 582 altuser 581 altuser 580 altuser 579 altuser 578 altuser 577 altuser 576 altuser 575 altuser 574 altuser 573 altuser 572 altuser 571 altuser 570 altuser 569 altuser 568 altuser 567 altuser 566 altuser 565 altuser 564 altuser 563 altuser 562 altuser 561 altuser 560 altuser 559 altuser 558 altuser 557 altuser 556 altuser 555 altuser 554 altuser 553 altuser 552 altuser 551 altuser 550 altuser 549 altuser 548 altuser 547 altuser 546 altuser 545 altuser 544 altuser 543 altuser 542 altuser 541 altuser 540 altuser 539 altuser 538 altuser 537 altuser 536 altuser 535 altuser 534 altuser 533 altuser 532 altuser 531 altuser 530 altuser 529 altuser 528 altuser 527 altuser 526 altuser 525 altuser 524 altuser 523 altuser 522 altuser 521 altuser 520 altuser 519 altuser 518 altuser 517 altuser 516 altuser 515 altuser 514 altuser 513 altuser 512 altuser 511 altuser 510 altuser 509 altuser 508 altuser 507 altuser 506 altuser 505 altuser 504 altuser 503 altuser 502 altuser 501 altuser 500 altuser 499 altuser 498 altuser 497 altuser 496 altuser 495 altuser 494 altuser 493 altuser 492 altuser 491 altuser 490 altuser 489 altuser 488 altuser 487 altuser 486 altuser 485 altuser 484 altuser 483 altuser 482 altuser 481 altuser 480 altuser 479 altuser 478 altuser 477 altuser 476 altuser 475 altuser 474 altuser 473 altuser 472 altuser 471 altuser 470 altuser 469 altuser 468 altuser 467 altuser 466 altuser 465 altuser 464 altuser 463 altuser 462 altuser 461 altuser 460 altuser 459 altuser 458 altuser 457 altuser 456 altuser 455 altuser 454 altuser 453 altuser 452 altuser 451 altuser 450 altuser 449 altuser 448 altuser 447 altuser 446 altuser 445 altuser 444 altuser 443 altuser 442 altuser 441 altuser 440 altuser 439 altuser 438 altuser 437 altuser 436 altuser 435 altuser 434 altuser 433 altuser 432 altuser 431 altuser 430 altuser 429 altuser 428 altuser 427 altuser 426 altuser 425 altuser 424 altuser 423 altuser 422 altuser 421 altuser 420 altuser 419 altuser 418 altuser 417 altuser 416 altuser 415 altuser 414 altuser 413 altuser 412 altuser 411 altuser 410 altuser 409 altuser 408 altuser 407 altuser 406 altuser 405 altuser 404 altuser 403 altuser 402 altuser 401 altuser 400 altuser 399 altuser 398 altuser 397 altuser 396 altuser 395 altuser 394 altuser 393 altuser 392 altuser 391 altuser 390 altuser 389 altuser 388 altuser 387 altuser 386 altuser 385 altuser 384 altuser 383 altuser 382 altuser 381 altuser 380 altuser 379 altuser 378 altuser 377 altuser 376 altuser 375 altuser 374 altuser 373 altuser 372 altuser 371 altuser 370 altuser 369 altuser 368 altuser 367 altuser 366 altuser 365 altuser 364 altuser 363 altuser 362 altuser 361 altuser 360 altuser 359 altuser 358 altuser 357 altuser 356 altuser 355 altuser 354 altuser 353 altuser 352 altuser 351 altuser 350 altuser 349 altuser 348 altuser 347 altuser 346 altuser 345 altuser 344 altuser 343 altuser 342 altuser 341 altuser 340 altuser 339 altuser 338 altuser 337 altuser 336 altuser 335 altuser 334 altuser 333 altuser 332 altuser 331 altuser 330 altuser 329 altuser 328 altuser 327 altuser 326 altuser 325 altuser 324 altuser 323 altuser 322 altuser 321 altuser 320 altuser 319 altuser 318 altuser 317 altuser 316 altuser 315 altuser 314 altuser 313 altuser 312 altuser 311 altuser 310 altuser 309 altuser 308 altuser 307 altuser 306 altuser 305 altuser 304 altuser 303 altuser 302 altuser 301 altuser 300 altuser 299 altuser 298 altuser 297 altuser 296 altuser 295 altuser 294 altuser 293 altuser 292 altuser 291 altuser 290 altuser 289 altuser 288 altuser 287 altuser 286 altuser 285 altuser 284 altuser 283 altuser 282 altuser 281 altuser 280 altuser 279 altuser 278 altuser 277 altuser 276 altuser 275 altuser 274 altuser 273 altuser 272 altuser 271 altuser 270 altuser 269 altuser 268 altuser 267 altuser 266 altuser 265 altuser 264 altuser 263 altuser 262 altuser 261 altuser 260 altuser 259 altuser 258 altuser 257 altuser 256 altuser 255 altuser 254 altuser 253 altuser 252 altuser 251 altuser 250 altuser 249 altuser 248 altuser 247 altuser 246 altuser 245 altuser 244 altuser 243 altuser 242 altuser 241 altuser 240 altuser 239 altuser 238 altuser 237 altuser 236 altuser 235 altuser 234 altuser 233 altuser 232 altuser 231 altuser 230 altuser 229 altuser 228 altuser 227 altuser 226 altuser 225 altuser 224 altuser 223 altuser 222 altuser 221 altuser 220 altuser 219 altuser 218 altuser 217 altuser 216 altuser 215 altuser 214 altuser 213 altuser 212 altuser 211 altuser 210 altuser 209 altuser 208 altuser 207 altuser 206 altuser 205 altuser 204 altuser 203 altuser 202 altuser 201 altuser 200 altuser 199 altuser 198 altuser 197 altuser 196 altuser 195 altuser 194 altuser 193 altuser 192 altuser 191 altuser 190 altuser 189 altuser 188 altuser 187 altuser 186 altuser 185 altuser 184 altuser 183 altuser 182 altuser 181 altuser 180 altuser 179 altuser 178 altuser 177 altuser 176 altuser 175 altuser 174 altuser 173 altuser 172 altuser 171 altuser 170 altuser 169 altuser 168 altuser 167 altuser 166 altuser 165 altuser 164 altuser 163 altuser 162 altuser 161 altuser 160 altuser 159 altuser 158 altuser 157 altuser 156 altuser 155 altuser 154 altuser 153 altuser 152 altuser 151 altuser 150 altuser 149 altuser 148 altuser 147 altuser 146 altuser 145 altuser 144 altuser 143 altuser 142 altuser 141 altuser 140 altuser 139 altuser 138 altuser 137 altuser 136 altuser 135 altuser 134 altuser 133 altuser 132 altuser 131 altuser 130 altuser 129 altuser 128 altuser 127 altuser 126 altuser 125 altuser 124 altuser 123 altuser 122 altuser 121 altuser 120 altuser 119 altuser 118 altuser 117 altuser 116 altuser 115 altuser 114 altuser 113 altuser 112 altuser 111 altuser 110 altuser 109 altuser 108 altuser 107 altuser 106 altuser 105 altuser 104 altuser 103 altuser 102 altuser 101 altuser 100 altuser 99 altuser 98 altuser 97 altuser 96 altuser 95 altuser 94 altuser 93 altuser 92 altuser 91 altuser 90 altuser 89 altuser 88 altuser 87 altuser 86 altuser 85 altuser 84 altuser 83 altuser 82 altuser 81 altuser 80 altuser 79 altuser 78 altuser 77 altuser 76 altuser 75 altuser 74 altuser 73 altuser 72 altuser 71 altuser 70 altuser 69 altuser 68 altuser 67 altuser 66 altuser 65 altuser 64 altuser 63 altuser 62 altuser 61 altuser 60 altuser 59 altuser 58 altuser 57 altuser 56 altuser 55 altuser 54 altuser 53 altuser 52 altuser 51 altuser 50 altuser 49 altuser 48 altuser 47 altuser 46 altuser 45 altuser 44 altuser 43 altuser 42 altuser 41 altuser 40 altuser 39 altuser 38 altuser 37 altuser 36 altuser 35 altuser 34 altuser 33 altuser 32 altuser 31 altuser 30 altuser 29 altuser 28 altuser 27 altuser 26 altuser 25 altuser 24 altuser 23 altuser 22 altuser 21 altuser 20 altuser 19 altuser 18 altuser 17 altuser 16 altuser 15 altuser 14 altuser 13 altuser 12 altuser 11 altuser 10 altuser 9 altuser 8 altuser 7 altuser 6 altuser 5 altuser 4 altuser 3 altuser 2 altuser 1 altuser 0 uthash-1.9.9.1+git20151125/tests/test19.c000066400000000000000000000031361264051566200172360ustar00rootroot00000000000000#include "uthash.h" #include /* malloc */ #include /* printf */ typedef struct example_user_t { int id; int cookie; UT_hash_handle hh; UT_hash_handle alth; } example_user_t; static int ascending_sort(void *_a, void *_b) { example_user_t *a = (example_user_t*)_a; example_user_t *b = (example_user_t*)_b; if (a->id == b->id) { return 0; } return (a->id < b->id) ? -1 : 1; } static int descending_sort(void *_a, void *_b) { example_user_t *a = (example_user_t*)_a; example_user_t *b = (example_user_t*)_b; if (a->id == b->id) { return 0; } return (a->id < b->id) ? 1 : -1; } int main(int argc,char *argv[]) { int i; example_user_t *user, *users=NULL, *altusers=NULL; /* create elements */ for(i=0; i<1000; i++) { user = (example_user_t*)malloc(sizeof(example_user_t)); if (user == NULL) { exit(-1); } user->id = i; user->cookie = i*i; if (i<10) { HASH_ADD_INT(users,id,user); } HASH_ADD(alth,altusers,id,sizeof(int),user); } printf("sorting users ascending\n"); HASH_SRT(hh,users,ascending_sort); for(user=users; user!=NULL; user=(example_user_t*)user->hh.next) { printf("user %d\n", user->id); } printf("sorting altusers descending\n"); HASH_SRT(alth,altusers,descending_sort); for(user=altusers; user!=NULL; user=(example_user_t*)user->alth.next) { printf("altuser %d\n", user->id); } /* HASH_FSCK(hh,users); */ /* HASH_FSCK(alth,altusers); */ return 0; } uthash-1.9.9.1+git20151125/tests/test2.ans000066400000000000000000000002051264051566200174770ustar00rootroot00000000000000user id 0 found, cookie 0 user id 2 found, cookie 4 user id 4 found, cookie 16 user id 6 found, cookie 36 user id 8 found, cookie 64 uthash-1.9.9.1+git20151125/tests/test2.c000066400000000000000000000015401264051566200171430ustar00rootroot00000000000000#include "uthash.h" #include #include /* malloc */ #include /* printf */ typedef struct example_user_t { int id; int cookie; UT_hash_handle hh; } example_user_t; int main(int argc,char *argv[]) { int i; example_user_t *user, *tmp, *users=NULL; /* create elements */ for(i=0; i<10; i++) { user = (example_user_t*)malloc(sizeof(example_user_t)); if (user == NULL) { exit(-1); } user->id = i; user->cookie = i*i; HASH_ADD_INT(users,id,user); } /* find each even ID */ for(i=0; i<10; i+=2) { HASH_FIND_INT(users,&i,tmp); if (tmp != NULL) { printf("user id %d found, cookie %d\n", tmp->id, tmp->cookie); } else { printf("user id %d not found\n", i); } } return 0; } uthash-1.9.9.1+git20151125/tests/test20.ans000066400000000000000000000000061264051566200175560ustar00rootroot00000000000000found uthash-1.9.9.1+git20151125/tests/test20.c000066400000000000000000000015171264051566200172270ustar00rootroot00000000000000#include /* memcpy */ #include /* malloc */ #include /* printf */ #include "uthash.h" struct my_struct { char bkey[5]; /* "binary" key */ int data; UT_hash_handle hh; }; int main(int argc, char *argv[]) { struct my_struct *s, *t, *bins = NULL; char binary[5] = {'\3','\1','\4','\1','\6'}; /* allocate our structure. initialize to some values */ s = (struct my_struct*)calloc(1UL,sizeof(struct my_struct)); if (s == NULL) { exit(-1); } memcpy(s->bkey, binary, sizeof(binary)); /* add to hash table using general macro */ HASH_ADD( hh, bins, bkey, sizeof(binary), s); /* look up the structure we just added */ HASH_FIND( hh, bins, binary, sizeof(binary), t ); if (t != NULL) { printf("found\n"); } return 0; } uthash-1.9.9.1+git20151125/tests/test21.ans000066400000000000000000000000121264051566200175540ustar00rootroot00000000000000found a 1 uthash-1.9.9.1+git20151125/tests/test21.c000066400000000000000000000015231264051566200172250ustar00rootroot00000000000000#include #include #include "uthash.h" typedef struct { char a; int b; } record_key_t; typedef struct { record_key_t key; /* ... other data ... */ UT_hash_handle hh; } record_t; int main(int argc, char *argv[]) { record_t l, *p, *r, *tmp, *records = NULL; r = (record_t*)malloc( sizeof(record_t) ); if (r == NULL) { exit(-1); } memset(r, 0, sizeof(record_t)); r->key.a = 'a'; r->key.b = 1; HASH_ADD(hh, records, key, sizeof(record_key_t), r); memset(&l, 0, sizeof(record_t)); l.key.a = 'a'; l.key.b = 1; HASH_FIND(hh, records, &l.key, sizeof(record_key_t), p); if (p != NULL) { printf("found %c %d\n", p->key.a, p->key.b); } HASH_ITER(hh, records, p, tmp) { HASH_DEL(records, p); free(p); } return 0; } uthash-1.9.9.1+git20151125/tests/test22.ans000066400000000000000000000000071264051566200175610ustar00rootroot00000000000000found uthash-1.9.9.1+git20151125/tests/test22.c000066400000000000000000000036401264051566200172300ustar00rootroot00000000000000#include /* malloc */ #include /* offsetof */ #include /* printf */ #include /* memset */ #include "uthash.h" #define UTF32 '\x1' typedef struct { UT_hash_handle hh; size_t len; char encoding; /* these two fields */ int text[]; /* comprise the key */ } msg_t; typedef struct { char encoding; int text[]; } lookup_key_t; int main(int argc, char *argv[]) { unsigned keylen; msg_t *msg, *tmp, *msgs = NULL; lookup_key_t *lookup_key; int beijing[] = {0x5317, 0x4eac}; /* UTF-32LE for 北京 */ /* allocate and initialize our structure */ msg = (msg_t*)malloc( sizeof(msg_t) + sizeof(beijing) ); if (msg == NULL) { exit(-1); } memset(msg, 0, sizeof(msg_t)+sizeof(beijing)); /* zero fill */ msg->len = sizeof(beijing); msg->encoding = UTF32; memcpy(msg->text, beijing, sizeof(beijing)); /* calculate the key length including padding, using formula */ keylen = offsetof(msg_t, text) /* offset of last key field */ + sizeof(beijing) /* size of last key field */ - offsetof(msg_t, encoding); /* offset of first key field */ /* add our structure to the hash table */ HASH_ADD( hh, msgs, encoding, keylen, msg); /* look it up to prove that it worked :-) */ msg=NULL; lookup_key = (lookup_key_t*)malloc(sizeof(*lookup_key) + sizeof(beijing)); if (lookup_key == NULL) { exit(-1); } 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 ); if (msg != NULL) { printf("found \n"); } free(lookup_key); HASH_ITER(hh, msgs, msg, tmp) { HASH_DEL(msgs, msg); free(msg); } return 0; } uthash-1.9.9.1+git20151125/tests/test23.ans000066400000000000000000000001171264051566200175640ustar00rootroot00000000000000found 12345 found 6789 found 98765 deleting 12345 deleting 6789 deleting 98765 uthash-1.9.9.1+git20151125/tests/test23.c000066400000000000000000000024061264051566200172300ustar00rootroot00000000000000#include #include #include "uthash.h" typedef struct { int key; int data; UT_hash_handle hh; } item; int main() { item *i, *j, *items=NULL; int k; /* first item */ k = 12345; i = (item*)malloc(sizeof(item)); if (i == NULL) { exit(-1); } i->key = k; i->data = 0; HASH_ADD_INT(items,key,i); /* second item */ k = 6789; i = (item*)malloc(sizeof(item)); if (i == NULL) { exit(-1); } i->key = k; i->data = 0; HASH_ADD_INT(items,key,i); /* third item */ k = 98765; i = (item*)malloc(sizeof(item)); if (i == NULL) { exit(-1); } i->key = k; i->data = 0; HASH_ADD_INT(items,key,i); /* look them all up */ k = 12345; HASH_FIND_INT(items, &k, j); if (j != NULL) { printf("found %d\n",k); } k = 6789; HASH_FIND_INT(items, &k, j); if (j != NULL) { printf("found %d\n",k); } k = 98765; HASH_FIND_INT(items, &k, j); if (j != NULL) { printf("found %d\n",k); } /* delete them not the way we prefer but it works */ for(j=items; j != NULL; j=(item*)j->hh.next) { printf("deleting %d\n", j->key); HASH_DEL(items,j); } return 0; } uthash-1.9.9.1+git20151125/tests/test24.ans000066400000000000000000000000271264051566200175650ustar00rootroot00000000000000hash contains 10 items uthash-1.9.9.1+git20151125/tests/test24.c000066400000000000000000000011571264051566200172330ustar00rootroot00000000000000#include "uthash.h" #include /* malloc */ #include /* printf */ typedef struct example_user_t { int id; int cookie; UT_hash_handle hh; } example_user_t; int main(int argc,char *argv[]) { int i; example_user_t *user, *users=NULL; /* create elements */ for(i=0; i<10; i++) { user = (example_user_t*)malloc(sizeof(example_user_t)); if (user == NULL) { exit(-1); } user->id = i; user->cookie = i*i; HASH_ADD_INT(users,id,user); } printf("hash contains %u items\n", HASH_COUNT(users)); return 0; } uthash-1.9.9.1+git20151125/tests/test25.ans000066400000000000000000000004721264051566200175720ustar00rootroot00000000000000CDL macros c b a count = 3 advancing head pointer b a c b a c b a c b a c b b c a b c a b c a b deleting b a c deleting (a) c deleting (c) DL macros a b c count = 3 deleting tail c a b deleting head a b deleting head b LL macros a b c count = 3 deleting tail c a b deleting head a b deleting head b uthash-1.9.9.1+git20151125/tests/test25.c000066400000000000000000000055231264051566200172350ustar00rootroot00000000000000#include #include "utlist.h" typedef struct el { int id; struct el *next, *prev; } el; int main(int argc, char *argv[]) { int i; int count; el els[10], *e; el *head = NULL; for(i=0; i<10; i++) { els[i].id=(int)'a'+i; } /* test CDL macros */ printf("CDL macros\n"); CDL_PREPEND(head,&els[0]); CDL_PREPEND(head,&els[1]); CDL_PREPEND(head,&els[2]); CDL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); CDL_COUNT(head,e, count); printf("count = %d\n", count); /* point head to head->next */ printf("advancing head pointer\n"); head = head->next; CDL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); /* follow circular loop a few times */ for(i=0,e=head; e && i<10; i++,e=e->next) { printf("%c ", e->id); } printf("\n"); /* follow circular loop backwards a few times */ for(i=0,e=head; e && i<10; i++,e=e->prev) { printf("%c ", e->id); } printf("\n"); printf("deleting b\n"); CDL_DELETE(head,&els[1]); CDL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); printf("deleting (a)\n"); CDL_DELETE(head,&els[0]); CDL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); printf("deleting (c)\n"); CDL_DELETE(head,&els[2]); CDL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); /* test DL macros */ printf("DL macros\n"); DL_APPEND(head,&els[0]); DL_APPEND(head,&els[1]); DL_APPEND(head,&els[2]); DL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); DL_COUNT(head,e, count); printf("count = %d\n", count); printf("deleting tail c\n"); DL_DELETE(head,&els[2]); DL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); printf("deleting head a\n"); DL_DELETE(head,&els[0]); DL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); printf("deleting head b\n"); DL_DELETE(head,&els[1]); DL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); /* test LL macros */ printf("LL macros\n"); LL_APPEND(head,&els[0]); LL_APPEND(head,&els[1]); LL_APPEND(head,&els[2]); LL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); LL_COUNT(head,e,count); printf("count = %d\n", count); printf("deleting tail c\n"); LL_DELETE(head,&els[2]); LL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); printf("deleting head a\n"); LL_DELETE(head,&els[0]); LL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); printf("deleting head b\n"); LL_DELETE(head,&els[1]); LL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); return 0; } uthash-1.9.9.1+git20151125/tests/test26.ans000066400000000000000000000005451264051566200175740ustar00rootroot00000000000000ADRIAN ARNOLDO CARROLL CARY CHONG CLIFTON CODY COLTON CORNELL DAMON DANNIE DARIO DONN DOUG DOUGLAS FREDERICK FRITZ GERALD GUS HARVEY IRVING ISAIAH JARVIS JOHN KENTON LAURENCE LESTER LINCOLN LOWELL NELSON NEVILLE NIGEL NORMAND ODIS OMAR ORLANDO RAYMUNDO REX ROLANDO RON SHANE TONEY TRINIDAD WALTER WARNER WARREN WES WILLARD WILLIAM WINFRED XAVIER found WES uthash-1.9.9.1+git20151125/tests/test26.c000066400000000000000000000023341264051566200172330ustar00rootroot00000000000000#include #include #include #include "utlist.h" #define BUFLEN 20 typedef struct el { char bname[BUFLEN]; struct el *next, *prev; } el; static int namecmp(void *_a, void *_b) { el *a = (el*)_a; el *b = (el*)_b; return strcmp(a->bname,b->bname); } int main(int argc, char *argv[]) { el *name, *elt, *tmp, etmp; el *head = NULL; /* important- initialize to NULL! */ char linebuf[BUFLEN]; FILE *file; file = fopen( "test11.dat", "r" ); if (file == NULL) { perror("can't open: "); exit(-1); } while (fgets(linebuf,BUFLEN,file) != NULL) { name = (el*)malloc(sizeof(el)); if (name == NULL) { exit(-1); } strncpy(name->bname,linebuf,sizeof(name->bname)); DL_APPEND(head, name); } DL_SORT(head, namecmp); DL_FOREACH(head,elt) { printf("%s", elt->bname); } memcpy(etmp.bname, "WES\n", 5UL); DL_SEARCH(head,elt,&etmp,namecmp); if (elt != NULL) { printf("found %s\n", elt->bname); } /* now delete each element, use the safe iterator */ DL_FOREACH_SAFE(head,elt,tmp) { DL_DELETE(head,elt); } fclose(file); return 0; } uthash-1.9.9.1+git20151125/tests/test27.ans000066400000000000000000000004141264051566200175700ustar00rootroot00000000000000CDL macros c b a advancing head pointer b a c b a c b a c b a c b b c a b c a b c a b deleting b a c deleting head (a) c deleting new head (c) DL macros c b a deleting c b a deleting a b deleting b LL macros c b a deleting c b a deleting a b deleting b uthash-1.9.9.1+git20151125/tests/test27.c000066400000000000000000000051711264051566200172360ustar00rootroot00000000000000#include #include "utlist.h" typedef struct el { int id; struct el *next, *prev; } el; int main(int argc, char *argv[]) { int i; el els[10], *e; el *head = NULL; for(i=0; i<10; i++) { els[i].id=(int)'a'+i; } /* test CDL macros */ printf("CDL macros\n"); CDL_PREPEND(head,&els[0]); CDL_PREPEND(head,&els[1]); CDL_PREPEND(head,&els[2]); CDL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); /* point head to head->next */ printf("advancing head pointer\n"); head = head->next; CDL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); /* follow circular loop a few times */ for(i=0,e=head; e && i<10; i++,e=e->next) { printf("%c ", e->id); } printf("\n"); /* follow circular loop backwards a few times */ for(i=0,e=head; e && i<10; i++,e=e->prev) { printf("%c ", e->id); } printf("\n"); printf("deleting b\n"); CDL_DELETE(head,&els[1]); CDL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); printf("deleting head (a)\n"); CDL_DELETE(head,&els[0]); CDL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); printf("deleting new head (c)\n"); CDL_DELETE(head,&els[2]); CDL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); /* test DL macros */ printf("DL macros\n"); DL_PREPEND(head,&els[0]); DL_PREPEND(head,&els[1]); DL_PREPEND(head,&els[2]); DL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); printf("deleting c\n"); DL_DELETE(head,&els[2]); DL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); printf("deleting a\n"); DL_DELETE(head,&els[0]); DL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); printf("deleting b\n"); DL_DELETE(head,&els[1]); DL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); /* test LL macros */ printf("LL macros\n"); LL_PREPEND(head,&els[0]); LL_PREPEND(head,&els[1]); LL_PREPEND(head,&els[2]); LL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); printf("deleting c\n"); LL_DELETE(head,&els[2]); LL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); printf("deleting a\n"); LL_DELETE(head,&els[0]); LL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); printf("deleting b\n"); LL_DELETE(head,&els[1]); LL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); return 0; } uthash-1.9.9.1+git20151125/tests/test28.ans000066400000000000000000000004761264051566200176010ustar00rootroot00000000000000CDL macros d c b a advancing head pointer c b a d c b a d c b a d c b c d a b c d a b c d deleting b c a d deleting (a) c d deleting (c) d deleting (d) DL macros c b a d deleting c b a d deleting a b d deleting b d deleting d LL macros c b a d deleting c b a d deleting a b d deleting b d deleting d uthash-1.9.9.1+git20151125/tests/test28.c000066400000000000000000000061421264051566200172360ustar00rootroot00000000000000#include #include "utlist.h" typedef struct el { int id; struct el *next, *prev; } el; int main(int argc, char *argv[]) { int i; el els[10], *e; el *head = NULL; for(i=0; i<10; i++) { els[i].id=(int)'a'+i; } /* test CDL macros */ printf("CDL macros\n"); CDL_PREPEND(head,&els[0]); CDL_PREPEND(head,&els[1]); CDL_PREPEND(head,&els[2]); CDL_PREPEND(head,&els[3]); CDL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); /* point head to head->next */ printf("advancing head pointer\n"); head = head->next; CDL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); /* follow circular loop a few times */ for(i=0,e=head; e && i<10; i++,e=e->next) { printf("%c ", e->id); } printf("\n"); /* follow circular loop backwards a few times */ for(i=0,e=head; e && i<10; i++,e=e->prev) { printf("%c ", e->id); } printf("\n"); printf("deleting b\n"); CDL_DELETE(head,&els[1]); CDL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); printf("deleting (a)\n"); CDL_DELETE(head,&els[0]); CDL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); printf("deleting (c)\n"); CDL_DELETE(head,&els[2]); CDL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); printf("deleting (d)\n"); CDL_DELETE(head,&els[3]); CDL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); /* test DL macros */ printf("DL macros\n"); DL_PREPEND(head,&els[0]); DL_PREPEND(head,&els[1]); DL_PREPEND(head,&els[2]); DL_APPEND(head,&els[3]); DL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); printf("deleting c\n"); DL_DELETE(head,&els[2]); DL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); printf("deleting a\n"); DL_DELETE(head,&els[0]); DL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); printf("deleting b\n"); DL_DELETE(head,&els[1]); DL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); printf("deleting d\n"); DL_DELETE(head,&els[3]); DL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); /* test LL macros */ printf("LL macros\n"); LL_PREPEND(head,&els[0]); LL_PREPEND(head,&els[1]); LL_PREPEND(head,&els[2]); LL_APPEND(head,&els[3]); LL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); printf("deleting c\n"); LL_DELETE(head,&els[2]); LL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); printf("deleting a\n"); LL_DELETE(head,&els[0]); LL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); printf("deleting b\n"); LL_DELETE(head,&els[1]); LL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); printf("deleting d\n"); LL_DELETE(head,&els[3]); LL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); return 0; } uthash-1.9.9.1+git20151125/tests/test29.ans000066400000000000000000000013251264051566200175740ustar00rootroot00000000000000ADRIAN ARNOLDO CARROLL CARY CHONG CLIFTON CODY COLTON CORNELL DAMON DANNIE DARIO DONN DOUG DOUGLAS FREDERICK FRITZ GERALD GUS HARVEY IRVING ISAIAH JARVIS JOHN KENTON LAURENCE LESTER LINCOLN LOWELL NELSON NEVILLE NIGEL NORMAND ODIS OMAR ORLANDO RAYMUNDO REX ROLANDO RON SHANE TONEY TRINIDAD WALTER WARNER WARREN WES WILLARD WILLIAM WINFRED XAVIER deleting head ADRIAN head->prev: XAVIER ARNOLDO CARROLL CARY CHONG CLIFTON CODY COLTON CORNELL DAMON DANNIE DARIO DONN DOUG DOUGLAS FREDERICK FRITZ GERALD GUS HARVEY IRVING ISAIAH JARVIS JOHN KENTON LAURENCE LESTER LINCOLN LOWELL NELSON NEVILLE NIGEL NORMAND ODIS OMAR ORLANDO RAYMUNDO REX ROLANDO RON SHANE TONEY TRINIDAD WALTER WARNER WARREN WES WILLARD WILLIAM WINFRED XAVIER uthash-1.9.9.1+git20151125/tests/test29.c000066400000000000000000000021441264051566200172350ustar00rootroot00000000000000#include #include #include #include "utlist.h" #define BUFLEN 20 typedef struct el { char bname[BUFLEN]; struct el *next, *prev; } el; static int namecmp(void *_a, void *_b) { el *a = (el*)_a; el *b = (el*)_b; return strcmp(a->bname,b->bname); } int main(int argc, char *argv[]) { el *name, *tmp; el *head = NULL; char linebuf[BUFLEN]; FILE *file; file = fopen( "test11.dat", "r" ); if (file == NULL) { perror("can't open: "); exit(-1); } while (fgets(linebuf,BUFLEN,file) != NULL) { name = (el*)malloc(sizeof(el)); if (name == NULL) { exit(-1); } strncpy(name->bname,linebuf,sizeof(name->bname)); DL_APPEND(head, name); } DL_SORT(head, namecmp); DL_FOREACH(head,tmp) { printf("%s", tmp->bname); } /* now delete the list head */ printf("deleting head %shead->prev: %s", head->bname, head->prev->bname); DL_DELETE(head,head); DL_FOREACH(head,tmp) { printf("%s", tmp->bname); } fclose(file); return 0; } uthash-1.9.9.1+git20151125/tests/test3.ans000066400000000000000000000001301264051566200174750ustar00rootroot00000000000000user 1, cookie 1 user 3, cookie 9 user 5, cookie 25 user 7, cookie 49 user 9, cookie 81 uthash-1.9.9.1+git20151125/tests/test3.c000066400000000000000000000017471264051566200171550ustar00rootroot00000000000000#include "uthash.h" #include /* malloc */ #include /* printf */ typedef struct example_user_t { int id; int cookie; UT_hash_handle hh; } example_user_t; int main(int argc,char *argv[]) { int i; example_user_t *user, *tmp, *users=NULL; /* create elements */ for(i=0; i<10; i++) { user = (example_user_t*)malloc(sizeof(example_user_t)); if (user == NULL) { exit(-1); } user->id = i; user->cookie = i*i; HASH_ADD_INT(users,id,user); } /* delete each even ID */ for(i=0; i<10; i+=2) { HASH_FIND_INT(users,&i,tmp); if (tmp != NULL) { HASH_DEL(users,tmp); free(tmp); } else { printf("user id %d not found\n", i); } } /* show the hash */ for(user=users; user != NULL; user=(example_user_t*)(user->hh.next)) { printf("user %d, cookie %d\n", user->id, user->cookie); } return 0; } uthash-1.9.9.1+git20151125/tests/test30.ans000066400000000000000000000005321264051566200175630ustar00rootroot00000000000000ADRIAN ARNOLDO CARROLL CARY CHONG CLIFTON CODY COLTON CORNELL DAMON DANNIE DARIO DONN DOUG DOUGLAS FREDERICK FRITZ GERALD GUS HARVEY IRVING ISAIAH JARVIS JOHN KENTON LAURENCE LESTER LINCOLN LOWELL NELSON NEVILLE NIGEL NORMAND ODIS OMAR ORLANDO RAYMUNDO REX ROLANDO RON SHANE TONEY TRINIDAD WALTER WARNER WARREN WES WILLARD WILLIAM WINFRED XAVIER uthash-1.9.9.1+git20151125/tests/test30.c000066400000000000000000000016311264051566200172250ustar00rootroot00000000000000#include #include #include #include "utlist.h" #define BUFLEN 20 typedef struct el { char bname[BUFLEN]; struct el *next, *prev; } el; static int namecmp(void *_a, void *_b) { el *a = (el*)_a; el *b = (el*)_b; return strcmp(a->bname,b->bname); } int main(int argc, char *argv[]) { el *name, *tmp; el *head = NULL; char linebuf[BUFLEN]; FILE *file; file = fopen( "test11.dat", "r" ); if (file == NULL) { perror("can't open: "); exit(-1); } while (fgets(linebuf,BUFLEN,file) != NULL) { name = (el*)malloc(sizeof(el)); if (name == NULL) { exit(-1); } strncpy(name->bname,linebuf,sizeof(name->bname)); CDL_PREPEND(head, name); } CDL_SORT(head, namecmp); CDL_FOREACH(head,tmp) { printf("%s", tmp->bname); } fclose(file); return 0; } uthash-1.9.9.1+git20151125/tests/test31.ans000066400000000000000000000005321264051566200175640ustar00rootroot00000000000000ADRIAN ARNOLDO CARROLL CARY CHONG CLIFTON CODY COLTON CORNELL DAMON DANNIE DARIO DONN DOUG DOUGLAS FREDERICK FRITZ GERALD GUS HARVEY IRVING ISAIAH JARVIS JOHN KENTON LAURENCE LESTER LINCOLN LOWELL NELSON NEVILLE NIGEL NORMAND ODIS OMAR ORLANDO RAYMUNDO REX ROLANDO RON SHANE TONEY TRINIDAD WALTER WARNER WARREN WES WILLARD WILLIAM WINFRED XAVIER uthash-1.9.9.1+git20151125/tests/test31.c000066400000000000000000000016311264051566200172260ustar00rootroot00000000000000#include #include #include #include "utlist.h" #define BUFLEN 20 typedef struct el { char bname[BUFLEN]; struct el *next, *prev; } el; static int namecmp(void *_a, void *_b) { el *a = (el*)_a; el *b = (el*)_b; return strcmp(a->bname,b->bname); } int main(int argc, char *argv[]) { el *name, *tmp; el *head = NULL; char linebuf[BUFLEN]; FILE *file; file = fopen( "test11.dat", "r" ); if (file == NULL) { perror("can't open: "); exit(-1); } while (fgets(linebuf,BUFLEN,file) != NULL) { name = (el*)malloc(sizeof(el)); if (name == NULL) { exit(-1); } strncpy(name->bname,linebuf,sizeof(name->bname)); CDL_PREPEND(head, name); } CDL_SORT(head, namecmp); CDL_FOREACH(head,tmp) { printf("%s", tmp->bname); } fclose(file); return 0; } uthash-1.9.9.1+git20151125/tests/test32.ans000066400000000000000000000005321264051566200175650ustar00rootroot00000000000000ARNOLDO COLTON WES WARNER TONEY NEVILLE CHONG KENTON DARIO DANNIE ODIS TRINIDAD DONN FRITZ NORMAND NIGEL CORNELL LINCOLN RAYMUNDO WINFRED JARVIS GUS ISAIAH XAVIER CARY ROLANDO LAURENCE CARROLL IRVING LOWELL DAMON OMAR REX ORLANDO DOUG WILLARD CLIFTON NELSON CODY ADRIAN HARVEY RON LESTER SHANE WARREN FREDERICK GERALD DOUGLAS WALTER WILLIAM JOHN uthash-1.9.9.1+git20151125/tests/test32.c000066400000000000000000000015541264051566200172330ustar00rootroot00000000000000#include #include #include #include "utlist.h" #define BUFLEN 20 typedef struct el { char bname[BUFLEN]; 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; el *head = NULL; char linebuf[BUFLEN]; FILE *file; file = fopen( "test11.dat", "r" ); if (file == NULL) { perror("can't open: "); exit(-1); } while (fgets(linebuf,BUFLEN,file) != NULL) { name = (el*)malloc(sizeof(el)); if (name == NULL) { exit(-1); } strncpy(name->bname,linebuf,sizeof(name->bname)); DL_PREPEND(head, name); } /* DL_SORT(head, namecmp); */ DL_FOREACH(head,tmp) { printf("%s", tmp->bname); } fclose(file); return 0; } uthash-1.9.9.1+git20151125/tests/test33.ans000066400000000000000000000005321264051566200175660ustar00rootroot00000000000000ADRIAN ARNOLDO CARROLL CARY CHONG CLIFTON CODY COLTON CORNELL DAMON DANNIE DARIO DONN DOUG DOUGLAS FREDERICK FRITZ GERALD GUS HARVEY IRVING ISAIAH JARVIS JOHN KENTON LAURENCE LESTER LINCOLN LOWELL NELSON NEVILLE NIGEL NORMAND ODIS OMAR ORLANDO RAYMUNDO REX ROLANDO RON SHANE TONEY TRINIDAD WALTER WARNER WARREN WES WILLARD WILLIAM WINFRED XAVIER uthash-1.9.9.1+git20151125/tests/test33.c000066400000000000000000000016261264051566200172340ustar00rootroot00000000000000#include #include #include #include "utlist.h" #define BUFLEN 20 typedef struct el { char bname[BUFLEN]; struct el *next, *prev; } el; static int namecmp(void *_a, void *_b) { el *a = (el*)_a; el *b = (el*)_b; return strcmp(a->bname,b->bname); } int main(int argc, char *argv[]) { el *name, *tmp; el *head = NULL; char linebuf[BUFLEN]; FILE *file; file = fopen( "test11.dat", "r" ); if (file == NULL) { perror("can't open: "); exit(-1); } while (fgets(linebuf,BUFLEN,file) != NULL) { name = (el*)malloc(sizeof(el)); if (name == NULL) { exit(-1); } strncpy(name->bname,linebuf,sizeof(name->bname)); LL_PREPEND(head, name); } LL_SORT(head, namecmp); LL_FOREACH(head,tmp) { printf("%s", tmp->bname); } fclose(file); return 0; } uthash-1.9.9.1+git20151125/tests/test34.ans000066400000000000000000000005321264051566200175670ustar00rootroot00000000000000ARNOLDO COLTON WES WARNER TONEY NEVILLE CHONG KENTON DARIO DANNIE ODIS TRINIDAD DONN FRITZ NORMAND NIGEL CORNELL LINCOLN RAYMUNDO WINFRED JARVIS GUS ISAIAH XAVIER CARY ROLANDO LAURENCE CARROLL IRVING LOWELL DAMON OMAR REX ORLANDO DOUG WILLARD CLIFTON NELSON CODY ADRIAN HARVEY RON LESTER SHANE WARREN FREDERICK GERALD DOUGLAS WALTER WILLIAM JOHN uthash-1.9.9.1+git20151125/tests/test34.c000066400000000000000000000015571264051566200172400ustar00rootroot00000000000000#include #include #include #include "utlist.h" #define BUFLEN 20 typedef struct el { char bname[BUFLEN]; 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; el *head = NULL; char linebuf[BUFLEN]; FILE *file; file = fopen( "test11.dat", "r" ); if (file == NULL) { perror("can't open: "); exit(-1); } while (fgets(linebuf,BUFLEN,file) != NULL) { name = (el*)malloc(sizeof(el)); if (name == NULL) { exit(-1); } strncpy(name->bname,linebuf,sizeof(name->bname)); CDL_PREPEND(head, name); } /* CDL_SORT(head, namecmp); */ CDL_FOREACH(head,tmp) { printf("%s", tmp->bname); } fclose(file); return 0; } uthash-1.9.9.1+git20151125/tests/test35.ans000066400000000000000000000006201264051566200175660ustar00rootroot000000000000000: aello 1: bello 2: cello 3: dello 4: eello 5: fello 6: gello 7: hello 8: iello 9: jello found aello right address? yes found bello right address? yes found cello right address? yes found dello right address? yes found eello right address? yes found fello right address? yes found gello right address? yes found hello right address? yes found iello right address? yes found jello right address? yes uthash-1.9.9.1+git20151125/tests/test35.c000066400000000000000000000016461264051566200172400ustar00rootroot00000000000000#include "uthash.h" #include /* strcpy */ #include /* malloc */ #include /* printf */ typedef struct elt { char *s; UT_hash_handle hh; } elt; int main(int argc,char *argv[]) { int i; elt *head = NULL; elt elts[10]; char label[6]; for(i=0; i<10; i++) { elts[i].s = (char*)malloc(6UL); strncpy(elts[i].s, "hello",6UL); elts[i].s[0] = 'a' + i; printf("%d: %s\n", i, elts[i].s); HASH_ADD_KEYPTR(hh, head, elts[i].s, 6UL, &elts[i]); } /* look up each element and verify the result pointer */ strncpy(label, "hello", sizeof(label)); for(i=0; i<10; i++) { elt *e; label[0] = 'a' + i; HASH_FIND(hh,head,label,6UL,e); if (e != NULL) { printf( "found %s\n", e->s); printf( "right address? %s\n", (e == &elts[i]) ? "yes" : "no"); } } return 0; } uthash-1.9.9.1+git20151125/tests/test36.ans000066400000000000000000000001561264051566200175730ustar00rootroot00000000000000user 0 user 1 user 2 user 3 user 4 user 5 user 6 user 7 user 8 user 9 auser 0 auser 2 auser 4 auser 6 auser 8 uthash-1.9.9.1+git20151125/tests/test36.c000066400000000000000000000023051264051566200172320ustar00rootroot00000000000000#include "uthash.h" #include /* malloc */ #include /* printf */ typedef struct { int id; UT_hash_handle hh; UT_hash_handle ah; } example_user_t; #define EVENS(x) (((x)->id % 2) == 0) static int evens(void *userv) { example_user_t *user = (example_user_t*)userv; return ((user->id % 2) ? 0 : 1); } static int idcmp(void *_a, void *_b) { example_user_t *a = (example_user_t*)_a; example_user_t *b = (example_user_t*)_b; return (a->id - b->id); } int main(int argc,char *argv[]) { int i; example_user_t *user, *users=NULL, *ausers=NULL; /* create elements */ for(i=0; i<10; i++) { user = (example_user_t*)malloc(sizeof(example_user_t)); if (user == NULL) { exit(-1); } user->id = i; HASH_ADD_INT(users,id,user); } for(user=users; user!=NULL; user=(example_user_t*)(user->hh.next)) { printf("user %d\n", user->id); } /* now select some users into ausers */ HASH_SELECT(ah,ausers,hh,users,evens); HASH_SRT(ah,ausers,idcmp); for(user=ausers; user!=NULL; user=(example_user_t*)(user->ah.next)) { printf("auser %d\n", user->id); } return 0; } uthash-1.9.9.1+git20151125/tests/test37.ans000066400000000000000000000002761264051566200175770ustar00rootroot00000000000000user 0 user 1 user 2 user 3 user 4 user 5 user 6 user 7 user 8 user 9 users count: 10 auser 0 auser 2 auser 4 auser 6 auser 8 ausers count: 5 cleared ausers. ausers count: 0 users count: 10 uthash-1.9.9.1+git20151125/tests/test37.c000066400000000000000000000027521264051566200172410ustar00rootroot00000000000000#include "uthash.h" #include /* malloc */ #include /* printf */ typedef struct { int id; UT_hash_handle hh; UT_hash_handle ah; } example_user_t; #define EVENS(x) ((((example_user_t*)(x))->id % 2) == 0) static int idcmp(void *_a, void *_b) { example_user_t *a = (example_user_t*)_a; example_user_t *b = (example_user_t*)_b; return (a->id - b->id); } int main(int argc,char *argv[]) { int i; example_user_t *user, *users=NULL, *ausers=NULL; /* create elements */ for(i=0; i<10; i++) { user = (example_user_t*)malloc(sizeof(example_user_t)); if (user == NULL) { exit(-1); } user->id = i; HASH_ADD_INT(users,id,user); } for(user=users; user!=NULL; user=(example_user_t*)(user->hh.next)) { printf("user %d\n", user->id); } printf("users count: %u\n", HASH_CNT(hh,users)); /* now select some users into ausers */ HASH_SELECT(ah,ausers,hh,users,EVENS); HASH_SRT(ah,ausers,idcmp); for(user=ausers; user!=NULL; user=(example_user_t*)(user->ah.next)) { printf("auser %d\n", user->id); } printf("ausers count: %u\n", HASH_CNT(ah,ausers)); HASH_CLEAR(ah,ausers); printf("cleared ausers.\n"); printf("ausers count: %u\n", HASH_CNT(ah,ausers)); for(user=ausers; user!=NULL; user=(example_user_t*)(user->ah.next)) { printf("auser %d\n", user->id); } printf("users count: %u\n", HASH_CNT(hh,users)); return 0; } uthash-1.9.9.1+git20151125/tests/test38.ans000066400000000000000000000000161264051566200175700ustar00rootroot00000000000000hash count 10 uthash-1.9.9.1+git20151125/tests/test38.c000066400000000000000000000013541264051566200172370ustar00rootroot00000000000000#include "uthash.h" #include #include struct test_t { int a; UT_hash_handle hh; }; int main(void) { struct test_t *tests=NULL, *test; int a, b; for (b=0; b < 3; b++) { for (a=0; a < 10; a++) { test = NULL; HASH_FIND(hh, tests, &a, sizeof(a), test); if (test == NULL) { test = (struct test_t*)malloc(sizeof(struct test_t)); if (test == NULL) { exit(-1); } memset(test, 0, sizeof(struct test_t)); test->a = a; HASH_ADD(hh, tests, a, sizeof(a), test); } } } printf("hash count %u\n", HASH_COUNT(tests)); return 0; } uthash-1.9.9.1+git20151125/tests/test39.ans000066400000000000000000000002351264051566200175740ustar00rootroot00000000000000adding key eins adding key zwei adding key drei hash count is 3 looking for key eins... found. looking for key zwei... found. looking for key drei... found. uthash-1.9.9.1+git20151125/tests/test39.c000066400000000000000000000015211264051566200172340ustar00rootroot00000000000000#include #include #include "uthash.h" typedef struct { const char *name; UT_hash_handle hh; } ns_t; int main() { const char *keys[] = {"eins", "zwei", "drei"}; unsigned i; ns_t *nsp; ns_t *head = NULL; for(i=0; i < (sizeof(keys)/sizeof(keys[0])); i++) { printf("adding key %s\n", keys[i]); nsp = (ns_t*)malloc(sizeof(ns_t)); if (nsp == NULL) { exit(-1); } nsp->name = keys[i]; HASH_ADD_KEYPTR(hh,head,nsp->name,strlen(nsp->name),nsp); } printf("hash count is %u\n", HASH_COUNT(head)); for(i=0; i < (sizeof(keys)/sizeof(keys[0])); i++) { printf("looking for key %s... ", keys[i]); HASH_FIND(hh,head,keys[i],strlen(keys[i]),nsp); printf("%s.\n", (nsp!=NULL)?"found":"not found"); } return 0; } uthash-1.9.9.1+git20151125/tests/test4.ans000066400000000000000000000002601264051566200175020ustar00rootroot00000000000000cookie 0, user 0 cookie 1, user 1 cookie 4, user 2 cookie 9, user 3 cookie 16, user 4 cookie 25, user 5 cookie 36, user 6 cookie 49, user 7 cookie 64, user 8 cookie 81, user 9 uthash-1.9.9.1+git20151125/tests/test4.c000066400000000000000000000014541264051566200171510ustar00rootroot00000000000000#include "uthash.h" #include /* malloc */ #include /* printf */ typedef struct example_user_t { int id; int cookie; UT_hash_handle hh; UT_hash_handle alth; } example_user_t; int main(int argc,char *argv[]) { int i; example_user_t *user, *users=NULL, *altusers=NULL; /* create elements */ for(i=0; i<10; i++) { user = (example_user_t*)malloc(sizeof(example_user_t)); if (user == NULL) { exit(-1); } user->id = i; user->cookie = i*i; HASH_ADD_INT(users,id,user); HASH_ADD(alth,altusers,cookie,sizeof(int),user); } for(user=altusers; user != NULL; user=(example_user_t*)(user->alth.next)) { printf("cookie %d, user %d\n", user->cookie, user->id); } return 0; } uthash-1.9.9.1+git20151125/tests/test40.ans000066400000000000000000000000201264051566200175540ustar00rootroot00000000000000betty's id is 2 uthash-1.9.9.1+git20151125/tests/test40.c000066400000000000000000000016751264051566200172360ustar00rootroot00000000000000#include /* strcpy */ #include /* malloc */ #include /* printf */ #include "uthash.h" struct my_struct { const char *name; /* key */ int id; UT_hash_handle hh; /* makes this structure hashable */ }; int main(int argc, char *argv[]) { const char **n, *names[] = { "joe", "bob", "betty", NULL }; struct my_struct *s, *tmp, *users = NULL; int i=0; for (n = names; *n != NULL; n++) { s = (struct my_struct*)malloc(sizeof(struct my_struct)); if (s == NULL) { exit(-1); } s->name = *n; s->id = i++; HASH_ADD_KEYPTR( hh, users, s->name, strlen(s->name), s ); } HASH_FIND_STR( users, "betty", s); if (s != NULL) { printf("betty's id is %d\n", s->id); } /* free the hash table contents */ HASH_ITER(hh, users, s, tmp) { HASH_DEL(users, s); free(s); } return 0; } uthash-1.9.9.1+git20151125/tests/test41.ans000066400000000000000000000002271264051566200175660ustar00rootroot00000000000000CDL macros c b a deleting c deleting b deleting a DL macros a b c deleting a deleting b deleting c LL macros a b c deleting a deleting b deleting c uthash-1.9.9.1+git20151125/tests/test41.c000066400000000000000000000027441264051566200172350ustar00rootroot00000000000000#include #include "utlist.h" typedef struct el { int id; struct el *next, *prev; } el; int main(int argc, char *argv[]) { int i; el *head = NULL; el els[10], *e, *tmp, *tmp2; for(i=0; i<10; i++) { els[i].id=(int)'a'+i; } /* test CDL macros */ printf("CDL macros\n"); CDL_PREPEND(head,&els[0]); CDL_PREPEND(head,&els[1]); CDL_PREPEND(head,&els[2]); CDL_FOREACH(head,e) { printf("%c ", e->id); } /* point head to head->next */ CDL_FOREACH_SAFE(head,e,tmp,tmp2) { printf("deleting %c ", e->id); CDL_DELETE(head,e); } printf("\n"); if (head != NULL) { printf("non-null head\n"); } /* test DL macros */ printf("DL macros\n"); DL_APPEND(head,&els[0]); DL_APPEND(head,&els[1]); DL_APPEND(head,&els[2]); DL_FOREACH(head,e) { printf("%c ", e->id); } DL_FOREACH_SAFE(head,e,tmp) { printf("deleting %c ", e->id); DL_DELETE(head,e); } printf("\n"); if (head != NULL) { printf("non-null head\n"); } /* test LL macros */ printf("LL macros\n"); LL_APPEND(head,&els[0]); LL_APPEND(head,&els[1]); LL_APPEND(head,&els[2]); LL_FOREACH(head,e) { printf("%c ", e->id); } LL_FOREACH_SAFE(head,e,tmp) { printf("deleting %c ", e->id); LL_DELETE(head,e); } printf("\n"); if (head != NULL) { printf("non-null head\n"); } return 0; } uthash-1.9.9.1+git20151125/tests/test42.ans000066400000000000000000000002451264051566200175670ustar00rootroot00000000000000LL macros a b c search scalar found b search found a DL macros a b c search scalar found b search found a CDL macros c b a search scalar found b search found a uthash-1.9.9.1+git20151125/tests/test42.c000066400000000000000000000036051264051566200172330ustar00rootroot00000000000000#include #include "utlist.h" typedef struct el { int id; struct el *next, *prev; } el; static int eltcmp(el *a, el *b) { return a->id - b->id; } int main(int argc, char *argv[]) { int i; el *head = NULL; el els[10], *e, *tmp, *tmp2; for(i=0; i<10; i++) { els[i].id=(int)'a'+i; } /* test LL macros */ printf("LL macros\n"); LL_APPEND(head,&els[0]); LL_APPEND(head,&els[1]); LL_APPEND(head,&els[2]); LL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); LL_SEARCH_SCALAR(head, e, id, 'b'); if (e != NULL) { printf("search scalar found b\n"); } LL_SEARCH(head, e, &els[0], eltcmp); if (e != NULL) { printf("search found %c\n",e->id); } LL_FOREACH_SAFE(head,e,tmp) { LL_DELETE(head,e); } printf("\n"); /* test DL macros */ printf("DL macros\n"); DL_APPEND(head,&els[0]); DL_APPEND(head,&els[1]); DL_APPEND(head,&els[2]); DL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); DL_SEARCH_SCALAR(head, e, id, 'b'); if (e != NULL) { printf("search scalar found b\n"); } DL_SEARCH(head, e, &els[0], eltcmp); if (e != NULL) { printf("search found %c\n",e->id); } DL_FOREACH_SAFE(head,e,tmp) { DL_DELETE(head,e); } printf("\n"); /* test CDL macros */ printf("CDL macros\n"); CDL_PREPEND(head,&els[0]); CDL_PREPEND(head,&els[1]); CDL_PREPEND(head,&els[2]); CDL_FOREACH(head,e) { printf("%c ", e->id); } printf("\n"); CDL_SEARCH_SCALAR(head, e, id, 'b'); if (e != NULL) { printf("search scalar found b\n"); } CDL_SEARCH(head, e, &els[0], eltcmp); if (e != NULL) { printf("search found %c\n",e->id); } CDL_FOREACH_SAFE(head,e,tmp,tmp2) { CDL_DELETE(head,e); } return 0; } uthash-1.9.9.1+git20151125/tests/test43.ans000066400000000000000000000012251264051566200175670ustar00rootroot00000000000000length is 0 push length is 1 back is 1 2 pop length is 0 push push length is 2 1 2 3 4 erase [0] length is 1 3 4 push 3 4 1 2 clear length is 0 extend length is 1 ip points to [0] ? yes push 0 0 1 2 erase [1] length is 1 0 0 push 0 0 3 4 back is 3 4 copy cpy length is 2 cpy 0 0 cpy 3 4 insert cpy[0] cpy length is 3 cpy 5 6 cpy 0 0 cpy 3 4 erase cpy [0] [1] cpy length is 1 cpy 3 4 inserta at cpy[1] cpy length is 3 cpy 3 4 cpy 0 0 cpy 3 4 free cpy length is 2 resize to 30 length is 30 0 0 3 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 resize to 1 length is 1 resize to 0 length is 0 free uthash-1.9.9.1+git20151125/tests/test43.c000066400000000000000000000100461264051566200172310ustar00rootroot00000000000000#include #include "utarray.h" typedef struct { int a; int b; } intpair_t; int main() { UT_array *pairs, *pairs_cpy; intpair_t it, *ip; UT_icd pairicd = { sizeof(intpair_t),NULL,NULL,NULL}; size_t zero=0; utarray_new(pairs, &pairicd); printf("length is %u\n", utarray_len(pairs)); it.a = 1; it.b=2; utarray_push_back(pairs, &it); printf("push\n"); printf("length is %u\n", utarray_len(pairs)); ip = (intpair_t*)utarray_back(pairs); printf("back is %d %d\n", ip->a, ip->b); utarray_pop_back(pairs); printf("pop\n"); printf("length is %u\n", utarray_len(pairs)); it.a = 1; it.b=2; utarray_push_back(pairs, &it); printf("push\n"); it.a = 3; it.b=4; utarray_push_back(pairs, &it); printf("push\n"); printf("length is %u\n", utarray_len(pairs)); ip=NULL; while( (ip=(intpair_t*)utarray_next(pairs,ip)) != NULL ) { printf("%d %d\n", ip->a, ip->b); } utarray_erase(pairs,0,1); printf("erase [0]\n"); printf("length is %u\n", utarray_len(pairs)); while( (ip=(intpair_t*)utarray_next(pairs,ip)) != NULL ) { printf("%d %d\n", ip->a, ip->b); } it.a = 1; it.b=2; utarray_push_back(pairs, &it); printf("push\n"); while( (ip=(intpair_t*)utarray_next(pairs,ip)) != NULL ) { printf("%d %d\n", ip->a, ip->b); } utarray_clear(pairs); printf("clear\n"); printf("length is %u\n", utarray_len(pairs)); utarray_extend_back(pairs); printf("extend\n"); ip = (intpair_t*)utarray_back(pairs); printf("length is %u\n", utarray_len(pairs)); printf("ip points to [0] ? %s\n", (ip==(intpair_t*)utarray_front(pairs)) ? "yes" : "no"); it.a = 1; it.b=2; utarray_push_back(pairs, &it); printf("push\n"); ip=NULL; while( (ip=(intpair_t*)utarray_next(pairs,ip)) != NULL ) { printf("%d %d\n", ip->a, ip->b); } utarray_erase(pairs,1,1); printf("erase [1]\n"); printf("length is %u\n", utarray_len(pairs)); while( (ip=(intpair_t*)utarray_next(pairs,ip)) != NULL ) { printf("%d %d\n", ip->a, ip->b); } it.a = 3; it.b=4; utarray_push_back(pairs, &it); printf("push\n"); for(ip=(intpair_t*)utarray_front(pairs); ip!=NULL; ip=(intpair_t*)utarray_next(pairs,ip)) { printf("%d %d\n", ip->a,ip->b); } ip = (intpair_t*)utarray_back(pairs); printf("back is %d %d\n", ip->a, ip->b); utarray_new(pairs_cpy, &pairicd); utarray_concat(pairs_cpy, pairs); printf("copy\n"); printf("cpy length is %u\n", utarray_len(pairs_cpy)); ip=NULL; while( (ip=(intpair_t*)utarray_next(pairs_cpy,ip)) != NULL ) { printf("cpy %d %d\n", ip->a, ip->b); } it.a=5; it.b=6; utarray_insert(pairs_cpy, &it, 0); printf("insert cpy[0]\n"); printf("cpy length is %u\n", utarray_len(pairs_cpy)); while( (ip=(intpair_t*)utarray_next(pairs_cpy,ip)) != NULL ) { printf("cpy %d %d\n", ip->a, ip->b); } utarray_erase(pairs_cpy,0,2); printf("erase cpy [0] [1]\n"); printf("cpy length is %u\n", utarray_len(pairs_cpy)); while( (ip=(intpair_t*)utarray_next(pairs_cpy,ip)) != NULL ) { printf("cpy %d %d\n", ip->a, ip->b); } utarray_inserta(pairs_cpy, pairs, 1); printf("inserta at cpy[1]\n"); printf("cpy length is %u\n", utarray_len(pairs_cpy)); while( (ip=(intpair_t*)utarray_next(pairs_cpy,ip)) != NULL ) { printf("cpy %d %d\n", ip->a, ip->b); } utarray_free(pairs_cpy); printf("free cpy\n"); printf("length is %u\n", utarray_len(pairs)); utarray_resize(pairs, 30); printf("resize to 30\n"); printf("length is %u\n", utarray_len(pairs)); while( (ip=(intpair_t*)utarray_next(pairs,ip)) != NULL ) { printf("%d %d\n", ip->a, ip->b); } utarray_resize(pairs, 1); printf("resize to 1\n"); printf("length is %u\n", utarray_len(pairs)); utarray_resize(pairs, zero); printf("resize to 0\n"); printf("length is %u\n", utarray_len(pairs)); utarray_free(pairs); printf("free\n"); return 0; } uthash-1.9.9.1+git20151125/tests/test44.ans000066400000000000000000000001471264051566200175720ustar00rootroot000000000000000 1 2 3 4 5 6 7 8 9 9 8 7 6 5 4 3 2 1 0 9 8 7 3 2 1 0 9 3 2 1 0 3 2 1 0 3 2 1 3 2 1 0 0 3 2 1 uthash-1.9.9.1+git20151125/tests/test44.c000066400000000000000000000027271264051566200172410ustar00rootroot00000000000000#include #include "utarray.h" static int reverse(const void *a,const void*b) { int _a = *(int*)a; int _b = *(int*)b; return _b - _a; } int main() { UT_array *a; int i, *p; utarray_new(a, &ut_int_icd); for(i=0; i<10; i++) { utarray_push_back(a,&i); } for(p=(int*)utarray_front(a); p!=NULL; p=(int*)utarray_next(a,p)) { printf("%d ",*p); } printf("\n"); utarray_sort(a,reverse); while ( (p=(int*)utarray_next(a,p)) != NULL ) { printf("%d ", *p); } printf("\n"); utarray_erase(a,3,3); while ( (p=(int*)utarray_next(a,p)) != NULL ) { printf("%d ", *p); } printf("\n"); utarray_erase(a,1,2); while ( (p=(int*)utarray_next(a,p)) != NULL ) { printf("%d ", *p); } printf("\n"); utarray_erase(a,0,1); while ( (p=(int*)utarray_next(a,p)) != NULL ) { printf("%d ", *p); } printf("\n"); utarray_erase(a,3,1); while ( (p=(int*)utarray_next(a,p)) != NULL ) { printf("%d ", *p); } printf("\n"); utarray_resize(a,5); while ( (p=(int*)utarray_next(a,p)) != NULL ) { printf("%d ", *p); } printf("\n"); utarray_resize(a,3); while ( (p=(int*)utarray_next(a,p)) != NULL ) { printf("%d ", *p); } printf("\n"); utarray_erase(a,0,3); while ( (p=(int*)utarray_next(a,p)) != NULL ) { printf("%d ", *p); } printf("\n"); utarray_free(a); return 0; } uthash-1.9.9.1+git20151125/tests/test45.ans000066400000000000000000000001001264051566200175600ustar00rootroot000000000000001 2 3 4 5 6 7 8 1 2 3 100 4 5 6 7 8 1 2 3 100 4 5 6 7 8 1000 uthash-1.9.9.1+git20151125/tests/test45.c000066400000000000000000000013371264051566200172360ustar00rootroot00000000000000#include #include "utarray.h" int main() { UT_array *a; int i, *p=NULL; utarray_new(a, &ut_int_icd); for(i=0; i<10; i++) { utarray_push_back(a,&i); } utarray_pop_back(a); utarray_erase(a,0,1); while ( (p=(int*)utarray_next(a,p)) != NULL ) { printf("%d ",*p); } printf("\n"); i = 100; utarray_insert(a,&i,3); while ( (p=(int*)utarray_next(a,p)) != NULL ) { printf("%d ",*p); } printf("\n"); utarray_extend_back(a); p = (int*)utarray_back(a); *p = 1000; p = NULL; while ( (p=(int*)utarray_next(a,p)) != NULL ) { printf("%d ",*p); } printf("\n"); utarray_clear(a); utarray_free(a); return 0; } uthash-1.9.9.1+git20151125/tests/test46.ans000066400000000000000000000003251264051566200175720ustar00rootroot00000000000000hello world begin hello world alt begin hello world oth hello world oth hello world hello world begin hello world begin hello world sorting strs2 begin hello world reverse sorting strs2 world hello begin uthash-1.9.9.1+git20151125/tests/test46.c000066400000000000000000000040221264051566200172310ustar00rootroot00000000000000#include #include "utarray.h" static int strsort(const void *_a, const void *_b) { char *a = *(char**)_a; char *b = *(char**)_b; return strcmp(a,b); } static int revsort(const void *_a, const void *_b) { char *a = *(char**)_a; char *b = *(char**)_b; return strcmp(b,a); } int main() { UT_array *strs,*strs2; char *s, **p=NULL; utarray_new(strs, &ut_str_icd); s="hello"; utarray_push_back(strs, &s); s="world"; utarray_push_back(strs, &s); while ( (p=(char**)utarray_next(strs,p)) != NULL ) { printf("%s ",*p); } printf("\n"); s="begin"; utarray_insert(strs,&s,0); while ( (p=(char**)utarray_next(strs,p)) != NULL ) { printf("%s ",*p); } printf("\n"); utarray_new(strs2, &ut_str_icd); s="alt"; utarray_push_back(strs2, &s); s="oth"; utarray_push_back(strs2, &s); utarray_inserta(strs2, strs, 1); while ( (p=(char**)utarray_next(strs2,p)) != NULL ) { printf("%s ",*p); } printf("\n"); utarray_erase(strs2,0,2); while ( (p=(char**)utarray_next(strs2,p)) != NULL ) { printf("%s ",*p); } printf("\n"); utarray_pop_back(strs2); while ( (p=(char**)utarray_next(strs2,p)) != NULL ) { printf("%s ",*p); } printf("\n"); utarray_concat(strs2, strs); while ( (p=(char**)utarray_next(strs2,p)) != NULL ) { printf("%s ",*p); } printf("\n"); utarray_clear(strs2); utarray_concat(strs2, strs); while ( (p=(char**)utarray_next(strs2,p)) != NULL ) { printf("%s ",*p); } printf("\n"); printf("sorting strs2\n"); utarray_sort(strs2,strsort); while ( (p=(char**)utarray_next(strs2,p)) != NULL ) { printf("%s ",*p); } printf("\n"); printf("reverse sorting strs2\n"); utarray_sort(strs2,revsort); while ( (p=(char**)utarray_next(strs2,p)) != NULL ) { printf("%s ",*p); } printf("\n"); utarray_clear(strs2); utarray_free(strs2); utarray_free(strs); return 0; } uthash-1.9.9.1+git20151125/tests/test47.ans000066400000000000000000000002161264051566200175720ustar00rootroot00000000000000hello world hello world text second hello world text second cleared, length t now: 0 length s now: 23 one 1 two 2 three (3) length t now: 21 uthash-1.9.9.1+git20151125/tests/test47.c000066400000000000000000000014371264051566200172410ustar00rootroot00000000000000#include /* printf */ #include "utstring.h" int main() { UT_string *s,*t; char a[] = " text"; utstring_new(s); utstring_new(t); utstring_printf(s,"hello %s", "world"); printf("%s\n", utstring_body(s)); utstring_bincpy(s,a,sizeof(a)-1); printf("%s\n", utstring_body(s)); utstring_printf(t," second"); printf("%s\n", utstring_body(t)); utstring_concat(s,t); printf("%s\n", utstring_body(s)); utstring_clear(t); printf("cleared, length t now: %u\n", utstring_len(t)); printf("length s now: %u\n", utstring_len(s)); utstring_printf(t,"one %d two %u three %s", 1, 2, "(3)"); printf("%s\n", utstring_body(t)); printf("length t now: %u\n", utstring_len(t)); utstring_free(t); utstring_free(s); return 0; } uthash-1.9.9.1+git20151125/tests/test48.ans000066400000000000000000000000241264051566200175700ustar00rootroot000000000000000 1 2 3 4 5 6 7 8 9 uthash-1.9.9.1+git20151125/tests/test48.c000066400000000000000000000005651264051566200172430ustar00rootroot00000000000000#include #include "utarray.h" int main() { UT_array *nums; int i, *p; utarray_new(nums,&ut_int_icd); for(i=0; i < 10; i++) { utarray_push_back(nums,&i); } for(p=(int*)utarray_front(nums); p!=NULL; p=(int*)utarray_next(nums,p)) { printf("%d\n",*p); } utarray_free(nums); return 0; } uthash-1.9.9.1+git20151125/tests/test49.ans000066400000000000000000000000141264051566200175700ustar00rootroot00000000000000hello world uthash-1.9.9.1+git20151125/tests/test49.c000066400000000000000000000005671264051566200172460ustar00rootroot00000000000000#include #include "utarray.h" int main() { UT_array *strs; char *s, **p; utarray_new(strs,&ut_str_icd); s = "hello"; utarray_push_back(strs, &s); s = "world"; utarray_push_back(strs, &s); p = NULL; while ( (p=(char**)utarray_next(strs,p)) != NULL ) { printf("%s\n",*p); } utarray_free(strs); return 0; } uthash-1.9.9.1+git20151125/tests/test5.ans000066400000000000000000000002051264051566200175020ustar00rootroot00000000000000cookie 0 found, user id 0 cookie 4 found, user id 2 cookie 16 found, user id 4 cookie 36 found, user id 6 cookie 64 found, user id 8 uthash-1.9.9.1+git20151125/tests/test5.c000066400000000000000000000017501264051566200171510ustar00rootroot00000000000000#include "uthash.h" #include /* malloc */ #include /* printf */ typedef struct example_user_t { int id; int cookie; UT_hash_handle hh; UT_hash_handle alth; } example_user_t; int main(int argc,char *argv[]) { int i,j; example_user_t *user, *tmp, *users=NULL, *altusers=NULL; /* create elements */ for(i=0; i<10; i++) { user = (example_user_t*)malloc(sizeof(example_user_t)); if (user == NULL) { exit(-1); } user->id = i; user->cookie = i*i; HASH_ADD_INT(users,id,user); HASH_ADD(alth,altusers,cookie,sizeof(int),user); } /* find cookie corresponding to each even ID */ for(i=0; i<10; i+=2) { j=i*i; HASH_FIND(alth,altusers,&j,sizeof(int),tmp); if (tmp != NULL) { printf("cookie %d found, user id %d\n", tmp->cookie, tmp->id); } else { printf("cookie %d not found\n", j); } } return 0; } uthash-1.9.9.1+git20151125/tests/test50.ans000066400000000000000000000000041264051566200175570ustar00rootroot000000000000001 2 uthash-1.9.9.1+git20151125/tests/test50.c000066400000000000000000000006321264051566200172270ustar00rootroot00000000000000#include #include "utarray.h" int main() { UT_array *nums; long l, *p; UT_icd long_icd = {sizeof(long), NULL, NULL, NULL }; utarray_new(nums, &long_icd); l=1; utarray_push_back(nums, &l); l=2; utarray_push_back(nums, &l); p=NULL; while( (p=(long*)utarray_next(nums,p)) != NULL ) { printf("%ld\n", *p); } utarray_free(nums); return 0; } uthash-1.9.9.1+git20151125/tests/test51.ans000066400000000000000000000000121264051566200175570ustar00rootroot000000000000001 2 10 20 uthash-1.9.9.1+git20151125/tests/test51.c000066400000000000000000000011011264051566200172200ustar00rootroot00000000000000#include #include "utarray.h" typedef struct { int a; int b; } intpair_t; int main() { UT_array *pairs; intpair_t ip, *p; UT_icd intpair_icd = {sizeof(intpair_t), NULL, NULL, NULL}; utarray_new(pairs,&intpair_icd); ip.a=1; ip.b=2; utarray_push_back(pairs, &ip); ip.a=10; ip.b=20; utarray_push_back(pairs, &ip); for(p=(intpair_t*)utarray_front(pairs); p!=NULL; p=(intpair_t*)utarray_next(pairs,p)) { printf("%d %d\n", p->a, p->b); } utarray_free(pairs); return 0; } uthash-1.9.9.1+git20151125/tests/test52.ans000066400000000000000000000000201264051566200175570ustar00rootroot000000000000001 hello 2 world uthash-1.9.9.1+git20151125/tests/test52.c000066400000000000000000000017021264051566200172300ustar00rootroot00000000000000#include #include #include "utarray.h" typedef struct { int a; char *s; } intchar_t; static void intchar_copy(void *_dst, const void *_src) { intchar_t *dst = (intchar_t*)_dst, *src = (intchar_t*)_src; dst->a = src->a; dst->s = (src->s != NULL) ? strdup(src->s) : NULL; } static void intchar_dtor(void *_elt) { intchar_t *elt = (intchar_t*)_elt; if (elt->s != NULL) { free(elt->s); } } int main() { UT_array *intchars; intchar_t ic, *p; UT_icd intchar_icd = {sizeof(intchar_t), NULL, intchar_copy, intchar_dtor}; utarray_new(intchars, &intchar_icd); ic.a=1; ic.s="hello"; utarray_push_back(intchars, &ic); ic.a=2; ic.s="world"; utarray_push_back(intchars, &ic); p=NULL; while( (p=(intchar_t*)utarray_next(intchars,p)) != NULL ) { printf("%d %s\n", p->a, (p->s != NULL) ? p->s : "null"); } utarray_free(intchars); return 0; } uthash-1.9.9.1+git20151125/tests/test53.ans000066400000000000000000000000151264051566200175640ustar00rootroot00000000000000hello world! uthash-1.9.9.1+git20151125/tests/test53.c000066400000000000000000000003251264051566200172310ustar00rootroot00000000000000#include #include "utstring.h" int main() { UT_string *s; utstring_new(s); utstring_printf(s, "hello world!" ); printf("%s\n", utstring_body(s)); utstring_free(s); return 0; } uthash-1.9.9.1+git20151125/tests/test54.ans000066400000000000000000000000411264051566200175640ustar00rootroot00000000000000length: 21 hello world hi there uthash-1.9.9.1+git20151125/tests/test54.c000066400000000000000000000006571264051566200172420ustar00rootroot00000000000000#include #include "utstring.h" int main() { UT_string *s, *t; utstring_new(s); utstring_new(t); utstring_printf(s, "hello " ); utstring_printf(s, "world " ); utstring_printf(t, "hi " ); utstring_printf(t, "there " ); utstring_concat(s, t); printf("length: %u\n", utstring_len(s)); printf("%s\n", utstring_body(s)); utstring_free(s); utstring_free(t); return 0; } uthash-1.9.9.1+git20151125/tests/test55.ans000066400000000000000000000000261264051566200175700ustar00rootroot00000000000000length is 3 number 10 uthash-1.9.9.1+git20151125/tests/test55.c000066400000000000000000000005531264051566200172360ustar00rootroot00000000000000#include #include "utstring.h" int main() { UT_string *s; char binary[] = "\xff\xff"; utstring_new(s); utstring_bincpy(s, binary, sizeof(binary)); printf("length is %u\n", utstring_len(s)); utstring_clear(s); utstring_printf(s,"number %d", 10); printf("%s\n", utstring_body(s)); utstring_free(s); return 0; } uthash-1.9.9.1+git20151125/tests/test56.ans000066400000000000000000000010531264051566200175720ustar00rootroot00000000000000ADRIAN ARNOLDO CARROLL CARY CHONG CLIFTON CODY COLTON CORNELL DAMON DANNIE DARIO DONN DOUG DOUGLAS FREDERICK FRITZ GERALD GUS HARVEY IRVING ISAIAH JARVIS JOHN KENTON LAURENCE LESTER LINCOLN LOWELL NELSON NEVILLE NIGEL NORMAND ODIS OMAR ORLANDO RAYMUNDO REX ROLANDO RON SHANE TONEY TRINIDAD WALTER WARNER WARREN WES WILLARD WILLIAM WINFRED XAVIER found WES user 0, cookie 0 user 1, cookie 1 user 2, cookie 4 user 3, cookie 9 user 4, cookie 16 user 5, cookie 25 user 6, cookie 36 user 7, cookie 49 user 8, cookie 64 user 9, cookie 81 length is 3 number 10 uthash-1.9.9.1+git20151125/tests/test56.c000066400000000000000000000042011264051566200172310ustar00rootroot00000000000000#include /* malloc */ #include /* printf */ #include #include "uthash.h" #include "utlist.h" #include "utstring.h" typedef struct example_user_t { int id; int cookie; UT_hash_handle hh; } example_user_t; #define BUFLEN 20 typedef struct el { char bname[BUFLEN]; struct el *next, *prev; } el; static int namecmp(void *_a, void *_b) { el *a = (el*)_a; el *b = (el*)_b; return strcmp(a->bname,b->bname); } int main(int argc, char *argv[]) { el *name, *elt, *tmp, etmp; int i; example_user_t *user, *users=NULL; el *head = NULL; /* important- initialize to NULL! */ char linebuf[BUFLEN]; FILE *file; UT_string *s; char binary[] = "\xff\xff"; file = fopen( "test11.dat", "r" ); if (file == NULL) { perror("can't open: "); exit(-1); } while (fgets(linebuf,BUFLEN,file) != NULL) { name = (el*)malloc(sizeof(el)); if (name == NULL) { exit(-1); } strncpy(name->bname,linebuf,sizeof(name->bname)); DL_APPEND(head, name); } DL_SORT(head, namecmp); DL_FOREACH(head,elt) { printf("%s", elt->bname); } memcpy(etmp.bname, "WES\n", 5UL); DL_SEARCH(head,elt,&etmp,namecmp); if (elt != NULL) { printf("found %s\n", elt->bname); } /* now delete each element, use the safe iterator */ DL_FOREACH_SAFE(head,elt,tmp) { DL_DELETE(head,elt); } fclose(file); /* create elements */ for(i=0; i<10; i++) { user = (example_user_t*)malloc(sizeof(example_user_t)); if (user == NULL) { exit(-1); } user->id = i; user->cookie = i*i; HASH_ADD_INT(users,id,user); } for(user=users; user != NULL; user=(example_user_t*)(user->hh.next)) { printf("user %d, cookie %d\n", user->id, user->cookie); } utstring_new(s); utstring_bincpy(s, binary, sizeof(binary)); printf("length is %u\n", utstring_len(s)); utstring_clear(s); utstring_printf(s,"number %d", 10); printf("%s\n", utstring_body(s)); utstring_free(s); return 0; } uthash-1.9.9.1+git20151125/tests/test57.ans000066400000000000000000000000061264051566200175700ustar00rootroot00000000000000found uthash-1.9.9.1+git20151125/tests/test57.c000066400000000000000000000010311264051566200172300ustar00rootroot00000000000000#include #include #include "uthash.h" typedef struct { void *key; int i; UT_hash_handle hh; } el_t; int main() { el_t *d; el_t *hash = NULL; char *someaddr = NULL; el_t *e = (el_t*)malloc(sizeof(el_t)); if (!e) { return -1; } e->key = (void*)someaddr; e->i = 1; HASH_ADD_PTR(hash,key,e); HASH_FIND_PTR(hash, &someaddr, d); if (d != NULL) { printf("found\n"); } /* release memory */ HASH_DEL(hash,e); free(e); return 0; } uthash-1.9.9.1+git20151125/tests/test58.ans000066400000000000000000000005241264051566200175760ustar00rootroot00000000000000user 0, cookie 0 user 1, cookie 1 user 2, cookie 4 user 3, cookie 9 user 4, cookie 16 user 5, cookie 25 user 6, cookie 36 user 7, cookie 49 user 8, cookie 64 user 9, cookie 81 10 users. Deleting odd id's... user 0, cookie 0 user 2, cookie 4 user 4, cookie 16 user 6, cookie 36 user 8, cookie 64 5 users. Deleting remaining id's... 0 users. uthash-1.9.9.1+git20151125/tests/test58.c000066400000000000000000000030371264051566200172410ustar00rootroot00000000000000#include "uthash.h" #include /* malloc */ #include /* printf */ typedef struct example_user_t { int id; int cookie; UT_hash_handle hh; } example_user_t; int main(int argc,char *argv[]) { int i; unsigned c; example_user_t *user, *tmp, *users=NULL; /* create elements */ for(i=0; i<10; i++) { if ( (user = (example_user_t*)malloc(sizeof(example_user_t))) == NULL) { exit(-1); } user->id = i; user->cookie = i*i; HASH_ADD_INT(users,id,user); } /* show the hash */ for(user=users; user != NULL; user=(example_user_t*)(user->hh.next)) { printf("user %d, cookie %d\n", user->id, user->cookie); } c = HASH_COUNT(users); printf("%u users. Deleting odd id's...\n", c); /* delete the odd id's */ HASH_ITER(hh, users, user, tmp) { if ((user->id & 1) != 0) { HASH_DEL(users,user); } } /* show the hash */ for(user=users; user != NULL; user=(example_user_t*)(user->hh.next)) { printf("user %d, cookie %d\n", user->id, user->cookie); } c = HASH_COUNT(users); printf("%u users. Deleting remaining id's...\n", c); /* delete all that are left */ HASH_ITER(hh, users, user, tmp) { HASH_DEL(users,user); } c = HASH_COUNT(users); printf("%u users.\n", c); /* show the hash */ for(user=users; user != NULL; user=(example_user_t*)(user->hh.next)) { printf("user %d, cookie %d\n", user->id, user->cookie); } return 0; } uthash-1.9.9.1+git20151125/tests/test59.ans000066400000000000000000000000261264051566200175740ustar00rootroot00000000000000$items{bob}{age} = 37 uthash-1.9.9.1+git20151125/tests/test59.c000066400000000000000000000023501264051566200172370ustar00rootroot00000000000000#include #include #include #include "uthash.h" /* hash of hashes */ typedef struct item { char name[10]; struct item *sub; int val; UT_hash_handle hh; } item_t; int main(int argc, char *argvp[]) { item_t *item1, *item2, *tmp1, *tmp2; item_t *items=NULL; /* make initial element */ item_t *i = malloc(sizeof(*i)); if (i == NULL) { exit(-1); } strcpy(i->name, "bob"); i->sub = NULL; i->val = 0; HASH_ADD_STR(items, name, i); /* add a sub hash table off this element */ item_t *s = malloc(sizeof(*s)); if (s == NULL) { exit(-1); } strcpy(s->name, "age"); s->sub = NULL; s->val = 37; HASH_ADD_STR(i->sub, name, s); /* iterate over hash elements */ HASH_ITER(hh, items, item1, tmp1) { HASH_ITER(hh, item1->sub, item2, tmp2) { printf("$items{%s}{%s} = %d\n", item1->name, item2->name, item2->val); } } /* clean up both hash tables */ HASH_ITER(hh, items, item1, tmp1) { HASH_ITER(hh, item1->sub, item2, tmp2) { HASH_DEL(item1->sub, item2); free(item2); } HASH_DEL(items, item1); free(item1); } return 0; } uthash-1.9.9.1+git20151125/tests/test6.ans000066400000000000000000000000211264051566200174770ustar00rootroot00000000000000alt malloc table uthash-1.9.9.1+git20151125/tests/test6.c000066400000000000000000000026111264051566200171470ustar00rootroot00000000000000#include "uthash.h" #include /* malloc */ #include /* printf */ /* Set up macros for alternative malloc/free functions */ #undef uthash_malloc #undef uthash_free #define uthash_malloc(sz) alt_malloc(sz) #define uthash_free(ptr,sz) alt_free(ptr) typedef struct example_user_t { int id; int cookie; UT_hash_handle hh; } example_user_t; static void *alt_malloc(size_t sz) { if (sz == sizeof(UT_hash_table)) { printf("%s\n", "alt malloc table"); } return malloc(sz); } static void alt_free(void *ptr) { /* printf("%s\n", "alt_free"); */ free(ptr); } int main(int argc,char *argv[]) { int i; example_user_t *user, *tmp, *users=NULL; /* create elements */ for(i=0; i<10; i++) { user = (example_user_t*)malloc(sizeof(example_user_t)); if (user == NULL) { exit(-1); } user->id = i; user->cookie = i*i; HASH_ADD_INT(users,id,user); } /* delete each ID */ for(i=0; i<10; i++) { HASH_FIND_INT(users,&i,tmp); if (tmp != NULL) { HASH_DEL(users,tmp); free(tmp); } else { printf("user id %d not found\n", i); } } /* show the hash */ for(user=users; user != NULL; user=(example_user_t*)(user->hh.next)) { printf("user %d, cookie %d\n", user->id, user->cookie); } return 0; } uthash-1.9.9.1+git20151125/tests/test60.ans000066400000000000000000000000261264051566200175640ustar00rootroot00000000000000$items{bob}{age} = 37 uthash-1.9.9.1+git20151125/tests/test60.c000066400000000000000000000021641264051566200172320ustar00rootroot00000000000000#include #include #include #include "uthash.h" /* hash of hashes */ typedef struct item { char name[10]; struct item *sub; int val; UT_hash_handle hh; } item_t; int main(int argc, char *argvp[]) { item_t *item1, *item2, *tmp1, *tmp2; item_t *items=NULL; /* make initial element */ item_t *i = malloc(sizeof(*i)); if (i == NULL) { exit(-1); } strcpy(i->name, "bob"); i->sub = NULL; i->val = 0; HASH_ADD_STR(items, name, i); /* add a sub hash table off this element */ item_t *s = malloc(sizeof(*s)); if (s == NULL) { exit(-1); } strcpy(s->name, "age"); s->sub = NULL; s->val = 37; HASH_ADD_STR(i->sub, name, s); /* iterate over hash elements, printing and freeing them */ HASH_ITER(hh, items, item1, tmp1) { HASH_ITER(hh, item1->sub, item2, tmp2) { printf("$items{%s}{%s} = %d\n", item1->name, item2->name, item2->val); HASH_DEL(item1->sub, item2); free(item2); } HASH_DEL(items, item1); free(item1); } return 0; } uthash-1.9.9.1+git20151125/tests/test61.ans000066400000000000000000000002031264051566200175620ustar00rootroot00000000000000hello world one two three sorting finding hello hello finding one one finding three three finding two two finding world world uthash-1.9.9.1+git20151125/tests/test61.c000066400000000000000000000016741264051566200172400ustar00rootroot00000000000000#include #include "utarray.h" static int strsort(const void *_a, const void *_b) { char *a = *(char**)_a; char *b = *(char**)_b; return strcmp(a,b); } int main() { UT_array *strs; char *s, **p; utarray_new(strs,&ut_str_icd); s = "hello"; utarray_push_back(strs, &s); s = "world"; utarray_push_back(strs, &s); s = "one"; utarray_push_back(strs, &s); s = "two"; utarray_push_back(strs, &s); s = "three"; utarray_push_back(strs, &s); p = NULL; while ( (p=(char**)utarray_next(strs,p)) != NULL ) { s = *p; printf("%s\n",s); } printf("sorting\n"); utarray_sort(strs,strsort); p = NULL; while ( (p=(char**)utarray_next(strs,p)) != NULL ) { s = *p; printf("finding %s\n",s); p = utarray_find(strs,&s,strsort); printf(" %s\n", (p != NULL) ? (*p) : "failed"); } utarray_free(strs); return 0; } uthash-1.9.9.1+git20151125/tests/test62.ans000066400000000000000000000004141264051566200175670ustar00rootroot00000000000000al aligned (y): y u1 aligned (n): n u2 aligned (n): n u3 aligned (n): n al plus1 (n): n u1 plus1 (y): y u2 plus1 (n): n u3 plus1 (n): n al plus2 (n): n u1 plus2 (n): n u2 plus2 (y): y u3 plus2 (n): n al plus3 (n): n u1 plus3 (n): n u2 plus3 (n): n u3 plus3 (y): y uthash-1.9.9.1+git20151125/tests/test62.c000066400000000000000000000050271264051566200172350ustar00rootroot00000000000000#include #include #include #include "uthash.h" #define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 3UL) == 0UL) #define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 3UL) == 1UL) #define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 3UL) == 2UL) #define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 3UL) == 3UL) #define yn(rc) ((rc!=0U)?"y":"n") int main(int argc,char*argv[]) { unsigned rc; char *c = malloc(8UL); if (c == NULL) { exit(-1); } *(c+0) = 0x00; unsigned *al = (unsigned*)(c+0); *(c+1) = 0x01; unsigned *u1 = (unsigned*)(c+1); *(c+2) = 0x02; unsigned *u2 = (unsigned*)(c+2); *(c+3) = 0x03; unsigned *u3 = (unsigned*)(c+3); *(c+4) = 0x04; *(c+5) = 0x05; *(c+6) = 0x06; *(c+7) = 0x07; /* ---------------------------------------- */ /* test whether alignment is detected properly */ rc = MUR_PLUS0_ALIGNED(al); printf("al aligned (y): %s\n", yn(rc)); rc = MUR_PLUS0_ALIGNED(u1); printf("u1 aligned (n): %s\n", yn(rc)); rc = MUR_PLUS0_ALIGNED(u2); printf("u2 aligned (n): %s\n", yn(rc)); rc = MUR_PLUS0_ALIGNED(u3); printf("u3 aligned (n): %s\n", yn(rc)); printf("\n"); rc = MUR_PLUS1_ALIGNED(al); printf("al plus1 (n): %s\n", yn(rc)); rc = MUR_PLUS1_ALIGNED(u1); printf("u1 plus1 (y): %s\n", yn(rc)); rc = MUR_PLUS1_ALIGNED(u2); printf("u2 plus1 (n): %s\n", yn(rc)); rc = MUR_PLUS1_ALIGNED(u3); printf("u3 plus1 (n): %s\n", yn(rc)); printf("\n"); rc = MUR_PLUS2_ALIGNED(al); printf("al plus2 (n): %s\n", yn(rc)); rc = MUR_PLUS2_ALIGNED(u1); printf("u1 plus2 (n): %s\n", yn(rc)); rc = MUR_PLUS2_ALIGNED(u2); printf("u2 plus2 (y): %s\n", yn(rc)); rc = MUR_PLUS2_ALIGNED(u3); printf("u3 plus2 (n): %s\n", yn(rc)); printf("\n"); rc = MUR_PLUS3_ALIGNED(al); printf("al plus3 (n): %s\n", yn(rc)); rc = MUR_PLUS3_ALIGNED(u1); printf("u1 plus3 (n): %s\n", yn(rc)); rc = MUR_PLUS3_ALIGNED(u2); printf("u2 plus3 (n): %s\n", yn(rc)); rc = MUR_PLUS3_ALIGNED(u3); printf("u3 plus3 (y): %s\n", yn(rc)); printf("\n"); /* ---------------------------------------- */ /* test careful reassembly of an unaligned integer */ #if 0 /* commented out since result is endian dependent */ rc = MUR_GETBLOCK(al,0); printf("%x\n", rc); rc = MUR_GETBLOCK(u1,0); printf("%x\n", rc); rc = MUR_GETBLOCK(u2,0); printf("%x\n", rc); rc = MUR_GETBLOCK(u3,0); printf("%x\n", rc); #endif free(c); return 0; } uthash-1.9.9.1+git20151125/tests/test63.ans000066400000000000000000000000701264051566200175660ustar00rootroot00000000000000LL macros a b c d e f a b c d e f d e f d e f a b uthash-1.9.9.1+git20151125/tests/test63.c000066400000000000000000000023771264051566200172430ustar00rootroot00000000000000#include #include "utlist.h" typedef struct el { int id; struct el *next, *prev; } el; int main(int argc, char *argv[]) { int i; el els[10], *e; el *headA = NULL; el *headB = NULL; for(i=0; i<10; i++) { els[i].id=(int)'a'+i; } /* test LL macros */ printf("LL macros\n"); LL_APPEND(headA,&els[0]); LL_APPEND(headA,&els[1]); LL_APPEND(headA,&els[2]); LL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); LL_APPEND(headB,&els[3]); LL_APPEND(headB,&els[4]); LL_APPEND(headB,&els[5]); LL_FOREACH(headB,e) { printf("%c ", e->id); } printf("\n"); LL_CONCAT(headA,headB); LL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); /* other variations */ headA = NULL; LL_CONCAT(headA,headB); LL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); headB = NULL; LL_CONCAT(headA,headB); LL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); headA=NULL; headB=NULL; LL_APPEND(headA,&els[0]); LL_APPEND(headB,&els[1]); LL_CONCAT(headA,headB); LL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); return 0; } uthash-1.9.9.1+git20151125/tests/test64.ans000066400000000000000000000000701264051566200175670ustar00rootroot00000000000000DL macros a b c d e f a b c d e f d e f d e f a b uthash-1.9.9.1+git20151125/tests/test64.c000066400000000000000000000023771264051566200172440ustar00rootroot00000000000000#include #include "utlist.h" typedef struct el { int id; struct el *next, *prev; } el; int main(int argc, char *argv[]) { int i; el els[10], *e; el *headA = NULL; el *headB = NULL; for(i=0; i<10; i++) { els[i].id=(int)'a'+i; } /* test DL macros */ printf("DL macros\n"); DL_APPEND(headA,&els[0]); DL_APPEND(headA,&els[1]); DL_APPEND(headA,&els[2]); DL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); DL_APPEND(headB,&els[3]); DL_APPEND(headB,&els[4]); DL_APPEND(headB,&els[5]); DL_FOREACH(headB,e) { printf("%c ", e->id); } printf("\n"); DL_CONCAT(headA,headB); DL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); /* other variations */ headA = NULL; DL_CONCAT(headA,headB); DL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); headB = NULL; DL_CONCAT(headA,headB); DL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); headA=NULL; headB=NULL; DL_APPEND(headA,&els[0]); DL_APPEND(headB,&els[1]); DL_CONCAT(headA,headB); DL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); return 0; } uthash-1.9.9.1+git20151125/tests/test65.ans000066400000000000000000000000551264051566200175730ustar00rootroot00000000000000LRU deleting JOHN 0 LRU deleting WILLIAM 1 uthash-1.9.9.1+git20151125/tests/test65.c000066400000000000000000000040731264051566200172400ustar00rootroot00000000000000#include #include #include "uthash.h" // this is an example of how to do a LRU cache in C using uthash // http://troydhanson.github.com/uthash/ // by Jehiah Czebotar 2011 - jehiah@gmail.com // this code is in the public domain http://unlicense.org/ #define MAX_CACHE_SIZE 50U /* a real value would be much larger */ struct CacheEntry { char *key; char *value; UT_hash_handle hh; }; 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; entry = malloc(sizeof(struct CacheEntry)); if (entry == NULL) { exit(-1); } entry->key = strdup(key); entry->value = strdup(value); HASH_ADD_KEYPTR(hh, cache, entry->key, strlen(entry->key), entry); // prune the cache to MAX_CACHE_SIZE if (HASH_COUNT(cache) >= MAX_CACHE_SIZE) { HASH_ITER(hh, cache, entry, tmp_entry) { // prune the first entry (loop is based on insertion order so this deletes the oldest item) printf("LRU deleting %s %s\n", entry->key, entry->value); HASH_DELETE(hh, cache, entry); free(entry->key); free(entry->value); free(entry); break; } } } /* main added by Troy D. Hanson */ int main(int argc, char *argv[]) { char linebuf[100], nbuf[10]; FILE *file; int i=0; file = fopen( "test65.dat", "r" ); if (file == NULL) { perror("can't open: "); exit(-1); } while (fgets(linebuf,sizeof(linebuf),file) != NULL) { snprintf(nbuf,sizeof(nbuf),"%u",i++); add_to_cache(linebuf, nbuf); } fclose(file); return 0; } uthash-1.9.9.1+git20151125/tests/test65.dat000066400000000000000000000005321264051566200175620ustar00rootroot00000000000000JOHN WILLIAM WALTER DOUGLAS GERALD FREDERICK WARREN SHANE LESTER RON HARVEY ADRIAN CODY NELSON CLIFTON WILLARD DOUG ORLANDO REX OMAR DAMON LOWELL IRVING CARROLL LAURENCE ROLANDO CARY XAVIER ISAIAH GUS JARVIS WINFRED RAYMUNDO LINCOLN CORNELL NIGEL NORMAND FRITZ DONN TRINIDAD ODIS DANNIE DARIO KENTON CHONG NEVILLE TONEY WARNER WES COLTON ARNOLDO uthash-1.9.9.1+git20151125/tests/test66.ans000066400000000000000000000005301264051566200175720ustar00rootroot00000000000000added bob (id 0) added jack (id 1) added gary (id 2) added ty (id 3) added bo (id 4) added phil (id 5) added art (id 6) added gil (id 7) added buck (id 8) added ted (id 9) found bob (id 0) found jack (id 1) found gary (id 2) found ty (id 3) found bo (id 4) found phil (id 5) found art (id 6) found gil (id 7) found buck (id 8) found ted (id 9) uthash-1.9.9.1+git20151125/tests/test66.c000066400000000000000000000022061264051566200172350ustar00rootroot00000000000000#include "uthash.h" #include #include /* malloc */ typedef struct person_t { char first_name[10]; int id; UT_hash_handle hh; } person_t; int main(int argc, char*argv[]) { person_t *people=NULL, *person; const char **name; const char * names[] = { "bob", "jack", "gary", "ty", "bo", "phil", "art", "gil", "buck", "ted", NULL }; int id=0; for(name=names; *name!=NULL; name++) { person = (person_t*)malloc(sizeof(person_t)); if (person == NULL) { exit(-1); } strncpy(person->first_name, *name,sizeof(person->first_name)); person->id = id++; HASH_ADD_STR(people,first_name,person); printf("added %s (id %d)\n", person->first_name, person->id); } person=NULL; person_t **p=&person; for(name=names; *name!=NULL; name++) { HASH_FIND_STR(people,*name,*p); if (person != NULL) { printf("found %s (id %d)\n", person->first_name, person->id); } else { printf("failed to find %s\n", *name); } } return 0; } uthash-1.9.9.1+git20151125/tests/test67.ans000066400000000000000000000000501264051566200175700ustar00rootroot000000000000009 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 uthash-1.9.9.1+git20151125/tests/test67.c000066400000000000000000000010321264051566200172320ustar00rootroot00000000000000#include #include "utarray.h" int main() { UT_array *nums; int i, *p; utarray_new(nums,&ut_int_icd); for(i=0; i < 10; i++) { utarray_push_back(nums,&i); } for(p=(int*)utarray_back(nums); p!=NULL; p=(int*)utarray_prev(nums,p)) { printf("%d\n",*p); } /* the other form of iteration starting from NULL (back) */ p=NULL; while ( (p=(int*)utarray_prev(nums,p)) != NULL ) { printf("%d\n",*p); } utarray_free(nums); return 0; } uthash-1.9.9.1+git20151125/tests/test68.ans000066400000000000000000000001251264051566200175740ustar00rootroot00000000000000DL replace elem a b c d e b c d f b c d f b c g f b c h f i j h k l m n s t uthash-1.9.9.1+git20151125/tests/test68.c000066400000000000000000000035061264051566200172430ustar00rootroot00000000000000#include #include #include "utlist.h" typedef struct el { int id; struct el *next, *prev; } el; int main(int argc, char *argv[]) { int i; el els[20], *e, *tmp; el *headA = NULL; el *headB = NULL; for(i=0; i<20; i++) { els[i].id=(int)'a'+i; } /* test DL macros */ printf("DL replace elem\n"); DL_APPEND(headA,&els[0]); DL_APPEND(headA,&els[1]); DL_APPEND(headA,&els[2]); DL_APPEND(headA,&els[3]); DL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); /* replace head elem */ DL_REPLACE_ELEM(headA, &els[0], &els[4]); DL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); DL_REPLACE_ELEM(headA, &els[4], &els[5]); DL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); /* replace last elem */ DL_REPLACE_ELEM(headA, &els[3], &els[6]); DL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); DL_REPLACE_ELEM(headA, &els[6], &els[7]); DL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); /* replace middle elem */ DL_REPLACE_ELEM(headA, &els[1], &els[8]); DL_REPLACE_ELEM(headA, &els[2], &els[9]); DL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); /* replace all just to be sure the list is intact... */ i = 10; DL_FOREACH_SAFE(headA, e, tmp) { DL_REPLACE_ELEM(headA, e, &els[i]); i++; } DL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); /* single elem */ DL_APPEND(headB, &els[18]); DL_FOREACH(headB,e) { printf("%c ", e->id); } printf("\n"); DL_REPLACE_ELEM(headB, &els[18], &els[19]); DL_FOREACH(headB,e) { printf("%c ", e->id); } printf("\n"); return 0; } uthash-1.9.9.1+git20151125/tests/test69.ans000066400000000000000000000002361264051566200176000ustar00rootroot00000000000000DL prepend elem a b c d e a b c d f e a b c d f e a b c g d f e a b c h g d f e a b i j c h g d k f l e m a n b o i p j q c r h s g t d u v u w v u uthash-1.9.9.1+git20151125/tests/test69.c000066400000000000000000000037061264051566200172460ustar00rootroot00000000000000#include #include #include "utlist.h" typedef struct el { int id; struct el *next, *prev; } el; int main(int argc, char *argv[]) { int i; el els[26], *e, *tmp; el *headA = NULL; el *headB = NULL; for(i=0; i<25; i++) { els[i].id=(int)'a'+i; } /* test DL macros */ printf("DL prepend elem\n"); DL_APPEND(headA,&els[0]); DL_APPEND(headA,&els[1]); DL_APPEND(headA,&els[2]); DL_APPEND(headA,&els[3]); DL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); /* prepend head elem */ DL_PREPEND_ELEM(headA, &els[0], &els[4]); DL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); DL_PREPEND_ELEM(headA, &els[4], &els[5]); DL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); /* prepend last elem */ DL_PREPEND_ELEM(headA, &els[3], &els[6]); DL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); DL_PREPEND_ELEM(headA, &els[6], &els[7]); DL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); /* prepend middle elem */ DL_PREPEND_ELEM(headA, &els[2], &els[8]); DL_PREPEND_ELEM(headA, &els[2], &els[9]); DL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); /* prepend all just to be sure the list is intact... */ i = 10; DL_FOREACH_SAFE(headA, e, tmp) { DL_PREPEND_ELEM(headA, e, &els[i]); i++; } DL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); /* single elem */ DL_APPEND(headB, &els[20]); DL_FOREACH(headB,e) { printf("%c ", e->id); } printf("\n"); DL_PREPEND_ELEM(headB, &els[20], &els[21]); DL_FOREACH(headB,e) { printf("%c ", e->id); } printf("\n"); DL_PREPEND_ELEM(headB, &els[21], &els[22]); DL_FOREACH(headB,e) { printf("%c ", e->id); } printf("\n"); return 0; } uthash-1.9.9.1+git20151125/tests/test7.ans000066400000000000000000000000001264051566200174750ustar00rootroot00000000000000uthash-1.9.9.1+git20151125/tests/test7.c000066400000000000000000000017461264051566200171600ustar00rootroot00000000000000#include "uthash.h" #include /* malloc */ #include /* printf */ typedef struct example_user_t { int id; int cookie; UT_hash_handle hh; } example_user_t; int main(int argc,char *argv[]) { int i; example_user_t *user, *tmp, *users=NULL; /* create elements */ for(i=0; i<1000; i++) { user = (example_user_t*)malloc(sizeof(example_user_t)); if (user == NULL) { exit(-1); } user->id = i; user->cookie = i*i; HASH_ADD_INT(users,id,user); } /* delete each ID */ for(i=0; i<1000; i++) { HASH_FIND_INT(users,&i,tmp); if (tmp != NULL) { HASH_DEL(users,tmp); free(tmp); } else { printf("user id %d not found\n", i); } } /* show the hash */ for(user=users; user != NULL; user=(example_user_t*)(user->hh.next)) { printf("user %d, cookie %d\n", user->id, user->cookie); } return 0; } uthash-1.9.9.1+git20151125/tests/test70.ans000066400000000000000000000001251264051566200175650ustar00rootroot00000000000000LL replace elem a b c d e b c d f b c d f b c g f b c h f i j h k l m n s t uthash-1.9.9.1+git20151125/tests/test70.c000066400000000000000000000035061264051566200172340ustar00rootroot00000000000000#include #include #include "utlist.h" typedef struct el { int id; struct el *next, *prev; } el; int main(int argc, char *argv[]) { int i; el els[20], *e, *tmp; el *headA = NULL; el *headB = NULL; for(i=0; i<20; i++) { els[i].id=(int)'a'+i; } /* test LL macros */ printf("LL replace elem\n"); LL_APPEND(headA,&els[0]); LL_APPEND(headA,&els[1]); LL_APPEND(headA,&els[2]); LL_APPEND(headA,&els[3]); LL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); /* replace head elem */ LL_REPLACE_ELEM(headA, &els[0], &els[4]); LL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); LL_REPLACE_ELEM(headA, &els[4], &els[5]); LL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); /* replace last elem */ LL_REPLACE_ELEM(headA, &els[3], &els[6]); LL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); LL_REPLACE_ELEM(headA, &els[6], &els[7]); LL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); /* replace middle elem */ LL_REPLACE_ELEM(headA, &els[1], &els[8]); LL_REPLACE_ELEM(headA, &els[2], &els[9]); LL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); /* replace all just to be sure the list is intact... */ i = 10; LL_FOREACH_SAFE(headA, e, tmp) { LL_REPLACE_ELEM(headA, e, &els[i]); i++; } LL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); /* single elem */ LL_APPEND(headB, &els[18]); LL_FOREACH(headB,e) { printf("%c ", e->id); } printf("\n"); LL_REPLACE_ELEM(headB, &els[18], &els[19]); LL_FOREACH(headB,e) { printf("%c ", e->id); } printf("\n"); return 0; } uthash-1.9.9.1+git20151125/tests/test71.ans000066400000000000000000000002361264051566200175710ustar00rootroot00000000000000LL prepend elem a b c d e a b c d f e a b c d f e a b c g d f e a b c h g d f e a b i j c h g d k f l e m a n b o i p j q c r h s g t d u v u w v u uthash-1.9.9.1+git20151125/tests/test71.c000066400000000000000000000037061264051566200172370ustar00rootroot00000000000000#include #include #include "utlist.h" typedef struct el { int id; struct el *next, *prev; } el; int main(int argc, char *argv[]) { int i; el els[26], *e, *tmp; el *headA = NULL; el *headB = NULL; for(i=0; i<25; i++) { els[i].id=(int)'a'+i; } /* test LL macros */ printf("LL prepend elem\n"); LL_APPEND(headA,&els[0]); LL_APPEND(headA,&els[1]); LL_APPEND(headA,&els[2]); LL_APPEND(headA,&els[3]); LL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); /* prepend head elem */ LL_PREPEND_ELEM(headA, &els[0], &els[4]); LL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); LL_PREPEND_ELEM(headA, &els[4], &els[5]); LL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); /* prepend last elem */ LL_PREPEND_ELEM(headA, &els[3], &els[6]); LL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); LL_PREPEND_ELEM(headA, &els[6], &els[7]); LL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); /* prepend middle elem */ LL_PREPEND_ELEM(headA, &els[2], &els[8]); LL_PREPEND_ELEM(headA, &els[2], &els[9]); LL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); /* prepend all just to be sure the list is intact... */ i = 10; LL_FOREACH_SAFE(headA, e, tmp) { LL_PREPEND_ELEM(headA, e, &els[i]); i++; } LL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); /* single elem */ LL_APPEND(headB, &els[20]); LL_FOREACH(headB,e) { printf("%c ", e->id); } printf("\n"); LL_PREPEND_ELEM(headB, &els[20], &els[21]); LL_FOREACH(headB,e) { printf("%c ", e->id); } printf("\n"); LL_PREPEND_ELEM(headB, &els[21], &els[22]); LL_FOREACH(headB,e) { printf("%c ", e->id); } printf("\n"); return 0; } uthash-1.9.9.1+git20151125/tests/test72.ans000066400000000000000000000001261264051566200175700ustar00rootroot00000000000000CDL replace elem a b c d e b c d f b c d f b c g f b c h f i j h k l m n s t uthash-1.9.9.1+git20151125/tests/test72.c000066400000000000000000000035611264051566200172370ustar00rootroot00000000000000#include #include #include "utlist.h" typedef struct el { int id; struct el *next, *prev; } el; int main(int argc, char *argv[]) { int i; el els[20], *e, *tmp, *tmp2; el *headA = NULL; el *headB = NULL; for(i=0; i<20; i++) { els[i].id=(int)'a'+i; } /* test CDL macros */ printf("CDL replace elem\n"); CDL_PREPEND(headA,&els[3]); CDL_PREPEND(headA,&els[2]); CDL_PREPEND(headA,&els[1]); CDL_PREPEND(headA,&els[0]); CDL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); /* replace head elem */ CDL_REPLACE_ELEM(headA, &els[0], &els[4]); CDL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); CDL_REPLACE_ELEM(headA, &els[4], &els[5]); CDL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); /* replace last elem */ CDL_REPLACE_ELEM(headA, &els[3], &els[6]); CDL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); CDL_REPLACE_ELEM(headA, &els[6], &els[7]); CDL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); /* replace middle elem */ CDL_REPLACE_ELEM(headA, &els[1], &els[8]); CDL_REPLACE_ELEM(headA, &els[2], &els[9]); CDL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); /* replace all just to be sure the list is intact... */ i = 10; CDL_FOREACH_SAFE(headA, e, tmp, tmp2) { CDL_REPLACE_ELEM(headA, e, &els[i]); i++; } CDL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); /* single elem */ CDL_PREPEND(headB, &els[18]); CDL_FOREACH(headB,e) { printf("%c ", e->id); } printf("\n"); CDL_REPLACE_ELEM(headB, &els[18], &els[19]); CDL_FOREACH(headB,e) { printf("%c ", e->id); } printf("\n"); return 0; } uthash-1.9.9.1+git20151125/tests/test73.ans000066400000000000000000000002371264051566200175740ustar00rootroot00000000000000CDL prepend elem a b c d e a b c d f e a b c d f e a b c g d f e a b c h g d f e a b i j c h g d k f l e m a n b o i p j q c r h s g t d u v u w v u uthash-1.9.9.1+git20151125/tests/test73.c000066400000000000000000000037631264051566200172440ustar00rootroot00000000000000#include #include #include "utlist.h" typedef struct el { int id; struct el *next, *prev; } el; int main(int argc, char *argv[]) { int i; el els[26], *e, *tmp, *tmp2; el *headA = NULL; el *headB = NULL; for(i=0; i<25; i++) { els[i].id=(int)'a'+i; } /* test CDL macros */ printf("CDL prepend elem\n"); CDL_PREPEND(headA,&els[3]); CDL_PREPEND(headA,&els[2]); CDL_PREPEND(headA,&els[1]); CDL_PREPEND(headA,&els[0]); CDL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); /* prepend head elem */ CDL_PREPEND_ELEM(headA, &els[0], &els[4]); CDL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); CDL_PREPEND_ELEM(headA, &els[4], &els[5]); CDL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); /* prepend last elem */ CDL_PREPEND_ELEM(headA, &els[3], &els[6]); CDL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); CDL_PREPEND_ELEM(headA, &els[6], &els[7]); CDL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); /* prepend middle elem */ CDL_PREPEND_ELEM(headA, &els[2], &els[8]); CDL_PREPEND_ELEM(headA, &els[2], &els[9]); CDL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); /* prepend all just to be sure the list is intact... */ i = 10; CDL_FOREACH_SAFE(headA, e, tmp, tmp2) { CDL_PREPEND_ELEM(headA, e, &els[i]); i++; } CDL_FOREACH(headA,e) { printf("%c ", e->id); } printf("\n"); /* single elem */ CDL_PREPEND(headB, &els[20]); CDL_FOREACH(headB,e) { printf("%c ", e->id); } printf("\n"); CDL_PREPEND_ELEM(headB, &els[20], &els[21]); CDL_FOREACH(headB,e) { printf("%c ", e->id); } printf("\n"); CDL_PREPEND_ELEM(headB, &els[21], &els[22]); CDL_FOREACH(headB,e) { printf("%c ", e->id); } printf("\n"); return 0; } uthash-1.9.9.1+git20151125/tests/test74.ans000066400000000000000000000001601264051566200175700ustar00rootroot00000000000000"There are two needle" len=55 "needle" len=8 utstring_find()=14 utstring_find()=46 utstring_find()=-1 FindCnt=2 uthash-1.9.9.1+git20151125/tests/test74.c000066400000000000000000000021231264051566200172320ustar00rootroot00000000000000#include /* printf */ #include "utstring.h" int main() { UT_string *s,*t; char V_TestStr[] = "There are two needle\0s in this \0haystack with needle\0s."; char V_NeedleStr[] = "needle\0s"; long V_FindPos; size_t V_FindCnt; utstring_new(s); utstring_new(t); utstring_bincpy(s, V_TestStr, sizeof(V_TestStr)-1); printf("\"%s\" len=%u\n", utstring_body(s), utstring_len(s)); utstring_bincpy(t, V_NeedleStr, sizeof(V_NeedleStr)-1); printf("\"%s\" len=%u\n", utstring_body(t), utstring_len(t)); V_FindCnt = 0; V_FindPos = 0; do { V_FindPos = utstring_find(s, V_FindPos, utstring_body(t), utstring_len(t)); printf("utstring_find()=%ld\n", V_FindPos); if (V_FindPos >= 0) { V_FindPos++; V_FindCnt++; } } while (V_FindPos >= 0); printf("FindCnt=%u\n", (unsigned)V_FindCnt); utstring_free(s); utstring_free(t); return 0; } uthash-1.9.9.1+git20151125/tests/test75.ans000066400000000000000000000001631264051566200175740ustar00rootroot00000000000000"There are two needle" len=55 "needle" len=8 utstring_findR()=46 utstring_findR()=14 utstring_findR()=-1 FindCnt=2 uthash-1.9.9.1+git20151125/tests/test75.c000066400000000000000000000021311264051566200172320ustar00rootroot00000000000000#include /* printf */ #include "utstring.h" int main() { UT_string *s,*t; char V_TestStr[] = "There are two needle\0s in this \0haystack with needle\0s."; char V_NeedleStr[] = "needle\0s"; long V_FindPos; size_t V_FindCnt; utstring_new(s); utstring_new(t); utstring_bincpy(s, V_TestStr, sizeof(V_TestStr)-1); printf("\"%s\" len=%u\n", utstring_body(s), utstring_len(s)); utstring_bincpy(t, V_NeedleStr, sizeof(V_NeedleStr)-1); printf("\"%s\" len=%u\n", utstring_body(t), utstring_len(t)); V_FindCnt = 0; V_FindPos = -1; do { V_FindPos = utstring_findR(s, V_FindPos, utstring_body(t), utstring_len(t)); printf("utstring_findR()=%ld\n", V_FindPos); if (V_FindPos >= 0) { V_FindPos--; V_FindCnt++; } } while (V_FindPos >= 0); printf("FindCnt=%u\n", (unsigned)V_FindCnt); utstring_free(s); utstring_free(t); return 0; } uthash-1.9.9.1+git20151125/tests/test76.ans000066400000000000000000000001601264051566200175720ustar00rootroot00000000000000"There are two needle" len=55 "needle" len=8 utstring_find()=14 utstring_find()=46 utstring_find()=-1 FindCnt=2 uthash-1.9.9.1+git20151125/tests/test76.c000066400000000000000000000032131264051566200172350ustar00rootroot00000000000000#include /* printf */ #include "utstring.h" int main() { UT_string *s,*t; char V_TestStr[] = "There are two needle\0s in this \0haystack with needle\0s."; char V_NeedleStr[] = "needle\0s"; long *V_KMP_Table; long V_FindPos; size_t V_StartPos; size_t V_FindCnt; utstring_new(s); utstring_new(t); utstring_bincpy(s, V_TestStr, sizeof(V_TestStr)-1); printf("\"%s\" len=%u\n", utstring_body(s), utstring_len(s)); utstring_bincpy(t, V_NeedleStr, sizeof(V_NeedleStr)-1); printf("\"%s\" len=%u\n", utstring_body(t), utstring_len(t)); V_KMP_Table = (long *)malloc(sizeof(long) * (utstring_len(t) + 1)); 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, utstring_body(t), utstring_len(t), V_KMP_Table); if (V_FindPos >= 0) { V_FindPos += V_StartPos; V_FindCnt++; V_StartPos = V_FindPos + 1; } printf("utstring_find()=%ld\n", V_FindPos); } while (V_FindPos >= 0); printf("FindCnt=%u\n", (unsigned)V_FindCnt); free(V_KMP_Table); } else { printf("malloc() failed...\n"); } utstring_free(s); utstring_free(t); return 0; } uthash-1.9.9.1+git20151125/tests/test77.ans000066400000000000000000000003101264051566200175700ustar00rootroot00000000000000"There are two needle" len=55 "needle" len=8 utstring_find()=46 utstring_find()=14 utstring_find()=-1 FindCnt=2 expect 15 15 expect 4 4 expect -1 -1 expect 11 11 expect 4 4 expect 11 11 expect 0 0 uthash-1.9.9.1+git20151125/tests/test77.c000066400000000000000000000043211264051566200172370ustar00rootroot00000000000000#include /* printf */ #include "utstring.h" int main() { UT_string *s,*t; char V_TestStr[] = "There are two needle\0s in this \0haystack with needle\0s."; char V_NeedleStr[] = "needle\0s"; long *V_KMP_Table; long V_FindPos; size_t V_StartPos; size_t V_FindCnt; utstring_new(s); utstring_new(t); utstring_bincpy(s, V_TestStr, sizeof(V_TestStr)-1); printf("\"%s\" len=%u\n", utstring_body(s), utstring_len(s)); utstring_bincpy(t, V_NeedleStr, sizeof(V_NeedleStr)-1); printf("\"%s\" len=%u\n", utstring_body(t), utstring_len(t)); V_KMP_Table = (long *)malloc(sizeof(long) * (utstring_len(t) + 1)); 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), V_StartPos + 1, utstring_body(t), utstring_len(t), V_KMP_Table); if (V_FindPos >= 0) { V_FindCnt++; V_StartPos = V_FindPos - 1; } printf("utstring_find()=%ld\n", V_FindPos); } while (V_FindPos >= 0); printf("FindCnt=%u\n", (unsigned)V_FindCnt); free(V_KMP_Table); } else { printf("malloc() failed...\n"); } utstring_free(t); utstring_clear(s); utstring_printf(s,"ABC ABCDAB ABCDABCDABDE"); int o; o=utstring_find( s, -9, "ABC", 3 ) ; printf("expect 15 %d\n",o); o=utstring_find( s, 3, "ABC", 3 ) ; printf("expect 4 %d\n",o); o=utstring_find( s, 16, "ABC", 3 ) ; printf("expect -1 %d\n",o); o=utstring_findR( s, -9, "ABC", 3 ) ; printf("expect 11 %d\n",o); o=utstring_findR( s, 12, "ABC", 3 ) ; printf("expect 4 %d\n",o); o=utstring_findR( s, 13, "ABC", 3 ) ; printf("expect 11 %d\n",o); o=utstring_findR( s, 2, "ABC", 3 ) ; printf("expect 0 %d\n",o); utstring_free(s); return 0; } uthash-1.9.9.1+git20151125/tests/test78.ans000066400000000000000000000004341264051566200176000ustar00rootroot00000000000000CDL macros c b a advancing head pointer b a c b a c b a c b a c b b c a b c a b c a b deleting b a c deleting (a) c deleting (c) DL macros a b c deleting tail c a b deleting head a b deleting head b LL macros a b c deleting tail c a b deleting head a b deleting head b uthash-1.9.9.1+git20151125/tests/test78.c000066400000000000000000000055711264051566200172500ustar00rootroot00000000000000#include #include "utlist.h" typedef struct el { int id; struct el *Next, *Prev; } el; int main(int argc, char *argv[]) { int i; el els[10], *e; el *head = NULL; for(i=0; i<10; i++) { els[i].id=(int)'a'+i; } /* test CDL macros */ printf("CDL macros\n"); CDL_PREPEND2(head,&els[0],Prev,Next); CDL_PREPEND2(head,&els[1],Prev,Next); CDL_PREPEND2(head,&els[2],Prev,Next); CDL_FOREACH2(head,e,Next) { printf("%c ", e->id); } printf("\n"); /* point head to head->next */ printf("advancing head pointer\n"); head = head->Next; CDL_FOREACH2(head,e,Next) { printf("%c ", e->id); } printf("\n"); /* follow circular loop a few times */ for(i=0,e=head; e && i<10; i++,e=e->Next) { printf("%c ", e->id); } printf("\n"); /* follow circular loop backwards a few times */ for(i=0,e=head; e && i<10; i++,e=e->Prev) { printf("%c ", e->id); } printf("\n"); printf("deleting b\n"); CDL_DELETE2(head,&els[1],Prev,Next); CDL_FOREACH2(head,e,Next) { printf("%c ", e->id); } printf("\n"); printf("deleting (a)\n"); CDL_DELETE2(head,&els[0],Prev,Next); CDL_FOREACH2(head,e,Next) { printf("%c ", e->id); } printf("\n"); printf("deleting (c)\n"); CDL_DELETE2(head,&els[2],Prev,Next); CDL_FOREACH2(head,e,Next) { printf("%c ", e->id); } printf("\n"); /* test DL macros */ printf("DL macros\n"); DL_APPEND2(head,&els[0],Prev,Next); DL_APPEND2(head,&els[1],Prev,Next); DL_APPEND2(head,&els[2],Prev,Next); DL_FOREACH2(head,e,Next) { printf("%c ", e->id); } printf("\n"); printf("deleting tail c\n"); DL_DELETE2(head,&els[2],Prev,Next); DL_FOREACH2(head,e,Next) { printf("%c ", e->id); } printf("\n"); printf("deleting head a\n"); DL_DELETE2(head,&els[0],Prev,Next); DL_FOREACH2(head,e,Next) { printf("%c ", e->id); } printf("\n"); printf("deleting head b\n"); DL_DELETE2(head,&els[1],Prev,Next); DL_FOREACH2(head,e,Next) { printf("%c ", e->id); } printf("\n"); /* test LL macros */ printf("LL macros\n"); LL_APPEND2(head,&els[0],Next); LL_APPEND2(head,&els[1],Next); LL_APPEND2(head,&els[2],Next); LL_FOREACH2(head,e,Next) { printf("%c ", e->id); } printf("\n"); printf("deleting tail c\n"); LL_DELETE2(head,&els[2],Next); LL_FOREACH2(head,e,Next) { printf("%c ", e->id); } printf("\n"); printf("deleting head a\n"); LL_DELETE2(head,&els[0],Next); LL_FOREACH2(head,e,Next) { printf("%c ", e->id); } printf("\n"); printf("deleting head b\n"); LL_DELETE2(head,&els[1],Next); LL_FOREACH2(head,e,Next) { printf("%c ", e->id); } printf("\n"); return 0; } uthash-1.9.9.1+git20151125/tests/test79.ans000066400000000000000000000002171264051566200176000ustar00rootroot00000000000000added 10 100 id 10, tag 100 added 11 101 id 10, tag 100 id 11, tag 101 replaced 11 that had tag 101 with tag 102 id 10, tag 100 id 11, tag 102 uthash-1.9.9.1+git20151125/tests/test79.c000066400000000000000000000027671264051566200172550ustar00rootroot00000000000000#include #include #include "uthash.h" typedef struct hs_t { int id; int tag; UT_hash_handle hh; } hs_t; static void pr(hs_t **hdpp) { hs_t *el, *tmp, *hdp = *hdpp; HASH_ITER(hh, hdp, el, tmp) { printf("id %d, tag %d\n",el->id,el->tag); } } int main(int argc, char *argv[]) { hs_t *hs_head=NULL, *tmp, *replaced=NULL; tmp = (hs_t*)malloc(sizeof(hs_t)); if (tmp == NULL) { exit(-1); } tmp->id = 10; tmp->tag = 100; HASH_REPLACE_INT(hs_head,id,tmp,replaced); if(replaced == NULL) { printf("added %d %d\n",tmp->id,tmp->tag); } else { printf("ERROR, ended up replacing a value, replaced: %p\n",replaced); } pr(&hs_head); tmp = (hs_t*)malloc(sizeof(hs_t)); if (tmp == NULL) { exit(-1); } tmp->id=11; tmp->tag = 101; HASH_REPLACE_INT(hs_head,id,tmp,replaced); if(replaced == NULL) { printf("added %d %d\n",tmp->id,tmp->tag); } else { printf("ERROR, ended up replacing a value, replaced: %p\n",replaced); } pr(&hs_head); tmp = (hs_t*)malloc(sizeof(hs_t)); if (tmp == NULL) { exit(-1); } tmp->id=11; tmp->tag = 102; HASH_REPLACE_INT(hs_head,id,tmp,replaced); if(replaced == NULL) { printf("ERROR, exected to replace a value with key: %d\n",tmp->id); } else { printf("replaced %d that had tag %d with tag %d\n",tmp->id,replaced->tag,tmp->tag); } pr(&hs_head); return 0; } uthash-1.9.9.1+git20151125/tests/test8.ans000066400000000000000000000005511264051566200175110ustar00rootroot00000000000000num_items in hash: 1 num_items in hash: 2 num_items in hash: 3 num_items in hash: 4 num_items in hash: 5 num_items in hash: 6 num_items in hash: 7 num_items in hash: 8 num_items in hash: 9 num_items in hash: 10 deleted; num_items in hash: 9 deleted; num_items in hash: 8 deleted; num_items in hash: 7 deleted; num_items in hash: 6 deleted; num_items in hash: 5 uthash-1.9.9.1+git20151125/tests/test8.c000066400000000000000000000017221264051566200171530ustar00rootroot00000000000000#include "uthash.h" #include /* malloc */ #include /* printf */ typedef struct example_user_t { int id; int cookie; UT_hash_handle hh; } example_user_t; int main(int argc,char *argv[]) { int i; example_user_t *user, *tmp, *users=NULL; /* create elements */ for(i=0; i<10; i++) { user = (example_user_t*)malloc(sizeof(example_user_t)); if (user == NULL) { exit(-1); } user->id = i; user->cookie = i*i; HASH_ADD_INT(users,id,user); printf("num_items in hash: %u\n", user->hh.tbl->num_items); } /* delete each even ID */ for(i=0; i<10; i+=2) { HASH_FIND_INT(users,&i,tmp); if (tmp != NULL) { HASH_DEL(users,tmp); free(tmp); printf("deleted; num_items in hash: %u\n", user->hh.tbl->num_items); } else { printf("user id %d not found\n", i); } } return 0; } uthash-1.9.9.1+git20151125/tests/test80.ans000066400000000000000000000001011264051566200175600ustar00rootroot000000000000000 1 2 3 4 5 6 7 8 9 len: 10 0 1 2 3 4 5 6 7 8 9 0 11 len: 12 uthash-1.9.9.1+git20151125/tests/test80.c000066400000000000000000000011001264051566200172210ustar00rootroot00000000000000#include #include "utarray.h" int main() { UT_array *a; int i, *p; utarray_new(a, &ut_int_icd); for(i=0; i<10; i++) { utarray_push_back(a,&i); } for(p=(int*)utarray_front(a); p!=NULL; p=(int*)utarray_next(a,p)) { printf("%d ",*p); } printf("\n"); printf("len: %u\n\n", utarray_len(a)); i=11; utarray_insert(a, &i, 11); while ( (p=(int*)utarray_next(a,p)) != NULL ) { printf("%d ", *p); } printf("\n"); printf("len: %u\n\n", utarray_len(a)); utarray_free(a); return 0; } uthash-1.9.9.1+git20151125/tests/test81.ans000066400000000000000000000000771264051566200175750ustar00rootroot000000000000000 1 2 3 4 5 6 7 8 9 len: 10 0 1 2 3 4 5 6 7 8 9 10 len: 11 uthash-1.9.9.1+git20151125/tests/test81.c000066400000000000000000000011001264051566200172220ustar00rootroot00000000000000#include #include "utarray.h" int main() { UT_array *a; int i, *p; utarray_new(a, &ut_int_icd); for(i=0; i<10; i++) { utarray_push_back(a,&i); } for(p=(int*)utarray_front(a); p!=NULL; p=(int*)utarray_next(a,p)) { printf("%d ",*p); } printf("\n"); printf("len: %u\n\n", utarray_len(a)); i=10; utarray_insert(a, &i, 10); while ( (p=(int*)utarray_next(a,p)) != NULL ) { printf("%d ", *p); } printf("\n"); printf("len: %u\n\n", utarray_len(a)); utarray_free(a); return 0; } uthash-1.9.9.1+git20151125/tests/test82.ans000066400000000000000000000003551264051566200175750ustar00rootroot000000000000000 1 2 3 4 5 6 7 8 9 len: 10 0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5 6 7 8 9 len: 20 0 1 2 3 4 5 6 7 8 9 0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5 6 7 8 9 len: 30 0 1 2 3 4 5 6 7 8 9 0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 0 1 2 3 4 5 6 7 8 9 5 6 7 8 9 len: 40 uthash-1.9.9.1+git20151125/tests/test82.c000066400000000000000000000017201264051566200172330ustar00rootroot00000000000000#include #include "utarray.h" int main() { UT_array *a,*b; int i, *p; utarray_new(a, &ut_int_icd); utarray_new(b, &ut_int_icd); for(i=0; i<10; i++) { utarray_push_back(a,&i); } for(p=(int*)utarray_front(a); p!=NULL; p=(int*)utarray_next(a,p)) { printf("%d ",*p); } printf("\n"); printf("len: %u\n\n", utarray_len(a)); utarray_inserta(b,a,10); for(p=(int*)utarray_front(b); p!=NULL; p=(int*)utarray_next(b,p)) { printf("%d ",*p); } printf("len: %u\n\n", utarray_len(b)); utarray_inserta(b,a,0); for(p=(int*)utarray_front(b); p!=NULL; p=(int*)utarray_next(b,p)) { printf("%d ",*p); } printf("len: %u\n\n", utarray_len(b)); utarray_inserta(b,a,25); for(p=(int*)utarray_front(b); p!=NULL; p=(int*)utarray_next(b,p)) { printf("%d ",*p); } printf("len: %u\n\n", utarray_len(b)); utarray_free(a); utarray_free(b); return 0; } uthash-1.9.9.1+git20151125/tests/test83.ans000066400000000000000000000014151264051566200175740ustar00rootroot00000000000000added bob (id 0) added jack (id 1) added gary (id 2) added ty (id 3) added bo (id 4) added phil (id 5) added art (id 6) added gil (id 7) added buck (id 8) added ted (id 9) found bob (id 0) replaced (y) with bob (id 0) found jack (id 1) replaced (y) with jack (id 10) found gary (id 2) replaced (y) with gary (id 20) found ty (id 3) replaced (y) with ty (id 30) found bo (id 4) replaced (y) with bo (id 40) found phil (id 5) replaced (y) with phil (id 50) found art (id 6) replaced (y) with art (id 60) found gil (id 7) replaced (y) with gil (id 70) found buck (id 8) replaced (y) with buck (id 80) found ted (id 9) replaced (y) with ted (id 90) traversing... bob (id 0) jack (id 10) gary (id 20) ty (id 30) bo (id 40) phil (id 50) art (id 60) gil (id 70) buck (id 80) ted (id 90) uthash-1.9.9.1+git20151125/tests/test83.c000066400000000000000000000035041264051566200172360ustar00rootroot00000000000000#include "uthash.h" #include #include /* malloc */ typedef struct person_t { char first_name[10]; int id; UT_hash_handle hh; } person_t; int main(int argc, char*argv[]) { person_t *people=NULL, *person, *new_person, *tmp; const char **name; const char * names[] = { "bob", "jack", "gary", "ty", "bo", "phil", "art", "gil", "buck", "ted", NULL }; int id=0; for(name=names; *name!=NULL; name++) { person = (person_t*)malloc(sizeof(person_t)); if (person == NULL) { exit(-1); } strncpy(person->first_name, *name,sizeof(person->first_name)); person->id = id++; HASH_ADD_STR(people,first_name,person); printf("added %s (id %d)\n", person->first_name, person->id); } person=NULL; person_t **p=&person; for(name=names; *name!=NULL; name++) { HASH_FIND_STR(people,*name,*p); if (person != NULL) { printf("found %s (id %d)\n", person->first_name, person->id); new_person = malloc(sizeof(person_t)); if (new_person == NULL) { exit(-1); } memcpy(new_person, person, sizeof(person_t)); new_person->id = person->id*10; HASH_REPLACE_STR(people,first_name,new_person,tmp); printf("replaced (%c) with %s (id %d)\n", (tmp!=NULL)?'y':'n', new_person->first_name, new_person->id); if (tmp != NULL) { free(tmp); } } else { printf("failed to find %s\n", *name); } } printf("traversing... \n"); HASH_ITER(hh, people, person, tmp) { printf("%s (id %d)\n", person->first_name, person->id); HASH_DEL(people,person); free(person); } return 0; } uthash-1.9.9.1+git20151125/tests/test84.ans000066400000000000000000000014151264051566200175750ustar00rootroot00000000000000added bob (id 0) added jack (id 1) added gary (id 2) added ty (id 3) added bo (id 4) added phil (id 5) added art (id 6) added gil (id 7) added buck (id 8) added ted (id 9) found bob (id 0) replaced (y) with bob (id 0) found jack (id 1) replaced (y) with jack (id 10) found gary (id 2) replaced (y) with gary (id 20) found ty (id 3) replaced (y) with ty (id 30) found bo (id 4) replaced (y) with bo (id 40) found phil (id 5) replaced (y) with phil (id 50) found art (id 6) replaced (y) with art (id 60) found gil (id 7) replaced (y) with gil (id 70) found buck (id 8) replaced (y) with buck (id 80) found ted (id 9) replaced (y) with ted (id 90) traversing... bob (id 0) jack (id 10) gary (id 20) ty (id 30) bo (id 40) phil (id 50) art (id 60) gil (id 70) buck (id 80) ted (id 90) uthash-1.9.9.1+git20151125/tests/test84.c000066400000000000000000000042021264051566200172330ustar00rootroot00000000000000#include "uthash.h" #include #include /* malloc */ typedef struct person_t { char *first_name; int id; UT_hash_handle hh; } person_t; int main(int argc, char*argv[]) { person_t *people=NULL, *person, *new_person, *tmp; const char **name; const char * names[] = { "bob", "jack", "gary", "ty", "bo", "phil", "art", "gil", "buck", "ted", NULL }; int id=0; for(name=names; *name!=NULL; name++) { person = (person_t*)malloc(sizeof(person_t)); if (person == NULL) { exit(-1); } person->first_name = malloc(10UL); if (person->first_name == NULL) { exit(-1); } strncpy(person->first_name, *name,10UL); person->id = id++; HASH_ADD_STR(people,first_name,person); printf("added %s (id %d)\n", person->first_name, person->id); } person=NULL; person_t **p=&person; for(name=names; *name!=NULL; name++) { HASH_FIND_STR(people,*name,*p); if (person != NULL) { printf("found %s (id %d)\n", person->first_name, person->id); new_person = malloc(sizeof(person_t)); if (new_person == NULL) { exit(-1); } new_person->first_name = malloc(10UL); if (new_person->first_name == NULL) { exit(-1); } strncpy(new_person->first_name, person->first_name,10UL); new_person->id = person->id*10; HASH_REPLACE_STR(people,first_name,new_person,tmp); printf("replaced (%c) with %s (id %d)\n", (tmp!=NULL)?'y':'n', new_person->first_name, new_person->id); if (tmp != NULL) { free(tmp->first_name); free(tmp); } } else { printf("failed to find %s\n", *name); } } printf("traversing... \n"); HASH_ITER(hh, people, person, tmp) { printf("%s (id %d)\n", person->first_name, person->id); HASH_DEL(people,person); free(person->first_name); free(person); } return 0; } uthash-1.9.9.1+git20151125/tests/test85.ans000066400000000000000000000000401264051566200175670ustar00rootroot00000000000000overhead non-zero overhead zero uthash-1.9.9.1+git20151125/tests/test85.c000066400000000000000000000015311264051566200172360ustar00rootroot00000000000000#include "uthash.h" #include /* malloc */ #include /* printf */ typedef struct example_user_t { int id; int cookie; UT_hash_handle hh; } example_user_t; int main(int argc,char *argv[]) { int i; example_user_t *user, *users=NULL; /* create elements */ for(i=0; i<10; i++) { user = (example_user_t*)malloc(sizeof(example_user_t)); if (user == NULL) { exit(-1); } user->id = i; user->cookie = i*i; HASH_ADD_INT(users,id,user); } size_t s = HASH_OVERHEAD(hh,users); printf("overhead %s\n", (s==0U)?"zero":"non-zero"); HASH_CLEAR(hh,users); // should free those elements // but this test is not concerned with that s = HASH_OVERHEAD(hh,users); printf("overhead %s\n", (s==0U)?"zero":"non-zero"); return 0; } uthash-1.9.9.1+git20151125/tests/test9.ans000066400000000000000000000267011264051566200175170ustar00rootroot00000000000000user 0, cookie 0 user 2, cookie 4 user 4, cookie 16 user 6, cookie 36 user 8, cookie 64 user 10, cookie 100 user 12, cookie 144 user 14, cookie 196 user 16, cookie 256 user 18, cookie 324 user 20, cookie 400 user 22, cookie 484 user 24, cookie 576 user 26, cookie 676 user 28, cookie 784 user 30, cookie 900 user 32, cookie 1024 user 34, cookie 1156 user 36, cookie 1296 user 38, cookie 1444 user 40, cookie 1600 user 42, cookie 1764 user 44, cookie 1936 user 46, cookie 2116 user 48, cookie 2304 user 50, cookie 2500 user 52, cookie 2704 user 54, cookie 2916 user 56, cookie 3136 user 58, cookie 3364 user 60, cookie 3600 user 62, cookie 3844 user 64, cookie 4096 user 66, cookie 4356 user 68, cookie 4624 user 70, cookie 4900 user 72, cookie 5184 user 74, cookie 5476 user 76, cookie 5776 user 78, cookie 6084 user 80, cookie 6400 user 82, cookie 6724 user 84, cookie 7056 user 86, cookie 7396 user 88, cookie 7744 user 90, cookie 8100 user 92, cookie 8464 user 94, cookie 8836 user 96, cookie 9216 user 98, cookie 9604 user 100, cookie 10000 user 102, cookie 10404 user 104, cookie 10816 user 106, cookie 11236 user 108, cookie 11664 user 110, cookie 12100 user 112, cookie 12544 user 114, cookie 12996 user 116, cookie 13456 user 118, cookie 13924 user 120, cookie 14400 user 122, cookie 14884 user 124, cookie 15376 user 126, cookie 15876 user 128, cookie 16384 user 130, cookie 16900 user 132, cookie 17424 user 134, cookie 17956 user 136, cookie 18496 user 138, cookie 19044 user 140, cookie 19600 user 142, cookie 20164 user 144, cookie 20736 user 146, cookie 21316 user 148, cookie 21904 user 150, cookie 22500 user 152, cookie 23104 user 154, cookie 23716 user 156, cookie 24336 user 158, cookie 24964 user 160, cookie 25600 user 162, cookie 26244 user 164, cookie 26896 user 166, cookie 27556 user 168, cookie 28224 user 170, cookie 28900 user 172, cookie 29584 user 174, cookie 30276 user 176, cookie 30976 user 178, cookie 31684 user 180, cookie 32400 user 182, cookie 33124 user 184, cookie 33856 user 186, cookie 34596 user 188, cookie 35344 user 190, cookie 36100 user 192, cookie 36864 user 194, cookie 37636 user 196, cookie 38416 user 198, cookie 39204 user 200, cookie 40000 user 202, cookie 40804 user 204, cookie 41616 user 206, cookie 42436 user 208, cookie 43264 user 210, cookie 44100 user 212, cookie 44944 user 214, cookie 45796 user 216, cookie 46656 user 218, cookie 47524 user 220, cookie 48400 user 222, cookie 49284 user 224, cookie 50176 user 226, cookie 51076 user 228, cookie 51984 user 230, cookie 52900 user 232, cookie 53824 user 234, cookie 54756 user 236, cookie 55696 user 238, cookie 56644 user 240, cookie 57600 user 242, cookie 58564 user 244, cookie 59536 user 246, cookie 60516 user 248, cookie 61504 user 250, cookie 62500 user 252, cookie 63504 user 254, cookie 64516 user 256, cookie 65536 user 258, cookie 66564 user 260, cookie 67600 user 262, cookie 68644 user 264, cookie 69696 user 266, cookie 70756 user 268, cookie 71824 user 270, cookie 72900 user 272, cookie 73984 user 274, cookie 75076 user 276, cookie 76176 user 278, cookie 77284 user 280, cookie 78400 user 282, cookie 79524 user 284, cookie 80656 user 286, cookie 81796 user 288, cookie 82944 user 290, cookie 84100 user 292, cookie 85264 user 294, cookie 86436 user 296, cookie 87616 user 298, cookie 88804 user 300, cookie 90000 user 302, cookie 91204 user 304, cookie 92416 user 306, cookie 93636 user 308, cookie 94864 user 310, cookie 96100 user 312, cookie 97344 user 314, cookie 98596 user 316, cookie 99856 user 318, cookie 101124 user 320, cookie 102400 user 322, cookie 103684 user 324, cookie 104976 user 326, cookie 106276 user 328, cookie 107584 user 330, cookie 108900 user 332, cookie 110224 user 334, cookie 111556 user 336, cookie 112896 user 338, cookie 114244 user 340, cookie 115600 user 342, cookie 116964 user 344, cookie 118336 user 346, cookie 119716 user 348, cookie 121104 user 350, cookie 122500 user 352, cookie 123904 user 354, cookie 125316 user 356, cookie 126736 user 358, cookie 128164 user 360, cookie 129600 user 362, cookie 131044 user 364, cookie 132496 user 366, cookie 133956 user 368, cookie 135424 user 370, cookie 136900 user 372, cookie 138384 user 374, cookie 139876 user 376, cookie 141376 user 378, cookie 142884 user 380, cookie 144400 user 382, cookie 145924 user 384, cookie 147456 user 386, cookie 148996 user 388, cookie 150544 user 390, cookie 152100 user 392, cookie 153664 user 394, cookie 155236 user 396, cookie 156816 user 398, cookie 158404 user 400, cookie 160000 user 402, cookie 161604 user 404, cookie 163216 user 406, cookie 164836 user 408, cookie 166464 user 410, cookie 168100 user 412, cookie 169744 user 414, cookie 171396 user 416, cookie 173056 user 418, cookie 174724 user 420, cookie 176400 user 422, cookie 178084 user 424, cookie 179776 user 426, cookie 181476 user 428, cookie 183184 user 430, cookie 184900 user 432, cookie 186624 user 434, cookie 188356 user 436, cookie 190096 user 438, cookie 191844 user 440, cookie 193600 user 442, cookie 195364 user 444, cookie 197136 user 446, cookie 198916 user 448, cookie 200704 user 450, cookie 202500 user 452, cookie 204304 user 454, cookie 206116 user 456, cookie 207936 user 458, cookie 209764 user 460, cookie 211600 user 462, cookie 213444 user 464, cookie 215296 user 466, cookie 217156 user 468, cookie 219024 user 470, cookie 220900 user 472, cookie 222784 user 474, cookie 224676 user 476, cookie 226576 user 478, cookie 228484 user 480, cookie 230400 user 482, cookie 232324 user 484, cookie 234256 user 486, cookie 236196 user 488, cookie 238144 user 490, cookie 240100 user 492, cookie 242064 user 494, cookie 244036 user 496, cookie 246016 user 498, cookie 248004 user 500, cookie 250000 user 502, cookie 252004 user 504, cookie 254016 user 506, cookie 256036 user 508, cookie 258064 user 510, cookie 260100 user 512, cookie 262144 user 514, cookie 264196 user 516, cookie 266256 user 518, cookie 268324 user 520, cookie 270400 user 522, cookie 272484 user 524, cookie 274576 user 526, cookie 276676 user 528, cookie 278784 user 530, cookie 280900 user 532, cookie 283024 user 534, cookie 285156 user 536, cookie 287296 user 538, cookie 289444 user 540, cookie 291600 user 542, cookie 293764 user 544, cookie 295936 user 546, cookie 298116 user 548, cookie 300304 user 550, cookie 302500 user 552, cookie 304704 user 554, cookie 306916 user 556, cookie 309136 user 558, cookie 311364 user 560, cookie 313600 user 562, cookie 315844 user 564, cookie 318096 user 566, cookie 320356 user 568, cookie 322624 user 570, cookie 324900 user 572, cookie 327184 user 574, cookie 329476 user 576, cookie 331776 user 578, cookie 334084 user 580, cookie 336400 user 582, cookie 338724 user 584, cookie 341056 user 586, cookie 343396 user 588, cookie 345744 user 590, cookie 348100 user 592, cookie 350464 user 594, cookie 352836 user 596, cookie 355216 user 598, cookie 357604 user 600, cookie 360000 user 602, cookie 362404 user 604, cookie 364816 user 606, cookie 367236 user 608, cookie 369664 user 610, cookie 372100 user 612, cookie 374544 user 614, cookie 376996 user 616, cookie 379456 user 618, cookie 381924 user 620, cookie 384400 user 622, cookie 386884 user 624, cookie 389376 user 626, cookie 391876 user 628, cookie 394384 user 630, cookie 396900 user 632, cookie 399424 user 634, cookie 401956 user 636, cookie 404496 user 638, cookie 407044 user 640, cookie 409600 user 642, cookie 412164 user 644, cookie 414736 user 646, cookie 417316 user 648, cookie 419904 user 650, cookie 422500 user 652, cookie 425104 user 654, cookie 427716 user 656, cookie 430336 user 658, cookie 432964 user 660, cookie 435600 user 662, cookie 438244 user 664, cookie 440896 user 666, cookie 443556 user 668, cookie 446224 user 670, cookie 448900 user 672, cookie 451584 user 674, cookie 454276 user 676, cookie 456976 user 678, cookie 459684 user 680, cookie 462400 user 682, cookie 465124 user 684, cookie 467856 user 686, cookie 470596 user 688, cookie 473344 user 690, cookie 476100 user 692, cookie 478864 user 694, cookie 481636 user 696, cookie 484416 user 698, cookie 487204 user 700, cookie 490000 user 702, cookie 492804 user 704, cookie 495616 user 706, cookie 498436 user 708, cookie 501264 user 710, cookie 504100 user 712, cookie 506944 user 714, cookie 509796 user 716, cookie 512656 user 718, cookie 515524 user 720, cookie 518400 user 722, cookie 521284 user 724, cookie 524176 user 726, cookie 527076 user 728, cookie 529984 user 730, cookie 532900 user 732, cookie 535824 user 734, cookie 538756 user 736, cookie 541696 user 738, cookie 544644 user 740, cookie 547600 user 742, cookie 550564 user 744, cookie 553536 user 746, cookie 556516 user 748, cookie 559504 user 750, cookie 562500 user 752, cookie 565504 user 754, cookie 568516 user 756, cookie 571536 user 758, cookie 574564 user 760, cookie 577600 user 762, cookie 580644 user 764, cookie 583696 user 766, cookie 586756 user 768, cookie 589824 user 770, cookie 592900 user 772, cookie 595984 user 774, cookie 599076 user 776, cookie 602176 user 778, cookie 605284 user 780, cookie 608400 user 782, cookie 611524 user 784, cookie 614656 user 786, cookie 617796 user 788, cookie 620944 user 790, cookie 624100 user 792, cookie 627264 user 794, cookie 630436 user 796, cookie 633616 user 798, cookie 636804 user 800, cookie 640000 user 802, cookie 643204 user 804, cookie 646416 user 806, cookie 649636 user 808, cookie 652864 user 810, cookie 656100 user 812, cookie 659344 user 814, cookie 662596 user 816, cookie 665856 user 818, cookie 669124 user 820, cookie 672400 user 822, cookie 675684 user 824, cookie 678976 user 826, cookie 682276 user 828, cookie 685584 user 830, cookie 688900 user 832, cookie 692224 user 834, cookie 695556 user 836, cookie 698896 user 838, cookie 702244 user 840, cookie 705600 user 842, cookie 708964 user 844, cookie 712336 user 846, cookie 715716 user 848, cookie 719104 user 850, cookie 722500 user 852, cookie 725904 user 854, cookie 729316 user 856, cookie 732736 user 858, cookie 736164 user 860, cookie 739600 user 862, cookie 743044 user 864, cookie 746496 user 866, cookie 749956 user 868, cookie 753424 user 870, cookie 756900 user 872, cookie 760384 user 874, cookie 763876 user 876, cookie 767376 user 878, cookie 770884 user 880, cookie 774400 user 882, cookie 777924 user 884, cookie 781456 user 886, cookie 784996 user 888, cookie 788544 user 890, cookie 792100 user 892, cookie 795664 user 894, cookie 799236 user 896, cookie 802816 user 898, cookie 806404 user 900, cookie 810000 user 902, cookie 813604 user 904, cookie 817216 user 906, cookie 820836 user 908, cookie 824464 user 910, cookie 828100 user 912, cookie 831744 user 914, cookie 835396 user 916, cookie 839056 user 918, cookie 842724 user 920, cookie 846400 user 922, cookie 850084 user 924, cookie 853776 user 926, cookie 857476 user 928, cookie 861184 user 930, cookie 864900 user 932, cookie 868624 user 934, cookie 872356 user 936, cookie 876096 user 938, cookie 879844 user 940, cookie 883600 user 942, cookie 887364 user 944, cookie 891136 user 946, cookie 894916 user 948, cookie 898704 user 950, cookie 902500 user 952, cookie 906304 user 954, cookie 910116 user 956, cookie 913936 user 958, cookie 917764 user 960, cookie 921600 user 962, cookie 925444 user 964, cookie 929296 user 966, cookie 933156 user 968, cookie 937024 user 970, cookie 940900 user 972, cookie 944784 user 974, cookie 948676 user 976, cookie 952576 user 978, cookie 956484 user 980, cookie 960400 user 982, cookie 964324 user 984, cookie 968256 user 986, cookie 972196 user 988, cookie 976144 user 990, cookie 980100 user 992, cookie 984064 user 994, cookie 988036 user 996, cookie 992016 user 998, cookie 996004 uthash-1.9.9.1+git20151125/tests/test9.c000066400000000000000000000015061264051566200171540ustar00rootroot00000000000000#include "uthash.h" #include /* malloc */ #include /* printf */ typedef struct example_user_t { int id; int cookie; UT_hash_handle hh; } example_user_t; int main(int argc,char *argv[]) { int i; example_user_t *user, *tmp, *users=NULL; /* create elements */ for(i=0; i<1000; i++) { user = (example_user_t*)malloc(sizeof(example_user_t)); if (user == NULL) { exit(-1); } user->id = i; user->cookie = i*i; HASH_ADD_INT(users,id,user); } /* delete each ID */ for(i=0; i<1000; i+=2) { HASH_FIND_INT(users,&i,tmp); if (tmp != NULL) { printf("user %d, cookie %d\n", tmp->id, tmp->cookie); } else { printf("user id %d not found\n", i); } } return 0; } uthash-1.9.9.1+git20151125/tests/threads/000077500000000000000000000000001264051566200173705ustar00rootroot00000000000000uthash-1.9.9.1+git20151125/tests/threads/Makefile000066400000000000000000000012161264051566200210300ustar00rootroot00000000000000HASHDIR = ../../src PROGS = test1 test2 # Thread support requires compiler-specific options # ---------------------------------------------------------------------------- # GNU CFLAGS += -I$(HASHDIR) -g -pthread # Solaris (Studio 11) #CFLAGS = -I$(HASHDIR) -g -mt # ---------------------------------------------------------------------------- ifeq ($(HASH_DEBUG),1) CFLAGS += -DHASH_DEBUG=1 endif all: $(PROGS) run_tests $(PROGS) : $(HASHDIR)/uthash.h $(CC) $(CPPLFAGS) $(CFLAGS) $(LDFLAGS) -o $@ $(@).c debug: $(MAKE) all HASH_DEBUG=1 run_tests: $(PROGS) perl ../do_tests .PHONY: clean clean: rm -f $(PROGS) test*.out rm -rf test*.dSYM uthash-1.9.9.1+git20151125/tests/threads/README000066400000000000000000000001701264051566200202460ustar00rootroot00000000000000test1: exercise a two-reader, one-writer, rwlock-protected hash. test2: a template for a nthread, nloop kind of program uthash-1.9.9.1+git20151125/tests/threads/do_tests000077500000000000000000000006461264051566200211500ustar00rootroot00000000000000#!/usr/bin/perl use strict; use warnings; my @tests; for (glob "test*[0-9]") { push @tests, $_ if -e "$_.ans"; } my $num_failed=0; for my $test (@tests) { `./$test > $test.out 2> $test.err`; `diff $test.out $test.ans`; print "$test failed\n" if $?; $num_failed++ if $?; unlink "$test.err" if -z "$test.err"; } print scalar @tests . " tests conducted, $num_failed failed.\n"; exit $num_failed; uthash-1.9.9.1+git20151125/tests/threads/test1.c000066400000000000000000000057161264051566200206050ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include "uthash.h" #undef uthash_noexpand_fyi #define uthash_noexpand_fyi fprintf(stderr,"warning: bucket expansion inhibited\n"); #define LOOPS 100000 typedef struct { int i; UT_hash_handle hh; } elt; elt *elts=NULL; /* this is our hash table which two threads will use */ pthread_rwlock_t lock; void *thread_routine_r( void *arg ) { int i; long num_found=0; elt *e; for(i=0;ii = i; HASH_ADD_INT(elts, i, e); } pthread_rwlock_unlock(&lock); } return (void*)num_deld; } int main() { unsigned i; long num_added=0; int status; pthread_t thread_r1,thread_r2,thread_w1,thread_w2; void *thread_result; elt tmp, *e; if (pthread_rwlock_init(&lock,NULL) != 0) { fprintf(stderr,"lock init failed\n"); exit(-1); } if ( status = pthread_create( &thread_r1, NULL, thread_routine_r, NULL )) { printf("failure: status %d\n", status); exit(-1); } if ( status = pthread_create( &thread_r2, NULL, thread_routine_r, NULL )) { printf("failure: status %d\n", status); exit(-1); } if ( status = pthread_create( &thread_w1, NULL, thread_routine_w, NULL )) { printf("failure: status %d\n", status); exit(-1); } if ( status = pthread_create( &thread_w2, NULL, thread_routine_w, NULL )) { printf("failure: status %d\n", status); exit(-1); } status = pthread_join( thread_r1, &thread_result ); printf("thread result: %d %ld\n", status, (long)thread_result); status = pthread_join( thread_r2, &thread_result ); printf("thread result: %d %ld\n", status, (long)thread_result); status = pthread_join( thread_w1, &thread_result ); printf("thread result: %d %ld\n", status, (long)thread_result); status = pthread_join( thread_w2, &thread_result ); printf("thread result: %d %ld\n", status, (long)thread_result); i = HASH_COUNT(elts); printf("final count of items in hash: %u\n", i); if (pthread_rwlock_destroy(&lock) != 0) { fprintf(stderr,"lock destroy failed\n"); exit(-1); } } uthash-1.9.9.1+git20151125/tests/threads/test2.c000066400000000000000000000031471264051566200206020ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include "uthash.h" #undef uthash_noexpand_fyi #define uthash_noexpand_fyi fprintf(stderr,"warning: bucket expansion inhibited\n"); #define LOOPS 100000 #define NTHREADS 2 typedef struct { int i; int v; UT_hash_handle hh; } elt; elt *elts=NULL; /* this is our hash table which two threads will use */ pthread_rwlock_t lock; void *thread_routine( void *arg ) { int keepgoing=0; /* TODO write me */ return NULL; } int main() { unsigned i; long num_added=0; int status; pthread_t thread[NTHREADS]; void *thread_result; elt tmp, *e; if (pthread_rwlock_init(&lock,NULL) != 0) { fprintf(stderr,"lock init failed\n"); exit(-1); } /* populate it to start */ for(i=0; ii = i; e->v = 0; HASH_ADD_INT(elts, i, e); } for(i=0; i