d
This commit is contained in:
120
c/ext/uthash/tests/Makefile
Normal file
120
c/ext/uthash/tests/Makefile
Normal file
@@ -0,0 +1,120 @@
|
||||
#CC=clang
|
||||
HASHDIR = ../src
|
||||
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 test86 test87 test88 test89 \
|
||||
test90 test91 test92 test93 test94 test95 test96
|
||||
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
|
||||
|
||||
# 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) keystat $(TEST_TARGET)
|
||||
|
||||
tests_only: $(PROGS) $(TEST_TARGET)
|
||||
|
||||
GITIGN = .gitignore
|
||||
MKGITIGN = [ -f "$(GITIGN)" ] || echo "$(GITIGN)" > $(GITIGN); grep -q '^\$@$$' $(GITIGN) || echo "$@" >> $(GITIGN)
|
||||
|
||||
debug:
|
||||
$(MAKE) all HASH_DEBUG=1
|
||||
|
||||
pedantic:
|
||||
$(MAKE) all HASH_PEDANTIC=1
|
||||
|
||||
cplusplus:
|
||||
CC="$(CXX) -x c++" $(MAKE) all
|
||||
|
||||
thorough:
|
||||
$(MAKE) clean && $(MAKE) all EXTRA_CFLAGS='-pedantic'
|
||||
$(MAKE) clean && $(MAKE) all EXTRA_CFLAGS='-pedantic -DHASH_BLOOM=16'
|
||||
$(MAKE) clean && $(MAKE) tests_only EXTRA_CFLAGS='-pedantic -DHASH_BLOOM=16 -DHASH_DEBUG -DNO_DECLTYPE'
|
||||
$(MAKE) clean && CC="$(CXX) -x c++" $(MAKE) all EXTRA_CFLAGS='-pedantic'
|
||||
$(MAKE) clean && CC="$(CXX) -x c++" $(MAKE) all EXTRA_CFLAGS='-pedantic -DHASH_BLOOM=16'
|
||||
$(MAKE) clean && CC="$(CXX) -x c++" $(MAKE) tests_only EXTRA_CFLAGS='-pedantic -DHASH_BLOOM=16 -DHASH_DEBUG -DNO_DECLTYPE'
|
||||
|
||||
example: example.c $(HASHDIR)/uthash.h
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $(@).c
|
||||
|
||||
$(PROGS) $(UTILS) : $(HASHDIR)/uthash.h
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $(@).c
|
||||
@$(MKGITIGN)
|
||||
|
||||
hashscan : $(HASHDIR)/uthash.h
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $(@).c
|
||||
@$(MKGITIGN)
|
||||
|
||||
sleep_test : $(HASHDIR)/uthash.h
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -DHASH_BLOOM=16 $(LDFLAGS) -o $@ $(@).c
|
||||
@$(MKGITIGN)
|
||||
|
||||
keystat : $(HASHDIR)/uthash.h
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -DHASH_FUNCTION=HASH_BER $(LDFLAGS) -o keystat.BER keystat.c
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -DHASH_FUNCTION=HASH_FNV $(LDFLAGS) -o keystat.FNV keystat.c
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -DHASH_FUNCTION=HASH_JEN $(LDFLAGS) -o keystat.JEN keystat.c
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -DHASH_FUNCTION=HASH_OAT $(LDFLAGS) -o keystat.OAT keystat.c
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -DHASH_FUNCTION=HASH_SAX $(LDFLAGS) -o keystat.SAX keystat.c
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -DHASH_FUNCTION=HASH_SFH $(LDFLAGS) -o keystat.SFH 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 hashscan sleep_test *.exe $(GITIGN)
|
||||
rm -rf *.dSYM
|
||||
132
c/ext/uthash/tests/README
Normal file
132
c/ext/uthash/tests/README
Normal file
@@ -0,0 +1,132 @@
|
||||
Automated 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 (and alt key-comparison macro)
|
||||
test7: test alt malloc macros with 1000 structs so bucket expansion occurs
|
||||
test8: test num_items counter in UT_hash_handle
|
||||
test9: test "find" after bucket expansion
|
||||
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
|
||||
test86: test *_APPEND_ELEM / *_PREPEND_ELEM (Thilo Schulz)
|
||||
test87: test HASH_ADD_INORDER() macro (Thilo Schulz)
|
||||
test88: test alt key-comparison and strlen macros
|
||||
test89: test code from the tinydtls project
|
||||
test90: regression-test HASH_ADD_KEYPTR_INORDER (IronBug)
|
||||
test91: test LL_INSERT_INORDER etc.
|
||||
test92: HASH_NONFATAL_OOM
|
||||
test93: alt_fatal
|
||||
test94: utlist with fields named other than 'next' and 'prev'
|
||||
test95: utstack
|
||||
test96: HASH_FUNCTION + HASH_KEYCMP
|
||||
|
||||
Other Make targets
|
||||
================================================================================
|
||||
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
|
||||
|
||||
13
c/ext/uthash/tests/all_funcs
Executable file
13
c/ext/uthash/tests/all_funcs
Executable file
@@ -0,0 +1,13 @@
|
||||
#!/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_FNV'; proceed
|
||||
make clean tests_only EXTRA_CFLAGS='-DHASH_FUNCTION=HASH_JEN'; proceed
|
||||
make clean tests_only EXTRA_CFLAGS='-DHASH_FUNCTION=HASH_OAT'; proceed
|
||||
make clean tests_only EXTRA_CFLAGS='-DHASH_FUNCTION=HASH_SAX'; proceed
|
||||
make clean tests_only EXTRA_CFLAGS='-DHASH_FUNCTION=HASH_SFH'; proceed
|
||||
82
c/ext/uthash/tests/bloom_perf.c
Normal file
82
c/ext/uthash/tests/bloom_perf.c
Normal file
@@ -0,0 +1,82 @@
|
||||
#include <stdlib.h> /* malloc */
|
||||
#include <sys/time.h> /* gettimeofday */
|
||||
#include <errno.h> /* perror */
|
||||
#include <stdio.h> /* 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);
|
||||
}
|
||||
strcpy(name->boy_name, linebuf);
|
||||
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;
|
||||
}
|
||||
|
||||
17
c/ext/uthash/tests/bloom_perf.sh
Executable file
17
c/ext/uthash/tests/bloom_perf.sh
Executable file
@@ -0,0 +1,17 @@
|
||||
#!/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
|
||||
|
||||
21
c/ext/uthash/tests/do_tests
Executable file
21
c/ext/uthash/tests/do_tests
Executable file
@@ -0,0 +1,21 @@
|
||||
#!/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;
|
||||
22
c/ext/uthash/tests/do_tests.cygwin
Executable file
22
c/ext/uthash/tests/do_tests.cygwin
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/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;
|
||||
20
c/ext/uthash/tests/do_tests.mingw
Normal file
20
c/ext/uthash/tests/do_tests.mingw
Normal file
@@ -0,0 +1,20 @@
|
||||
#!/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"
|
||||
16
c/ext/uthash/tests/do_tests_win32.cmd
Normal file
16
c/ext/uthash/tests/do_tests_win32.cmd
Normal file
@@ -0,0 +1,16 @@
|
||||
:: 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
|
||||
48
c/ext/uthash/tests/emit_keys.c
Normal file
48
c/ext/uthash/tests/emit_keys.c
Normal file
@@ -0,0 +1,48 @@
|
||||
#include <stdlib.h> /* malloc */
|
||||
#include <errno.h> /* perror */
|
||||
#include <stdio.h> /* printf */
|
||||
#include <unistd.h> /* 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);
|
||||
}
|
||||
strcpy(name->boy_name, linebuf);
|
||||
HASH_ADD_STR(names,boy_name,name);
|
||||
i++;
|
||||
}
|
||||
|
||||
fprintf(stderr,"%d keys emitted.\n", i);
|
||||
fclose(file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
149
c/ext/uthash/tests/example.c
Normal file
149
c/ext/uthash/tests/example.c
Normal file
@@ -0,0 +1,149 @@
|
||||
#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()
|
||||
{
|
||||
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;
|
||||
}
|
||||
678
c/ext/uthash/tests/hashscan.c
Normal file
678
c/ext/uthash/tests/hashscan.c
Normal file
@@ -0,0 +1,678 @@
|
||||
/*
|
||||
Copyright (c) 2005-2021, 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 <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/types.h> /* on OSX, must come before ptrace.h */
|
||||
#include <sys/ptrace.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#include <sys/param.h> /* MAXPATHLEN */
|
||||
#include <vm/vm.h> /* VM_PROT_* flags */
|
||||
#endif
|
||||
|
||||
#if defined(PT_ATTACH) && !defined(PTRACE_ATTACH)
|
||||
#define PTRACE_ATTACH PT_ATTACH
|
||||
#define PTRACE_DETACH PT_DETACH
|
||||
#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 NUM_HASH_FUNCS 7 /* includes id 0, the non-function */
|
||||
const char *hash_fcns[] = {"???","JEN","BER","SFH","SAX","FNV","OAT"};
|
||||
|
||||
/* 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 ohashv;
|
||||
/* BER SAX FNV OAT JEN SFH */
|
||||
HASH_JEN(key,keylen,ohashv);
|
||||
if (ohashv == hashv) {
|
||||
return JEN;
|
||||
}
|
||||
HASH_BER(key,keylen,ohashv);
|
||||
if (ohashv == hashv) {
|
||||
return BER;
|
||||
}
|
||||
HASH_SFH(key,keylen,ohashv);
|
||||
if (ohashv == hashv) {
|
||||
return SFH;
|
||||
}
|
||||
HASH_SAX(key,keylen,ohashv);
|
||||
if (ohashv == hashv) {
|
||||
return SAX;
|
||||
}
|
||||
HASH_FNV(key,keylen,ohashv);
|
||||
if (ohashv == hashv) {
|
||||
return FNV;
|
||||
}
|
||||
HASH_OAT(key,keylen,ohashv);
|
||||
if (ohashv == hashv) {
|
||||
return OAT;
|
||||
}
|
||||
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_hh, *key=NULL;
|
||||
const char *peer_key;
|
||||
const char *hash_fcn = NULL;
|
||||
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;
|
||||
int has_bloom_filter_fields = 0;
|
||||
|
||||
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", (void*)peer_sig);
|
||||
peer_tbl = tbl_from_sig_addr(peer_sig);
|
||||
vvv("reading table at peer %p\n", (void*)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 %u buckets at peer %p\n", tbl->num_buckets, (void*)peer_bkts);
|
||||
bkts = (UT_hash_bucket*)malloc(sizeof(UT_hash_bucket)*tbl->num_buckets);
|
||||
if (bkts == NULL) {
|
||||
fprintf(stderr, "out of memory\n");
|
||||
goto done;
|
||||
}
|
||||
#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 = (const 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", (void*)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", (void*)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++;
|
||||
}
|
||||
}
|
||||
has_bloom_filter_fields = 1;
|
||||
vvv("there were %u on_bits among %u total bits\n", (unsigned)bloom_on_bits, (unsigned)bloom_bitlen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* choose apparent hash function */
|
||||
hash_fcn_winner=0;
|
||||
for(i=0; i<NUM_HASH_FUNCS; i++) {
|
||||
if (hash_fcn_hits[i] > hash_fcn_hits[hash_fcn_winner]) {
|
||||
hash_fcn_winner=i;
|
||||
}
|
||||
}
|
||||
hash_fcn = hash_fcns[hash_fcn_winner];
|
||||
|
||||
/*
|
||||
Address ideal items buckets mc fl bloom sat fcn keys saved to
|
||||
------------------ ----- -------- -------- -- -- ----- ----- --- -------------
|
||||
0x10aa4090 98% 10000000 32000000 10 ok BER /tmp/9110-0.key
|
||||
0x10abcdef 100% 10000000 32000000 9 NX 27 12% BER /tmp/9110-1.key
|
||||
*/
|
||||
printf("Address ideal items buckets mc fl bloom sat fcn keys saved to\n");
|
||||
printf("------------------ ----- -------- -------- -- -- ----- ----- --- -------------\n");
|
||||
if (has_bloom_filter_fields) {
|
||||
printf("%-18p %4.0f%% %8u %8u %2u %2s %5u %4.0f%c %3s %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",
|
||||
bloom_nbits,
|
||||
bloom_on_bits * 100.0 / bloom_bitlen, '%',
|
||||
hash_fcn,
|
||||
(getkeys ? keyfile : ""));
|
||||
} else {
|
||||
printf("%-18p %4.0f%% %8u %8u %2u %2s %5s %4s%c %3s %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",
|
||||
"",
|
||||
"", ' ',
|
||||
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<num_vmas; i++) {
|
||||
vma = vmas[i];
|
||||
sigscan(pid, vma.start, vma.end, sig);
|
||||
}
|
||||
|
||||
die:
|
||||
vv("detaching and resuming peer\n");
|
||||
if (ptrace(PT_DETACH, pid, NULL, 0) == -1) {
|
||||
fprintf(stderr,"failed to detach from %u: %s\n", (unsigned)pid, strerror(errno));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
# else
|
||||
static int scan(pid_t pid)
|
||||
{
|
||||
FILE *mapf;
|
||||
char mapfile[30], memfile[30], line[100];
|
||||
vma_t *vmas=NULL, vma;
|
||||
unsigned i, num_vmas = 0;
|
||||
int memfd;
|
||||
void *pstart, *pend, *unused;
|
||||
|
||||
/* attach to the target process and wait for it to suspend */
|
||||
vv("attaching to peer\n");
|
||||
if (ptrace(PTRACE_ATTACH, pid, NULL, 0) == -1) {
|
||||
fprintf(stderr,"failed to attach to %u: %s\n", (unsigned)pid, strerror(errno));
|
||||
exit(-1);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
/* get ready to open its memory map. this gives us its valid memory areas */
|
||||
snprintf(mapfile,sizeof(mapfile),"/proc/%u/maps",(unsigned)pid);
|
||||
snprintf(memfile,sizeof(memfile),"/proc/%u/mem", (unsigned)pid);
|
||||
vv("opening peer memory map [%s]\n", mapfile);
|
||||
if ( (mapf = fopen(mapfile,"r")) == NULL) {
|
||||
fprintf(stderr,"failed to open %s: %s\n", mapfile, strerror(errno));
|
||||
goto die;
|
||||
}
|
||||
vv("listing peer virtual memory areas\n");
|
||||
while(fgets(line,sizeof(line),mapf)) {
|
||||
if (sscanf(line, "%p-%p %4c %p %5c", &pstart, &pend, vma.perms,
|
||||
&unused, vma.device) == 5) {
|
||||
vma.start = (off_t)pstart;
|
||||
vma.end = (off_t)pend;
|
||||
if (vma.perms[0] != 'r') {
|
||||
continue; /* only readable vma's */
|
||||
}
|
||||
if (memcmp(vma.device,"fd",2)==0) {
|
||||
continue; /* skip mapped files */
|
||||
}
|
||||
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);
|
||||
fclose(mapf);
|
||||
|
||||
/* ok, open up its memory and start looking around in there */
|
||||
vv("opening peer memory\n");
|
||||
if ( (memfd=open(memfile,O_RDONLY)) == -1) {
|
||||
fprintf(stderr,"failed to open %s: %s\n", memfile, strerror(errno));
|
||||
goto die;
|
||||
}
|
||||
/* look for the hash signature */
|
||||
vv("scanning peer memory for hash table signatures\n");
|
||||
for(i=0; i<num_vmas; i++) {
|
||||
vma = vmas[i];
|
||||
pstart = (void*)vma.start;
|
||||
pend = (void*)vma.end;
|
||||
/*fprintf(stderr,"scanning %p-%p %.4s %.5s\n", pstart, pend,
|
||||
vma.perms, vma.device);*/
|
||||
sigscan(memfd, vma.start, vma.end, sig, pid);
|
||||
}
|
||||
|
||||
/* done. close memory and detach. this resumes the target process */
|
||||
close(memfd);
|
||||
|
||||
die:
|
||||
vv("detaching and resuming peer\n");
|
||||
if (ptrace(PTRACE_DETACH, pid, NULL, 0) == -1) {
|
||||
fprintf(stderr,"failed to detach from %u: %s\n", (unsigned)pid, strerror(errno));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static int usage(const char *prog)
|
||||
{
|
||||
fprintf(stderr,"usage: %s [-v] [-k] <pid>\n", prog);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int opt;
|
||||
|
||||
while ( (opt = getopt(argc, argv, "kv")) != -1) {
|
||||
switch (opt) {
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
case 'k':
|
||||
getkeys++;
|
||||
break;
|
||||
default:
|
||||
return usage(argv[0]);
|
||||
}
|
||||
}
|
||||
|
||||
if (optind < argc) {
|
||||
pid_t pid = atoi(argv[optind++]);
|
||||
return scan(pid);
|
||||
} else {
|
||||
return usage(argv[0]);
|
||||
}
|
||||
}
|
||||
42
c/ext/uthash/tests/keystats
Executable file
42
c/ext/uthash/tests/keystats
Executable file
@@ -0,0 +1,42 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
|
||||
use FindBin;
|
||||
|
||||
sub usage {
|
||||
print "usage: keystats [-v] keyfile\n";
|
||||
print "usage: keystats [-p <pct> [-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) {
|
||||
$exe =~ s/\ /\\ /g;
|
||||
$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]);
|
||||
}
|
||||
21
c/ext/uthash/tests/lru_cache/Makefile
Normal file
21
c/ext/uthash/tests/lru_cache/Makefile
Normal file
@@ -0,0 +1,21 @@
|
||||
CC=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
|
||||
221
c/ext/uthash/tests/lru_cache/cache.c
Normal file
221
c/ext/uthash/tests/lru_cache/cache.c
Normal file
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* 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 <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include "cache.h"
|
||||
#include "uthash.h"
|
||||
|
||||
/**
|
||||
* A cache entry
|
||||
*/
|
||||
struct foo_cache_entry {
|
||||
char *key; /**<The key */
|
||||
void *data; /**<Payload */
|
||||
UT_hash_handle hh; /**<Hash Handle for uthash */
|
||||
};
|
||||
#define KEY_MAX_LENGTH 32
|
||||
|
||||
/**
|
||||
* A cache object
|
||||
*/
|
||||
struct foo_cache {
|
||||
size_t max_entries; /**<Amount of entries this cache object can hold */
|
||||
pthread_rwlock_t cache_lock; /**<A lock for concurrent access */
|
||||
struct foo_cache_entry *entries; /**<Head pointer for uthash */
|
||||
void (*free_cb) (void *element);/**<Callback function to free cache entries */
|
||||
};
|
||||
|
||||
/** Creates a new cache object
|
||||
|
||||
@param dst
|
||||
Where the newly allocated cache object will be stored in
|
||||
|
||||
@param capacity
|
||||
The maximum number of elements this cache object can hold
|
||||
|
||||
@return EINVAL if dst is NULL, ENOMEM if malloc fails, 0 otherwise
|
||||
*/
|
||||
int foo_cache_create(struct foo_cache **dst, const size_t capacity,
|
||||
void (*free_cb) (void *element))
|
||||
{
|
||||
struct foo_cache *new = NULL;
|
||||
int rv;
|
||||
|
||||
if (!dst)
|
||||
return EINVAL;
|
||||
|
||||
if ((new = malloc(sizeof(*new))) == NULL)
|
||||
return ENOMEM;
|
||||
|
||||
if ((rv = pthread_rwlock_init(&(new->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 <key, value> pair into the cache
|
||||
|
||||
@param cache
|
||||
The cache object
|
||||
|
||||
@param key
|
||||
The key that identifies <value>
|
||||
|
||||
@param data
|
||||
Data associated with <key>
|
||||
|
||||
@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;
|
||||
|
||||
}
|
||||
31
c/ext/uthash/tests/lru_cache/cache.h
Normal file
31
c/ext/uthash/tests/lru_cache/cache.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* 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
|
||||
191
c/ext/uthash/tests/lru_cache/main.c
Normal file
191
c/ext/uthash/tests/lru_cache/main.c
Normal file
@@ -0,0 +1,191 @@
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#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()
|
||||
{
|
||||
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;
|
||||
}
|
||||
28
c/ext/uthash/tests/simkeys.pl
Executable file
28
c/ext/uthash/tests/simkeys.pl
Executable file
@@ -0,0 +1,28 @@
|
||||
#!/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;
|
||||
}
|
||||
|
||||
32
c/ext/uthash/tests/sleep_test.c
Normal file
32
c/ext/uthash/tests/sleep_test.c
Normal file
@@ -0,0 +1,32 @@
|
||||
#include "uthash.h"
|
||||
#include <stdlib.h> /* malloc */
|
||||
#include <stdio.h> /* printf */
|
||||
#include <unistd.h> /* getpid */
|
||||
|
||||
typedef struct example_user_t {
|
||||
int id;
|
||||
int cookie;
|
||||
UT_hash_handle hh;
|
||||
} example_user_t;
|
||||
|
||||
int main()
|
||||
{
|
||||
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;
|
||||
}
|
||||
34
c/ext/uthash/tests/tdiff.cpp
Normal file
34
c/ext/uthash/tests/tdiff.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
// Windows does not have unix diff so this is a simple replacement
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
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;
|
||||
}
|
||||
|
||||
10
c/ext/uthash/tests/test1.ans
Normal file
10
c/ext/uthash/tests/test1.ans
Normal file
@@ -0,0 +1,10 @@
|
||||
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
|
||||
31
c/ext/uthash/tests/test1.c
Normal file
31
c/ext/uthash/tests/test1.c
Normal file
@@ -0,0 +1,31 @@
|
||||
#include "uthash.h"
|
||||
#include <stdlib.h> /* malloc */
|
||||
#include <stdio.h> /* printf */
|
||||
|
||||
typedef struct example_user_t {
|
||||
int id;
|
||||
int cookie;
|
||||
UT_hash_handle hh;
|
||||
} example_user_t;
|
||||
|
||||
int main()
|
||||
{
|
||||
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;
|
||||
}
|
||||
4
c/ext/uthash/tests/test10.ans
Normal file
4
c/ext/uthash/tests/test10.ans
Normal file
@@ -0,0 +1,4 @@
|
||||
9 found in hh
|
||||
9 found in alth
|
||||
10 not found in hh
|
||||
10 found in alth
|
||||
54
c/ext/uthash/tests/test10.c
Normal file
54
c/ext/uthash/tests/test10.c
Normal file
@@ -0,0 +1,54 @@
|
||||
#include "uthash.h"
|
||||
#include <stdlib.h> /* malloc */
|
||||
#include <stdio.h> /* printf */
|
||||
|
||||
typedef struct example_user_t {
|
||||
int id;
|
||||
int cookie;
|
||||
UT_hash_handle hh;
|
||||
UT_hash_handle alth;
|
||||
} example_user_t;
|
||||
|
||||
int main()
|
||||
{
|
||||
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");
|
||||
|
||||
HASH_CLEAR(hh, users);
|
||||
HASH_CLEAR(alth, altusers);
|
||||
|
||||
return 0;
|
||||
}
|
||||
51
c/ext/uthash/tests/test11.ans
Normal file
51
c/ext/uthash/tests/test11.ans
Normal file
@@ -0,0 +1,51 @@
|
||||
ADRIAN
|
||||
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
|
||||
57
c/ext/uthash/tests/test11.c
Normal file
57
c/ext/uthash/tests/test11.c
Normal file
@@ -0,0 +1,57 @@
|
||||
#include "uthash.h"
|
||||
#include <stdlib.h> /* malloc */
|
||||
#include <errno.h> /* perror */
|
||||
#include <stdio.h> /* 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()
|
||||
{
|
||||
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);
|
||||
}
|
||||
strcpy(name->boy_name, linebuf);
|
||||
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;
|
||||
}
|
||||
|
||||
51
c/ext/uthash/tests/test11.dat
Normal file
51
c/ext/uthash/tests/test11.dat
Normal file
@@ -0,0 +1,51 @@
|
||||
JOHN
|
||||
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
|
||||
20
c/ext/uthash/tests/test12.ans
Normal file
20
c/ext/uthash/tests/test12.ans
Normal file
@@ -0,0 +1,20 @@
|
||||
added 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)
|
||||
40
c/ext/uthash/tests/test12.c
Normal file
40
c/ext/uthash/tests/test12.c
Normal file
@@ -0,0 +1,40 @@
|
||||
#include "uthash.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> /* malloc */
|
||||
|
||||
typedef struct person_t {
|
||||
char first_name[10];
|
||||
int id;
|
||||
UT_hash_handle hh;
|
||||
} person_t;
|
||||
|
||||
int main()
|
||||
{
|
||||
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);
|
||||
}
|
||||
strcpy(person->first_name, *name);
|
||||
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;
|
||||
}
|
||||
5
c/ext/uthash/tests/test13.ans
Normal file
5
c/ext/uthash/tests/test13.ans
Normal file
@@ -0,0 +1,5 @@
|
||||
id 9, following prev...
|
||||
id 7, following prev...
|
||||
id 5, following prev...
|
||||
id 3, following prev...
|
||||
id 1, following prev...
|
||||
50
c/ext/uthash/tests/test13.c
Normal file
50
c/ext/uthash/tests/test13.c
Normal file
@@ -0,0 +1,50 @@
|
||||
#include "uthash.h"
|
||||
#include <stdlib.h> /* malloc */
|
||||
#include <stdio.h> /* printf */
|
||||
|
||||
typedef struct example_user_t {
|
||||
int id;
|
||||
int cookie;
|
||||
UT_hash_handle hh;
|
||||
} example_user_t;
|
||||
|
||||
int main()
|
||||
{
|
||||
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;
|
||||
}
|
||||
1
c/ext/uthash/tests/test14.ans
Normal file
1
c/ext/uthash/tests/test14.ans
Normal file
@@ -0,0 +1 @@
|
||||
lookup on 1219 of 1219 names succeeded
|
||||
54
c/ext/uthash/tests/test14.c
Normal file
54
c/ext/uthash/tests/test14.c
Normal file
@@ -0,0 +1,54 @@
|
||||
#include "uthash.h"
|
||||
#include <stdlib.h> /* malloc */
|
||||
#include <errno.h> /* perror */
|
||||
#include <stdio.h> /* 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()
|
||||
{
|
||||
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);
|
||||
}
|
||||
strcpy(name->boy_name, linebuf);
|
||||
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;
|
||||
}
|
||||
|
||||
1219
c/ext/uthash/tests/test14.dat
Normal file
1219
c/ext/uthash/tests/test14.dat
Normal file
File diff suppressed because it is too large
Load Diff
1
c/ext/uthash/tests/test15.ans
Normal file
1
c/ext/uthash/tests/test15.ans
Normal file
@@ -0,0 +1 @@
|
||||
betty's id is 2
|
||||
40
c/ext/uthash/tests/test15.c
Normal file
40
c/ext/uthash/tests/test15.c
Normal file
@@ -0,0 +1,40 @@
|
||||
#include <string.h> /* strcpy */
|
||||
#include <stdlib.h> /* malloc */
|
||||
#include <stdio.h> /* printf */
|
||||
#include "uthash.h"
|
||||
|
||||
struct my_struct {
|
||||
char name[10]; /* key */
|
||||
int id;
|
||||
UT_hash_handle hh; /* makes this structure hashable */
|
||||
};
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
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);
|
||||
}
|
||||
strcpy(s->name, *n);
|
||||
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;
|
||||
}
|
||||
1
c/ext/uthash/tests/test16.ans
Normal file
1
c/ext/uthash/tests/test16.ans
Normal file
@@ -0,0 +1 @@
|
||||
found: user 5, unix time 157680000
|
||||
53
c/ext/uthash/tests/test16.c
Normal file
53
c/ext/uthash/tests/test16.c
Normal file
@@ -0,0 +1,53 @@
|
||||
#include <stdlib.h> /* malloc */
|
||||
#include <stddef.h> /* offsetof */
|
||||
#include <stdio.h> /* printf */
|
||||
#include <string.h> /* 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()
|
||||
{
|
||||
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;
|
||||
}
|
||||
134
c/ext/uthash/tests/test17.ans
Normal file
134
c/ext/uthash/tests/test17.ans
Normal file
@@ -0,0 +1,134 @@
|
||||
user 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
|
||||
63
c/ext/uthash/tests/test17.c
Normal file
63
c/ext/uthash/tests/test17.c
Normal file
@@ -0,0 +1,63 @@
|
||||
#include "uthash.h"
|
||||
#include <stdlib.h> /* malloc */
|
||||
#include <stdio.h> /* 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 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;
|
||||
}
|
||||
20
c/ext/uthash/tests/test18.ans
Normal file
20
c/ext/uthash/tests/test18.ans
Normal file
@@ -0,0 +1,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
|
||||
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
|
||||
37
c/ext/uthash/tests/test18.c
Normal file
37
c/ext/uthash/tests/test18.c
Normal file
@@ -0,0 +1,37 @@
|
||||
#include "uthash.h"
|
||||
#include <stdlib.h> /* malloc */
|
||||
#include <stdio.h> /* printf */
|
||||
|
||||
typedef struct example_user_t {
|
||||
int id;
|
||||
int cookie;
|
||||
UT_hash_handle hh;
|
||||
} example_user_t;
|
||||
|
||||
int main()
|
||||
{
|
||||
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;
|
||||
}
|
||||
1012
c/ext/uthash/tests/test19.ans
Normal file
1012
c/ext/uthash/tests/test19.ans
Normal file
File diff suppressed because it is too large
Load Diff
66
c/ext/uthash/tests/test19.c
Normal file
66
c/ext/uthash/tests/test19.c
Normal file
@@ -0,0 +1,66 @@
|
||||
#include "uthash.h"
|
||||
#include <stdlib.h> /* malloc */
|
||||
#include <stdio.h> /* 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 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;
|
||||
}
|
||||
5
c/ext/uthash/tests/test2.ans
Normal file
5
c/ext/uthash/tests/test2.ans
Normal file
@@ -0,0 +1,5 @@
|
||||
user 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
|
||||
38
c/ext/uthash/tests/test2.c
Normal file
38
c/ext/uthash/tests/test2.c
Normal file
@@ -0,0 +1,38 @@
|
||||
#include "uthash.h"
|
||||
#include <time.h>
|
||||
#include <stdlib.h> /* malloc */
|
||||
#include <stdio.h> /* printf */
|
||||
|
||||
typedef struct example_user_t {
|
||||
int id;
|
||||
int cookie;
|
||||
UT_hash_handle hh;
|
||||
} example_user_t;
|
||||
|
||||
int main()
|
||||
{
|
||||
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;
|
||||
}
|
||||
1
c/ext/uthash/tests/test20.ans
Normal file
1
c/ext/uthash/tests/test20.ans
Normal file
@@ -0,0 +1 @@
|
||||
found
|
||||
34
c/ext/uthash/tests/test20.c
Normal file
34
c/ext/uthash/tests/test20.c
Normal file
@@ -0,0 +1,34 @@
|
||||
#include <string.h> /* memcpy */
|
||||
#include <stdlib.h> /* malloc */
|
||||
#include <stdio.h> /* printf */
|
||||
#include "uthash.h"
|
||||
|
||||
struct my_struct {
|
||||
char bkey[5]; /* "binary" key */
|
||||
int data;
|
||||
UT_hash_handle hh;
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
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;
|
||||
}
|
||||
1
c/ext/uthash/tests/test21.ans
Normal file
1
c/ext/uthash/tests/test21.ans
Normal file
@@ -0,0 +1 @@
|
||||
found a 1
|
||||
44
c/ext/uthash/tests/test21.c
Normal file
44
c/ext/uthash/tests/test21.c
Normal file
@@ -0,0 +1,44 @@
|
||||
#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()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
1
c/ext/uthash/tests/test22.ans
Normal file
1
c/ext/uthash/tests/test22.ans
Normal file
@@ -0,0 +1 @@
|
||||
found
|
||||
68
c/ext/uthash/tests/test22.c
Normal file
68
c/ext/uthash/tests/test22.c
Normal file
@@ -0,0 +1,68 @@
|
||||
#include <stdlib.h> /* malloc */
|
||||
#include <stddef.h> /* offsetof */
|
||||
#include <stdio.h> /* printf */
|
||||
#include <string.h> /* 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()
|
||||
{
|
||||
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;
|
||||
}
|
||||
6
c/ext/uthash/tests/test23.ans
Normal file
6
c/ext/uthash/tests/test23.ans
Normal file
@@ -0,0 +1,6 @@
|
||||
found 12345
|
||||
found 6789
|
||||
found 98765
|
||||
deleting 12345
|
||||
deleting 6789
|
||||
deleting 98765
|
||||
69
c/ext/uthash/tests/test23.c
Normal file
69
c/ext/uthash/tests/test23.c
Normal file
@@ -0,0 +1,69 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#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;
|
||||
}
|
||||
1
c/ext/uthash/tests/test24.ans
Normal file
1
c/ext/uthash/tests/test24.ans
Normal file
@@ -0,0 +1 @@
|
||||
hash contains 10 items
|
||||
29
c/ext/uthash/tests/test24.c
Normal file
29
c/ext/uthash/tests/test24.c
Normal file
@@ -0,0 +1,29 @@
|
||||
#include "uthash.h"
|
||||
#include <stdlib.h> /* malloc */
|
||||
#include <stdio.h> /* printf */
|
||||
|
||||
typedef struct example_user_t {
|
||||
int id;
|
||||
int cookie;
|
||||
UT_hash_handle hh;
|
||||
} example_user_t;
|
||||
|
||||
int main()
|
||||
{
|
||||
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;
|
||||
}
|
||||
31
c/ext/uthash/tests/test25.ans
Normal file
31
c/ext/uthash/tests/test25.ans
Normal file
@@ -0,0 +1,31 @@
|
||||
CDL 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
|
||||
|
||||
138
c/ext/uthash/tests/test25.c
Normal file
138
c/ext/uthash/tests/test25.c
Normal file
@@ -0,0 +1,138 @@
|
||||
#include <stdio.h>
|
||||
#include "utlist.h"
|
||||
|
||||
typedef struct el {
|
||||
int id;
|
||||
struct el *next, *prev;
|
||||
} el;
|
||||
|
||||
int main()
|
||||
{
|
||||
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;
|
||||
}
|
||||
53
c/ext/uthash/tests/test26.ans
Normal file
53
c/ext/uthash/tests/test26.ans
Normal file
@@ -0,0 +1,53 @@
|
||||
ADRIAN
|
||||
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
|
||||
|
||||
61
c/ext/uthash/tests/test26.c
Normal file
61
c/ext/uthash/tests/test26.c
Normal file
@@ -0,0 +1,61 @@
|
||||
#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;
|
||||
|
||||
static int namecmp(void *_a, void *_b)
|
||||
{
|
||||
el *a = (el*)_a;
|
||||
el *b = (el*)_b;
|
||||
return strcmp(a->bname,b->bname);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
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);
|
||||
}
|
||||
strcpy(name->bname, linebuf);
|
||||
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;
|
||||
}
|
||||
28
c/ext/uthash/tests/test27.ans
Normal file
28
c/ext/uthash/tests/test27.ans
Normal file
@@ -0,0 +1,28 @@
|
||||
CDL 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
|
||||
|
||||
130
c/ext/uthash/tests/test27.c
Normal file
130
c/ext/uthash/tests/test27.c
Normal file
@@ -0,0 +1,130 @@
|
||||
#include <stdio.h>
|
||||
#include "utlist.h"
|
||||
|
||||
typedef struct el {
|
||||
int id;
|
||||
struct el *next, *prev;
|
||||
} el;
|
||||
|
||||
int main()
|
||||
{
|
||||
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;
|
||||
}
|
||||
34
c/ext/uthash/tests/test28.ans
Normal file
34
c/ext/uthash/tests/test28.ans
Normal file
@@ -0,0 +1,34 @@
|
||||
CDL 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
|
||||
|
||||
153
c/ext/uthash/tests/test28.c
Normal file
153
c/ext/uthash/tests/test28.c
Normal file
@@ -0,0 +1,153 @@
|
||||
#include <stdio.h>
|
||||
#include "utlist.h"
|
||||
|
||||
typedef struct el {
|
||||
int id;
|
||||
struct el *next, *prev;
|
||||
} el;
|
||||
|
||||
int main()
|
||||
{
|
||||
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;
|
||||
}
|
||||
103
c/ext/uthash/tests/test29.ans
Normal file
103
c/ext/uthash/tests/test29.ans
Normal file
@@ -0,0 +1,103 @@
|
||||
ADRIAN
|
||||
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
|
||||
57
c/ext/uthash/tests/test29.c
Normal file
57
c/ext/uthash/tests/test29.c
Normal file
@@ -0,0 +1,57 @@
|
||||
#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;
|
||||
|
||||
static int namecmp(void *_a, void *_b)
|
||||
{
|
||||
el *a = (el*)_a;
|
||||
el *b = (el*)_b;
|
||||
return strcmp(a->bname,b->bname);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
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);
|
||||
}
|
||||
strcpy(name->bname, linebuf);
|
||||
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;
|
||||
}
|
||||
5
c/ext/uthash/tests/test3.ans
Normal file
5
c/ext/uthash/tests/test3.ans
Normal file
@@ -0,0 +1,5 @@
|
||||
user 1, cookie 1
|
||||
user 3, cookie 9
|
||||
user 5, cookie 25
|
||||
user 7, cookie 49
|
||||
user 9, cookie 81
|
||||
43
c/ext/uthash/tests/test3.c
Normal file
43
c/ext/uthash/tests/test3.c
Normal file
@@ -0,0 +1,43 @@
|
||||
#include "uthash.h"
|
||||
#include <stdlib.h> /* malloc */
|
||||
#include <stdio.h> /* printf */
|
||||
|
||||
typedef struct example_user_t {
|
||||
int id;
|
||||
int cookie;
|
||||
UT_hash_handle hh;
|
||||
} example_user_t;
|
||||
|
||||
int main()
|
||||
{
|
||||
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;
|
||||
}
|
||||
51
c/ext/uthash/tests/test30.ans
Normal file
51
c/ext/uthash/tests/test30.ans
Normal file
@@ -0,0 +1,51 @@
|
||||
ADRIAN
|
||||
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
|
||||
50
c/ext/uthash/tests/test30.c
Normal file
50
c/ext/uthash/tests/test30.c
Normal file
@@ -0,0 +1,50 @@
|
||||
#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;
|
||||
|
||||
static int namecmp(void *_a, void *_b)
|
||||
{
|
||||
el *a = (el*)_a;
|
||||
el *b = (el*)_b;
|
||||
return strcmp(a->bname,b->bname);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
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);
|
||||
}
|
||||
strcpy(name->bname, linebuf);
|
||||
CDL_PREPEND(head, name);
|
||||
}
|
||||
CDL_SORT(head, namecmp);
|
||||
CDL_FOREACH(head,tmp) {
|
||||
printf("%s", tmp->bname);
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
51
c/ext/uthash/tests/test31.ans
Normal file
51
c/ext/uthash/tests/test31.ans
Normal file
@@ -0,0 +1,51 @@
|
||||
ADRIAN
|
||||
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
|
||||
50
c/ext/uthash/tests/test31.c
Normal file
50
c/ext/uthash/tests/test31.c
Normal file
@@ -0,0 +1,50 @@
|
||||
#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;
|
||||
|
||||
static int namecmp(void *_a, void *_b)
|
||||
{
|
||||
el *a = (el*)_a;
|
||||
el *b = (el*)_b;
|
||||
return strcmp(a->bname,b->bname);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
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);
|
||||
}
|
||||
strcpy(name->bname, linebuf);
|
||||
CDL_PREPEND(head, name);
|
||||
}
|
||||
CDL_SORT(head, namecmp);
|
||||
CDL_FOREACH(head,tmp) {
|
||||
printf("%s", tmp->bname);
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
51
c/ext/uthash/tests/test32.ans
Normal file
51
c/ext/uthash/tests/test32.ans
Normal file
@@ -0,0 +1,51 @@
|
||||
ARNOLDO
|
||||
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
|
||||
43
c/ext/uthash/tests/test32.c
Normal file
43
c/ext/uthash/tests/test32.c
Normal file
@@ -0,0 +1,43 @@
|
||||
#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 main()
|
||||
{
|
||||
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);
|
||||
}
|
||||
strcpy(name->bname, linebuf);
|
||||
DL_PREPEND(head, name);
|
||||
}
|
||||
/* DL_SORT(head, namecmp); */
|
||||
DL_FOREACH(head,tmp) {
|
||||
printf("%s", tmp->bname);
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
51
c/ext/uthash/tests/test33.ans
Normal file
51
c/ext/uthash/tests/test33.ans
Normal file
@@ -0,0 +1,51 @@
|
||||
ADRIAN
|
||||
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
|
||||
50
c/ext/uthash/tests/test33.c
Normal file
50
c/ext/uthash/tests/test33.c
Normal file
@@ -0,0 +1,50 @@
|
||||
#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;
|
||||
|
||||
static int namecmp(void *_a, void *_b)
|
||||
{
|
||||
el *a = (el*)_a;
|
||||
el *b = (el*)_b;
|
||||
return strcmp(a->bname,b->bname);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
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);
|
||||
}
|
||||
strcpy(name->bname, linebuf);
|
||||
LL_PREPEND(head, name);
|
||||
}
|
||||
LL_SORT(head, namecmp);
|
||||
LL_FOREACH(head,tmp) {
|
||||
printf("%s", tmp->bname);
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
51
c/ext/uthash/tests/test34.ans
Normal file
51
c/ext/uthash/tests/test34.ans
Normal file
@@ -0,0 +1,51 @@
|
||||
ARNOLDO
|
||||
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
|
||||
43
c/ext/uthash/tests/test34.c
Normal file
43
c/ext/uthash/tests/test34.c
Normal file
@@ -0,0 +1,43 @@
|
||||
#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 main()
|
||||
{
|
||||
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);
|
||||
}
|
||||
strcpy(name->bname, linebuf);
|
||||
CDL_PREPEND(head, name);
|
||||
}
|
||||
/* CDL_SORT(head, namecmp); */
|
||||
CDL_FOREACH(head,tmp) {
|
||||
printf("%s", tmp->bname);
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
30
c/ext/uthash/tests/test35.ans
Normal file
30
c/ext/uthash/tests/test35.ans
Normal file
@@ -0,0 +1,30 @@
|
||||
0: 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
|
||||
37
c/ext/uthash/tests/test35.c
Normal file
37
c/ext/uthash/tests/test35.c
Normal file
@@ -0,0 +1,37 @@
|
||||
#include "uthash.h"
|
||||
#include <string.h> /* strcpy */
|
||||
#include <stdlib.h> /* malloc */
|
||||
#include <stdio.h> /* printf */
|
||||
|
||||
typedef struct elt {
|
||||
char *s;
|
||||
UT_hash_handle hh;
|
||||
} elt;
|
||||
|
||||
int main()
|
||||
{
|
||||
int i;
|
||||
elt *head = NULL;
|
||||
elt elts[10];
|
||||
char label[6] = "hello";
|
||||
for(i=0; i<10; i++) {
|
||||
elts[i].s = (char*)malloc(6UL);
|
||||
strcpy(elts[i].s, "hello");
|
||||
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 */
|
||||
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;
|
||||
}
|
||||
25
c/ext/uthash/tests/test36.ans
Normal file
25
c/ext/uthash/tests/test36.ans
Normal file
@@ -0,0 +1,25 @@
|
||||
user 0
|
||||
user 1
|
||||
user 2
|
||||
user 3
|
||||
user 4
|
||||
user 5
|
||||
user 6
|
||||
user 7
|
||||
user 8
|
||||
user 9
|
||||
user 0, should_find=1, found=1
|
||||
user 1, should_find=0, found=0
|
||||
user 2, should_find=1, found=1
|
||||
user 3, should_find=0, found=0
|
||||
user 4, should_find=1, found=1
|
||||
user 5, should_find=0, found=0
|
||||
user 6, should_find=1, found=1
|
||||
user 7, should_find=0, found=0
|
||||
user 8, should_find=1, found=1
|
||||
user 9, should_find=0, found=0
|
||||
auser 0
|
||||
auser 2
|
||||
auser 4
|
||||
auser 6
|
||||
auser 8
|
||||
60
c/ext/uthash/tests/test36.c
Normal file
60
c/ext/uthash/tests/test36.c
Normal file
@@ -0,0 +1,60 @@
|
||||
#include "uthash.h"
|
||||
#include <stdlib.h> /* malloc */
|
||||
#include <stdio.h> /* 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 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=users; user!=NULL; user=(example_user_t*)(user->hh.next)) {
|
||||
example_user_t *found = NULL;
|
||||
int should_find = !!evens(user);
|
||||
HASH_FIND(ah, ausers, &user->id, sizeof(user->id), found);
|
||||
printf("user %d, should_find=%d, found=%d\n", user->id, should_find, (int)(!!found));
|
||||
}
|
||||
|
||||
for(user=ausers; user!=NULL; user=(example_user_t*)(user->ah.next)) {
|
||||
printf("auser %d\n", user->id);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
20
c/ext/uthash/tests/test37.ans
Normal file
20
c/ext/uthash/tests/test37.ans
Normal file
@@ -0,0 +1,20 @@
|
||||
user 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
|
||||
56
c/ext/uthash/tests/test37.c
Normal file
56
c/ext/uthash/tests/test37.c
Normal file
@@ -0,0 +1,56 @@
|
||||
#include "uthash.h"
|
||||
#include <stdlib.h> /* malloc */
|
||||
#include <stdio.h> /* 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 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;
|
||||
}
|
||||
1
c/ext/uthash/tests/test38.ans
Normal file
1
c/ext/uthash/tests/test38.ans
Normal file
@@ -0,0 +1 @@
|
||||
hash count 10
|
||||
31
c/ext/uthash/tests/test38.c
Normal file
31
c/ext/uthash/tests/test38.c
Normal file
@@ -0,0 +1,31 @@
|
||||
#include "uthash.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
struct test_t {
|
||||
int a;
|
||||
UT_hash_handle hh;
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
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;
|
||||
}
|
||||
7
c/ext/uthash/tests/test39.ans
Normal file
7
c/ext/uthash/tests/test39.ans
Normal file
@@ -0,0 +1,7 @@
|
||||
adding 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.
|
||||
34
c/ext/uthash/tests/test39.c
Normal file
34
c/ext/uthash/tests/test39.c
Normal file
@@ -0,0 +1,34 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#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;
|
||||
}
|
||||
10
c/ext/uthash/tests/test4.ans
Normal file
10
c/ext/uthash/tests/test4.ans
Normal file
@@ -0,0 +1,10 @@
|
||||
cookie 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
|
||||
33
c/ext/uthash/tests/test4.c
Normal file
33
c/ext/uthash/tests/test4.c
Normal file
@@ -0,0 +1,33 @@
|
||||
#include "uthash.h"
|
||||
#include <stdlib.h> /* malloc */
|
||||
#include <stdio.h> /* printf */
|
||||
|
||||
typedef struct example_user_t {
|
||||
int id;
|
||||
int cookie;
|
||||
UT_hash_handle hh;
|
||||
UT_hash_handle alth;
|
||||
} example_user_t;
|
||||
|
||||
int main()
|
||||
{
|
||||
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;
|
||||
}
|
||||
1
c/ext/uthash/tests/test40.ans
Normal file
1
c/ext/uthash/tests/test40.ans
Normal file
@@ -0,0 +1 @@
|
||||
betty's id is 2
|
||||
40
c/ext/uthash/tests/test40.c
Normal file
40
c/ext/uthash/tests/test40.c
Normal file
@@ -0,0 +1,40 @@
|
||||
#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()
|
||||
{
|
||||
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;
|
||||
}
|
||||
6
c/ext/uthash/tests/test41.ans
Normal file
6
c/ext/uthash/tests/test41.ans
Normal file
@@ -0,0 +1,6 @@
|
||||
CDL 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
|
||||
72
c/ext/uthash/tests/test41.c
Normal file
72
c/ext/uthash/tests/test41.c
Normal file
@@ -0,0 +1,72 @@
|
||||
#include <stdio.h>
|
||||
#include "utlist.h"
|
||||
|
||||
typedef struct el {
|
||||
int id;
|
||||
struct el *next, *prev;
|
||||
} el;
|
||||
|
||||
int main()
|
||||
{
|
||||
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;
|
||||
}
|
||||
14
c/ext/uthash/tests/test42.ans
Normal file
14
c/ext/uthash/tests/test42.ans
Normal file
@@ -0,0 +1,14 @@
|
||||
LL 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
|
||||
90
c/ext/uthash/tests/test42.c
Normal file
90
c/ext/uthash/tests/test42.c
Normal file
@@ -0,0 +1,90 @@
|
||||
#include <stdio.h>
|
||||
#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 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;
|
||||
}
|
||||
88
c/ext/uthash/tests/test43.ans
Normal file
88
c/ext/uthash/tests/test43.ans
Normal file
@@ -0,0 +1,88 @@
|
||||
length 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
|
||||
130
c/ext/uthash/tests/test43.c
Normal file
130
c/ext/uthash/tests/test43.c
Normal file
@@ -0,0 +1,130 @@
|
||||
#include <stdio.h>
|
||||
#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;
|
||||
}
|
||||
9
c/ext/uthash/tests/test44.ans
Normal file
9
c/ext/uthash/tests/test44.ans
Normal file
@@ -0,0 +1,9 @@
|
||||
0 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
|
||||
|
||||
66
c/ext/uthash/tests/test44.c
Normal file
66
c/ext/uthash/tests/test44.c
Normal file
@@ -0,0 +1,66 @@
|
||||
#include <stdio.h>
|
||||
#include "utarray.h"
|
||||
|
||||
static int reverse(const void *a, const void *b)
|
||||
{
|
||||
int _a = *(const int*)a;
|
||||
int _b = *(const 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;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user