├── .gitignore ├── ska_flat_hash_map ├── flat_hash_map.hpp ├── Makefile └── test.cpp ├── __logs ├── 231212-M1.tgz ├── 231213-M1.tgz ├── 180112-gcloud-a.png ├── 180112-gcloud.tgz ├── 180929-gcloud-a.png ├── 180929-gcloud-f.png ├── 180929-gcloud.tgz ├── 180929-server-a.png ├── 180929-server-f.png ├── 180929-server.tgz ├── 191228-server.tgz ├── 231212-M1-del.png ├── 231213-M1-del.png ├── 231213-M1-ins.png ├── 191228-server-del.png ├── 191228-server-ins.png ├── 231212-plot.gp ├── 180112-plot.gp ├── 231213-plot.gp └── 180929-plot.gp ├── kavl ├── Makefile └── test.c ├── kbtree ├── Makefile └── test.c ├── Makefile ├── libcuckoo ├── Makefile ├── test.cpp ├── cuckoohash_config.hh └── cuckoohash_util.hh ├── stb ├── Makefile └── test.c ├── uthash ├── Makefile └── test.c ├── khashpp ├── Makefile ├── test.cpp └── khash.hpp ├── khashlmpp ├── Makefile └── test.cpp ├── map ├── Makefile └── test.cpp ├── _absl ├── Makefile ├── CMakeLists.txt └── test.cpp ├── sparsehash ├── Makefile ├── test-1.cpp ├── test.cpp └── sparsehash │ ├── internal │ ├── sparseconfig.h │ └── libc_allocator_with_realloc.h │ └── template_util.h ├── tommyds ├── Makefile ├── test-1.c ├── test.c ├── tommy.c ├── tommylist.c ├── tommyarrayblk.c ├── tommyarray.c ├── tommyarrayblkof.c ├── tommyarrayof.c ├── tommyalloc.h ├── tommyarrayblkof.h ├── tommyarrayof.h ├── tommyalloc.c ├── tommyarrayblk.h ├── tommyhashtbl.c ├── tommyarray.h ├── tommyhash.h ├── tommyhashdyn.c ├── tommychain.h ├── tommyhash.c ├── tommytree.c └── tommytree.h ├── c++11 ├── Makefile ├── test.cpp └── test-1.cpp ├── sparsepp ├── Makefile ├── sparsepp │ ├── spp_stdint.h │ ├── spp_timer.h │ ├── spp_smartptr.h │ ├── spp_traits.h │ └── spp_memory.h ├── test-1.cpp └── test.cpp ├── mlib ├── Makefile └── test.c ├── khashlpp ├── Makefile └── test.cpp ├── phmap ├── Makefile ├── test.cpp ├── phmap_fwd_decl.h ├── meminfo.h └── phmap_dump.h ├── tsl_robin_map ├── Makefile └── test.cpp ├── verstable ├── Makefile └── test.c ├── ska_bytell_hash_map ├── Makefile └── test.cpp ├── _glib ├── Makefile ├── test.c └── test-1.c ├── robin_hood ├── Makefile └── test.cpp ├── emilib ├── Makefile └── test.cpp ├── _gcc_ext ├── Makefile ├── test-1.cpp ├── test-2.cpp └── test.cpp ├── unordered_dense ├── Makefile └── test.cpp ├── _boost ├── Makefile └── test.cpp ├── bkthomps-hashmap ├── Makefile ├── test-1a.c ├── test.c └── unordered_map.h ├── khashl ├── Makefile ├── test.c └── test-block.c ├── khash ├── Makefile ├── test.c └── test-1.c ├── tsl_hopscotch_map ├── Makefile ├── test.cpp └── test-1.cpp ├── README.md ├── common.c └── common-block.c /.gitignore: -------------------------------------------------------------------------------- 1 | .*.swp 2 | run-test* 3 | -------------------------------------------------------------------------------- /ska_flat_hash_map/flat_hash_map.hpp: -------------------------------------------------------------------------------- 1 | ../ska_bytell_hash_map/flat_hash_map.hpp -------------------------------------------------------------------------------- /__logs/231212-M1.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/attractivechaos/udb2/HEAD/__logs/231212-M1.tgz -------------------------------------------------------------------------------- /__logs/231213-M1.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/attractivechaos/udb2/HEAD/__logs/231213-M1.tgz -------------------------------------------------------------------------------- /__logs/180112-gcloud-a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/attractivechaos/udb2/HEAD/__logs/180112-gcloud-a.png -------------------------------------------------------------------------------- /__logs/180112-gcloud.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/attractivechaos/udb2/HEAD/__logs/180112-gcloud.tgz -------------------------------------------------------------------------------- /__logs/180929-gcloud-a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/attractivechaos/udb2/HEAD/__logs/180929-gcloud-a.png -------------------------------------------------------------------------------- /__logs/180929-gcloud-f.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/attractivechaos/udb2/HEAD/__logs/180929-gcloud-f.png -------------------------------------------------------------------------------- /__logs/180929-gcloud.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/attractivechaos/udb2/HEAD/__logs/180929-gcloud.tgz -------------------------------------------------------------------------------- /__logs/180929-server-a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/attractivechaos/udb2/HEAD/__logs/180929-server-a.png -------------------------------------------------------------------------------- /__logs/180929-server-f.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/attractivechaos/udb2/HEAD/__logs/180929-server-f.png -------------------------------------------------------------------------------- /__logs/180929-server.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/attractivechaos/udb2/HEAD/__logs/180929-server.tgz -------------------------------------------------------------------------------- /__logs/191228-server.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/attractivechaos/udb2/HEAD/__logs/191228-server.tgz -------------------------------------------------------------------------------- /__logs/231212-M1-del.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/attractivechaos/udb2/HEAD/__logs/231212-M1-del.png -------------------------------------------------------------------------------- /__logs/231213-M1-del.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/attractivechaos/udb2/HEAD/__logs/231213-M1-del.png -------------------------------------------------------------------------------- /__logs/231213-M1-ins.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/attractivechaos/udb2/HEAD/__logs/231213-M1-ins.png -------------------------------------------------------------------------------- /__logs/191228-server-del.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/attractivechaos/udb2/HEAD/__logs/191228-server-del.png -------------------------------------------------------------------------------- /__logs/191228-server-ins.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/attractivechaos/udb2/HEAD/__logs/191228-server-ins.png -------------------------------------------------------------------------------- /kavl/Makefile: -------------------------------------------------------------------------------- 1 | run-test:test.c ../common.c kavl.h 2 | $(CC) -O2 -Wall $< -o $@ 3 | 4 | clean: 5 | rm -f run-test* 6 | -------------------------------------------------------------------------------- /kbtree/Makefile: -------------------------------------------------------------------------------- 1 | run-test:test.c ../common.c kbtree.h 2 | $(CC) -O2 -Wall $< -o $@ 3 | 4 | clean: 5 | rm -f run-test* 6 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | for dir in `ls | egrep -v '^(Makefile|common.c|_)'`; do (cd $$dir && make); done 3 | 4 | clean: 5 | rm -f */run-test* 6 | -------------------------------------------------------------------------------- /libcuckoo/Makefile: -------------------------------------------------------------------------------- 1 | run-test:test.cpp ../common.c 2 | $(CXX) -O3 -Wall -pthread -std=c++11 $< -o $@ 3 | 4 | clean: 5 | rm -f run-test* 6 | -------------------------------------------------------------------------------- /stb/Makefile: -------------------------------------------------------------------------------- 1 | all:run-test 2 | 3 | run-test:test.c ../common.c stb.h 4 | $(CC) -O2 -Wall $< -o $@ -lm 5 | 6 | clean: 7 | rm -f run-test* 8 | -------------------------------------------------------------------------------- /uthash/Makefile: -------------------------------------------------------------------------------- 1 | all:run-test 2 | 3 | run-test:test.c ../common.c uthash.h 4 | $(CC) -O2 -Wall $< -o $@ 5 | 6 | clean: 7 | rm -f run-test* 8 | -------------------------------------------------------------------------------- /khashpp/Makefile: -------------------------------------------------------------------------------- 1 | all:run-test 2 | 3 | run-test:test.cpp ../common.c khash.hpp 4 | $(CXX) -O3 -Wall $< -o $@ 5 | 6 | clean: 7 | rm -f run-test* 8 | -------------------------------------------------------------------------------- /khashlmpp/Makefile: -------------------------------------------------------------------------------- 1 | all:run-test 2 | 3 | run-test:test.cpp ../common.c khashlm.hpp 4 | $(CXX) -O3 -Wall $< -o $@ 5 | 6 | clean: 7 | rm -f run-test* 8 | -------------------------------------------------------------------------------- /map/Makefile: -------------------------------------------------------------------------------- 1 | all:run-test run-test-1 2 | 3 | run-test:test.cpp ../common.c 4 | $(CXX) -O3 -Wall -std=c++11 $< -o $@ 5 | 6 | clean: 7 | rm -f run-test* 8 | -------------------------------------------------------------------------------- /_absl/Makefile: -------------------------------------------------------------------------------- 1 | all:run-test 2 | 3 | LIBS=-L. -labsl_container 4 | 5 | run-test:test.cpp ../common.c 6 | $(CXX) -O3 -Wall -std=c++11 -I. $< -o $@ $(LIBS) 7 | 8 | clean: 9 | rm -f run-test* 10 | -------------------------------------------------------------------------------- /sparsehash/Makefile: -------------------------------------------------------------------------------- 1 | all:run-test run-test-1 2 | 3 | run-test:test.cpp ../common.c 4 | $(CXX) -O3 -Wall -I. $< -o $@ 5 | 6 | run-test-1:test-1.cpp ../common.c 7 | $(CXX) -O3 -Wall -I. $< -o $@ 8 | 9 | clean: 10 | rm -f run-test* 11 | -------------------------------------------------------------------------------- /tommyds/Makefile: -------------------------------------------------------------------------------- 1 | all:run-test run-test-1 2 | 3 | run-test:test.c ../common.c 4 | $(CC) -O2 -Wall $< tommy.c -o $@ 5 | 6 | run-test-1:test-1.c ../common.c 7 | $(CC) -O2 -Wall $< tommy.c -o $@ 8 | 9 | clean: 10 | rm -f run-test* 11 | -------------------------------------------------------------------------------- /c++11/Makefile: -------------------------------------------------------------------------------- 1 | all:run-test run-test-1 2 | 3 | run-test:test.cpp ../common.c 4 | $(CXX) -O3 -Wall -std=c++11 $< -o $@ 5 | 6 | run-test-1:test-1.cpp ../common.c 7 | $(CXX) -O3 -Wall -std=c++11 $< -o $@ 8 | 9 | clean: 10 | rm -f run-test* 11 | -------------------------------------------------------------------------------- /sparsepp/Makefile: -------------------------------------------------------------------------------- 1 | all:run-test run-test-1 2 | 3 | run-test:test.cpp ../common.c 4 | $(CXX) -O3 -Wall -std=c++11 $< -o $@ 5 | 6 | run-test-1:test-1.cpp ../common.c 7 | $(CXX) -O3 -Wall -std=c++11 $< -o $@ 8 | 9 | clean: 10 | rm -f run-test* 11 | -------------------------------------------------------------------------------- /mlib/Makefile: -------------------------------------------------------------------------------- 1 | all:run-test run-test-del 2 | 3 | run-test:test.c ../common.c m-dict.h 4 | $(CC) -O2 -Wall $< -o $@ 5 | 6 | run-test-del:test.c ../common.c m-dict.h 7 | $(CC) -O2 -Wall -DUDB2_TEST_DEL $< -o $@ 8 | 9 | clean: 10 | rm -fr run-*test* a.out 11 | -------------------------------------------------------------------------------- /khashlpp/Makefile: -------------------------------------------------------------------------------- 1 | all:run-test run-test-del 2 | 3 | run-test:test.cpp ../common.c khashl.hpp 4 | $(CXX) -O3 -Wall $< -o $@ 5 | 6 | run-test-del:test.cpp ../common.c khashl.hpp 7 | $(CXX) -O3 -Wall -DUDB2_TEST_DEL $< -o $@ 8 | 9 | clean: 10 | rm -f run-test* 11 | -------------------------------------------------------------------------------- /phmap/Makefile: -------------------------------------------------------------------------------- 1 | all:run-test run-test-del 2 | 3 | run-test:test.cpp ../common.c 4 | $(CXX) -O3 -Wall -std=c++11 $< -o $@ 5 | 6 | run-test-del:test.cpp ../common.c 7 | $(CXX) -O3 -Wall -std=c++11 -DUDB2_TEST_DEL $< -o $@ 8 | 9 | clean: 10 | rm -f run-test* 11 | -------------------------------------------------------------------------------- /tsl_robin_map/Makefile: -------------------------------------------------------------------------------- 1 | all:run-test run-test-del 2 | 3 | run-test:test.cpp ../common.c 4 | $(CXX) -O3 -Wall -std=c++11 $< -o $@ 5 | 6 | run-test-del:test.cpp ../common.c 7 | $(CXX) -O3 -Wall -std=c++11 -DUDB2_TEST_DEL $< -o $@ 8 | 9 | clean: 10 | rm -f run-test* 11 | -------------------------------------------------------------------------------- /verstable/Makefile: -------------------------------------------------------------------------------- 1 | all:run-test run-test-del 2 | 3 | run-test:test.c ../common.c verstable.h 4 | $(CC) -O2 -Wall $< -o $@ 5 | 6 | run-test-del:test.c ../common.c verstable.h 7 | $(CC) -O2 -Wall -DUDB2_TEST_DEL $< -o $@ 8 | 9 | clean: 10 | rm -fr run-*test* a.out 11 | -------------------------------------------------------------------------------- /ska_bytell_hash_map/Makefile: -------------------------------------------------------------------------------- 1 | all:run-test run-test-del 2 | 3 | run-test:test.cpp ../common.c 4 | $(CXX) -O3 -Wall -std=c++14 $< -o $@ 5 | 6 | run-test-del:test.cpp ../common.c 7 | $(CXX) -O3 -Wall -std=c++14 -DUDB2_TEST_DEL $< -o $@ 8 | 9 | clean: 10 | rm -f run-test* 11 | -------------------------------------------------------------------------------- /ska_flat_hash_map/Makefile: -------------------------------------------------------------------------------- 1 | all:run-test run-test-del 2 | 3 | run-test:test.cpp ../common.c 4 | $(CXX) -O3 -Wall -std=c++11 $< -o $@ 5 | 6 | run-test-del:test.cpp ../common.c 7 | $(CXX) -O3 -Wall -std=c++11 -DUDB2_TEST_DEL $< -o $@ 8 | 9 | clean: 10 | rm -f run-test* 11 | -------------------------------------------------------------------------------- /_glib/Makefile: -------------------------------------------------------------------------------- 1 | all:run-test run-test-1 2 | 3 | run-test:test.c 4 | gcc -O2 $< -o $@ `pkg-config --cflags glib-2.0` `pkg-config --libs glib-2.0` 5 | 6 | run-test-1:test-1.c 7 | gcc -O2 $< -o $@ `pkg-config --cflags glib-2.0` `pkg-config --libs glib-2.0` 8 | 9 | clean: 10 | rm -f run-test* 11 | -------------------------------------------------------------------------------- /robin_hood/Makefile: -------------------------------------------------------------------------------- 1 | all:run-test run-test-del 2 | 3 | run-test:test.cpp ../common.c robin_hood.h 4 | $(CXX) -O3 -Wall -std=c++11 $< -o $@ 5 | 6 | run-test-del:test.cpp ../common.c robin_hood.h 7 | $(CXX) -O3 -Wall -std=c++11 -DUDB2_TEST_DEL $< -o $@ 8 | 9 | clean: 10 | rm -f run-test* 11 | -------------------------------------------------------------------------------- /emilib/Makefile: -------------------------------------------------------------------------------- 1 | all:run-test run-test-del 2 | 3 | run-test:test.cpp ../common.c hash_map.hpp 4 | $(CXX) -O3 -Wall -std=c++11 -I. $< -o $@ 5 | 6 | run-test-del:test.cpp ../common.c hash_map.hpp 7 | $(CXX) -O3 -Wall -std=c++11 -DUDB2_TEST_DEL -I. $< -o $@ 8 | 9 | clean: 10 | rm -f run-test* 11 | -------------------------------------------------------------------------------- /_gcc_ext/Makefile: -------------------------------------------------------------------------------- 1 | all:run-test run-test-1 2 | 3 | run-test:test.cpp ../common.c 4 | $(CXX) -O3 -Wall $< -o $@ 5 | 6 | run-test-1:test-1.cpp ../common.c 7 | $(CXX) -O3 -Wall $< -o $@ 8 | 9 | run-test-2:test-2.cpp ../common.c 10 | $(CXX) -O3 -Wall $< -o $@ 11 | 12 | clean: 13 | rm -f run-test* 14 | -------------------------------------------------------------------------------- /unordered_dense/Makefile: -------------------------------------------------------------------------------- 1 | all:run-test run-test-del 2 | 3 | run-test:test.cpp ../common.c unordered_dense.h 4 | $(CXX) -O3 -Wall -std=c++17 $< -o $@ 5 | 6 | run-test-del:test.cpp ../common.c unordered_dense.h 7 | $(CXX) -O3 -Wall -std=c++17 -DUDB2_TEST_DEL $< -o $@ 8 | 9 | clean: 10 | rm -f run-test* 11 | -------------------------------------------------------------------------------- /_boost/Makefile: -------------------------------------------------------------------------------- 1 | BOOST_ROOT=. 2 | 3 | all:run-test run-test-del 4 | 5 | run-test:test.cpp ../common.c 6 | $(CXX) -O3 -Wall -std=c++11 -I$(BOOST_ROOT) $< -o $@ 7 | 8 | run-test-del:test.cpp ../common.c 9 | $(CXX) -O3 -Wall -std=c++11 -I$(BOOST_ROOT) -DUDB2_TEST_DEL $< -o $@ 10 | 11 | clean: 12 | rm -f run-test* 13 | -------------------------------------------------------------------------------- /bkthomps-hashmap/Makefile: -------------------------------------------------------------------------------- 1 | all:run-test run-test-1a 2 | 3 | run-test:test.c ../common.c unordered_map.c unordered_map.h 4 | $(CC) -O2 -Wall -std=gnu99 $< unordered_map.c -o $@ 5 | 6 | run-test-1a:test-1a.c ../common.c unordered_map.c unordered_map.h 7 | $(CC) -O2 -Wall -std=gnu99 $< unordered_map.c -o $@ 8 | 9 | clean: 10 | rm -f run-test* 11 | -------------------------------------------------------------------------------- /khashl/Makefile: -------------------------------------------------------------------------------- 1 | all:run-test run-test-del run-block-test 2 | 3 | run-test:test.c ../common.c khashl.h 4 | $(CC) -O2 -Wall $< -o $@ 5 | 6 | run-test-del:test.c ../common.c khashl.h 7 | $(CC) -O2 -Wall -DUDB2_TEST_DEL $< -o $@ 8 | 9 | run-block-test:test-block.c ../common.c khashl.h 10 | $(CC) -O2 -Wall $< -o $@ 11 | 12 | clean: 13 | rm -fr run-*test* a.out 14 | -------------------------------------------------------------------------------- /map/test.cpp: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | #include 3 | 4 | uint32_t test_int(uint32_t n, uint32_t x0) 5 | { 6 | uint32_t i, x, z = 0; 7 | std::map h; 8 | for (i = 0, x = x0; i < n; ++i) { 9 | x = hash32(x); 10 | z += ++h[get_key(n, x)]; 11 | } 12 | fprintf(stderr, "# unique keys: %ld; checksum: %u\n", h.size(), z); 13 | return h.size(); 14 | } 15 | -------------------------------------------------------------------------------- /sparsepp/sparsepp/spp_stdint.h: -------------------------------------------------------------------------------- 1 | #if !defined(spp_stdint_h_guard) 2 | #define spp_stdint_h_guard 3 | 4 | #include "spp_config.h" 5 | 6 | #if defined(SPP_HAS_CSTDINT) && (__cplusplus >= 201103) 7 | #include 8 | #else 9 | #if defined(__FreeBSD__) || defined(__IBMCPP__) || defined(_AIX) 10 | #include 11 | #else 12 | #include 13 | #endif 14 | #endif 15 | 16 | #endif // spp_stdint_h_guard 17 | -------------------------------------------------------------------------------- /khash/Makefile: -------------------------------------------------------------------------------- 1 | all:run-test run-test-del run-test-1 run-test-del-1 2 | 3 | run-test:test.c ../common.c khash.h 4 | $(CC) -O2 -Wall $< -o $@ 5 | 6 | run-test-del:test.c ../common.c khash.h 7 | $(CC) -O2 -Wall -DUDB2_TEST_DEL $< -o $@ 8 | 9 | run-test-1:test-1.c ../common.c khash.h 10 | $(CC) -O2 -Wall $< -o $@ 11 | 12 | run-test-del-1:test-1.c ../common.c khash.h 13 | $(CC) -O2 -Wall -DUDB2_TEST_DEL $< -o $@ 14 | 15 | clean: 16 | rm -fr run-test* a.out *.dSYM 17 | -------------------------------------------------------------------------------- /_absl/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | project(my_project) 4 | 5 | # Abseil requires C++11 6 | set(CMAKE_CXX_STANDARD 11) 7 | 8 | # Process Abseil's CMake build system 9 | add_subdirectory(abseil-cpp) 10 | 11 | add_executable(run-test test.cpp) 12 | 13 | # Declare dependency on the absl::strings library 14 | find_package(Threads) 15 | target_link_libraries(run-test absl::container absl::raw_hash_set absl::hash absl::hashtablez_sampler Threads::Threads) 16 | -------------------------------------------------------------------------------- /tsl_hopscotch_map/Makefile: -------------------------------------------------------------------------------- 1 | all:run-test run-test-1 run-test-del run-test-del-1 2 | 3 | run-test:test.cpp ../common.c 4 | $(CXX) -O3 -Wall -std=c++11 $< -o $@ 5 | 6 | run-test-1:test-1.cpp ../common.c 7 | $(CXX) -O3 -Wall -std=c++11 $< -o $@ 8 | 9 | run-test-del:test.cpp ../common.c 10 | $(CXX) -O3 -Wall -std=c++11 -DUDB2_TEST_DEL $< -o $@ 11 | 12 | run-test-del-1:test-1.cpp ../common.c 13 | $(CXX) -O3 -Wall -std=c++11 -DUDB2_TEST_DEL $< -o $@ 14 | 15 | clean: 16 | rm -f run-test* 17 | -------------------------------------------------------------------------------- /c++11/test.cpp: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | #include 3 | 4 | struct Hash32 { 5 | inline size_t operator()(const uint32_t x) const { 6 | return hash_fn(x); 7 | } 8 | }; 9 | 10 | uint32_t test_int(uint32_t n, uint32_t x0) 11 | { 12 | uint32_t i, x, z = 0; 13 | std::unordered_map h; 14 | for (i = 0, x = x0; i < n; ++i) { 15 | x = hash32(x); 16 | z += ++h[get_key(n, x)]; 17 | } 18 | fprintf(stderr, "# unique keys: %ld; checksum: %u\n", h.size(), z); 19 | return h.size(); 20 | } 21 | -------------------------------------------------------------------------------- /_gcc_ext/test-1.cpp: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | #include 3 | 4 | struct Hash32 { 5 | inline size_t operator()(const uint32_t x) const { 6 | return hash_fn(x); 7 | } 8 | }; 9 | 10 | uint32_t test_int(uint32_t n, uint32_t x0) 11 | { 12 | uint32_t i, x, z = 0; 13 | __gnu_cxx::hash_map h; 14 | for (i = 0, x = x0; i < n; ++i) { 15 | x = hash32(x); 16 | z += ++h[get_key(n, x)]; 17 | } 18 | fprintf(stderr, "# unique keys: %ld; checksum: %u\n", h.size(), z); 19 | return h.size(); 20 | } 21 | -------------------------------------------------------------------------------- /_gcc_ext/test-2.cpp: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | #include 3 | 4 | struct Hash32 { 5 | inline size_t operator()(const uint32_t x) const { 6 | return hash_fn(x); 7 | } 8 | }; 9 | 10 | uint32_t test_int(uint32_t n, uint32_t x0) 11 | { 12 | uint32_t i, x, z = 0; 13 | std::tr1::unordered_map h; 14 | for (i = 0, x = x0; i < n; ++i) { 15 | x = hash32(x); 16 | z += ++h[get_key(n, x)]; 17 | } 18 | fprintf(stderr, "# unique keys: %ld; checksum: %u\n", h.size(), z); 19 | return h.size(); 20 | } 21 | -------------------------------------------------------------------------------- /_gcc_ext/test.cpp: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | #include 3 | 4 | struct Hash32 { 5 | inline size_t operator()(const uint32_t x) const { 6 | return hash_fn(x); 7 | } 8 | }; 9 | 10 | uint32_t test_int(uint32_t n, uint32_t x0) 11 | { 12 | uint32_t i, x, z = 0; 13 | __gnu_pbds::cc_hash_table h; 14 | for (i = 0, x = x0; i < n; ++i) { 15 | x = hash32(x); 16 | z += ++h[get_key(n, x)]; 17 | } 18 | fprintf(stderr, "# unique keys: %ld; checksum: %u\n", h.size(), z); 19 | return h.size(); 20 | } 21 | -------------------------------------------------------------------------------- /c++11/test-1.cpp: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | #include 3 | 4 | struct Hash32 { 5 | inline size_t operator()(const uint32_t x) const { 6 | return hash_fn(x); 7 | } 8 | }; 9 | 10 | uint32_t test_int(uint32_t n, uint32_t x0) 11 | { 12 | uint32_t i, x, z = 0; 13 | std::unordered_map h; 14 | for (i = 0, x = x0; i < n; ++i) { 15 | x = hash32(x); 16 | auto p = h.emplace(get_key(n, x), 0); 17 | z += ++p.first->second; 18 | } 19 | fprintf(stderr, "# unique keys: %ld; checksum: %u\n", h.size(), z); 20 | return h.size(); 21 | } 22 | -------------------------------------------------------------------------------- /sparsepp/test-1.cpp: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | #include "sparsepp/spp.h" 3 | 4 | struct Hash32 { 5 | inline size_t operator()(const uint32_t x) const { 6 | return hash_fn(x); 7 | } 8 | }; 9 | 10 | uint32_t test_int(uint32_t n, uint32_t x0) 11 | { 12 | uint32_t i, x, z = 0; 13 | spp::sparse_hash_map h; 14 | for (i = 0, x = x0; i < n; ++i) { 15 | x = hash32(x); 16 | auto p = h.emplace(get_key(n, x), 0); 17 | z += ++p.first->second; 18 | } 19 | fprintf(stderr, "# unique keys: %ld; checksum: %u\n", h.size(), z); 20 | return h.size(); 21 | } 22 | -------------------------------------------------------------------------------- /sparsehash/test-1.cpp: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | #include 3 | 4 | struct Hash32 { 5 | inline size_t operator()(const uint32_t x) const { 6 | return hash_fn(x); 7 | } 8 | }; 9 | 10 | uint32_t test_int(uint32_t n, uint32_t x0) 11 | { 12 | uint32_t i, x, z = 0; 13 | google::sparse_hash_map h; 14 | h.set_deleted_key(0xfffffffeu); 15 | for (i = 0, x = x0; i < n; ++i) { 16 | x = hash32(x); 17 | z += ++h[get_key(n, x)]; 18 | } 19 | fprintf(stderr, "# unique keys: %ld; checksum: %u\n", h.size(), z); 20 | return h.size(); 21 | } 22 | -------------------------------------------------------------------------------- /sparsepp/test.cpp: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | 3 | // https://github.com/greg7mdp/sparsepp 4 | // cloned on 2018-01-12 5 | #include "sparsepp/spp.h" 6 | 7 | struct Hash32 { 8 | inline size_t operator()(const uint32_t x) const { 9 | return hash_fn(x); 10 | } 11 | }; 12 | 13 | uint32_t test_int(uint32_t n, uint32_t x0) 14 | { 15 | uint32_t i, x, z = 0; 16 | spp::sparse_hash_map h; 17 | for (i = 0, x = x0; i < n; ++i) { 18 | x = hash32(x); 19 | z += ++h[get_key(n, x)]; 20 | } 21 | fprintf(stderr, "# unique keys: %ld; checksum: %u\n", h.size(), z); 22 | return h.size(); 23 | } 24 | -------------------------------------------------------------------------------- /khashlmpp/test.cpp: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | #include "khashlm.hpp" 3 | 4 | struct aux_hash { 5 | uint32_t operator() (uint32_t a) const { 6 | return hash_fn(a); 7 | }; 8 | }; 9 | 10 | uint32_t test_int(uint32_t n, uint32_t x0) 11 | { 12 | uint32_t i, x, z = 0; 13 | klib::KHashMap h; 14 | for (i = 0, x = x0; i < n; ++i) { 15 | uint32_t k; 16 | int absent; 17 | x = hash32(x); 18 | k = h.put(get_key(n, x), &absent); 19 | if (absent) h.value(k) = 0; 20 | z += ++h.value(k); 21 | } 22 | fprintf(stderr, "# unique keys: %ld; checksum: %u\n", (long)h.size(), z); 23 | return h.size(); 24 | } 25 | -------------------------------------------------------------------------------- /libcuckoo/test.cpp: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | 3 | // https://github.com/efficient/libcuckoo 4 | // cloned on 2018-01-12 5 | #include "cuckoohash_map.hh" 6 | 7 | struct Hash32 { 8 | inline size_t operator()(const uint32_t x) const { 9 | return hash_fn(x); 10 | } 11 | }; 12 | 13 | uint32_t test_int(uint32_t n, uint32_t x0) 14 | { 15 | uint32_t i, x, z = 0; 16 | cuckoohash_map h; 17 | for (i = 0, x = x0; i < n; ++i) { 18 | x = hash32(x); 19 | h.upsert(get_key(n, x), [&z](uint32_t &v) { z += ++v; }); // FIXME: not sure if this is correct... 20 | ++z; 21 | } 22 | fprintf(stderr, "# unique keys: %ld; checksum: %u\n", h.size(), z); 23 | return h.size(); 24 | } 25 | -------------------------------------------------------------------------------- /sparsehash/test.cpp: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | 3 | // https://github.com/sparsehash/sparsehash 4 | // cloned on 2018-01-12 5 | #include 6 | 7 | struct Hash32 { 8 | inline size_t operator()(const uint32_t x) const { 9 | return hash_fn(x); 10 | } 11 | }; 12 | 13 | uint32_t test_int(uint32_t n, uint32_t x0) 14 | { 15 | uint32_t i, x, z = 0; 16 | google::dense_hash_map h; 17 | h.set_empty_key(0xffffffffu); 18 | h.set_deleted_key(0xfffffffeu); 19 | for (i = 0, x = x0; i < n; ++i) { 20 | x = hash32(x); 21 | z += ++h[get_key(n, x)]; 22 | } 23 | fprintf(stderr, "# unique keys: %ld; checksum: %u\n", h.size(), z); 24 | return h.size(); 25 | } 26 | -------------------------------------------------------------------------------- /_absl/test.cpp: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | #include 3 | 4 | struct Hash32 { 5 | inline size_t operator()(const uint32_t x) const { 6 | return hash_fn(x); 7 | } 8 | }; 9 | 10 | uint32_t test_int(uint32_t n, uint32_t x0) 11 | { 12 | uint32_t i, x, z = 0; 13 | absl::flat_hash_map h; 14 | for (i = 0, x = x0; i < n; ++i) { 15 | x = hash32(x); 16 | #ifndef UDB2_TEST_DEL 17 | z += ++h[get_key(n, x)]; 18 | #else 19 | auto p = h.insert(std::pair(get_key(n, x), i)); 20 | if (p.second == false) h.erase(p.first); 21 | #endif 22 | } 23 | fprintf(stderr, "# unique keys: %ld; checksum: %u\n", h.size(), z); 24 | return h.size(); 25 | } 26 | -------------------------------------------------------------------------------- /_glib/test.c: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | #include 3 | 4 | void test_int(uint32_t n, uint32_t x0) 5 | { 6 | uint32_t i, x, z = 0; 7 | GHashTable *h; 8 | h = g_hash_table_new(NULL, NULL); 9 | for (i = 0, x = x0; i < n; ++i) { 10 | gpointer v, ori_key; 11 | uint32_t key, cnt; 12 | x = hash32(x); 13 | key = get_key(n, x); 14 | if (g_hash_table_lookup_extended(h, GINT_TO_POINTER(key), &ori_key, &v)) { 15 | cnt = GPOINTER_TO_INT(v) + 1; 16 | } else { 17 | cnt = 1; 18 | } 19 | g_hash_table_insert(h, GINT_TO_POINTER(key), GINT_TO_POINTER(cnt)); 20 | z += cnt; 21 | } 22 | fprintf(stderr, "# unique keys: %d; checksum: %u\n", g_hash_table_size(h), z); 23 | g_hash_table_destroy(h); 24 | } 25 | -------------------------------------------------------------------------------- /stb/test.c: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | 3 | // https://github.com/nothings/stb 4 | // cloned on 2018-01-17 5 | #define STB_DEFINE 6 | #include "stb.h" 7 | 8 | uint32_t test_int(uint32_t n, uint32_t x0) 9 | { 10 | uint32_t i, x, z = 0, size = 0; 11 | stb_idict *h; 12 | h = stb_idict_create(); 13 | for (i = 0, x = x0; i < n; ++i) { 14 | uint32_t key, val = 1; 15 | x = hash32(x); 16 | key = get_key(n, x); 17 | if (stb_idict_get_flag(h, key, &val)) { 18 | stb_idict_set(h, key, val + 1); 19 | } else { 20 | stb_idict_set(h, key, 1); 21 | ++size; 22 | } 23 | z += val; 24 | } 25 | fprintf(stderr, "# unique keys: %d; checksum: %u\n", size, z); 26 | stb_idict_destroy(h); 27 | return size; 28 | } 29 | -------------------------------------------------------------------------------- /khash/test.c: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | #include "khash.h" 3 | KHASH_INIT(32a, uint32_t, uint32_t, 1, hash_fn, kh_int_hash_equal) 4 | 5 | uint32_t test_int(uint32_t n, uint32_t x0) 6 | { 7 | uint32_t i, x, z = 0; 8 | khash_t(32a) *h; 9 | h = kh_init(32a); 10 | for (i = 0, x = x0; i < n; ++i) { 11 | khint_t k; 12 | int absent; 13 | x = hash32(x); 14 | k = kh_put(32a, h, get_key(n, x), &absent); 15 | #ifndef UDB2_TEST_DEL 16 | if (absent) kh_val(h, k) = 0; 17 | z += ++kh_val(h, k); 18 | #else 19 | if (absent) ++z; 20 | else kh_del(32a, h, k); 21 | #endif 22 | } 23 | fprintf(stderr, "# unique keys: %d; checksum: %u\n", kh_size(h), z); 24 | x = kh_size(h); 25 | kh_destroy(32a, h); 26 | return x; 27 | } 28 | -------------------------------------------------------------------------------- /_glib/test-1.c: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | #include 3 | 4 | void test_int(uint32_t n, uint32_t x0) 5 | { 6 | uint32_t i, x, z = 0; 7 | GHashTable *h; 8 | h = g_hash_table_new_full(g_direct_hash, g_direct_equal, 0, free); 9 | for (i = 0, x = x0; i < n; ++i) { 10 | gpointer v; 11 | uint32_t key; 12 | x = hash32(x); 13 | key = get_key(n, x); 14 | v = g_hash_table_lookup(h, GINT_TO_POINTER(key)); 15 | if (v == 0) { 16 | uint32_t *cnt; 17 | cnt = malloc(4); 18 | *cnt = 1; 19 | g_hash_table_insert(h, GINT_TO_POINTER(key), cnt); 20 | ++z; 21 | } else z += ++*(uint32_t*)v; 22 | } 23 | fprintf(stderr, "# unique keys: %d; checksum: %u\n", g_hash_table_size(h), z); 24 | g_hash_table_destroy(h); 25 | } 26 | -------------------------------------------------------------------------------- /khashlpp/test.cpp: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | #include "khashl.hpp" 3 | 4 | struct aux_hash { 5 | uint32_t operator() (uint32_t a) const { 6 | return hash_fn(a); 7 | }; 8 | }; 9 | 10 | uint32_t test_int(uint32_t n, uint32_t x0) 11 | { 12 | uint32_t i, x, z = 0; 13 | klib::KHashMap h; 14 | for (i = 0, x = x0; i < n; ++i) { 15 | uint32_t k; 16 | int absent; 17 | x = hash32(x); 18 | k = h.put(get_key(n, x), &absent); 19 | #ifndef UDB2_TEST_DEL 20 | if (absent) h.value(k) = 0; 21 | z += ++h.value(k); 22 | #else 23 | if (absent) ++z; 24 | else h.del(k); 25 | #endif 26 | } 27 | fprintf(stderr, "# unique keys: %d; checksum: %u; capacity: %d\n", h.size(), z, h.n_buckets()); 28 | return h.size(); 29 | } 30 | -------------------------------------------------------------------------------- /khashl/test.c: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | #include "khashl.h" 3 | 4 | KHASHL_MAP_INIT(, intmap_t, intmap, uint32_t, int, hash_fn, kh_eq_generic) 5 | 6 | uint32_t test_int(uint32_t n, uint32_t x0) 7 | { 8 | uint32_t i, x, z = 0; 9 | intmap_t *h; 10 | h = intmap_init(); 11 | for (i = 0, x = x0; i < n; ++i) { 12 | khint_t k; 13 | int absent; 14 | x = hash32(x); 15 | k = intmap_put(h, get_key(n, x), &absent); 16 | #ifndef UDB2_TEST_DEL 17 | if (absent) kh_val(h, k) = 0; 18 | z += ++kh_val(h, k); 19 | #else 20 | if (absent) ++z; 21 | else intmap_del(h, k); 22 | #endif 23 | } 24 | fprintf(stderr, "# unique keys: %d; checksum: %u; capacity: %u\n", kh_size(h), z, kh_capacity(h)); 25 | x = kh_size(h); 26 | intmap_destroy(h); 27 | return x; 28 | } 29 | -------------------------------------------------------------------------------- /kbtree/test.c: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | #include "kbtree.h" 3 | 4 | typedef struct { 5 | uint32_t key, cnt; 6 | } aux_t; 7 | #define aux_cmp(a, b) (((a).key > (b).key) - ((a).key < (b).key)) 8 | KBTREE_INIT(32, aux_t, aux_cmp) 9 | 10 | uint32_t test_int(uint32_t n, uint32_t x0) 11 | { 12 | uint32_t i, x, z = 0; 13 | kbtree_t(32) *h; 14 | h = kb_init(32, KB_DEFAULT_SIZE); 15 | for (i = 0, x = x0; i < n; ++i) { 16 | aux_t a, *p; 17 | x = hash32(x); 18 | a.key = get_key(n, x), a.cnt = 1; 19 | p = kb_getp(32, h, &a); 20 | if (p == 0) { 21 | kb_putp(32, h, &a); 22 | ++z; 23 | } else z += ++p->cnt; 24 | } 25 | fprintf(stderr, "# unique keys: %d; checksum: %u\n", kb_size(h), z); 26 | x = kb_size(h); 27 | kb_destroy(32, h); 28 | return x; 29 | } 30 | -------------------------------------------------------------------------------- /tsl_robin_map/test.cpp: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | 3 | // https://github.com/Tessil/hopscotch-map 4 | // cloned on 2019-12-26 5 | #include "robin_map.h" 6 | 7 | struct Hash32 { 8 | inline size_t operator()(const uint32_t x) const { 9 | return hash_fn(x); 10 | } 11 | }; 12 | 13 | uint32_t test_int(uint32_t n, uint32_t x0) 14 | { 15 | uint32_t i, x, z = 0; 16 | tsl::robin_map h; 17 | for (i = 0, x = x0; i < n; ++i) { 18 | x = hash32(x); 19 | #ifndef UDB2_TEST_DEL 20 | z += ++h[get_key(n, x)]; 21 | #else 22 | auto p = h.insert(std::pair(get_key(n, x), i)); 23 | if (p.second == false) h.erase(p.first); 24 | #endif 25 | } 26 | fprintf(stderr, "# unique keys: %ld; checksum: %u\n", h.size(), z); 27 | return h.size(); 28 | } 29 | -------------------------------------------------------------------------------- /tsl_hopscotch_map/test.cpp: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | 3 | // https://github.com/Tessil/hopscotch-map 4 | // cloned on 2019-12-26 5 | #include "hopscotch_map.h" 6 | 7 | struct Hash32 { 8 | inline size_t operator()(const uint32_t x) const { 9 | return hash_fn(x); 10 | } 11 | }; 12 | 13 | uint32_t test_int(uint32_t n, uint32_t x0) 14 | { 15 | uint32_t i, x, z = 0; 16 | tsl::hopscotch_map h; 17 | for (i = 0, x = x0; i < n; ++i) { 18 | x = hash32(x); 19 | #ifndef UDB2_TEST_DEL 20 | z += ++h[get_key(n, x)]; 21 | #else 22 | auto p = h.insert(std::pair(get_key(n, x), i)); 23 | if (p.second == false) h.erase(p.first); 24 | #endif 25 | } 26 | fprintf(stderr, "# unique keys: %ld; checksum: %u\n", h.size(), z); 27 | return h.size(); 28 | } 29 | -------------------------------------------------------------------------------- /robin_hood/test.cpp: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | #include 3 | 4 | // https://github.com/martinus/robin-hood-hashing 5 | // cloned on 2023-12-12 6 | #include "robin_hood.h" 7 | 8 | struct Hash32 { 9 | inline size_t operator()(const uint32_t x) const { 10 | return hash_fn(x); 11 | } 12 | }; 13 | 14 | uint32_t test_int(uint32_t n, uint32_t x0) 15 | { 16 | uint32_t i, x, z = 0; 17 | robin_hood::unordered_map h; 18 | for (i = 0, x = x0; i < n; ++i) { 19 | x = hash32(x); 20 | #ifndef UDB2_TEST_DEL 21 | z += ++h[get_key(n, x)]; 22 | #else 23 | auto p = h.try_emplace(get_key(n, x), i); 24 | if (p.second == false) h.erase(p.first); 25 | #endif 26 | } 27 | fprintf(stderr, "# unique keys: %ld; checksum: %u\n", h.size(), z); 28 | return h.size(); 29 | } 30 | -------------------------------------------------------------------------------- /tsl_hopscotch_map/test-1.cpp: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | 3 | // https://github.com/Tessil/hopscotch-map 4 | // cloned on 2019-12-26 5 | #include "bhopscotch_map.h" 6 | 7 | struct Hash32 { 8 | inline size_t operator()(const uint32_t x) const { 9 | return hash_fn(x); 10 | } 11 | }; 12 | 13 | uint32_t test_int(uint32_t n, uint32_t x0) 14 | { 15 | uint32_t i, x, z = 0; 16 | tsl::bhopscotch_map h; 17 | for (i = 0, x = x0; i < n; ++i) { 18 | x = hash32(x); 19 | #ifndef UDB2_TEST_DEL 20 | z += ++h[get_key(n, x)]; 21 | #else 22 | auto p = h.insert(std::pair(get_key(n, x), i)); 23 | if (p.second == false) h.erase(p.first); 24 | #endif 25 | } 26 | fprintf(stderr, "# unique keys: %ld; checksum: %u\n", h.size(), z); 27 | return h.size(); 28 | } 29 | -------------------------------------------------------------------------------- /phmap/test.cpp: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | #include 3 | 4 | // https://github.com/martinus/robin-hood-hashing 5 | // cloned on 2019-12-26 6 | #include "phmap.h" 7 | 8 | struct Hash32 { 9 | inline size_t operator()(const uint32_t x) const { 10 | return hash_fn(x); 11 | } 12 | }; 13 | 14 | uint32_t test_int(uint32_t n, uint32_t x0) 15 | { 16 | uint32_t i, x, z = 0; 17 | phmap::flat_hash_map h; 18 | for (i = 0, x = x0; i < n; ++i) { 19 | x = hash32(x); 20 | #ifndef UDB2_TEST_DEL 21 | z += ++h[get_key(n, x)]; 22 | #else 23 | auto p = h.insert(std::pair(get_key(n, x), i)); 24 | if (p.second == false) h.erase(p.first); 25 | #endif 26 | } 27 | fprintf(stderr, "# unique keys: %ld; checksum: %u\n", h.size(), z); 28 | return h.size(); 29 | } 30 | -------------------------------------------------------------------------------- /emilib/test.cpp: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | #include // needed by hash_map.hpp 3 | 4 | // https://github.com/emilk/emilib 5 | // cloned on 2019-12-26 6 | #include "hash_map.hpp" 7 | 8 | struct Hash32 { 9 | inline size_t operator()(const uint32_t x) const { 10 | return hash_fn(x); 11 | } 12 | }; 13 | 14 | uint32_t test_int(uint32_t n, uint32_t x0) 15 | { 16 | uint32_t i, x, z = 0; 17 | emilib::HashMap h; 18 | for (i = 0, x = x0; i < n; ++i) { 19 | x = hash32(x); 20 | #ifndef UDB2_TEST_DEL 21 | z += ++h[get_key(n, x)]; 22 | #else 23 | auto p = h.insert(std::pair(get_key(n, x), i)); 24 | if (p.second == false) h.erase(p.first); 25 | #endif 26 | } 27 | fprintf(stderr, "# unique keys: %ld; checksum: %u\n", h.size(), z); 28 | return h.size(); 29 | } 30 | -------------------------------------------------------------------------------- /khashpp/test.cpp: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | #include "khash.hpp" 3 | 4 | struct aux_t { 5 | uint32_t key, cnt; 6 | }; 7 | 8 | struct aux_eq { 9 | bool operator() (const aux_t &a, const aux_t &b) const { 10 | return a.key == b.key; 11 | }; 12 | }; 13 | 14 | struct aux_hash { 15 | uint32_t operator() (const aux_t &a) const { 16 | return hash_fn(a.key); 17 | }; 18 | }; 19 | 20 | uint32_t test_int(uint32_t n, uint32_t x0) 21 | { 22 | uint32_t i, x, z = 0; 23 | klib::KHash h; 24 | for (i = 0, x = x0; i < n; ++i) { 25 | aux_t a; 26 | size_t k; 27 | int absent; 28 | x = hash32(x); 29 | a.key = get_key(n, x), a.cnt = 0; 30 | k = h.put(a, &absent); 31 | z += ++h.at(k).cnt; 32 | } 33 | fprintf(stderr, "# unique keys: %d; checksum: %u\n", h.size(), z); 34 | return h.size(); 35 | } 36 | -------------------------------------------------------------------------------- /unordered_dense/test.cpp: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | #include 3 | 4 | // https://github.com/martinus/unordered_dense 5 | // cloned on 2023-12-12 6 | #include "unordered_dense.h" 7 | 8 | struct Hash32 { 9 | //using is_avalanching = void; 10 | inline size_t operator()(const uint32_t x) const { 11 | return hash_fn(x); 12 | } 13 | }; 14 | 15 | uint32_t test_int(uint32_t n, uint32_t x0) 16 | { 17 | uint32_t i, x, z = 0; 18 | ankerl::unordered_dense::map h; 19 | for (i = 0, x = x0; i < n; ++i) { 20 | x = hash32(x); 21 | #ifndef UDB2_TEST_DEL 22 | z += ++h[get_key(n, x)]; 23 | #else 24 | auto p = h.try_emplace(get_key(n, x), i); 25 | if (p.second == false) h.erase(p.first); 26 | #endif 27 | } 28 | fprintf(stderr, "# unique keys: %ld; checksum: %u\n", h.size(), z); 29 | return h.size(); 30 | } 31 | -------------------------------------------------------------------------------- /kavl/test.c: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | #include "kavl.h" 3 | 4 | typedef struct aux_s { 5 | uint32_t key, cnt; 6 | KAVL_HEAD(struct aux_s) head; 7 | } aux_t; 8 | #define aux_cmp(a, b) (((a)->key > (b)->key) - ((a)->key < (b)->key)) 9 | KAVL_INIT(32, aux_t, head, aux_cmp) 10 | 11 | uint32_t test_int(uint32_t n, uint32_t x0) 12 | { 13 | uint32_t i, x, z = 0; 14 | aux_t *root = 0, *p, *q; 15 | p = (aux_t*)malloc(sizeof(aux_t)); 16 | for (i = 0, x = x0; i < n; ++i) { 17 | x = hash32(x); 18 | p->key = get_key(n, x), p->cnt = 0; 19 | q = kavl_insert(32, &root, p, 0); 20 | if (p == q) p = (aux_t*)malloc(sizeof(aux_t)); 21 | z += ++q->cnt; 22 | } 23 | free(p); 24 | fprintf(stderr, "# unique keys: %d; checksum: %u\n", kavl_size(head, root), z); 25 | x = kavl_size(head, root); 26 | kavl_free(aux_t, head, root, free); 27 | return x; 28 | } 29 | -------------------------------------------------------------------------------- /_boost/test.cpp: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | #include 3 | 4 | // https://github.com/martinus/robin-hood-hashing 5 | // cloned on 2023-12-12 6 | #include 7 | 8 | struct Hash32 { 9 | //using is_avalanching = void; 10 | inline size_t operator()(const uint32_t x) const { 11 | return hash_fn(x); 12 | } 13 | }; 14 | 15 | uint32_t test_int(uint32_t n, uint32_t x0) 16 | { 17 | uint32_t i, x, z = 0; 18 | boost::unordered_flat_map h; 19 | for (i = 0, x = x0; i < n; ++i) { 20 | x = hash32(x); 21 | #ifndef UDB2_TEST_DEL 22 | z += ++h[get_key(n, x)]; 23 | #else 24 | auto p = h.try_emplace(get_key(n, x), i); 25 | if (p.second == false) h.erase(p.first); 26 | #endif 27 | } 28 | fprintf(stderr, "# unique keys: %ld; checksum: %u\n", h.size(), z); 29 | return h.size(); 30 | } 31 | -------------------------------------------------------------------------------- /khash/test-1.c: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | #include "khash.h" 3 | 4 | typedef struct { 5 | uint32_t key, cnt; 6 | } aux_t; 7 | #define aux_eq(a, b) ((a).key == (b).key) 8 | #define aux_hash(a) (hash_fn((a).key)) 9 | KHASH_INIT(32b, aux_t, char, 0, aux_hash, aux_eq) 10 | 11 | uint32_t test_int(uint32_t n, uint32_t x0) 12 | { 13 | uint32_t i, x, z = 0; 14 | khash_t(32b) *h; 15 | h = kh_init(32b); 16 | for (i = 0, x = x0; i < n; ++i) { 17 | aux_t a; 18 | khint_t k; 19 | int absent; 20 | x = hash32(x); 21 | a.key = get_key(n, x), a.cnt = 0; 22 | k = kh_put(32b, h, a, &absent); 23 | #ifndef UDB2_TEST_DEL 24 | z += ++kh_key(h, k).cnt; 25 | #else 26 | if (absent) ++z; 27 | else kh_del(32b, h, k); 28 | #endif 29 | } 30 | fprintf(stderr, "# unique keys: %d; checksum: %u\n", kh_size(h), z); 31 | x = kh_size(h); 32 | kh_destroy(32b, h); 33 | return x; 34 | } 35 | -------------------------------------------------------------------------------- /ska_flat_hash_map/test.cpp: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | 3 | // https://github.com/skarupke/flat_hash_map 4 | // cloned on 2018-09-29 5 | #include "flat_hash_map.hpp" 6 | 7 | struct Hash32 { 8 | inline size_t operator()(const uint32_t x) const { 9 | return hash_fn(x); 10 | } 11 | //typedef ska::power_of_two_hash_policy hash_policy; 12 | }; 13 | 14 | uint32_t test_int(uint32_t n, uint32_t x0) 15 | { 16 | uint32_t i, x, z = 0; 17 | ska::flat_hash_map h; 18 | h.max_load_factor(0.75f); 19 | for (i = 0, x = x0; i < n; ++i) { 20 | x = hash32(x); 21 | #ifndef UDB2_TEST_DEL 22 | z += ++h[get_key(n, x)]; 23 | #else 24 | auto p = h.insert(std::pair(get_key(n, x), i)); 25 | if (p.second == false) h.erase(p.first); 26 | #endif 27 | } 28 | fprintf(stderr, "# unique keys: %ld; checksum: %u\n", h.size(), z); 29 | return h.size(); 30 | } 31 | -------------------------------------------------------------------------------- /uthash/test.c: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | 3 | // https://github.com/troydhanson/uthash 4 | // checked out on 2019-12-26 5 | #include "uthash.h" 6 | 7 | typedef struct { 8 | uint32_t key; 9 | uint32_t cnt; 10 | UT_hash_handle hh; 11 | } intcell_t; 12 | 13 | uint32_t test_int(uint32_t n, uint32_t x0) 14 | { 15 | uint32_t i, x, n_unique = 0, z = 0; 16 | intcell_t *h = 0, *r, *tmp; 17 | for (i = 0, x = x0; i < n; ++i) { 18 | uint32_t y; 19 | x = hash32(x); 20 | y = get_key(n, x); 21 | HASH_FIND_INT(h, &y, r); 22 | if (r == 0) { 23 | r = (intcell_t*)malloc(sizeof(intcell_t)); 24 | r->key = y, r->cnt = 0; 25 | HASH_ADD_INT(h, key, r); 26 | ++n_unique; 27 | } 28 | z += ++r->cnt; 29 | } 30 | HASH_ITER(hh, h, r, tmp) { 31 | HASH_DEL(h, r); 32 | free(r); 33 | } 34 | fprintf(stderr, "# unique keys: %d; checksum: %u\n", n_unique, z); 35 | return n_unique; 36 | } 37 | -------------------------------------------------------------------------------- /verstable/test.c: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | 3 | #define NAME intmap_t 4 | #define KEY_TY uint32_t 5 | #define VAL_TY int 6 | #define HASH_FN hash_fn 7 | #define CMPR_FN vt_cmpr_integer 8 | #include "verstable.h" 9 | 10 | uint32_t test_int(uint32_t n, uint32_t x0) 11 | { 12 | uint32_t i, x, z = 0; 13 | intmap_t h; 14 | intmap_t_init(&h); 15 | for (i = 0, x = x0; i < n; ++i) { 16 | uint32_t key; 17 | x = hash32(x); 18 | key = get_key(n, x); 19 | size_t ori_size = intmap_t_size(&h); 20 | intmap_t_itr itr = intmap_t_get_or_insert(&h, key, 0); 21 | #ifndef UDB2_TEST_DEL 22 | z += ++itr.data->val; 23 | #else 24 | if (intmap_t_size(&h) == ori_size) 25 | intmap_t_erase_itr(&h, itr); 26 | else ++z; 27 | #endif 28 | } 29 | fprintf(stderr, "# unique keys: %ld; checksum: %u; capacity: %lu\n", 30 | intmap_t_size(&h), z, intmap_t_bucket_count(&h)); 31 | x = intmap_t_size(&h); 32 | intmap_t_cleanup(&h); 33 | return x; 34 | } 35 | -------------------------------------------------------------------------------- /ska_bytell_hash_map/test.cpp: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | 3 | // https://github.com/skarupke/flat_hash_map 4 | // cloned on 2018-09-29 5 | // Update on 2023-12-12: the last commit is 2018-07-15, so this should be the latest 6 | #include "bytell_hash_map.hpp" 7 | 8 | struct Hash32 { 9 | inline size_t operator()(const uint32_t x) const { 10 | return hash_fn(x); 11 | } 12 | //typedef ska::power_of_two_hash_policy hash_policy; 13 | }; 14 | 15 | uint32_t test_int(uint32_t n, uint32_t x0) 16 | { 17 | uint32_t i, x, z = 0; 18 | ska::bytell_hash_map h; 19 | h.max_load_factor(0.75f); 20 | for (i = 0, x = x0; i < n; ++i) { 21 | x = hash32(x); 22 | #ifndef UDB2_TEST_DEL 23 | z += ++h[get_key(n, x)]; 24 | #else 25 | auto p = h.insert(std::pair(get_key(n, x), i)); 26 | if (p.second == false) h.erase(p.first); 27 | #endif 28 | } 29 | fprintf(stderr, "# unique keys: %ld; checksum: %u\n", h.size(), z); 30 | return h.size(); 31 | } 32 | -------------------------------------------------------------------------------- /tommyds/test-1.c: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | 3 | // https://github.com/amadvance/tommyds 4 | // checked out on 2018-01-11 5 | #include "tommytrie.h" 6 | 7 | typedef struct { 8 | uint32_t key; 9 | uint32_t cnt; 10 | tommy_node node; 11 | } intcell_t; 12 | 13 | uint32_t test_int(uint32_t n, uint32_t x0) 14 | { 15 | uint32_t i, x, z = 0; 16 | tommy_allocator alloc; 17 | tommy_trie h; 18 | tommy_allocator_init(&alloc, TOMMY_TRIE_BLOCK_SIZE, TOMMY_TRIE_BLOCK_SIZE); 19 | tommy_trie_init(&h, &alloc); 20 | for (i = 0, x = x0; i < n; ++i) { 21 | uint32_t key; 22 | intcell_t *p; 23 | x = hash32(x); 24 | key = get_key(n, x); 25 | p = tommy_trie_search(&h, key); 26 | if (!p) { 27 | p = malloc(sizeof(intcell_t)); 28 | p->key = key, p->cnt = 1; 29 | tommy_trie_insert(&h, &p->node, p, p->key); 30 | ++z; 31 | } else z += ++p->cnt; 32 | } 33 | fprintf(stderr, "# unique keys: %d; checksum: %u\n", tommy_trie_count(&h), z); 34 | x = tommy_trie_count(&h); 35 | tommy_allocator_done(&alloc); 36 | return x; 37 | } 38 | -------------------------------------------------------------------------------- /bkthomps-hashmap/test-1a.c: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | 3 | // https://github.com/bkthomps/Containers 4 | // checked out on 2018-01-11 5 | #include "unordered_map.h" 6 | 7 | static int compare_int(const void *const one, const void *const two) // FIXME: this doesn't compare uint32_t 8 | { 9 | const int a = *(int *) one; 10 | const int b = *(int *) two; 11 | return a - b; 12 | } 13 | 14 | static unsigned long hash_int(const void *const key) 15 | { 16 | return hash_fn(*(uint32_t*)key); 17 | } 18 | 19 | uint32_t test_int(uint32_t n, uint32_t x0) 20 | { 21 | uint32_t i, x, z = 0; 22 | unordered_map h; 23 | h = unordered_map_init(sizeof(uint32_t), sizeof(uint32_t), hash_int, compare_int); 24 | for (i = 0, x = x0; i < n; ++i) { 25 | uint32_t key, v = 1; 26 | x = hash32(x); 27 | key = get_key(n, x); 28 | unordered_map_put(h, &key, &v); 29 | z += v; 30 | } 31 | fprintf(stderr, "# unique keys: %d; checksum: %u\n", unordered_map_size(h), z); 32 | x = unordered_map_size(h); 33 | unordered_map_destroy(h); 34 | return x; 35 | } 36 | -------------------------------------------------------------------------------- /khashl/test-block.c: -------------------------------------------------------------------------------- 1 | #include "../common-block.c" 2 | #include "khashl.h" 3 | 4 | KHASHL_CMAP_INIT(, blockmap_t, blockmap, udb_data_t, int, hash_fn_block, hash_eq_block) 5 | 6 | uint32_t test_int(uint32_t n, uint32_t x0) 7 | { 8 | uint32_t i, x, z = 0; 9 | khint_t k; 10 | udb_data_t t0, t; 11 | uint8_t block[MAX_BLOCK_LEN]; 12 | blockmap_t *h; 13 | 14 | t0.data = block; 15 | h = blockmap_init(); 16 | for (i = 0, x = x0; i < n; ++i) { 17 | khint_t k; 18 | int absent; 19 | x = hash32(x); 20 | t0.len = get_key_block(n, x, t0.data); 21 | k = blockmap_put(h, t0, &absent); 22 | if (absent) { 23 | t.len = t0.len; 24 | t.data = (uint8_t*)malloc(t.len); 25 | memcpy(t.data, t0.data, t.len); 26 | kh_key(h, k) = t; 27 | kh_val(h, k) = 0; 28 | } 29 | z += ++kh_val(h, k); 30 | } 31 | fprintf(stderr, "# unique keys: %d; checksum: %u; capacity: %u\n", kh_size(h), z, kh_capacity(h)); 32 | x = kh_size(h); 33 | for (k = 0; k != kh_end(h); ++k) 34 | if (kh_exist(h, k)) 35 | free(kh_key(h, k).data); 36 | blockmap_destroy(h); 37 | return x; 38 | } 39 | -------------------------------------------------------------------------------- /tommyds/test.c: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | 3 | // https://github.com/amadvance/tommyds 4 | // checked out on 2018-01-11 5 | #include "tommyhashlin.h" 6 | 7 | typedef struct { 8 | uint32_t key; 9 | uint32_t cnt; 10 | tommy_node node; 11 | } intcell_t; 12 | 13 | int compare(const void* arg, const void* obj) 14 | { 15 | return *(const uint32_t*)arg != ((const intcell_t*)obj)->key; 16 | } 17 | 18 | uint32_t test_int(uint32_t n, uint32_t x0) 19 | { 20 | uint32_t i, x, z = 0; 21 | tommy_hashlin h; 22 | tommy_hashlin_init(&h); 23 | for (i = 0, x = x0; i < n; ++i) { 24 | uint32_t key; 25 | intcell_t *p; 26 | x = hash32(x); 27 | key = get_key(n, x); 28 | p = tommy_hashlin_search(&h, compare, &key, hash_fn(key)); 29 | if (!p) { 30 | p = malloc(sizeof(intcell_t)); 31 | p->key = key, p->cnt = 1; 32 | tommy_hashlin_insert(&h, &p->node, p, hash_fn(key)); 33 | ++z; 34 | } else z += ++p->cnt; 35 | } 36 | fprintf(stderr, "# unique keys: %d; checksum: %u\n", tommy_hashlin_count(&h), z); 37 | x = tommy_hashlin_count(&h); 38 | tommy_hashlin_done(&h); 39 | return x; 40 | } 41 | -------------------------------------------------------------------------------- /mlib/test.c: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | #include "m-dict.h" 3 | 4 | static inline int oor_equal_p(uint32_t k, unsigned char n) 5 | { 6 | return (k == (uint32_t)(-n-1)); 7 | } 8 | 9 | static inline void oor_set(uint32_t *k, unsigned char n) 10 | { 11 | *k = (uint32_t)(-n-1); 12 | } 13 | 14 | DICT_OA_DEF2(intmap, uint32_t, M_OPEXTEND(M_BASIC_OPLIST, OOR_EQUAL(oor_equal_p), OOR_SET(API_2(oor_set))), int, M_BASIC_OPLIST) 15 | 16 | uint32_t test_int(uint32_t n, uint32_t x0) 17 | { 18 | uint32_t i, x, z = 0; 19 | intmap_t h; 20 | intmap_init(h); 21 | for (i = 0, x = x0; i < n; ++i) { 22 | uint32_t key; 23 | int *p; 24 | x = hash32(x); 25 | key = get_key(n, x); 26 | p = intmap_get(h, key); 27 | #ifndef UDB2_TEST_DEL 28 | if (p == 0) { 29 | intmap_set_at(h, key, 1); 30 | ++z; 31 | } else z += ++*p; 32 | #else 33 | if (p == 0) { 34 | intmap_set_at(h, key, 1); 35 | ++z; 36 | } else intmap_erase(h, key); 37 | #endif 38 | } 39 | fprintf(stderr, "# unique keys: %ld; checksum: %u\n", intmap_size(h), z); 40 | x = intmap_size(h); 41 | intmap_clear(h); 42 | return x; 43 | } 44 | -------------------------------------------------------------------------------- /bkthomps-hashmap/test.c: -------------------------------------------------------------------------------- 1 | #include "../common.c" 2 | 3 | // https://github.com/bkthomps/Containers 4 | // checked out on 2018-01-11 5 | #include "unordered_map.h" 6 | 7 | static int compare_int(const void *const one, const void *const two) // FIXME: this doesn't compare uint32_t 8 | { 9 | const int a = *(int *) one; 10 | const int b = *(int *) two; 11 | return a - b; 12 | } 13 | 14 | static unsigned long hash_int(const void *const key) 15 | { 16 | return hash_fn(*(uint32_t*)key); 17 | } 18 | 19 | uint32_t test_int(uint32_t n, uint32_t x0) 20 | { 21 | uint32_t i, x, z = 0; 22 | unordered_map h; 23 | h = unordered_map_init(sizeof(uint32_t), sizeof(uint32_t), hash_int, compare_int); 24 | for (i = 0, x = x0; i < n; ++i) { 25 | uint32_t key, v; 26 | x = hash32(x); 27 | key = get_key(n, x); 28 | if (!unordered_map_get(&v, h, &key)) { 29 | v = 1; 30 | unordered_map_put(h, &key, &v); 31 | } else { 32 | ++v; 33 | unordered_map_put(h, &key, &v); 34 | } 35 | z += v; 36 | } 37 | fprintf(stderr, "# unique keys: %d; checksum: %u\n", unordered_map_size(h), z); 38 | x = unordered_map_size(h); 39 | unordered_map_destroy(h); 40 | return x; 41 | } 42 | -------------------------------------------------------------------------------- /libcuckoo/cuckoohash_config.hh: -------------------------------------------------------------------------------- 1 | /** \file */ 2 | 3 | #ifndef _CUCKOOHASH_CONFIG_HH 4 | #define _CUCKOOHASH_CONFIG_HH 5 | 6 | #include 7 | #include 8 | 9 | //! The default maximum number of keys per bucket 10 | constexpr size_t LIBCUCKOO_DEFAULT_SLOT_PER_BUCKET = 4; 11 | 12 | //! The default number of elements in an empty hash table 13 | constexpr size_t LIBCUCKOO_DEFAULT_SIZE = 14 | (1U << 16) * LIBCUCKOO_DEFAULT_SLOT_PER_BUCKET; 15 | 16 | //! The default minimum load factor that the table allows for automatic 17 | //! expansion. It must be a number between 0.0 and 1.0. The table will throw 18 | //! libcuckoo_load_factor_too_low if the load factor falls below this value 19 | //! during an automatic expansion. 20 | constexpr double LIBCUCKOO_DEFAULT_MINIMUM_LOAD_FACTOR = 0.05; 21 | 22 | //! An alias for the value that sets no limit on the maximum hashpower. If this 23 | //! value is set as the maximum hashpower limit, there will be no limit. This 24 | //! is also the default initial value for the maximum hashpower in a table. 25 | constexpr size_t LIBCUCKOO_NO_MAXIMUM_HASHPOWER = 26 | std::numeric_limits::max(); 27 | 28 | //! set LIBCUCKOO_DEBUG to 1 to enable debug output 29 | #define LIBCUCKOO_DEBUG 0 30 | 31 | #endif // _CUCKOOHASH_CONFIG_HH 32 | -------------------------------------------------------------------------------- /__logs/231212-plot.gp: -------------------------------------------------------------------------------- 1 | set t po eps co noenh dashed dl 0.3 "Helvetica,18" 2 | 3 | set style line 1 dt 1 lc rgb "#a6cee3" lw 3; 4 | set style line 2 dt 1 lc rgb "#1f78b4" lw 3; 5 | set style line 3 dt 3 lc rgb "#b2df8a" lw 3; 6 | set style line 4 dt 4 lc rgb "#33a02c" lw 3; 7 | set style line 5 dt 5 lc rgb "#fb9a99" lw 3; 8 | set style line 6 dt 6 lc rgb "#e31a1c" lw 3; 9 | set style line 7 dt 7 lc rgb "#fdbf6f" lw 3; 10 | set style line 8 dt 8 lc rgb "#ff7f00" lw 3; 11 | set style line 9 dt 9 lc rgb "#cab2d6" lw 3; 12 | set style line 10 dt 2 lc rgb "#6a3d9a" lw 3; 13 | 14 | set xlab "CPU seconds per million inputs" 15 | set ylab "#bytes per distinct key" 16 | set xran [0:0.18] 17 | 18 | set pointsize 1.5 19 | 20 | set yran [0:*] 21 | set label "Bucket size" at 0.001,6.5 font "Helvetica,14" 22 | 23 | f(x)=8 24 | 25 | set out "udb2-del.eps" 26 | set key top left width -2 font "Helvetica,16" 27 | plot f(x) lc rgb "#080808" dt 6 not, \ 28 | "_boost/run-test-del.log" u 5:6 t "boost flat map" w lp ls 6, \ 29 | "khashl/run-test-del.log" u 5:6 t "khashl" w lp ls 5, \ 30 | "robin_hood/run-test-del.log" u 5:6 t "robin-hood" w lp ls 2, \ 31 | "ska_bytell_hash_map/run-test-del.log" u 5:6 t "ska bytell" w lp ls 3, \ 32 | "unordered_dense/run-test-del.log" u 5:6 t "unordered-dense" w lp ls 4, \ 33 | "verstable/run-test-del.log" u 5:6 t "verstable" w lp ls 8 34 | -------------------------------------------------------------------------------- /__logs/180112-plot.gp: -------------------------------------------------------------------------------- 1 | set style line 1 lt 1 lc rgb "#a6cee3" lw 3; 2 | set style line 2 lt 2 lc rgb "#1f78b4" lw 3; 3 | set style line 3 lt 3 lc rgb "#b2df8a" lw 3; 4 | set style line 4 lt 4 lc rgb "#33a02c" lw 3; 5 | set style line 5 lt 5 lc rgb "#fb9a99" lw 3; 6 | set style line 6 lt 6 lc rgb "#e31a1c" lw 3; 7 | set style line 7 lt 7 lc rgb "#fdbf6f" lw 3; 8 | set style line 8 lt 8 lc rgb "#ff7f00" lw 3; 9 | set style line 9 lt 9 lc rgb "#cab2d6" lw 3; 10 | set style line 10 lt 10 lc rgb "#6a3d9a" lw 3; 11 | 12 | set t po eps co "Helvetica,18" 13 | set out "udb2.eps" 14 | 15 | set xlab "CPU seconds per million inputs" 16 | set ylab "#bytes per distinct key" 17 | set xran [0:*] 18 | 19 | set pointsize 1.5 20 | set key top left width -3 font "Helvetica,16" 21 | 22 | plot \ 23 | "flat_hash_map/run-test.log" u 5:($6*4) t 'flat_hash_map' w lp ls 6, \ 24 | "sparsehash/run-test.log" u 5:($6*4) t 'google_dense' w lp ls 2, \ 25 | "sparsehash/run-test-1.log" u 5:($6*4) t 'google_sparse' w lp ls 3, \ 26 | "hopscotch-map/run-test.log" u 5:($6*4) t 'hopscotch-map' w lp ls 4, \ 27 | "khash/run-test-1.log" u 5:($6*4) t 'khash' w lp ls 5, \ 28 | "libcuckoo/run-test.log" u 5:($6*4) t 'libcuckoo' w lp ls 1, \ 29 | "sparsepp/run-test.log" u 5:($6*4) t 'sparsepp' w lp ls 7, \ 30 | "c++11/run-test.log" u 5:($6*4) t 'unordered_map/gcc' w lp ls 8, \ 31 | "uthash/run-test.log" u 5:($6*4) t 'uthash' w lp ls 9 32 | -------------------------------------------------------------------------------- /sparsehash/sparsehash/internal/sparseconfig.h: -------------------------------------------------------------------------------- 1 | /* 2 | * NOTE: This file is for internal use only. 3 | * Do not use these #defines in your own program! 4 | */ 5 | 6 | /* Namespace for Google classes */ 7 | #define GOOGLE_NAMESPACE ::google 8 | 9 | /* the location of the header defining hash functions */ 10 | #define HASH_FUN_H 11 | 12 | /* the namespace of the hash<> function */ 13 | #define HASH_NAMESPACE std 14 | 15 | /* Define to 1 if you have the header file. */ 16 | #define HAVE_INTTYPES_H 1 17 | 18 | /* Define to 1 if the system has the type `long long'. */ 19 | #define HAVE_LONG_LONG 1 20 | 21 | /* Define to 1 if you have the `memcpy' function. */ 22 | #define HAVE_MEMCPY 1 23 | 24 | /* Define to 1 if you have the header file. */ 25 | #define HAVE_STDINT_H 1 26 | 27 | /* Define to 1 if you have the header file. */ 28 | #define HAVE_SYS_TYPES_H 1 29 | 30 | /* Define to 1 if the system has the type `uint16_t'. */ 31 | #define HAVE_UINT16_T 1 32 | 33 | /* Define to 1 if the system has the type `u_int16_t'. */ 34 | #define HAVE_U_INT16_T 1 35 | 36 | /* Define to 1 if the system has the type `__uint16'. */ 37 | /* #undef HAVE___UINT16 */ 38 | 39 | /* The system-provided hash function including the namespace. */ 40 | #define SPARSEHASH_HASH HASH_NAMESPACE::hash 41 | 42 | /* Stops putting the code inside the Google namespace */ 43 | #define _END_GOOGLE_NAMESPACE_ } 44 | 45 | /* Puts following code inside the Google namespace */ 46 | #define _START_GOOGLE_NAMESPACE_ namespace google { 47 | -------------------------------------------------------------------------------- /tommyds/tommy.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010, Andrea Mazzoleni. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "tommyhash.c" 29 | #include "tommyalloc.c" 30 | #include "tommyarray.c" 31 | #include "tommyarrayof.c" 32 | #include "tommyarrayblk.c" 33 | #include "tommyarrayblkof.c" 34 | #include "tommylist.c" 35 | #include "tommytree.c" 36 | #include "tommytrie.c" 37 | #include "tommytrieinp.c" 38 | #include "tommyhashtbl.c" 39 | #include "tommyhashdyn.c" 40 | #include "tommyhashlin.c" 41 | 42 | -------------------------------------------------------------------------------- /__logs/231213-plot.gp: -------------------------------------------------------------------------------- 1 | set t po eps co noenh dashed dl 0.3 "Helvetica,18" 2 | 3 | set style line 1 dt 1 lc rgb "#a6cee3" lw 3; 4 | set style line 2 dt 1 lc rgb "#1f78b4" lw 3; 5 | set style line 3 dt 3 lc rgb "#b2df8a" lw 3; 6 | set style line 4 dt 4 lc rgb "#33a02c" lw 3; 7 | set style line 5 dt 5 lc rgb "#fb9a99" lw 3; 8 | set style line 6 dt 6 lc rgb "#e31a1c" lw 3; 9 | set style line 7 dt 7 lc rgb "#fdbf6f" lw 3; 10 | set style line 8 dt 8 lc rgb "#ff7f00" lw 3; 11 | set style line 9 dt 9 lc rgb "#cab2d6" lw 3; 12 | set style line 10 dt 2 lc rgb "#6a3d9a" lw 3; 13 | 14 | set xlab "CPU seconds per million inputs" 15 | set ylab "#bytes per distinct key" 16 | 17 | set pointsize 1.5 18 | 19 | set yran [0:*] 20 | set label "Bucket size" at 0.001,6.5 font "Helvetica,14" 21 | 22 | f(x)=8 23 | 24 | set yran [0:70] 25 | 26 | set xran [0:0.1] 27 | set out "udb2-ins.eps" 28 | set key top left width -2 font "Helvetica,16" 29 | plot f(x) lc rgb "#080808" dt 6 not, \ 30 | "_boost/run-test.log" u 5:6 t "boost flat map" w lp ls 6, \ 31 | "khashl/run-test.log" u 5:6 t "khashl" w lp ls 5, \ 32 | "robin_hood/run-test.log" u 5:6 t "robin-hood" w lp ls 2, \ 33 | "ska_bytell_hash_map/run-test.log" u 5:6 t "ska bytell" w lp ls 3, \ 34 | "unordered_dense/run-test.log" u 5:6 t "unordered-dense" w lp ls 4, \ 35 | "verstable/run-test.log" u 5:6 t "verstable" w lp ls 8 36 | 37 | set xran [0:0.16] 38 | set out "udb2-del.eps" 39 | set key top left width -2 font "Helvetica,16" 40 | plot f(x) lc rgb "#080808" dt 6 not, \ 41 | "_boost/run-test-del.log" u 5:6 t "boost flat map" w lp ls 6, \ 42 | "khashl/run-test-del.log" u 5:6 t "khashl" w lp ls 5, \ 43 | "robin_hood/run-test-del.log" u 5:6 t "robin-hood" w lp ls 2, \ 44 | "ska_bytell_hash_map/run-test-del.log" u 5:6 t "ska bytell" w lp ls 3, \ 45 | "unordered_dense/run-test-del.log" u 5:6 t "unordered-dense" w lp ls 4, \ 46 | "verstable/run-test-del.log" u 5:6 t "verstable" w lp ls 8 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Getting Started 2 | ```sh 3 | git clone https://github.com/attractivechaos/udb2 4 | cd udb2 5 | # compile directories that include the library code; C++11/14 required for some libraries 6 | make 7 | # run benchmarks for compiled programs 8 | ls */run-test*|grep -v log|xargs -i echo '{} > {}.log 2>&1'|sh 9 | ``` 10 | 11 | ## Introduction 12 | 13 | This repo implements a *micro*-benchmark to evaluate the performance of various 14 | hashtable libraries in C/C++. Each library is given *N* 32-bit integers with 15 | ~25% of them are distinct. The task is to find the occurrence of each distinct 16 | integer with a dictionary. To show the effect of rehashing, the benchmark 17 | program runs the task for six rounds with *N* set to 10, 18, 26, 34, 42 and 50 18 | million, respectively. 19 | 20 | Each directory in this repo typically corresponds to one library. Directories 21 | *not* prefixed with underscores include the library source code and can be 22 | compiled without external dependencies (warning: most C++ libraries require 23 | C++11). Directories prefixed with underscores require third-party libraries or 24 | compiler-specific extensions. They are not compiled when you type `make`. You 25 | have to install the external dependencies first and then compile manually by 26 | yourself. 27 | 28 | ## Results 29 | 30 | Complete results can be found in the [\_\_logs][rst] directory. The following 31 | figure shows the memory vs runtime when the benchmark is run on "n1-standard-1" 32 | machine from the Google Cloud: 33 | 34 | ![](https://raw.githubusercontent.com/attractivechaos/udb2/master/__logs/180929-gcloud-a.png) 35 | 36 | It is worth noting that the results vary with machines. The following figure 37 | was derived from runs on a Linux server with a much larger cache (CPU: Xeon 38 | E5-2683 v3, 2.0GHz, 35MB cache; memory: 640GB; gcc: v5.4.0): 39 | 40 | ![](https://raw.githubusercontent.com/attractivechaos/udb2/master/__logs/180929-server-a.png) 41 | 42 | The [companion blog post][blog] gives more context about this benchmark. 43 | 44 | [rst]: https://github.com/attractivechaos/udb2/tree/master/__logs 45 | [blog]: https://attractivechaos.wordpress.com/2018/01/13/revisiting-hash-table-performance/ 46 | -------------------------------------------------------------------------------- /tommyds/tommylist.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010, Andrea Mazzoleni. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "tommylist.h" 29 | #include "tommychain.h" 30 | 31 | /** \internal 32 | * Setup a list. 33 | */ 34 | tommy_inline void tommy_list_set(tommy_list* list, tommy_node* head, tommy_node* tail) 35 | { 36 | head->prev = tail; 37 | tail->next = 0; 38 | *list = head; 39 | } 40 | 41 | void tommy_list_sort(tommy_list* list, tommy_compare_func* cmp) 42 | { 43 | tommy_chain chain; 44 | tommy_node* head; 45 | 46 | if (tommy_list_empty(list)) 47 | return; 48 | 49 | head = tommy_list_head(list); 50 | 51 | /* create a chain from the list */ 52 | chain.head = head; 53 | chain.tail = head->prev; 54 | 55 | tommy_chain_mergesort(&chain, cmp); 56 | 57 | /* restore the list */ 58 | tommy_list_set(list, chain.head, chain.tail); 59 | } 60 | 61 | -------------------------------------------------------------------------------- /__logs/180929-plot.gp: -------------------------------------------------------------------------------- 1 | set style line 1 lt 1 lc rgb "#a6cee3" lw 3; 2 | set style line 2 lt 2 lc rgb "#1f78b4" lw 3; 3 | set style line 3 lt 3 lc rgb "#b2df8a" lw 3; 4 | set style line 4 lt 4 lc rgb "#33a02c" lw 3; 5 | set style line 5 lt 5 lc rgb "#fb9a99" lw 3; 6 | set style line 6 lt 6 lc rgb "#e31a1c" lw 3; 7 | set style line 7 lt 7 lc rgb "#fdbf6f" lw 3; 8 | set style line 8 lt 8 lc rgb "#ff7f00" lw 3; 9 | set style line 9 lt 9 lc rgb "#cab2d6" lw 3; 10 | set style line 10 lt 10 lc rgb "#6a3d9a" lw 3; 11 | 12 | set t po eps co "Helvetica,18" 13 | 14 | set xlab "CPU seconds per million inputs" 15 | set ylab "#bytes per distinct key" 16 | set xran [0:*] 17 | 18 | set pointsize 1.5 19 | 20 | set yran [0:*] 21 | 22 | set out "udb2-all.eps" 23 | set key top left width -6 font "Helvetica,16" 24 | plot \ 25 | "_absl/run-test.log" u 5:($6*4) t 'absl::flag_hash_map' w lp ls 5, \ 26 | "sparsehash/run-test.log" u 5:($6*4) t 'google_dense' w lp ls 6, \ 27 | "sparsehash/run-test-1.log" u 5:($6*4) t 'google_sparse' w lp ls 9, \ 28 | "khash/run-test-1.log" u 5:($6*4) t 'khash' w lp ls 7, \ 29 | "libcuckoo/run-test.log" u 5:($6*4) t 'libcuckoo' w lp ls 8, \ 30 | "ska_bytell_hash_map/run-test.log" u 5:($6*4) t 'ska::bytell_hash_map' w lp ls 1, \ 31 | "sparsepp/run-test.log" u 5:($6*4) t 'sparsepp' w lp ls 10, \ 32 | "tsl_robin_map/run-test.log" u 5:($6*4) t 'tsl::robin_map' w lp ls 4, \ 33 | "c++11/run-test.log" u 5:($6*4) t 'std::unordered_map/gcc' w lp ls 2, \ 34 | "uthash/run-test.log" u 5:($6*4) t 'uthash' w lp ls 3 35 | 36 | set out "udb2-fast.eps" 37 | set key top right width -6 font "Helvetica,16" 38 | plot \ 39 | "_absl/run-test.log" u 5:($6*4) t 'absl::flag_hash_map' w lp ls 5, \ 40 | "sparsehash/run-test.log" u 5:($6*4) t 'google_dense' w lp ls 6, \ 41 | "sparsehash/run-test-1.log" u 5:($6*4) t 'google_sparse' w lp ls 9, \ 42 | "khash/run-test-1.log" u 5:($6*4) t 'khash' w lp ls 7, \ 43 | "libcuckoo/run-test.log" u 5:($6*4) t 'libcuckoo' w lp ls 8, \ 44 | "ska_bytell_hash_map/run-test.log" u 5:($6*4) t 'ska::bytell_hash_map' w lp ls 1, \ 45 | "ska_flat_hash_map/run-test.log" u 5:($6*4) t 'ska::flat_hash_map' w lp ls 2, \ 46 | "sparsepp/run-test.log" u 5:($6*4) t 'sparsepp' w lp ls 10, \ 47 | "tsl_hopscotch_map/run-test.log" u 5:($6*4) t 'tsl::hopscotch_map' w lp ls 3, \ 48 | "tsl_robin_map/run-test.log" u 5:($6*4) t 'tsl::robin_map' w lp ls 4 49 | -------------------------------------------------------------------------------- /sparsepp/sparsepp/spp_timer.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2016 Mariano Gonzalez 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #ifndef spp_timer_h_guard 24 | #define spp_timer_h_guard 25 | 26 | #include 27 | 28 | namespace spp 29 | { 30 | template 31 | class Timer 32 | { 33 | public: 34 | Timer() { reset(); } 35 | void reset() { _start = _snap = clock::now(); } 36 | void snap() { _snap = clock::now(); } 37 | 38 | float get_total() const { return get_diff(_start, clock::now()); } 39 | float get_delta() const { return get_diff(_snap, clock::now()); } 40 | 41 | private: 42 | using clock = std::chrono::high_resolution_clock; 43 | using point = std::chrono::time_point; 44 | 45 | template 46 | static T get_diff(const point& start, const point& end) 47 | { 48 | using duration_t = std::chrono::duration; 49 | 50 | return std::chrono::duration_cast(end - start).count(); 51 | } 52 | 53 | point _start; 54 | point _snap; 55 | }; 56 | } 57 | 58 | #endif // spp_timer_h_guard 59 | -------------------------------------------------------------------------------- /bkthomps-hashmap/unordered_map.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Bailey Thompson 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #ifndef CONTAINERS_UNORDERED_MAP_H 24 | #define CONTAINERS_UNORDERED_MAP_H 25 | 26 | #include 27 | 28 | typedef struct _unordered_map *unordered_map; 29 | 30 | // Starting 31 | unordered_map unordered_map_init(size_t key_size, 32 | size_t value_size, 33 | unsigned long (*hash)(const void *const key), 34 | int (*comparator)(const void *const one, 35 | const void *const two)); 36 | 37 | // Utility 38 | int unordered_map_rehash(unordered_map me); 39 | int unordered_map_size(unordered_map me); 40 | bool unordered_map_is_empty(unordered_map me); 41 | 42 | // Accessing 43 | int unordered_map_put(unordered_map me, void *key, void *value); 44 | bool unordered_map_get(void *value, unordered_map me, void *key); 45 | bool unordered_map_contains(unordered_map me, void *key); 46 | bool unordered_map_remove(unordered_map me, void *key); 47 | 48 | // Ending 49 | int unordered_map_clear(unordered_map me); 50 | unordered_map unordered_map_destroy(unordered_map me); 51 | 52 | #endif /* CONTAINERS_UNORDERED_MAP_H */ 53 | -------------------------------------------------------------------------------- /sparsepp/sparsepp/spp_smartptr.h: -------------------------------------------------------------------------------- 1 | #if !defined(spp_smartptr_h_guard) 2 | #define spp_smartptr_h_guard 3 | 4 | 5 | /* ----------------------------------------------------------------------------------------------- 6 | * quick version of intrusive_ptr 7 | * ----------------------------------------------------------------------------------------------- 8 | */ 9 | 10 | #include 11 | #include "spp_config.h" 12 | 13 | // ------------------------------------------------------------------------ 14 | class spp_rc 15 | { 16 | public: 17 | spp_rc() : _cnt(0) {} 18 | spp_rc(const spp_rc &) : _cnt(0) {} 19 | void increment() const { ++_cnt; } 20 | void decrement() const { assert(_cnt); if (--_cnt == 0) delete this; } 21 | unsigned count() const { return _cnt; } 22 | 23 | protected: 24 | virtual ~spp_rc() {} 25 | 26 | private: 27 | mutable unsigned _cnt; 28 | }; 29 | 30 | // ------------------------------------------------------------------------ 31 | template 32 | class spp_sptr 33 | { 34 | public: 35 | spp_sptr() : _p(0) {} 36 | spp_sptr(T *p) : _p(p) { if (_p) _p->increment(); } 37 | spp_sptr(const spp_sptr &o) : _p(o._p) { if (_p) _p->increment(); } 38 | #ifndef SPP_NO_CXX11_RVALUE_REFERENCES 39 | spp_sptr(spp_sptr &&o) : _p(o._p) { o._p = (T *)0; } 40 | spp_sptr& operator=(spp_sptr &&o) 41 | { 42 | if (_p) _p->decrement(); 43 | _p = o._p; 44 | o._p = (T *)0; 45 | } 46 | #endif 47 | ~spp_sptr() { if (_p) _p->decrement(); } 48 | spp_sptr& operator=(const spp_sptr &o) { reset(o._p); return *this; } 49 | T* get() const { return _p; } 50 | void swap(spp_sptr &o) { T *tmp = _p; _p = o._p; o._p = tmp; } 51 | void reset(const T *p = 0) 52 | { 53 | if (p == _p) 54 | return; 55 | if (_p) _p->decrement(); 56 | _p = (T *)p; 57 | if (_p) _p->increment(); 58 | } 59 | T* operator->() const { return const_cast(_p); } 60 | bool operator!() const { return _p == 0; } 61 | 62 | private: 63 | T *_p; 64 | }; 65 | 66 | // ------------------------------------------------------------------------ 67 | namespace std 68 | { 69 | template 70 | inline void swap(spp_sptr &a, spp_sptr &b) 71 | { 72 | a.swap(b); 73 | } 74 | } 75 | 76 | #endif // spp_smartptr_h_guard 77 | -------------------------------------------------------------------------------- /tommyds/tommyarrayblk.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Andrea Mazzoleni. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "tommyarrayblk.h" 29 | 30 | /******************************************************************************/ 31 | /* array */ 32 | 33 | void tommy_arrayblk_init(tommy_arrayblk* array) 34 | { 35 | tommy_array_init(&array->block); 36 | 37 | array->count = 0; 38 | } 39 | 40 | void tommy_arrayblk_done(tommy_arrayblk* array) 41 | { 42 | tommy_count_t i; 43 | 44 | for (i = 0; i < tommy_array_size(&array->block); ++i) 45 | tommy_free(tommy_array_get(&array->block, i)); 46 | 47 | tommy_array_done(&array->block); 48 | } 49 | 50 | void tommy_arrayblk_grow(tommy_arrayblk* array, tommy_count_t count) 51 | { 52 | tommy_count_t block_max; 53 | tommy_count_t block_mac; 54 | 55 | if (array->count >= count) 56 | return; 57 | array->count = count; 58 | 59 | block_max = (count + TOMMY_ARRAYBLK_SIZE - 1) / TOMMY_ARRAYBLK_SIZE; 60 | block_mac = tommy_array_size(&array->block); 61 | 62 | if (block_mac < block_max) { 63 | /* grow the block array */ 64 | tommy_array_grow(&array->block, block_max); 65 | 66 | /* allocate new blocks */ 67 | while (block_mac < block_max) { 68 | void** ptr = tommy_cast(void**, tommy_calloc(TOMMY_ARRAYBLK_SIZE, sizeof(void*))); 69 | 70 | /* set the new block */ 71 | tommy_array_set(&array->block, block_mac, ptr); 72 | 73 | ++block_mac; 74 | } 75 | } 76 | } 77 | 78 | tommy_size_t tommy_arrayblk_memory_usage(tommy_arrayblk* array) 79 | { 80 | return tommy_array_memory_usage(&array->block) + tommy_array_size(&array->block) * TOMMY_ARRAYBLK_SIZE * sizeof(void*); 81 | } 82 | 83 | -------------------------------------------------------------------------------- /common.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | /*********************************** 9 | * Measuring CPU time and peak RSS * 10 | ***********************************/ 11 | 12 | static double cputime(void) 13 | { 14 | struct rusage r; 15 | getrusage(RUSAGE_SELF, &r); 16 | return r.ru_utime.tv_sec + r.ru_stime.tv_sec + 1e-6 * (r.ru_utime.tv_usec + r.ru_stime.tv_usec); 17 | } 18 | 19 | static long peakrss(void) 20 | { 21 | struct rusage r; 22 | getrusage(RUSAGE_SELF, &r); 23 | #ifdef __linux__ 24 | return r.ru_maxrss * 1024; 25 | #else 26 | return r.ru_maxrss; 27 | #endif 28 | } 29 | 30 | /****************** 31 | * Key generation * 32 | ******************/ 33 | 34 | static inline uint32_t hash32(uint32_t key) 35 | { 36 | key += ~(key << 15); 37 | key ^= (key >> 10); 38 | key += (key << 3); 39 | key ^= (key >> 6); 40 | key += ~(key << 11); 41 | key ^= (key >> 16); 42 | return key; 43 | } 44 | 45 | static inline uint32_t get_key(const uint32_t n, const uint32_t x) 46 | { 47 | return hash32(x % (n>>2)); 48 | } 49 | 50 | /********************************************** 51 | * For testing key generation time (baseline) * 52 | **********************************************/ 53 | 54 | uint64_t traverse_rng(uint32_t n, uint32_t x0) 55 | { 56 | uint64_t sum = 0; 57 | uint32_t i, x; 58 | for (i = 0, x = x0; i < n; ++i) { 59 | x = hash32(x); 60 | sum += get_key(n, x); 61 | } 62 | return sum; 63 | } 64 | 65 | /***************************************************** 66 | * This is the hash function used by almost everyone * 67 | *****************************************************/ 68 | 69 | static inline uint32_t hash_fn(uint32_t key) 70 | { 71 | return key; 72 | } 73 | 74 | /***************** 75 | * Main function * 76 | *****************/ 77 | 78 | int main(int argc, char *argv[]) 79 | { 80 | uint32_t test_int(uint32_t n, uint32_t x0); 81 | int c; 82 | double t, t0; 83 | uint32_t i, m = 5, max = 50000000, n = 10000000, x0 = 1, step; 84 | uint64_t sum; 85 | long m0; 86 | 87 | while ((c = getopt(argc, argv, "n:x:0:k:")) >= 0) { 88 | if (c == 'n') n = atol(optarg); 89 | else if (c == 'x') max = atol(optarg); 90 | else if (c == '0') x0 = atol(optarg); 91 | else if (c == 'k') m = atoi(optarg); 92 | } 93 | 94 | t = cputime(); 95 | sum = traverse_rng(max, x0); 96 | t0 = cputime() - t; 97 | fprintf(stderr, "CPU time spent on RNG: %.3f sec; total sum: %lu\n", t0, (unsigned long)sum); 98 | m0 = peakrss(); 99 | 100 | step = (max - n) / m; 101 | for (i = 0; i <= m; ++i, n += step) { 102 | double t, mem, tpm; 103 | uint32_t size; 104 | t = cputime(); 105 | size = test_int(n, x0); 106 | t = cputime() - t; 107 | mem = peakrss() - m0; 108 | tpm = (t - t0 * n / max) / n * 1e6; 109 | printf("%d\t%d\t%.3f\t%.3f\t%.4f\t%.4f\n", i, n, t, mem/1024./1024., tpm, mem / size); 110 | } 111 | return 0; 112 | } 113 | -------------------------------------------------------------------------------- /tommyds/tommyarray.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011, Andrea Mazzoleni. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "tommyarray.h" 29 | 30 | /******************************************************************************/ 31 | /* array */ 32 | 33 | void tommy_array_init(tommy_array* array) 34 | { 35 | tommy_uint_t i; 36 | 37 | /* fixed initial size */ 38 | array->bucket_bit = TOMMY_ARRAY_BIT; 39 | array->bucket_max = 1 << array->bucket_bit; 40 | array->bucket[0] = tommy_cast(void**, tommy_calloc(array->bucket_max, sizeof(void*))); 41 | for (i = 1; i < TOMMY_ARRAY_BIT; ++i) 42 | array->bucket[i] = array->bucket[0]; 43 | 44 | array->count = 0; 45 | } 46 | 47 | void tommy_array_done(tommy_array* array) 48 | { 49 | tommy_uint_t i; 50 | 51 | tommy_free(array->bucket[0]); 52 | for (i = TOMMY_ARRAY_BIT; i < array->bucket_bit; ++i) { 53 | void** segment = array->bucket[i]; 54 | tommy_free(&segment[((tommy_ptrdiff_t)1) << i]); 55 | } 56 | } 57 | 58 | void tommy_array_grow(tommy_array* array, tommy_count_t count) 59 | { 60 | if (array->count >= count) 61 | return; 62 | array->count = count; 63 | 64 | while (count > array->bucket_max) { 65 | void** segment; 66 | 67 | /* allocate one more segment */ 68 | segment = tommy_cast(void**, tommy_calloc(array->bucket_max, sizeof(void*))); 69 | 70 | /* store it adjusting the offset */ 71 | /* cast to ptrdiff_t to ensure to get a negative value */ 72 | array->bucket[array->bucket_bit] = &segment[-(tommy_ptrdiff_t)array->bucket_max]; 73 | 74 | ++array->bucket_bit; 75 | array->bucket_max = 1 << array->bucket_bit; 76 | } 77 | } 78 | 79 | tommy_size_t tommy_array_memory_usage(tommy_array* array) 80 | { 81 | return array->bucket_max * (tommy_size_t)sizeof(void*); 82 | } 83 | 84 | -------------------------------------------------------------------------------- /tommyds/tommyarrayblkof.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Andrea Mazzoleni. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "tommyarrayblkof.h" 29 | 30 | /******************************************************************************/ 31 | /* array */ 32 | 33 | void tommy_arrayblkof_init(tommy_arrayblkof* array, tommy_size_t element_size) 34 | { 35 | tommy_array_init(&array->block); 36 | 37 | array->element_size = element_size; 38 | array->count = 0; 39 | } 40 | 41 | void tommy_arrayblkof_done(tommy_arrayblkof* array) 42 | { 43 | tommy_count_t i; 44 | 45 | for (i = 0; i < tommy_array_size(&array->block); ++i) 46 | tommy_free(tommy_array_get(&array->block, i)); 47 | 48 | tommy_array_done(&array->block); 49 | } 50 | 51 | void tommy_arrayblkof_grow(tommy_arrayblkof* array, tommy_count_t count) 52 | { 53 | tommy_count_t block_max; 54 | tommy_count_t block_mac; 55 | 56 | if (array->count >= count) 57 | return; 58 | array->count = count; 59 | 60 | block_max = (count + TOMMY_ARRAYBLKOF_SIZE - 1) / TOMMY_ARRAYBLKOF_SIZE; 61 | block_mac = tommy_array_size(&array->block); 62 | 63 | if (block_mac < block_max) { 64 | /* grow the block array */ 65 | tommy_array_grow(&array->block, block_max); 66 | 67 | /* allocate new blocks */ 68 | while (block_mac < block_max) { 69 | void** ptr = tommy_cast(void**, tommy_calloc(TOMMY_ARRAYBLKOF_SIZE, array->element_size)); 70 | 71 | /* set the new block */ 72 | tommy_array_set(&array->block, block_mac, ptr); 73 | 74 | ++block_mac; 75 | } 76 | } 77 | } 78 | 79 | tommy_size_t tommy_arrayblkof_memory_usage(tommy_arrayblkof* array) 80 | { 81 | return tommy_array_memory_usage(&array->block) + tommy_array_size(&array->block) * TOMMY_ARRAYBLKOF_SIZE * array->element_size; 82 | } 83 | 84 | -------------------------------------------------------------------------------- /tommyds/tommyarrayof.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Andrea Mazzoleni. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "tommyarrayof.h" 29 | 30 | /******************************************************************************/ 31 | /* array */ 32 | 33 | void tommy_arrayof_init(tommy_arrayof* array, tommy_size_t element_size) 34 | { 35 | tommy_uint_t i; 36 | 37 | /* fixed initial size */ 38 | array->element_size = element_size; 39 | array->bucket_bit = TOMMY_ARRAYOF_BIT; 40 | array->bucket_max = 1 << array->bucket_bit; 41 | array->bucket[0] = tommy_calloc(array->bucket_max, array->element_size); 42 | for (i = 1; i < TOMMY_ARRAYOF_BIT; ++i) 43 | array->bucket[i] = array->bucket[0]; 44 | 45 | array->count = 0; 46 | } 47 | 48 | void tommy_arrayof_done(tommy_arrayof* array) 49 | { 50 | tommy_uint_t i; 51 | 52 | tommy_free(array->bucket[0]); 53 | for (i = TOMMY_ARRAYOF_BIT; i < array->bucket_bit; ++i) { 54 | unsigned char* segment = tommy_cast(unsigned char*, array->bucket[i]); 55 | tommy_free(segment + (((tommy_ptrdiff_t)1) << i) * array->element_size); 56 | } 57 | } 58 | 59 | void tommy_arrayof_grow(tommy_arrayof* array, tommy_count_t count) 60 | { 61 | if (array->count >= count) 62 | return; 63 | array->count = count; 64 | 65 | while (count > array->bucket_max) { 66 | unsigned char* segment; 67 | 68 | /* allocate one more segment */ 69 | segment = tommy_cast(unsigned char*, tommy_calloc(array->bucket_max, array->element_size)); 70 | 71 | /* store it adjusting the offset */ 72 | /* cast to ptrdiff_t to ensure to get a negative value */ 73 | array->bucket[array->bucket_bit] = segment - (tommy_ptrdiff_t)array->bucket_max * array->element_size; 74 | 75 | ++array->bucket_bit; 76 | array->bucket_max = 1 << array->bucket_bit; 77 | } 78 | } 79 | 80 | tommy_size_t tommy_arrayof_memory_usage(tommy_arrayof* array) 81 | { 82 | return array->bucket_max * (tommy_size_t)array->element_size; 83 | } 84 | 85 | -------------------------------------------------------------------------------- /tommyds/tommyalloc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010, Andrea Mazzoleni. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | /** \file 29 | * Allocator of fixed size blocks. 30 | */ 31 | 32 | #ifndef __TOMMYALLOC_H 33 | #define __TOMMYALLOC_H 34 | 35 | #include "tommytypes.h" 36 | 37 | /******************************************************************************/ 38 | /* allocator */ 39 | 40 | /** \internal 41 | * Allocator entry. 42 | */ 43 | struct tommy_allocator_entry_struct { 44 | struct tommy_allocator_entry_struct* next; /**< Pointer to the next entry. 0 for last. */ 45 | }; 46 | typedef struct tommy_allocator_entry_struct tommy_allocator_entry; 47 | 48 | /** 49 | * Allocator of fixed size blocks. 50 | */ 51 | typedef struct tommy_allocator_struct { 52 | struct tommy_allocator_entry_struct* free_block; /**< List of free blocks. */ 53 | struct tommy_allocator_entry_struct* used_segment; /**< List of allocated segments. */ 54 | tommy_size_t block_size; /**< Block size. */ 55 | tommy_size_t align_size; /**< Alignment size. */ 56 | tommy_count_t count; /**< Number of allocated elements. */ 57 | } tommy_allocator; 58 | 59 | /** 60 | * Initializes the allocator. 61 | * \param alloc Allocator to initialize. 62 | * \param block_size Size of the block to allocate. 63 | * \param align_size Minimum alignment requirement. No less than sizeof(void*). 64 | */ 65 | void tommy_allocator_init(tommy_allocator* alloc, tommy_size_t block_size, tommy_size_t align_size); 66 | 67 | /** 68 | * Deinitialize the allocator. 69 | * It also releases all the allocated memory to the heap. 70 | * \param alloc Allocator to deinitialize. 71 | */ 72 | void tommy_allocator_done(tommy_allocator* alloc); 73 | 74 | /** 75 | * Allocates a block. 76 | * \param alloc Allocator to use. 77 | */ 78 | void* tommy_allocator_alloc(tommy_allocator* alloc); 79 | 80 | /** 81 | * Deallocates a block. 82 | * You must use the same allocator used in the tommy_allocator_alloc() call. 83 | * \param alloc Allocator to use. 84 | * \param ptr Block to free. 85 | */ 86 | void tommy_allocator_free(tommy_allocator* alloc, void* ptr); 87 | 88 | /** 89 | * Gets the size of allocated memory. 90 | * \param alloc Allocator to use. 91 | */ 92 | tommy_size_t tommy_allocator_memory_usage(tommy_allocator* alloc); 93 | 94 | #endif 95 | 96 | -------------------------------------------------------------------------------- /tommyds/tommyarrayblkof.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Andrea Mazzoleni. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | /** \file 29 | * Dynamic array based on blocks of fixed size. 30 | * 31 | * This array is able to grow dynamically upon request, without any reallocation. 32 | * 33 | * This is very similar at ::tommy_arrayblk, but it allows to store elements of any 34 | * size and not just pointers. 35 | * 36 | * Note that in this case tommy_arrayblkof_ref() returns a pointer to the element, 37 | * that should be used for getting and setting elements in the array, 38 | * as generic getter and setter are not available. 39 | */ 40 | 41 | #ifndef __TOMMYARRAYBLKOF_H 42 | #define __TOMMYARRAYBLKOF_H 43 | 44 | #include "tommytypes.h" 45 | #include "tommyarray.h" 46 | 47 | #include /* for assert */ 48 | 49 | /******************************************************************************/ 50 | /* array */ 51 | 52 | /** 53 | * Elements for each block. 54 | */ 55 | #define TOMMY_ARRAYBLKOF_SIZE (4 * 1024) 56 | 57 | /** 58 | * Array container type. 59 | * \note Don't use internal fields directly, but access the container only using functions. 60 | */ 61 | typedef struct tommy_arrayblkof_struct { 62 | tommy_array block; /**< Array of blocks. */ 63 | tommy_size_t element_size; /**< Size of the stored element in bytes. */ 64 | tommy_count_t count; /**< Number of initialized elements in the array. */ 65 | } tommy_arrayblkof; 66 | 67 | /** 68 | * Initializes the array. 69 | * \param element_size Size in byte of the element to store in the array. 70 | */ 71 | void tommy_arrayblkof_init(tommy_arrayblkof* array, tommy_size_t element_size); 72 | 73 | /** 74 | * Deinitializes the array. 75 | */ 76 | void tommy_arrayblkof_done(tommy_arrayblkof* array); 77 | 78 | /** 79 | * Grows the size up to the specified value. 80 | * All the new elements in the array are initialized with the 0 value. 81 | */ 82 | void tommy_arrayblkof_grow(tommy_arrayblkof* array, tommy_count_t size); 83 | 84 | /** 85 | * Gets a reference of the element at the specified position. 86 | * You must be sure that space for this position is already 87 | * allocated calling tommy_arrayblkof_grow(). 88 | */ 89 | tommy_inline void* tommy_arrayblkof_ref(tommy_arrayblkof* array, tommy_count_t pos) 90 | { 91 | unsigned char* base; 92 | 93 | assert(pos < array->count); 94 | 95 | base = tommy_cast(unsigned char*, tommy_array_get(&array->block, pos / TOMMY_ARRAYBLKOF_SIZE)); 96 | 97 | return base + (pos % TOMMY_ARRAYBLKOF_SIZE) * array->element_size; 98 | } 99 | 100 | /** 101 | * Gets the initialized size of the array. 102 | */ 103 | tommy_inline tommy_count_t tommy_arrayblkof_size(tommy_arrayblkof* array) 104 | { 105 | return array->count; 106 | } 107 | 108 | /** 109 | * Gets the size of allocated memory. 110 | */ 111 | tommy_size_t tommy_arrayblkof_memory_usage(tommy_arrayblkof* array); 112 | 113 | #endif 114 | 115 | -------------------------------------------------------------------------------- /common-block.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | /*********************************** 10 | * Measuring CPU time and peak RSS * 11 | ***********************************/ 12 | 13 | static double cputime(void) 14 | { 15 | struct rusage r; 16 | getrusage(RUSAGE_SELF, &r); 17 | return r.ru_utime.tv_sec + r.ru_stime.tv_sec + 1e-6 * (r.ru_utime.tv_usec + r.ru_stime.tv_usec); 18 | } 19 | 20 | static long peakrss(void) 21 | { 22 | struct rusage r; 23 | getrusage(RUSAGE_SELF, &r); 24 | #ifdef __linux__ 25 | return r.ru_maxrss * 1024; 26 | #else 27 | return r.ru_maxrss; 28 | #endif 29 | } 30 | 31 | /****************** 32 | * Key generation * 33 | ******************/ 34 | 35 | static inline uint32_t hash32(uint32_t key) 36 | { 37 | key += ~(key << 15); 38 | key ^= (key >> 10); 39 | key += (key << 3); 40 | key ^= (key >> 6); 41 | key += ~(key << 11); 42 | key ^= (key >> 16); 43 | return key; 44 | } 45 | 46 | typedef struct { 47 | int32_t len; 48 | uint8_t *data; 49 | } udb_data_t; 50 | 51 | #define MAX_BLOCK_LEN 16 52 | 53 | static inline int32_t get_key_block(const uint32_t n, const uint32_t x, uint8_t block[MAX_BLOCK_LEN]) 54 | { 55 | uint32_t y; 56 | int32_t i, len; 57 | y = hash32(x % (n>>2)); 58 | len = MAX_BLOCK_LEN; 59 | for (i = 0; i < len; i += 4) 60 | memcpy(&block[i], &y, 4); 61 | return len; 62 | } 63 | 64 | /********************************************** 65 | * For testing key generation time (baseline) * 66 | **********************************************/ 67 | 68 | uint64_t traverse_rng(uint32_t n, uint32_t x0) 69 | { 70 | uint64_t sum = 0; 71 | uint32_t i, x; 72 | uint8_t block[MAX_BLOCK_LEN]; 73 | for (i = 0, x = x0; i < n; ++i) { 74 | x = hash32(x); 75 | sum += get_key_block(n, x, block); 76 | } 77 | return sum; 78 | } 79 | 80 | /***************************************************** 81 | * This is the hash function used by almost everyone * 82 | *****************************************************/ 83 | 84 | static inline uint32_t murmur_32_scramble(uint32_t k) 85 | { 86 | k *= 0xcc9e2d51; 87 | k = (k << 15) | (k >> 17); 88 | k *= 0x1b873593; 89 | return k; 90 | } 91 | 92 | uint32_t murmur3_32(const uint8_t* key, size_t len, uint32_t seed) // from wiki 93 | { 94 | uint32_t h = seed; 95 | uint32_t k; 96 | size_t i; 97 | for (i = len >> 2; i; i--) { 98 | memcpy(&k, key, sizeof(uint32_t)); 99 | key += sizeof(uint32_t); 100 | h ^= murmur_32_scramble(k); 101 | h = (h << 13) | (h >> 19); 102 | h = h * 5 + 0xe6546b64; 103 | } 104 | k = 0; 105 | for (i = len & 3; i; i--) { 106 | k <<= 8; 107 | k |= key[i - 1]; 108 | } 109 | h ^= murmur_32_scramble(k); 110 | h ^= len; 111 | h ^= h >> 16; 112 | h *= 0x85ebca6b; 113 | h ^= h >> 13; 114 | h *= 0xc2b2ae35; 115 | h ^= h >> 16; 116 | return h; 117 | } 118 | 119 | static inline uint32_t hash_fn_block(const udb_data_t x) 120 | { 121 | return murmur3_32(x.data, x.len, 11); 122 | } 123 | 124 | static inline int hash_eq_block(const udb_data_t x, const udb_data_t y) 125 | { 126 | return x.len == y.len && memcmp(x.data, y.data, x.len) == 0; 127 | } 128 | 129 | /***************** 130 | * Main function * 131 | *****************/ 132 | 133 | int main(int argc, char *argv[]) 134 | { 135 | uint32_t test_int(uint32_t n, uint32_t x0); 136 | int c; 137 | double t, t0; 138 | uint32_t i, m = 5, max = 50000000, n = 10000000, x0 = 1, step; 139 | uint64_t sum; 140 | long m0; 141 | 142 | while ((c = getopt(argc, argv, "n:x:0:k:")) >= 0) { 143 | if (c == 'n') n = atol(optarg); 144 | else if (c == 'x') max = atol(optarg); 145 | else if (c == '0') x0 = atol(optarg); 146 | else if (c == 'k') m = atoi(optarg); 147 | } 148 | 149 | t = cputime(); 150 | sum = traverse_rng(n, x0); 151 | t0 = cputime() - t; 152 | fprintf(stderr, "CPU time spent on RNG: %.3f sec; total sum: %lu\n", t0, (unsigned long)sum); 153 | m0 = peakrss(); 154 | 155 | step = (max - n) / m; 156 | for (i = 0; i <= m; ++i, n += step) { 157 | double t, mem; 158 | uint32_t size; 159 | t = cputime(); 160 | size = test_int(n, x0); 161 | t = cputime() - t; 162 | mem = (peakrss() - m0) / 1024.0 / 1024.0; 163 | printf("%d\t%d\t%.3f\t%.3f\t%.4f\t%.4f\n", i, n, t, mem, t * 1e6 / n, mem * 1e6 / size); 164 | } 165 | return 0; 166 | } 167 | -------------------------------------------------------------------------------- /sparsehash/sparsehash/internal/libc_allocator_with_realloc.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2010, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | // --- 31 | 32 | #ifndef UTIL_GTL_LIBC_ALLOCATOR_WITH_REALLOC_H_ 33 | #define UTIL_GTL_LIBC_ALLOCATOR_WITH_REALLOC_H_ 34 | 35 | #include 36 | #include // for malloc/realloc/free 37 | #include // for ptrdiff_t 38 | #include // for placement new 39 | 40 | _START_GOOGLE_NAMESPACE_ 41 | 42 | template 43 | class libc_allocator_with_realloc { 44 | public: 45 | typedef T value_type; 46 | typedef size_t size_type; 47 | typedef ptrdiff_t difference_type; 48 | 49 | typedef T* pointer; 50 | typedef const T* const_pointer; 51 | typedef T& reference; 52 | typedef const T& const_reference; 53 | 54 | libc_allocator_with_realloc() {} 55 | libc_allocator_with_realloc(const libc_allocator_with_realloc&) {} 56 | ~libc_allocator_with_realloc() {} 57 | 58 | pointer address(reference r) const { return &r; } 59 | const_pointer address(const_reference r) const { return &r; } 60 | 61 | pointer allocate(size_type n, const_pointer = 0) { 62 | return static_cast(malloc(n * sizeof(value_type))); 63 | } 64 | void deallocate(pointer p, size_type) { 65 | free(p); 66 | } 67 | pointer reallocate(pointer p, size_type n) { 68 | return static_cast(realloc(p, n * sizeof(value_type))); 69 | } 70 | 71 | size_type max_size() const { 72 | return static_cast(-1) / sizeof(value_type); 73 | } 74 | 75 | void construct(pointer p, const value_type& val) { 76 | new(p) value_type(val); 77 | } 78 | void destroy(pointer p) { p->~value_type(); } 79 | 80 | template 81 | libc_allocator_with_realloc(const libc_allocator_with_realloc&) {} 82 | 83 | template 84 | struct rebind { 85 | typedef libc_allocator_with_realloc other; 86 | }; 87 | }; 88 | 89 | // libc_allocator_with_realloc specialization. 90 | template<> 91 | class libc_allocator_with_realloc { 92 | public: 93 | typedef void value_type; 94 | typedef size_t size_type; 95 | typedef ptrdiff_t difference_type; 96 | typedef void* pointer; 97 | typedef const void* const_pointer; 98 | 99 | template 100 | struct rebind { 101 | typedef libc_allocator_with_realloc other; 102 | }; 103 | }; 104 | 105 | template 106 | inline bool operator==(const libc_allocator_with_realloc&, 107 | const libc_allocator_with_realloc&) { 108 | return true; 109 | } 110 | 111 | template 112 | inline bool operator!=(const libc_allocator_with_realloc&, 113 | const libc_allocator_with_realloc&) { 114 | return false; 115 | } 116 | 117 | _END_GOOGLE_NAMESPACE_ 118 | 119 | #endif // UTIL_GTL_LIBC_ALLOCATOR_WITH_REALLOC_H_ 120 | -------------------------------------------------------------------------------- /tommyds/tommyarrayof.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Andrea Mazzoleni. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | /** \file 29 | * Dynamic array based on segments of exponential growing size. 30 | * 31 | * This array is able to grow dynamically upon request, without any reallocation. 32 | * 33 | * This is very similar at ::tommy_array, but it allows to store elements of any 34 | * size and not just pointers. 35 | * 36 | * Note that in this case tommy_arrayof_ref() returns a pointer to the element, 37 | * that should be used for getting and setting elements in the array, 38 | * as generic getter and setter are not available. 39 | */ 40 | 41 | #ifndef __TOMMYARRAYOF_H 42 | #define __TOMMYARRAYOF_H 43 | 44 | #include "tommytypes.h" 45 | 46 | #include /* for assert */ 47 | 48 | /******************************************************************************/ 49 | /* array */ 50 | 51 | /** 52 | * Initial and minimal size of the array expressed as a power of 2. 53 | * The initial size is 2^TOMMY_ARRAYOF_BIT. 54 | */ 55 | #define TOMMY_ARRAYOF_BIT 6 56 | 57 | /** \internal 58 | * Max number of elements as a power of 2. 59 | */ 60 | #define TOMMY_ARRAYOF_BIT_MAX 32 61 | 62 | /** 63 | * Array container type. 64 | * \note Don't use internal fields directly, but access the container only using functions. 65 | */ 66 | typedef struct tommy_arrayof_struct { 67 | void* bucket[TOMMY_ARRAYOF_BIT_MAX]; /**< Dynamic array of buckets. */ 68 | tommy_size_t element_size; /**< Size of the stored element in bytes. */ 69 | tommy_uint_t bucket_bit; /**< Bits used in the bit mask. */ 70 | tommy_count_t bucket_max; /**< Number of buckets. */ 71 | tommy_count_t count; /**< Number of initialized elements in the array. */ 72 | } tommy_arrayof; 73 | 74 | /** 75 | * Initializes the array. 76 | * \param element_size Size in byte of the element to store in the array. 77 | */ 78 | void tommy_arrayof_init(tommy_arrayof* array, tommy_size_t element_size); 79 | 80 | /** 81 | * Deinitializes the array. 82 | */ 83 | void tommy_arrayof_done(tommy_arrayof* array); 84 | 85 | /** 86 | * Grows the size up to the specified value. 87 | * All the new elements in the array are initialized with the 0 value. 88 | */ 89 | void tommy_arrayof_grow(tommy_arrayof* array, tommy_count_t size); 90 | 91 | /** 92 | * Gets a reference of the element at the specified position. 93 | * You must be sure that space for this position is already 94 | * allocated calling tommy_arrayof_grow(). 95 | */ 96 | tommy_inline void* tommy_arrayof_ref(tommy_arrayof* array, tommy_count_t pos) 97 | { 98 | unsigned char* ptr; 99 | tommy_uint_t bsr; 100 | 101 | assert(pos < array->count); 102 | 103 | /* get the highest bit set, in case of all 0, return 0 */ 104 | bsr = tommy_ilog2_u32(pos | 1); 105 | 106 | ptr = tommy_cast(unsigned char*, array->bucket[bsr]); 107 | 108 | return ptr + pos * array->element_size; 109 | } 110 | 111 | /** 112 | * Gets the initialized size of the array. 113 | */ 114 | tommy_inline tommy_count_t tommy_arrayof_size(tommy_arrayof* array) 115 | { 116 | return array->count; 117 | } 118 | 119 | /** 120 | * Gets the size of allocated memory. 121 | */ 122 | tommy_size_t tommy_arrayof_memory_usage(tommy_arrayof* array); 123 | 124 | #endif 125 | 126 | -------------------------------------------------------------------------------- /libcuckoo/cuckoohash_util.hh: -------------------------------------------------------------------------------- 1 | /** \file */ 2 | 3 | #ifndef _CUCKOOHASH_UTIL_HH 4 | #define _CUCKOOHASH_UTIL_HH 5 | 6 | #include "cuckoohash_config.hh" // for LIBCUCKOO_DEBUG 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #if LIBCUCKOO_DEBUG 13 | //! When \ref LIBCUCKOO_DEBUG is 0, LIBCUCKOO_DBG will printing out status 14 | //! messages in various situations 15 | #define LIBCUCKOO_DBG(fmt, ...) \ 16 | fprintf(stderr, "\x1b[32m" \ 17 | "[libcuckoo:%s:%d:%lu] " fmt "" \ 18 | "\x1b[0m", \ 19 | __FILE__, __LINE__, \ 20 | std::hash()(std::this_thread::get_id()), \ 21 | __VA_ARGS__) 22 | #else 23 | //! When \ref LIBCUCKOO_DEBUG is 0, LIBCUCKOO_DBG does nothing 24 | #define LIBCUCKOO_DBG(fmt, ...) \ 25 | do { \ 26 | } while (0) 27 | #endif 28 | 29 | /** 30 | * alignas() requires GCC >= 4.9, so we stick with the alignment attribute for 31 | * GCC. 32 | */ 33 | #ifdef __GNUC__ 34 | #define LIBCUCKOO_ALIGNAS(x) __attribute__((aligned(x))) 35 | #else 36 | #define LIBCUCKOO_ALIGNAS(x) alignas(x) 37 | #endif 38 | 39 | /** 40 | * At higher warning levels, MSVC produces an annoying warning that alignment 41 | * may cause wasted space: "structure was padded due to __declspec(align())". 42 | */ 43 | #ifdef _MSC_VER 44 | #define LIBCUCKOO_SQUELCH_PADDING_WARNING __pragma(warning(suppress : 4324)) 45 | #else 46 | #define LIBCUCKOO_SQUELCH_PADDING_WARNING 47 | #endif 48 | 49 | /** 50 | * At higher warning levels, MSVC may issue a deadcode warning which depends on 51 | * the template arguments given. For certain other template arguments, the code 52 | * is not really "dead". 53 | */ 54 | #ifdef _MSC_VER 55 | #define LIBCUCKOO_SQUELCH_DEADCODE_WARNING_BEGIN \ 56 | do { \ 57 | __pragma(warning(push)); \ 58 | __pragma(warning(disable : 4702)) \ 59 | } while (0) 60 | #define LIBCUCKOO_SQUELCH_DEADCODE_WARNING_END __pragma(warning(pop)) 61 | #else 62 | #define LIBCUCKOO_SQUELCH_DEADCODE_WARNING_BEGIN 63 | #define LIBCUCKOO_SQUELCH_DEADCODE_WARNING_END 64 | #endif 65 | 66 | /** 67 | * Thrown when an automatic expansion is triggered, but the load factor of the 68 | * table is below a minimum threshold, which can be set by the \ref 69 | * cuckoohash_map::minimum_load_factor method. This can happen if the hash 70 | * function does not properly distribute keys, or for certain adversarial 71 | * workloads. 72 | */ 73 | class libcuckoo_load_factor_too_low : public std::exception { 74 | public: 75 | /** 76 | * Constructor 77 | * 78 | * @param lf the load factor of the table when the exception was thrown 79 | */ 80 | libcuckoo_load_factor_too_low(const double lf) : load_factor_(lf) {} 81 | 82 | /** 83 | * @return a descriptive error message 84 | */ 85 | virtual const char *what() const noexcept override { 86 | return "Automatic expansion triggered when load factor was below " 87 | "minimum threshold"; 88 | } 89 | 90 | /** 91 | * @return the load factor of the table when the exception was thrown 92 | */ 93 | double load_factor() const { return load_factor_; } 94 | 95 | private: 96 | const double load_factor_; 97 | }; 98 | 99 | /** 100 | * Thrown when an expansion is triggered, but the hashpower specified is greater 101 | * than the maximum, which can be set with the \ref 102 | * cuckoohash_map::maximum_hashpower method. 103 | */ 104 | class libcuckoo_maximum_hashpower_exceeded : public std::exception { 105 | public: 106 | /** 107 | * Constructor 108 | * 109 | * @param hp the hash power we were trying to expand to 110 | */ 111 | libcuckoo_maximum_hashpower_exceeded(const size_t hp) : hashpower_(hp) {} 112 | 113 | /** 114 | * @return a descriptive error message 115 | */ 116 | virtual const char *what() const noexcept override { 117 | return "Expansion beyond maximum hashpower"; 118 | } 119 | 120 | /** 121 | * @return the hashpower we were trying to expand to 122 | */ 123 | size_t hashpower() const { return hashpower_; } 124 | 125 | private: 126 | const size_t hashpower_; 127 | }; 128 | 129 | #endif // _CUCKOOHASH_UTIL_HH 130 | -------------------------------------------------------------------------------- /tommyds/tommyalloc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010, Andrea Mazzoleni. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "tommyalloc.h" 29 | 30 | /******************************************************************************/ 31 | /* allocator */ 32 | 33 | /** 34 | * Basic allocation segment. 35 | * Smaller of a memory page, to allow also a little heap overread. 36 | * The heap manager may put it in a single memory page. 37 | */ 38 | #define TOMMY_ALLOCATOR_BLOCK_SIZE (4096 - 64) 39 | 40 | void tommy_allocator_init(tommy_allocator* alloc, tommy_size_t block_size, tommy_size_t align_size) 41 | { 42 | /* setup the minimal alignment */ 43 | if (align_size < sizeof(void*)) 44 | align_size = sizeof(void*); 45 | 46 | /* ensure that the block_size keeps the alignment */ 47 | if (block_size % align_size != 0) 48 | block_size += align_size - block_size % align_size; 49 | 50 | alloc->block_size = block_size; 51 | alloc->align_size = align_size; 52 | 53 | alloc->count = 0; 54 | alloc->free_block = 0; 55 | alloc->used_segment = 0; 56 | } 57 | 58 | /** 59 | * Reset the allocator and free all. 60 | */ 61 | static void allocator_reset(tommy_allocator* alloc) 62 | { 63 | tommy_allocator_entry* block = alloc->used_segment; 64 | 65 | while (block) { 66 | tommy_allocator_entry* block_next = block->next; 67 | tommy_free(block); 68 | block = block_next; 69 | } 70 | 71 | alloc->count = 0; 72 | alloc->free_block = 0; 73 | alloc->used_segment = 0; 74 | } 75 | 76 | void tommy_allocator_done(tommy_allocator* alloc) 77 | { 78 | allocator_reset(alloc); 79 | } 80 | 81 | void* tommy_allocator_alloc(tommy_allocator* alloc) 82 | { 83 | void* ptr; 84 | 85 | /* if no free block available */ 86 | if (!alloc->free_block) { 87 | tommy_uintptr_t off, mis; 88 | tommy_size_t size; 89 | char* data; 90 | tommy_allocator_entry* segment; 91 | 92 | /* default allocation size */ 93 | size = TOMMY_ALLOCATOR_BLOCK_SIZE; 94 | 95 | /* ensure that we can allocate at least one block */ 96 | if (size < sizeof(tommy_allocator_entry) + alloc->align_size + alloc->block_size) 97 | size = sizeof(tommy_allocator_entry) + alloc->align_size + alloc->block_size; 98 | 99 | data = tommy_cast(char*, tommy_malloc(size)); 100 | segment = (tommy_allocator_entry*)data; 101 | 102 | /* put in the segment list */ 103 | segment->next = alloc->used_segment; 104 | alloc->used_segment = segment; 105 | data += sizeof(tommy_allocator_entry); 106 | 107 | /* align if not aligned */ 108 | off = (tommy_uintptr_t)data; 109 | mis = off % alloc->align_size; 110 | if (mis != 0) { 111 | data += alloc->align_size - mis; 112 | size -= alloc->align_size - mis; 113 | } 114 | 115 | /* insert in free list */ 116 | do { 117 | tommy_allocator_entry* free_block = (tommy_allocator_entry*)data; 118 | free_block->next = alloc->free_block; 119 | alloc->free_block = free_block; 120 | 121 | data += alloc->block_size; 122 | size -= alloc->block_size; 123 | } while (size >= alloc->block_size); 124 | } 125 | 126 | /* remove one from the free list */ 127 | ptr = alloc->free_block; 128 | alloc->free_block = alloc->free_block->next; 129 | 130 | ++alloc->count; 131 | 132 | return ptr; 133 | } 134 | 135 | void tommy_allocator_free(tommy_allocator* alloc, void* ptr) 136 | { 137 | tommy_allocator_entry* free_block = tommy_cast(tommy_allocator_entry*, ptr); 138 | 139 | /* put it in the free list */ 140 | free_block->next = alloc->free_block; 141 | alloc->free_block = free_block; 142 | 143 | --alloc->count; 144 | } 145 | 146 | tommy_size_t tommy_allocator_memory_usage(tommy_allocator* alloc) 147 | { 148 | return alloc->count * (tommy_size_t)alloc->block_size; 149 | } 150 | 151 | -------------------------------------------------------------------------------- /tommyds/tommyarrayblk.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Andrea Mazzoleni. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | /** \file 29 | * Dynamic array based on blocks of fixed size. 30 | * 31 | * This array is able to grow dynamically upon request, without any reallocation. 32 | * 33 | * The grow operation involves an allocation of a new array block, without reallocating 34 | * the already used memory, and then not increasing the heap fragmentation, 35 | * and minimize the space occupation. 36 | * This also implies that the address of the stored elements never change. 37 | * 38 | * Allocated blocks are always of the same fixed size of 4 Ki pointers. 39 | */ 40 | 41 | #ifndef __TOMMYARRAYBLK_H 42 | #define __TOMMYARRAYBLK_H 43 | 44 | #include "tommytypes.h" 45 | #include "tommyarray.h" 46 | 47 | #include /* for assert */ 48 | 49 | /******************************************************************************/ 50 | /* array */ 51 | 52 | /** 53 | * Elements for each block. 54 | */ 55 | #define TOMMY_ARRAYBLK_SIZE (4 * 1024) 56 | 57 | /** 58 | * Array container type. 59 | * \note Don't use internal fields directly, but access the container only using functions. 60 | */ 61 | typedef struct tommy_arrayblk_struct { 62 | tommy_array block; /**< Array of blocks. */ 63 | tommy_count_t count; /**< Number of initialized elements in the array. */ 64 | } tommy_arrayblk; 65 | 66 | /** 67 | * Initializes the array. 68 | */ 69 | void tommy_arrayblk_init(tommy_arrayblk* array); 70 | 71 | /** 72 | * Deinitializes the array. 73 | */ 74 | void tommy_arrayblk_done(tommy_arrayblk* array); 75 | 76 | /** 77 | * Grows the size up to the specified value. 78 | * All the new elements in the array are initialized with the 0 value. 79 | */ 80 | void tommy_arrayblk_grow(tommy_arrayblk* array, tommy_count_t size); 81 | 82 | /** 83 | * Gets a reference of the element at the specified position. 84 | * You must be sure that space for this position is already 85 | * allocated calling tommy_arrayblk_grow(). 86 | */ 87 | tommy_inline void** tommy_arrayblk_ref(tommy_arrayblk* array, tommy_count_t pos) 88 | { 89 | void** ptr; 90 | 91 | assert(pos < array->count); 92 | 93 | ptr = tommy_cast(void**, tommy_array_get(&array->block, pos / TOMMY_ARRAYBLK_SIZE)); 94 | 95 | return &ptr[pos % TOMMY_ARRAYBLK_SIZE]; 96 | } 97 | 98 | /** 99 | * Sets the element at the specified position. 100 | * You must be sure that space for this position is already 101 | * allocated calling tommy_arrayblk_grow(). 102 | */ 103 | tommy_inline void tommy_arrayblk_set(tommy_arrayblk* array, tommy_count_t pos, void* element) 104 | { 105 | *tommy_arrayblk_ref(array, pos) = element; 106 | } 107 | 108 | /** 109 | * Gets the element at the specified position. 110 | * You must be sure that space for this position is already 111 | * allocated calling tommy_arrayblk_grow(). 112 | */ 113 | tommy_inline void* tommy_arrayblk_get(tommy_arrayblk* array, tommy_count_t pos) 114 | { 115 | return *tommy_arrayblk_ref(array, pos); 116 | } 117 | 118 | /** 119 | * Grows and inserts a new element at the end of the array. 120 | */ 121 | tommy_inline void tommy_arrayblk_insert(tommy_arrayblk* array, void* element) 122 | { 123 | tommy_count_t pos = array->count; 124 | 125 | tommy_arrayblk_grow(array, pos + 1); 126 | 127 | tommy_arrayblk_set(array, pos, element); 128 | } 129 | 130 | /** 131 | * Gets the initialized size of the array. 132 | */ 133 | tommy_inline tommy_count_t tommy_arrayblk_size(tommy_arrayblk* array) 134 | { 135 | return array->count; 136 | } 137 | 138 | /** 139 | * Gets the size of allocated memory. 140 | */ 141 | tommy_size_t tommy_arrayblk_memory_usage(tommy_arrayblk* array); 142 | 143 | #endif 144 | 145 | -------------------------------------------------------------------------------- /tommyds/tommyhashtbl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010, Andrea Mazzoleni. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "tommyhashtbl.h" 29 | #include "tommylist.h" 30 | 31 | #include /* for memset */ 32 | 33 | /******************************************************************************/ 34 | /* hashtable */ 35 | 36 | void tommy_hashtable_init(tommy_hashtable* hashtable, tommy_count_t bucket_max) 37 | { 38 | if (bucket_max < 16) 39 | bucket_max = 16; 40 | else 41 | bucket_max = tommy_roundup_pow2_u32(bucket_max); 42 | 43 | hashtable->bucket_max = bucket_max; 44 | hashtable->bucket_mask = hashtable->bucket_max - 1; 45 | 46 | /* initialize the vector using malloc()+memset() instead of calloc() */ 47 | /* to ensure that all the memory in really allocated immediately */ 48 | /* by the OS, and not deferred at later time. */ 49 | /* this improves performance, because we start with a fully initialized hashtable. */ 50 | hashtable->bucket = tommy_cast(tommy_hashtable_node**, tommy_malloc(hashtable->bucket_max * sizeof(tommy_hashtable_node*))); 51 | memset(hashtable->bucket, 0, hashtable->bucket_max * sizeof(tommy_hashtable_node*)); 52 | 53 | hashtable->count = 0; 54 | } 55 | 56 | void tommy_hashtable_done(tommy_hashtable* hashtable) 57 | { 58 | tommy_free(hashtable->bucket); 59 | } 60 | 61 | void tommy_hashtable_insert(tommy_hashtable* hashtable, tommy_hashtable_node* node, void* data, tommy_hash_t hash) 62 | { 63 | tommy_count_t pos = hash & hashtable->bucket_mask; 64 | 65 | tommy_list_insert_tail(&hashtable->bucket[pos], node, data); 66 | 67 | node->key = hash; 68 | 69 | ++hashtable->count; 70 | } 71 | 72 | void* tommy_hashtable_remove_existing(tommy_hashtable* hashtable, tommy_hashtable_node* node) 73 | { 74 | tommy_count_t pos = node->key & hashtable->bucket_mask; 75 | 76 | tommy_list_remove_existing(&hashtable->bucket[pos], node); 77 | 78 | --hashtable->count; 79 | 80 | return node->data; 81 | } 82 | 83 | void* tommy_hashtable_remove(tommy_hashtable* hashtable, tommy_search_func* cmp, const void* cmp_arg, tommy_hash_t hash) 84 | { 85 | tommy_count_t pos = hash & hashtable->bucket_mask; 86 | tommy_hashtable_node* node = hashtable->bucket[pos]; 87 | 88 | while (node) { 89 | /* we first check if the hash matches, as in the same bucket we may have multiples hash values */ 90 | if (node->key == hash && cmp(cmp_arg, node->data) == 0) { 91 | tommy_list_remove_existing(&hashtable->bucket[pos], node); 92 | 93 | --hashtable->count; 94 | 95 | return node->data; 96 | } 97 | node = node->next; 98 | } 99 | 100 | return 0; 101 | } 102 | 103 | void tommy_hashtable_foreach(tommy_hashtable* hashtable, tommy_foreach_func* func) 104 | { 105 | tommy_count_t bucket_max = hashtable->bucket_max; 106 | tommy_hashtable_node** bucket = hashtable->bucket; 107 | tommy_count_t pos; 108 | 109 | for (pos = 0; pos < bucket_max; ++pos) { 110 | tommy_hashtable_node* node = bucket[pos]; 111 | 112 | while (node) { 113 | void* data = node->data; 114 | node = node->next; 115 | func(data); 116 | } 117 | } 118 | } 119 | 120 | void tommy_hashtable_foreach_arg(tommy_hashtable* hashtable, tommy_foreach_arg_func* func, void* arg) 121 | { 122 | tommy_count_t bucket_max = hashtable->bucket_max; 123 | tommy_hashtable_node** bucket = hashtable->bucket; 124 | tommy_count_t pos; 125 | 126 | for (pos = 0; pos < bucket_max; ++pos) { 127 | tommy_hashtable_node* node = bucket[pos]; 128 | 129 | while (node) { 130 | void* data = node->data; 131 | node = node->next; 132 | func(arg, data); 133 | } 134 | } 135 | } 136 | 137 | tommy_size_t tommy_hashtable_memory_usage(tommy_hashtable* hashtable) 138 | { 139 | return hashtable->bucket_max * (tommy_size_t)sizeof(hashtable->bucket[0]) 140 | + tommy_hashtable_count(hashtable) * (tommy_size_t)sizeof(tommy_hashtable_node); 141 | } 142 | 143 | -------------------------------------------------------------------------------- /tommyds/tommyarray.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011, Andrea Mazzoleni. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | /** \file 29 | * Dynamic array based on segments of exponential growing size. 30 | * 31 | * This array is able to grow dynamically upon request, without any reallocation. 32 | * 33 | * The grow operation involves an allocation of a new array segment, without reallocating 34 | * the already used memory, and then not increasing the heap fragmentation. 35 | * This also implies that the address of the stored elements never change. 36 | * 37 | * Allocated segments grow in size exponentially. 38 | */ 39 | 40 | #ifndef __TOMMYARRAY_H 41 | #define __TOMMYARRAY_H 42 | 43 | #include "tommytypes.h" 44 | 45 | #include /* for assert */ 46 | 47 | /******************************************************************************/ 48 | /* array */ 49 | 50 | /** 51 | * Initial and minimal size of the array expressed as a power of 2. 52 | * The initial size is 2^TOMMY_ARRAY_BIT. 53 | */ 54 | #define TOMMY_ARRAY_BIT 6 55 | 56 | /** \internal 57 | * Max number of elements as a power of 2. 58 | */ 59 | #define TOMMY_ARRAY_BIT_MAX 32 60 | 61 | /** 62 | * Array container type. 63 | * \note Don't use internal fields directly, but access the container only using functions. 64 | */ 65 | typedef struct tommy_array_struct { 66 | void** bucket[TOMMY_ARRAY_BIT_MAX]; /**< Dynamic array of buckets. */ 67 | tommy_uint_t bucket_bit; /**< Bits used in the bit mask. */ 68 | tommy_count_t bucket_max; /**< Number of buckets. */ 69 | tommy_count_t count; /**< Number of initialized elements in the array. */ 70 | } tommy_array; 71 | 72 | /** 73 | * Initializes the array. 74 | */ 75 | void tommy_array_init(tommy_array* array); 76 | 77 | /** 78 | * Deinitializes the array. 79 | */ 80 | void tommy_array_done(tommy_array* array); 81 | 82 | /** 83 | * Grows the size up to the specified value. 84 | * All the new elements in the array are initialized with the 0 value. 85 | */ 86 | void tommy_array_grow(tommy_array* array, tommy_count_t size); 87 | 88 | /** 89 | * Gets a reference of the element at the specified position. 90 | * You must be sure that space for this position is already 91 | * allocated calling tommy_array_grow(). 92 | */ 93 | tommy_inline void** tommy_array_ref(tommy_array* array, tommy_count_t pos) 94 | { 95 | tommy_uint_t bsr; 96 | 97 | assert(pos < array->count); 98 | 99 | /* get the highest bit set, in case of all 0, return 0 */ 100 | bsr = tommy_ilog2_u32(pos | 1); 101 | 102 | return &array->bucket[bsr][pos]; 103 | } 104 | 105 | /** 106 | * Sets the element at the specified position. 107 | * You must be sure that space for this position is already 108 | * allocated calling tommy_array_grow(). 109 | */ 110 | tommy_inline void tommy_array_set(tommy_array* array, tommy_count_t pos, void* element) 111 | { 112 | *tommy_array_ref(array, pos) = element; 113 | } 114 | 115 | /** 116 | * Gets the element at the specified position. 117 | * You must be sure that space for this position is already 118 | * allocated calling tommy_array_grow(). 119 | */ 120 | tommy_inline void* tommy_array_get(tommy_array* array, tommy_count_t pos) 121 | { 122 | return *tommy_array_ref(array, pos); 123 | } 124 | 125 | /** 126 | * Grows and inserts a new element at the end of the array. 127 | */ 128 | tommy_inline void tommy_array_insert(tommy_array* array, void* element) 129 | { 130 | tommy_count_t pos = array->count; 131 | 132 | tommy_array_grow(array, pos + 1); 133 | 134 | tommy_array_set(array, pos, element); 135 | } 136 | 137 | /** 138 | * Gets the initialized size of the array. 139 | */ 140 | tommy_inline tommy_count_t tommy_array_size(tommy_array* array) 141 | { 142 | return array->count; 143 | } 144 | 145 | /** 146 | * Gets the size of allocated memory. 147 | */ 148 | tommy_size_t tommy_array_memory_usage(tommy_array* array); 149 | 150 | #endif 151 | 152 | -------------------------------------------------------------------------------- /sparsehash/sparsehash/template_util.h: -------------------------------------------------------------------------------- 1 | // Copyright 2005 Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | // ---- 31 | // 32 | // Template metaprogramming utility functions. 33 | // 34 | // This code is compiled directly on many platforms, including client 35 | // platforms like Windows, Mac, and embedded systems. Before making 36 | // any changes here, make sure that you're not breaking any platforms. 37 | // 38 | // 39 | // The names choosen here reflect those used in tr1 and the boost::mpl 40 | // library, there are similar operations used in the Loki library as 41 | // well. I prefer the boost names for 2 reasons: 42 | // 1. I think that portions of the Boost libraries are more likely to 43 | // be included in the c++ standard. 44 | // 2. It is not impossible that some of the boost libraries will be 45 | // included in our own build in the future. 46 | // Both of these outcomes means that we may be able to directly replace 47 | // some of these with boost equivalents. 48 | // 49 | #ifndef BASE_TEMPLATE_UTIL_H_ 50 | #define BASE_TEMPLATE_UTIL_H_ 51 | 52 | #include 53 | _START_GOOGLE_NAMESPACE_ 54 | 55 | // Types small_ and big_ are guaranteed such that sizeof(small_) < 56 | // sizeof(big_) 57 | typedef char small_; 58 | 59 | struct big_ { 60 | char dummy[2]; 61 | }; 62 | 63 | // Identity metafunction. 64 | template 65 | struct identity_ { 66 | typedef T type; 67 | }; 68 | 69 | // integral_constant, defined in tr1, is a wrapper for an integer 70 | // value. We don't really need this generality; we could get away 71 | // with hardcoding the integer type to bool. We use the fully 72 | // general integer_constant for compatibility with tr1. 73 | 74 | template 75 | struct integral_constant { 76 | static const T value = v; 77 | typedef T value_type; 78 | typedef integral_constant type; 79 | }; 80 | 81 | template const T integral_constant::value; 82 | 83 | 84 | // Abbreviations: true_type and false_type are structs that represent boolean 85 | // true and false values. Also define the boost::mpl versions of those names, 86 | // true_ and false_. 87 | typedef integral_constant true_type; 88 | typedef integral_constant false_type; 89 | typedef true_type true_; 90 | typedef false_type false_; 91 | 92 | // if_ is a templatized conditional statement. 93 | // if_ is a compile time evaluation of cond. 94 | // if_<>::type contains A if cond is true, B otherwise. 95 | template 96 | struct if_{ 97 | typedef A type; 98 | }; 99 | 100 | template 101 | struct if_ { 102 | typedef B type; 103 | }; 104 | 105 | 106 | // type_equals_ is a template type comparator, similar to Loki IsSameType. 107 | // type_equals_::value is true iff "A" is the same type as "B". 108 | // 109 | // New code should prefer base::is_same, defined in base/type_traits.h. 110 | // It is functionally identical, but is_same is the standard spelling. 111 | template 112 | struct type_equals_ : public false_ { 113 | }; 114 | 115 | template 116 | struct type_equals_ : public true_ { 117 | }; 118 | 119 | // and_ is a template && operator. 120 | // and_::value evaluates "A::value && B::value". 121 | template 122 | struct and_ : public integral_constant { 123 | }; 124 | 125 | // or_ is a template || operator. 126 | // or_::value evaluates "A::value || B::value". 127 | template 128 | struct or_ : public integral_constant { 129 | }; 130 | 131 | 132 | _END_GOOGLE_NAMESPACE_ 133 | 134 | #endif // BASE_TEMPLATE_UTIL_H_ 135 | -------------------------------------------------------------------------------- /tommyds/tommyhash.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010, Andrea Mazzoleni. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | /** \file 29 | * Hash functions for the use with ::tommy_hashtable, ::tommy_hashdyn and ::tommy_hashlin. 30 | */ 31 | 32 | #ifndef __TOMMYHASH_H 33 | #define __TOMMYHASH_H 34 | 35 | #include "tommytypes.h" 36 | 37 | /******************************************************************************/ 38 | /* hash */ 39 | 40 | /** 41 | * Hash type used in hashtables. 42 | */ 43 | typedef tommy_key_t tommy_hash_t; 44 | 45 | /** 46 | * Hash function with a 32 bits result. 47 | * Implementation of the Robert Jenkins "lookup3" hash 32 bits version, 48 | * from http://www.burtleburtle.net/bob/hash/doobs.html, function hashlittle(). 49 | * 50 | * This hash is designed to provide a good overall performance in all platforms, 51 | * including 32 bits. If you target only 64 bits, you can use faster hashes, 52 | * like SpookyHash or FarmHash. 53 | * 54 | * \param init_val Initialization value. 55 | * Using a different initialization value, you can generate a completely different set of hash values. 56 | * Use 0 if not relevant. 57 | * \param void_key Pointer to the data to hash. 58 | * \param key_len Size of the data to hash. 59 | * \note 60 | * This function is endianess independent. 61 | * \return The hash value of 32 bits. 62 | */ 63 | tommy_uint32_t tommy_hash_u32(tommy_uint32_t init_val, const void* void_key, tommy_size_t key_len); 64 | 65 | /** 66 | * Hash function with a 64 bits result. 67 | * Implementation of the Robert Jenkins "lookup3" hash 64 bits versions, 68 | * from http://www.burtleburtle.net/bob/hash/doobs.html, function hashlittle2(). 69 | * 70 | * This hash is designed to provide a good overall performance in all platforms, 71 | * including 32 bits. If you target only 64 bits, you can use faster hashes, 72 | * like SpookyHash or FarmHash. 73 | * 74 | * \param init_val Initialization value. 75 | * Using a different initialization value, you can generate a completely different set of hash values. 76 | * Use 0 if not relevant. 77 | * \param void_key Pointer to the data to hash. 78 | * \param key_len Size of the data to hash. 79 | * \note 80 | * This function is endianess independent. 81 | * \return The hash value of 64 bits. 82 | */ 83 | tommy_uint64_t tommy_hash_u64(tommy_uint64_t init_val, const void* void_key, tommy_size_t key_len); 84 | 85 | /** 86 | * String hash function with a 32 bits result. 87 | * Implementation is based on the the Robert Jenkins "lookup3" hash 32 bits version, 88 | * from http://www.burtleburtle.net/bob/hash/doobs.html, function hashlittle(). 89 | * 90 | * This hash is designed to handle strings with an unknown length. If you 91 | * know the string length, the other hash functions are surely faster. 92 | * 93 | * \param init_val Initialization value. 94 | * Using a different initialization value, you can generate a completely different set of hash values. 95 | * Use 0 if not relevant. 96 | * \param void_key Pointer to the string to hash. It has to be 0 terminated. 97 | * \note 98 | * This function is endianess independent. 99 | * \return The hash value of 32 bits. 100 | */ 101 | tommy_uint32_t tommy_strhash_u32(tommy_uint64_t init_val, const void* void_key); 102 | 103 | /** 104 | * Integer reversible hash function for 32 bits. 105 | * Implementation of the Robert Jenkins "4-byte Integer Hashing", 106 | * from http://burtleburtle.net/bob/hash/integer.html 107 | */ 108 | tommy_inline tommy_uint32_t tommy_inthash_u32(tommy_uint32_t key) 109 | { 110 | key -= key << 6; 111 | key ^= key >> 17; 112 | key -= key << 9; 113 | key ^= key << 4; 114 | key -= key << 3; 115 | key ^= key << 10; 116 | key ^= key >> 15; 117 | 118 | return key; 119 | } 120 | 121 | /** 122 | * Integer reversible hash function for 64 bits. 123 | * Implementation of the Thomas Wang "Integer Hash Function", 124 | * from http://web.archive.org/web/20071223173210/http://www.concentric.net/~Ttwang/tech/inthash.htm 125 | */ 126 | tommy_inline tommy_uint64_t tommy_inthash_u64(tommy_uint64_t key) 127 | { 128 | key = ~key + (key << 21); 129 | key = key ^ (key >> 24); 130 | key = key + (key << 3) + (key << 8); 131 | key = key ^ (key >> 14); 132 | key = key + (key << 2) + (key << 4); 133 | key = key ^ (key >> 28); 134 | key = key + (key << 31); 135 | 136 | return key; 137 | } 138 | 139 | #endif 140 | 141 | -------------------------------------------------------------------------------- /phmap/phmap_fwd_decl.h: -------------------------------------------------------------------------------- 1 | #if !defined(phmap_fwd_decl_h_guard_) 2 | #define phmap_fwd_decl_h_guard_ 3 | 4 | // --------------------------------------------------------------------------- 5 | // Copyright (c) 2019, Gregory Popovitch - greg7mdp@gmail.com 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // https://www.apache.org/licenses/LICENSE-2.0 12 | // --------------------------------------------------------------------------- 13 | 14 | #include 15 | #include 16 | 17 | #if defined(PHMAP_USE_ABSL_HASH) 18 | namespace absl { template struct Hash; }; 19 | #endif 20 | 21 | namespace phmap { 22 | 23 | #if defined(PHMAP_USE_ABSL_HASH) 24 | template using Hash = absl::Hash; 25 | #else 26 | template struct Hash; 27 | #endif 28 | 29 | template struct EqualTo; 30 | template using Allocator = typename std::allocator; 31 | template using Pair = typename std::pair; 32 | 33 | class NullMutex; 34 | 35 | namespace container_internal { 36 | 37 | // The hash of an object of type T is computed by using phmap::Hash. 38 | template 39 | struct HashEq 40 | { 41 | using Hash = phmap::Hash; 42 | using Eq = phmap::EqualTo; 43 | }; 44 | 45 | template 46 | using hash_default_hash = typename container_internal::HashEq::Hash; 47 | 48 | template 49 | using hash_default_eq = typename container_internal::HashEq::Eq; 50 | 51 | // type alias for std::allocator so we can forward declare without including other headers 52 | template 53 | using Allocator = typename phmap::Allocator; 54 | 55 | // type alias for std::pair so we can forward declare without including other headers 56 | template 57 | using Pair = typename phmap::Pair; 58 | 59 | } // namespace container_internal 60 | 61 | template , 63 | class Eq = phmap::container_internal::hash_default_eq, 64 | class Alloc = phmap::container_internal::Allocator> // alias for std::allocator 65 | class flat_hash_set; 66 | 67 | template , 69 | class Eq = phmap::container_internal::hash_default_eq, 70 | class Alloc = phmap::container_internal::Allocator< 71 | phmap::container_internal::Pair>> // alias for std::allocator 72 | class flat_hash_map; 73 | 74 | template , 76 | class Eq = phmap::container_internal::hash_default_eq, 77 | class Alloc = phmap::container_internal::Allocator> // alias for std::allocator 78 | class node_hash_set; 79 | 80 | template , 82 | class Eq = phmap::container_internal::hash_default_eq, 83 | class Alloc = phmap::container_internal::Allocator< 84 | phmap::container_internal::Pair>> // alias for std::allocator 85 | class node_hash_map; 86 | 87 | template , 89 | class Eq = phmap::container_internal::hash_default_eq, 90 | class Alloc = phmap::container_internal::Allocator, // alias for std::allocator 91 | size_t N = 4, // 2**N submaps 92 | class Mutex = phmap::NullMutex> // use std::mutex to enable internal locks 93 | class parallel_flat_hash_set; 94 | 95 | template , 97 | class Eq = phmap::container_internal::hash_default_eq, 98 | class Alloc = phmap::container_internal::Allocator< 99 | phmap::container_internal::Pair>, // alias for std::allocator 100 | size_t N = 4, // 2**N submaps 101 | class Mutex = phmap::NullMutex> // use std::mutex to enable internal locks 102 | class parallel_flat_hash_map; 103 | 104 | template , 106 | class Eq = phmap::container_internal::hash_default_eq, 107 | class Alloc = phmap::container_internal::Allocator, // alias for std::allocator 108 | size_t N = 4, // 2**N submaps 109 | class Mutex = phmap::NullMutex> // use std::mutex to enable internal locks 110 | class parallel_node_hash_set; 111 | 112 | template , 114 | class Eq = phmap::container_internal::hash_default_eq, 115 | class Alloc = phmap::container_internal::Allocator< 116 | phmap::container_internal::Pair>, // alias for std::allocator 117 | size_t N = 4, // 2**N submaps 118 | class Mutex = phmap::NullMutex> // use std::mutex to enable internal locks 119 | class parallel_node_hash_map; 120 | 121 | 122 | 123 | } // namespace phmap 124 | 125 | 126 | #endif // phmap_fwd_decl_h_guard_ 127 | -------------------------------------------------------------------------------- /sparsepp/sparsepp/spp_traits.h: -------------------------------------------------------------------------------- 1 | #if !defined(spp_traits_h_guard) 2 | #define spp_traits_h_guard 3 | 4 | #include "spp_config.h" 5 | 6 | template class HashObject; // for Google's benchmark, not in spp namespace! 7 | 8 | namespace spp_ 9 | { 10 | 11 | // --------------------------------------------------------------------------- 12 | // type_traits we need 13 | // --------------------------------------------------------------------------- 14 | template 15 | struct integral_constant { static const T value = v; }; 16 | 17 | template const T integral_constant::value; 18 | 19 | typedef integral_constant true_type; 20 | typedef integral_constant false_type; 21 | 22 | typedef integral_constant zero_type; 23 | typedef integral_constant one_type; 24 | typedef integral_constant two_type; 25 | typedef integral_constant three_type; 26 | 27 | template struct is_same : public false_type { }; 28 | template struct is_same : public true_type { }; 29 | 30 | template struct remove_const { typedef T type; }; 31 | template struct remove_const { typedef T type; }; 32 | 33 | template struct remove_volatile { typedef T type; }; 34 | template struct remove_volatile { typedef T type; }; 35 | 36 | template struct remove_cv 37 | { 38 | typedef typename remove_const::type>::type type; 39 | }; 40 | 41 | // ---------------- is_integral ---------------------------------------- 42 | template struct is_integral; 43 | template struct is_integral : false_type { }; 44 | template<> struct is_integral : true_type { }; 45 | template<> struct is_integral : true_type { }; 46 | template<> struct is_integral : true_type { }; 47 | template<> struct is_integral : true_type { }; 48 | template<> struct is_integral : true_type { }; 49 | template<> struct is_integral : true_type { }; 50 | template<> struct is_integral : true_type { }; 51 | template<> struct is_integral : true_type { }; 52 | template<> struct is_integral : true_type { }; 53 | template<> struct is_integral : true_type { }; 54 | #ifdef SPP_HAS_LONG_LONG 55 | template<> struct is_integral : true_type { }; 56 | template<> struct is_integral : true_type { }; 57 | #endif 58 | template struct is_integral : is_integral { }; 59 | template struct is_integral : is_integral { }; 60 | template struct is_integral : is_integral { }; 61 | 62 | // ---------------- is_floating_point ---------------------------------------- 63 | template struct is_floating_point; 64 | template struct is_floating_point : false_type { }; 65 | template<> struct is_floating_point : true_type { }; 66 | template<> struct is_floating_point : true_type { }; 67 | template<> struct is_floating_point : true_type { }; 68 | template struct is_floating_point : is_floating_point { }; 69 | template struct is_floating_point : is_floating_point { }; 70 | template struct is_floating_point : is_floating_point { }; 71 | 72 | // ---------------- is_pointer ---------------------------------------- 73 | template struct is_pointer; 74 | template struct is_pointer : false_type { }; 75 | template struct is_pointer : true_type { }; 76 | template struct is_pointer : is_pointer { }; 77 | template struct is_pointer : is_pointer { }; 78 | template struct is_pointer : is_pointer { }; 79 | 80 | // ---------------- is_reference ---------------------------------------- 81 | template struct is_reference; 82 | template struct is_reference : false_type {}; 83 | template struct is_reference : true_type {}; 84 | 85 | // ---------------- is_relocatable ---------------------------------------- 86 | // relocatable values can be moved around in memory using memcpy and remain 87 | // correct. Most types are relocatable, an example of a type who is not would 88 | // be a struct which contains a pointer to a buffer inside itself - this is the 89 | // case for std::string in gcc 5. 90 | // ------------------------------------------------------------------------ 91 | template struct is_relocatable; 92 | template struct is_relocatable : 93 | integral_constant::value || is_floating_point::value)> 94 | { }; 95 | 96 | template struct is_relocatable > : true_type { }; 97 | 98 | template struct is_relocatable : is_relocatable { }; 99 | template struct is_relocatable : is_relocatable { }; 100 | template struct is_relocatable : is_relocatable { }; 101 | template struct is_relocatable : is_relocatable { }; 102 | template struct is_relocatable > : 103 | integral_constant::value && is_relocatable::value)> 104 | { }; 105 | 106 | // A template helper used to select A or B based on a condition. 107 | // ------------------------------------------------------------ 108 | template 109 | struct if_ 110 | { 111 | typedef A type; 112 | }; 113 | 114 | template 115 | struct if_ 116 | { 117 | typedef B type; 118 | }; 119 | 120 | } // spp_ namespace 121 | 122 | #endif // spp_traits_h_guard 123 | -------------------------------------------------------------------------------- /sparsepp/sparsepp/spp_memory.h: -------------------------------------------------------------------------------- 1 | #if !defined(spp_memory_h_guard) 2 | #define spp_memory_h_guard 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #if defined(_WIN32) || defined( __CYGWIN__) 9 | #define SPP_WIN 10 | #endif 11 | 12 | #ifdef SPP_WIN 13 | #include 14 | #include 15 | #undef min 16 | #undef max 17 | #elif defined(__linux__) 18 | #include 19 | #include 20 | #elif defined(__FreeBSD__) 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #endif 28 | 29 | namespace spp 30 | { 31 | uint64_t GetSystemMemory() 32 | { 33 | #ifdef SPP_WIN 34 | MEMORYSTATUSEX memInfo; 35 | memInfo.dwLength = sizeof(MEMORYSTATUSEX); 36 | GlobalMemoryStatusEx(&memInfo); 37 | return static_cast(memInfo.ullTotalPageFile); 38 | #elif defined(__linux__) 39 | struct sysinfo memInfo; 40 | sysinfo (&memInfo); 41 | auto totalVirtualMem = memInfo.totalram; 42 | 43 | totalVirtualMem += memInfo.totalswap; 44 | totalVirtualMem *= memInfo.mem_unit; 45 | return static_cast(totalVirtualMem); 46 | #elif defined(__FreeBSD__) 47 | kvm_t *kd; 48 | u_int pageCnt; 49 | size_t pageCntLen = sizeof(pageCnt); 50 | u_int pageSize; 51 | struct kvm_swap kswap; 52 | uint64_t totalVirtualMem; 53 | 54 | pageSize = static_cast(getpagesize()); 55 | 56 | sysctlbyname("vm.stats.vm.v_page_count", &pageCnt, &pageCntLen, NULL, 0); 57 | totalVirtualMem = pageCnt * pageSize; 58 | 59 | kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open"); 60 | kvm_getswapinfo(kd, &kswap, 1, 0); 61 | kvm_close(kd); 62 | totalVirtualMem += kswap.ksw_total * pageSize; 63 | 64 | return totalVirtualMem; 65 | #else 66 | return 0; 67 | #endif 68 | } 69 | 70 | uint64_t GetTotalMemoryUsed() 71 | { 72 | #ifdef SPP_WIN 73 | MEMORYSTATUSEX memInfo; 74 | memInfo.dwLength = sizeof(MEMORYSTATUSEX); 75 | GlobalMemoryStatusEx(&memInfo); 76 | return static_cast(memInfo.ullTotalPageFile - memInfo.ullAvailPageFile); 77 | #elif defined(__linux__) 78 | struct sysinfo memInfo; 79 | sysinfo(&memInfo); 80 | auto virtualMemUsed = memInfo.totalram - memInfo.freeram; 81 | 82 | virtualMemUsed += memInfo.totalswap - memInfo.freeswap; 83 | virtualMemUsed *= memInfo.mem_unit; 84 | 85 | return static_cast(virtualMemUsed); 86 | #elif defined(__FreeBSD__) 87 | kvm_t *kd; 88 | u_int pageSize; 89 | u_int pageCnt, freeCnt; 90 | size_t pageCntLen = sizeof(pageCnt); 91 | size_t freeCntLen = sizeof(freeCnt); 92 | struct kvm_swap kswap; 93 | uint64_t virtualMemUsed; 94 | 95 | pageSize = static_cast(getpagesize()); 96 | 97 | sysctlbyname("vm.stats.vm.v_page_count", &pageCnt, &pageCntLen, NULL, 0); 98 | sysctlbyname("vm.stats.vm.v_free_count", &freeCnt, &freeCntLen, NULL, 0); 99 | virtualMemUsed = (pageCnt - freeCnt) * pageSize; 100 | 101 | kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open"); 102 | kvm_getswapinfo(kd, &kswap, 1, 0); 103 | kvm_close(kd); 104 | virtualMemUsed += kswap.ksw_used * pageSize; 105 | 106 | return virtualMemUsed; 107 | #else 108 | return 0; 109 | #endif 110 | } 111 | 112 | uint64_t GetProcessMemoryUsed() 113 | { 114 | #ifdef SPP_WIN 115 | PROCESS_MEMORY_COUNTERS_EX pmc; 116 | GetProcessMemoryInfo(GetCurrentProcess(), reinterpret_cast(&pmc), sizeof(pmc)); 117 | return static_cast(pmc.PrivateUsage); 118 | #elif defined(__linux__) 119 | auto parseLine = 120 | [](char* line)->int 121 | { 122 | auto i = strlen(line); 123 | 124 | while(*line < '0' || *line > '9') 125 | { 126 | line++; 127 | } 128 | 129 | line[i-3] = '\0'; 130 | i = atoi(line); 131 | return i; 132 | }; 133 | 134 | auto file = fopen("/proc/self/status", "r"); 135 | auto result = -1; 136 | char line[128]; 137 | 138 | while(fgets(line, 128, file) != nullptr) 139 | { 140 | if(strncmp(line, "VmSize:", 7) == 0) 141 | { 142 | result = parseLine(line); 143 | break; 144 | } 145 | } 146 | 147 | fclose(file); 148 | return static_cast(result) * 1024; 149 | #elif defined(__FreeBSD__) 150 | struct kinfo_proc info; 151 | size_t infoLen = sizeof(info); 152 | int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid() }; 153 | 154 | sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &infoLen, NULL, 0); 155 | return static_cast(info.ki_rssize * getpagesize()); 156 | #else 157 | return 0; 158 | #endif 159 | } 160 | 161 | uint64_t GetPhysicalMemory() 162 | { 163 | #ifdef SPP_WIN 164 | MEMORYSTATUSEX memInfo; 165 | memInfo.dwLength = sizeof(MEMORYSTATUSEX); 166 | GlobalMemoryStatusEx(&memInfo); 167 | return static_cast(memInfo.ullTotalPhys); 168 | #elif defined(__linux__) 169 | struct sysinfo memInfo; 170 | sysinfo(&memInfo); 171 | 172 | auto totalPhysMem = memInfo.totalram; 173 | 174 | totalPhysMem *= memInfo.mem_unit; 175 | return static_cast(totalPhysMem); 176 | #elif defined(__FreeBSD__) 177 | u_long physMem; 178 | size_t physMemLen = sizeof(physMem); 179 | int mib[] = { CTL_HW, HW_PHYSMEM }; 180 | 181 | sysctl(mib, sizeof(mib) / sizeof(*mib), &physMem, &physMemLen, NULL, 0); 182 | return physMem; 183 | #else 184 | return 0; 185 | #endif 186 | } 187 | 188 | } 189 | 190 | #endif // spp_memory_h_guard 191 | -------------------------------------------------------------------------------- /khashpp/khash.hpp: -------------------------------------------------------------------------------- 1 | #ifndef KHASH_HPP 2 | #define KHASH_HPP 3 | 4 | #include 5 | #include 6 | #include // for malloc() etc 7 | #include // for memset() 8 | 9 | #include // for uint32_t 10 | 11 | namespace klib { 12 | 13 | #ifndef kroundup32 // FIXME: doesn't work for 64-bit integers 14 | #define kroundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x)) 15 | #endif 16 | 17 | #define __ac_isempty(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&2) 18 | #define __ac_isdel(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&1) 19 | #define __ac_isempty(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&2) 20 | #define __ac_isdel(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&1) 21 | #define __ac_iseither(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&3) 22 | #define __ac_set_isdel_false(flag, i) (flag[i>>4]&=~(1ul<<((i&0xfU)<<1))) 23 | #define __ac_set_isempty_false(flag, i) (flag[i>>4]&=~(2ul<<((i&0xfU)<<1))) 24 | #define __ac_set_isboth_false(flag, i) (flag[i>>4]&=~(3ul<<((i&0xfU)<<1))) 25 | #define __ac_set_isdel_true(flag, i) (flag[i>>4]|=1ul<<((i&0xfU)<<1)) 26 | 27 | #define __ac_fsize(m) ((m) < 16? 1 : (m)>>4) 28 | 29 | template, typename khint_t = uint32_t> 30 | class KHash { 31 | khint_t n_buckets, count, n_occupied, upper_bound; 32 | uint32_t *flags; 33 | T *keys; 34 | public: 35 | KHash() : n_buckets(0), count(0), n_occupied(0), upper_bound(0), flags(NULL), keys(NULL) {}; 36 | ~KHash() { std::free(flags); std::free(keys); }; 37 | khint_t capacity(void) const { return n_buckets; }; 38 | khint_t size(void) const { return count; }; 39 | khint_t begin(void) const { return 0; }; 40 | khint_t end(void) const { return n_buckets; }; 41 | 42 | void exist(khint_t x) const { return !__ac_iseither(flags, x); }; 43 | T &at(khint_t x) { return keys[x]; }; 44 | 45 | khint_t get(const T &key) const { 46 | if (n_buckets) { 47 | khint_t k, i, last, mask, step = 0; 48 | mask = n_buckets - 1; 49 | k = Hash()(key); i = k & mask; 50 | last = i; 51 | while (!__ac_isempty(flags, i) && (__ac_isdel(flags, i) || !Eq()(keys[i], key))) { 52 | i = (i + (++step)) & mask; 53 | if (i == last) return n_buckets; 54 | } 55 | return __ac_iseither(flags, i)? n_buckets : i; 56 | } else return 0; 57 | }; 58 | 59 | int resize(khint_t new_n_buckets) { 60 | uint32_t *new_flags = 0; 61 | khint_t j = 1; 62 | { 63 | kroundup32(new_n_buckets); 64 | if (new_n_buckets < 4) new_n_buckets = 4; 65 | if (count >= (new_n_buckets>>1) + (new_n_buckets>>2)) j = 0; /* requested count is too small */ 66 | else { /* hash table count to be changed (shrink or expand); rehash */ 67 | new_flags = (uint32_t*)std::malloc(__ac_fsize(new_n_buckets) * sizeof(uint32_t)); 68 | if (!new_flags) return -1; 69 | ::memset(new_flags, 0xaa, __ac_fsize(new_n_buckets) * sizeof(uint32_t)); 70 | if (n_buckets < new_n_buckets) { /* expand */ 71 | T *new_keys = (T*)std::realloc((void *)keys, new_n_buckets * sizeof(T)); 72 | if (!new_keys) { std::free(new_flags); return -1; } 73 | keys = new_keys; 74 | } /* otherwise shrink */ 75 | } 76 | } 77 | if (j) { /* rehashing is needed */ 78 | for (j = 0; j != n_buckets; ++j) { 79 | if (__ac_iseither(flags, j) == 0) { 80 | T key = keys[j]; 81 | khint_t new_mask; 82 | new_mask = new_n_buckets - 1; 83 | __ac_set_isdel_true(flags, j); 84 | while (1) { /* kick-out process; sort of like in Cuckoo hashing */ 85 | khint_t k, i, step = 0; 86 | k = Hash()(key); 87 | i = k & new_mask; 88 | while (!__ac_isempty(new_flags, i)) i = (i + (++step)) & new_mask; 89 | __ac_set_isempty_false(new_flags, i); 90 | if (i < n_buckets && __ac_iseither(flags, i) == 0) { /* kick out the existing element */ 91 | { T tmp = keys[i]; keys[i] = key; key = tmp; } 92 | __ac_set_isdel_true(flags, i); /* mark it as deleted in the old hash table */ 93 | } else { /* write the element and jump out of the loop */ 94 | keys[i] = key; 95 | break; 96 | } 97 | } 98 | } 99 | } 100 | if (n_buckets > new_n_buckets) /* shrink the hash table */ 101 | keys = (T*)std::realloc((void *)keys, new_n_buckets * sizeof(T)); 102 | std::free(flags); /* free the working space */ 103 | flags = new_flags; 104 | n_buckets = new_n_buckets; 105 | n_occupied = count; 106 | upper_bound = (n_buckets>>1) + (n_buckets>>2); 107 | } 108 | return 0; 109 | }; 110 | 111 | khint_t put(const T &key, int *ret) { 112 | khint_t x; 113 | if (n_occupied >= upper_bound) { /* update the hash table */ 114 | if (n_buckets > (count<<1)) { 115 | if (resize(n_buckets - 1) < 0) { /* clear "deleted" elements */ 116 | *ret = -1; return n_buckets; 117 | } 118 | } else if (resize(n_buckets + 1) < 0) { /* expand the hash table */ 119 | *ret = -1; return n_buckets; 120 | } 121 | } /* TODO: to implement automatically shrinking; resize() already support shrinking */ 122 | { 123 | khint_t k, i, site, last, mask = n_buckets - 1, step = 0; 124 | x = site = n_buckets; k = Hash()(key); i = k & mask; 125 | if (__ac_isempty(flags, i)) x = i; /* for speed up */ 126 | else { 127 | last = i; 128 | while (!__ac_isempty(flags, i) && (__ac_isdel(flags, i) || !Eq()(keys[i], key))) { 129 | if (__ac_isdel(flags, i)) site = i; 130 | i = (i + (++step)) & mask; 131 | if (i == last) { x = site; break; } 132 | } 133 | if (x == n_buckets) { 134 | if (__ac_isempty(flags, i) && site != n_buckets) x = site; 135 | else x = i; 136 | } 137 | } 138 | } 139 | if (__ac_isempty(flags, x)) { /* not present at all */ 140 | keys[x] = key; 141 | __ac_set_isboth_false(flags, x); 142 | ++count; ++n_occupied; 143 | *ret = 1; 144 | } else if (__ac_isdel(flags, x)) { /* deleted */ 145 | keys[x] = key; 146 | __ac_set_isboth_false(flags, x); 147 | ++count; 148 | *ret = 2; 149 | } else *ret = 0; /* Don't touch keys[x] if present and not deleted */ 150 | return x; 151 | }; 152 | 153 | void del(khint_t x) { 154 | if (x != n_buckets && !__ac_iseither(flags, x)) { 155 | __ac_set_isdel_true(flags, x); 156 | --count; 157 | } 158 | }; 159 | }; 160 | 161 | } // end of namespace klib 162 | 163 | #endif 164 | -------------------------------------------------------------------------------- /phmap/meminfo.h: -------------------------------------------------------------------------------- 1 | #if !defined(spp_memory_h_guard) 2 | #define spp_memory_h_guard 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #if defined(_WIN32) || defined( __CYGWIN__) 9 | #define SPP_WIN 10 | #endif 11 | 12 | #ifdef SPP_WIN 13 | #include 14 | #include 15 | #undef min 16 | #undef max 17 | #elif defined(__linux__) 18 | #include 19 | #include 20 | #elif defined(__FreeBSD__) 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #endif 28 | 29 | namespace spp 30 | { 31 | uint64_t GetSystemMemory(); 32 | uint64_t GetTotalMemoryUsed(); 33 | uint64_t GetProcessMemoryUsed(); 34 | uint64_t GetPhysicalMemory(); 35 | 36 | uint64_t GetSystemMemory() 37 | { 38 | #ifdef SPP_WIN 39 | MEMORYSTATUSEX memInfo; 40 | memInfo.dwLength = sizeof(MEMORYSTATUSEX); 41 | GlobalMemoryStatusEx(&memInfo); 42 | return static_cast(memInfo.ullTotalPageFile); 43 | #elif defined(__linux__) 44 | struct sysinfo memInfo; 45 | sysinfo (&memInfo); 46 | auto totalVirtualMem = memInfo.totalram; 47 | 48 | totalVirtualMem += memInfo.totalswap; 49 | totalVirtualMem *= memInfo.mem_unit; 50 | return static_cast(totalVirtualMem); 51 | #elif defined(__FreeBSD__) 52 | kvm_t *kd; 53 | u_int pageCnt; 54 | size_t pageCntLen = sizeof(pageCnt); 55 | u_int pageSize; 56 | struct kvm_swap kswap; 57 | uint64_t totalVirtualMem; 58 | 59 | pageSize = static_cast(getpagesize()); 60 | 61 | sysctlbyname("vm.stats.vm.v_page_count", &pageCnt, &pageCntLen, NULL, 0); 62 | totalVirtualMem = pageCnt * pageSize; 63 | 64 | kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open"); 65 | kvm_getswapinfo(kd, &kswap, 1, 0); 66 | kvm_close(kd); 67 | totalVirtualMem += kswap.ksw_total * pageSize; 68 | 69 | return totalVirtualMem; 70 | #else 71 | return 0; 72 | #endif 73 | } 74 | 75 | uint64_t GetTotalMemoryUsed() 76 | { 77 | #ifdef SPP_WIN 78 | MEMORYSTATUSEX memInfo; 79 | memInfo.dwLength = sizeof(MEMORYSTATUSEX); 80 | GlobalMemoryStatusEx(&memInfo); 81 | return static_cast(memInfo.ullTotalPageFile - memInfo.ullAvailPageFile); 82 | #elif defined(__linux__) 83 | struct sysinfo memInfo; 84 | sysinfo(&memInfo); 85 | auto virtualMemUsed = memInfo.totalram - memInfo.freeram; 86 | 87 | virtualMemUsed += memInfo.totalswap - memInfo.freeswap; 88 | virtualMemUsed *= memInfo.mem_unit; 89 | 90 | return static_cast(virtualMemUsed); 91 | #elif defined(__FreeBSD__) 92 | kvm_t *kd; 93 | u_int pageSize; 94 | u_int pageCnt, freeCnt; 95 | size_t pageCntLen = sizeof(pageCnt); 96 | size_t freeCntLen = sizeof(freeCnt); 97 | struct kvm_swap kswap; 98 | uint64_t virtualMemUsed; 99 | 100 | pageSize = static_cast(getpagesize()); 101 | 102 | sysctlbyname("vm.stats.vm.v_page_count", &pageCnt, &pageCntLen, NULL, 0); 103 | sysctlbyname("vm.stats.vm.v_free_count", &freeCnt, &freeCntLen, NULL, 0); 104 | virtualMemUsed = (pageCnt - freeCnt) * pageSize; 105 | 106 | kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open"); 107 | kvm_getswapinfo(kd, &kswap, 1, 0); 108 | kvm_close(kd); 109 | virtualMemUsed += kswap.ksw_used * pageSize; 110 | 111 | return virtualMemUsed; 112 | #else 113 | return 0; 114 | #endif 115 | } 116 | 117 | uint64_t GetProcessMemoryUsed() 118 | { 119 | #ifdef SPP_WIN 120 | PROCESS_MEMORY_COUNTERS_EX pmc; 121 | GetProcessMemoryInfo(GetCurrentProcess(), reinterpret_cast(&pmc), sizeof(pmc)); 122 | return static_cast(pmc.PrivateUsage); 123 | #elif defined(__linux__) 124 | auto parseLine = 125 | [](char* line)->int 126 | { 127 | auto i = strlen(line); 128 | 129 | while(*line < '0' || *line > '9') 130 | { 131 | line++; 132 | } 133 | 134 | line[i-3] = '\0'; 135 | i = atoi(line); 136 | return i; 137 | }; 138 | 139 | auto file = fopen("/proc/self/status", "r"); 140 | auto result = -1; 141 | char line[128]; 142 | 143 | while(fgets(line, 128, file) != nullptr) 144 | { 145 | if(strncmp(line, "VmSize:", 7) == 0) 146 | { 147 | result = parseLine(line); 148 | break; 149 | } 150 | } 151 | 152 | fclose(file); 153 | return static_cast(result) * 1024; 154 | #elif defined(__FreeBSD__) 155 | struct kinfo_proc info; 156 | size_t infoLen = sizeof(info); 157 | int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid() }; 158 | 159 | sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &infoLen, NULL, 0); 160 | return static_cast(info.ki_rssize * getpagesize()); 161 | #else 162 | return 0; 163 | #endif 164 | } 165 | 166 | uint64_t GetPhysicalMemory() 167 | { 168 | #ifdef SPP_WIN 169 | MEMORYSTATUSEX memInfo; 170 | memInfo.dwLength = sizeof(MEMORYSTATUSEX); 171 | GlobalMemoryStatusEx(&memInfo); 172 | return static_cast(memInfo.ullTotalPhys); 173 | #elif defined(__linux__) 174 | struct sysinfo memInfo; 175 | sysinfo(&memInfo); 176 | 177 | auto totalPhysMem = memInfo.totalram; 178 | 179 | totalPhysMem *= memInfo.mem_unit; 180 | return static_cast(totalPhysMem); 181 | #elif defined(__FreeBSD__) 182 | u_long physMem; 183 | size_t physMemLen = sizeof(physMem); 184 | int mib[] = { CTL_HW, HW_PHYSMEM }; 185 | 186 | sysctl(mib, sizeof(mib) / sizeof(*mib), &physMem, &physMemLen, NULL, 0); 187 | return physMem; 188 | #else 189 | return 0; 190 | #endif 191 | } 192 | 193 | } 194 | 195 | #endif // spp_memory_h_guard 196 | -------------------------------------------------------------------------------- /tommyds/tommyhashdyn.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010, Andrea Mazzoleni. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "tommyhashdyn.h" 29 | #include "tommylist.h" 30 | 31 | /******************************************************************************/ 32 | /* hashdyn */ 33 | 34 | void tommy_hashdyn_init(tommy_hashdyn* hashdyn) 35 | { 36 | /* fixed initial size */ 37 | hashdyn->bucket_bit = TOMMY_HASHDYN_BIT; 38 | hashdyn->bucket_max = 1 << hashdyn->bucket_bit; 39 | hashdyn->bucket_mask = hashdyn->bucket_max - 1; 40 | hashdyn->bucket = tommy_cast(tommy_hashdyn_node**, tommy_calloc(hashdyn->bucket_max, sizeof(tommy_hashdyn_node*))); 41 | 42 | hashdyn->count = 0; 43 | } 44 | 45 | void tommy_hashdyn_done(tommy_hashdyn* hashdyn) 46 | { 47 | tommy_free(hashdyn->bucket); 48 | } 49 | 50 | /** 51 | * Resize the bucket vector. 52 | */ 53 | static void tommy_hashdyn_resize(tommy_hashdyn* hashdyn, tommy_count_t new_bucket_bit) 54 | { 55 | tommy_count_t bucket_bit; 56 | tommy_count_t bucket_max; 57 | tommy_count_t new_bucket_max; 58 | tommy_count_t new_bucket_mask; 59 | tommy_hashdyn_node** new_bucket; 60 | 61 | bucket_bit = hashdyn->bucket_bit; 62 | bucket_max = hashdyn->bucket_max; 63 | 64 | new_bucket_max = 1 << new_bucket_bit; 65 | new_bucket_mask = new_bucket_max - 1; 66 | 67 | /* allocate the new vector using malloc() and not calloc() */ 68 | /* because data is fully initialized in the update process */ 69 | new_bucket = tommy_cast(tommy_hashdyn_node**, tommy_malloc(new_bucket_max * sizeof(tommy_hashdyn_node*))); 70 | 71 | /* reinsert all the elements */ 72 | if (new_bucket_bit > bucket_bit) { 73 | tommy_count_t i; 74 | 75 | /* grow */ 76 | for (i = 0; i < bucket_max; ++i) { 77 | tommy_hashdyn_node* j; 78 | 79 | /* setup the new two buckets */ 80 | new_bucket[i] = 0; 81 | new_bucket[i + bucket_max] = 0; 82 | 83 | /* reinsert the bucket */ 84 | j = hashdyn->bucket[i]; 85 | while (j) { 86 | tommy_hashdyn_node* j_next = j->next; 87 | tommy_count_t pos = j->key & new_bucket_mask; 88 | if (new_bucket[pos]) 89 | tommy_list_insert_tail_not_empty(new_bucket[pos], j); 90 | else 91 | tommy_list_insert_first(&new_bucket[pos], j); 92 | j = j_next; 93 | } 94 | } 95 | } else { 96 | tommy_count_t i; 97 | 98 | /* shrink */ 99 | for (i = 0; i < new_bucket_max; ++i) { 100 | /* setup the new bucket with the lower bucket*/ 101 | new_bucket[i] = hashdyn->bucket[i]; 102 | 103 | /* concat the upper bucket */ 104 | tommy_list_concat(&new_bucket[i], &hashdyn->bucket[i + new_bucket_max]); 105 | } 106 | } 107 | 108 | tommy_free(hashdyn->bucket); 109 | 110 | /* setup */ 111 | hashdyn->bucket_bit = new_bucket_bit; 112 | hashdyn->bucket_max = new_bucket_max; 113 | hashdyn->bucket_mask = new_bucket_mask; 114 | hashdyn->bucket = new_bucket; 115 | } 116 | 117 | /** 118 | * Grow. 119 | */ 120 | tommy_inline void hashdyn_grow_step(tommy_hashdyn* hashdyn) 121 | { 122 | /* grow if more than 50% full */ 123 | if (hashdyn->count >= hashdyn->bucket_max / 2) 124 | tommy_hashdyn_resize(hashdyn, hashdyn->bucket_bit + 1); 125 | } 126 | 127 | /** 128 | * Shrink. 129 | */ 130 | tommy_inline void hashdyn_shrink_step(tommy_hashdyn* hashdyn) 131 | { 132 | /* shrink if less than 12.5% full */ 133 | if (hashdyn->count <= hashdyn->bucket_max / 8 && hashdyn->bucket_bit > TOMMY_HASHDYN_BIT) 134 | tommy_hashdyn_resize(hashdyn, hashdyn->bucket_bit - 1); 135 | } 136 | 137 | void tommy_hashdyn_insert(tommy_hashdyn* hashdyn, tommy_hashdyn_node* node, void* data, tommy_hash_t hash) 138 | { 139 | tommy_count_t pos = hash & hashdyn->bucket_mask; 140 | 141 | tommy_list_insert_tail(&hashdyn->bucket[pos], node, data); 142 | 143 | node->key = hash; 144 | 145 | ++hashdyn->count; 146 | 147 | hashdyn_grow_step(hashdyn); 148 | } 149 | 150 | void* tommy_hashdyn_remove_existing(tommy_hashdyn* hashdyn, tommy_hashdyn_node* node) 151 | { 152 | tommy_count_t pos = node->key & hashdyn->bucket_mask; 153 | 154 | tommy_list_remove_existing(&hashdyn->bucket[pos], node); 155 | 156 | --hashdyn->count; 157 | 158 | hashdyn_shrink_step(hashdyn); 159 | 160 | return node->data; 161 | } 162 | 163 | void* tommy_hashdyn_remove(tommy_hashdyn* hashdyn, tommy_search_func* cmp, const void* cmp_arg, tommy_hash_t hash) 164 | { 165 | tommy_count_t pos = hash & hashdyn->bucket_mask; 166 | tommy_hashdyn_node* node = hashdyn->bucket[pos]; 167 | 168 | while (node) { 169 | /* we first check if the hash matches, as in the same bucket we may have multiples hash values */ 170 | if (node->key == hash && cmp(cmp_arg, node->data) == 0) { 171 | tommy_list_remove_existing(&hashdyn->bucket[pos], node); 172 | 173 | --hashdyn->count; 174 | 175 | hashdyn_shrink_step(hashdyn); 176 | 177 | return node->data; 178 | } 179 | node = node->next; 180 | } 181 | 182 | return 0; 183 | } 184 | 185 | void tommy_hashdyn_foreach(tommy_hashdyn* hashdyn, tommy_foreach_func* func) 186 | { 187 | tommy_count_t bucket_max = hashdyn->bucket_max; 188 | tommy_hashdyn_node** bucket = hashdyn->bucket; 189 | tommy_count_t pos; 190 | 191 | for (pos = 0; pos < bucket_max; ++pos) { 192 | tommy_hashdyn_node* node = bucket[pos]; 193 | 194 | while (node) { 195 | void* data = node->data; 196 | node = node->next; 197 | func(data); 198 | } 199 | } 200 | } 201 | 202 | void tommy_hashdyn_foreach_arg(tommy_hashdyn* hashdyn, tommy_foreach_arg_func* func, void* arg) 203 | { 204 | tommy_count_t bucket_max = hashdyn->bucket_max; 205 | tommy_hashdyn_node** bucket = hashdyn->bucket; 206 | tommy_count_t pos; 207 | 208 | for (pos = 0; pos < bucket_max; ++pos) { 209 | tommy_hashdyn_node* node = bucket[pos]; 210 | 211 | while (node) { 212 | void* data = node->data; 213 | node = node->next; 214 | func(arg, data); 215 | } 216 | } 217 | } 218 | 219 | tommy_size_t tommy_hashdyn_memory_usage(tommy_hashdyn* hashdyn) 220 | { 221 | return hashdyn->bucket_max * (tommy_size_t)sizeof(hashdyn->bucket[0]) 222 | + tommy_hashdyn_count(hashdyn) * (tommy_size_t)sizeof(tommy_hashdyn_node); 223 | } 224 | 225 | -------------------------------------------------------------------------------- /tommyds/tommychain.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010, Andrea Mazzoleni. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | /** \file 29 | * Chain of nodes. 30 | * A chain of nodes is an abstraction used to implements complex list operations 31 | * like sorting. 32 | * 33 | * Do not use this directly. Use lists instead. 34 | */ 35 | 36 | #ifndef __TOMMYCHAIN_H 37 | #define __TOMMYCHAIN_H 38 | 39 | #include "tommytypes.h" 40 | 41 | /******************************************************************************/ 42 | /* chain */ 43 | 44 | /** 45 | * Chain of nodes. 46 | * A chain of nodes is a sequence of nodes with the following properties: 47 | * - It contains at least one node. A chains of zero nodes cannot exist. 48 | * - The next field of the tail is of *undefined* value. 49 | * - The prev field of the head is of *undefined* value. 50 | * - All the other inner prev and next fields are correctly set. 51 | */ 52 | typedef struct tommy_chain_struct { 53 | tommy_node* head; /**< Pointer to the head of the chain. */ 54 | tommy_node* tail; /**< Pointer to the tail of the chain. */ 55 | } tommy_chain; 56 | 57 | /** 58 | * Splices a chain in the middle of another chain. 59 | */ 60 | tommy_inline void tommy_chain_splice(tommy_node* first_before, tommy_node* first_after, tommy_node* second_head, tommy_node* second_tail) 61 | { 62 | /* set the prev list */ 63 | first_after->prev = second_tail; 64 | second_head->prev = first_before; 65 | 66 | /* set the next list */ 67 | first_before->next = second_head; 68 | second_tail->next = first_after; 69 | } 70 | 71 | /** 72 | * Concats two chains. 73 | */ 74 | tommy_inline void tommy_chain_concat(tommy_node* first_tail, tommy_node* second_head) 75 | { 76 | /* set the prev list */ 77 | second_head->prev = first_tail; 78 | 79 | /* set the next list */ 80 | first_tail->next = second_head; 81 | } 82 | 83 | /** 84 | * Merges two chains. 85 | */ 86 | tommy_inline void tommy_chain_merge(tommy_chain* first, tommy_chain* second, tommy_compare_func* cmp) 87 | { 88 | tommy_node* first_i = first->head; 89 | tommy_node* second_i = second->head; 90 | 91 | /* merge */ 92 | while (1) { 93 | if (cmp(first_i->data, second_i->data) > 0) { 94 | tommy_node* next = second_i->next; 95 | if (first_i == first->head) { 96 | tommy_chain_concat(second_i, first_i); 97 | first->head = second_i; 98 | } else { 99 | tommy_chain_splice(first_i->prev, first_i, second_i, second_i); 100 | } 101 | if (second_i == second->tail) 102 | break; 103 | second_i = next; 104 | } else { 105 | if (first_i == first->tail) { 106 | tommy_chain_concat(first_i, second_i); 107 | first->tail = second->tail; 108 | break; 109 | } 110 | first_i = first_i->next; 111 | } 112 | } 113 | } 114 | 115 | /** 116 | * Merges two chains managing special degenerated cases. 117 | * It's funtionally equivalent at tommy_chain_merge() but faster with already ordered chains. 118 | */ 119 | tommy_inline void tommy_chain_merge_degenerated(tommy_chain* first, tommy_chain* second, tommy_compare_func* cmp) 120 | { 121 | /* identify the condition first <= second */ 122 | if (cmp(first->tail->data, second->head->data) <= 0) { 123 | tommy_chain_concat(first->tail, second->head); 124 | first->tail = second->tail; 125 | return; 126 | } 127 | 128 | /* identify the condition second < first */ 129 | /* here we must be strict on comparison to keep the sort stable */ 130 | if (cmp(second->tail->data, first->head->data) < 0) { 131 | tommy_chain_concat(second->tail, first->head); 132 | first->head = second->head; 133 | return; 134 | } 135 | 136 | tommy_chain_merge(first, second, cmp); 137 | } 138 | 139 | /** 140 | * Max number of elements as a power of 2. 141 | */ 142 | #define TOMMY_CHAIN_BIT_MAX 32 143 | 144 | /** 145 | * Sorts a chain. 146 | * It's a stable merge sort using power of 2 buckets, with O(N*log(N)) complexity, 147 | * similar at the one used in the SGI STL libraries and in the Linux Kernel, 148 | * but faster on degenerated cases like already ordered lists. 149 | * 150 | * SGI STL stl_list.h 151 | * http://www.sgi.com/tech/stl/stl_list.h 152 | * 153 | * Linux Kernel lib/list_sort.c 154 | * http://lxr.linux.no/#linux+v2.6.36/lib/list_sort.c 155 | */ 156 | tommy_inline void tommy_chain_mergesort(tommy_chain* chain, tommy_compare_func* cmp) 157 | { 158 | /* 159 | * Bit buckets of chains. 160 | * Each bucket contains 2^i nodes or it's empty. 161 | * The chain at address TOMMY_CHAIN_BIT_MAX is an independet variable operating as "carry". 162 | * We keep it in the same "bit" vector to avoid reports from the valgrind tool sgcheck. 163 | */ 164 | tommy_chain bit[TOMMY_CHAIN_BIT_MAX + 1]; 165 | 166 | /** 167 | * Value stored inside the bit bucket. 168 | * It's used to know which bucket is empty of full. 169 | */ 170 | tommy_count_t counter; 171 | tommy_node* node = chain->head; 172 | tommy_node* tail = chain->tail; 173 | tommy_count_t mask; 174 | tommy_count_t i; 175 | 176 | counter = 0; 177 | while (1) { 178 | tommy_node* next; 179 | tommy_chain* last; 180 | 181 | /* carry bit to add */ 182 | last = &bit[TOMMY_CHAIN_BIT_MAX]; 183 | bit[TOMMY_CHAIN_BIT_MAX].head = node; 184 | bit[TOMMY_CHAIN_BIT_MAX].tail = node; 185 | next = node->next; 186 | 187 | /* add the bit, propagating the carry */ 188 | i = 0; 189 | mask = counter; 190 | while ((mask & 1) != 0) { 191 | tommy_chain_merge_degenerated(&bit[i], last, cmp); 192 | mask >>= 1; 193 | last = &bit[i]; 194 | ++i; 195 | } 196 | 197 | /* copy the carry in the first empty bit */ 198 | bit[i] = *last; 199 | 200 | /* add the carry in the counter */ 201 | ++counter; 202 | 203 | if (node == tail) 204 | break; 205 | node = next; 206 | } 207 | 208 | /* merge the buckets */ 209 | i = tommy_ctz_u32(counter); 210 | mask = counter >> i; 211 | while (mask != 1) { 212 | mask >>= 1; 213 | if (mask & 1) 214 | tommy_chain_merge_degenerated(&bit[i + 1], &bit[i], cmp); 215 | else 216 | bit[i + 1] = bit[i]; 217 | ++i; 218 | } 219 | 220 | *chain = bit[i]; 221 | } 222 | 223 | #endif 224 | 225 | -------------------------------------------------------------------------------- /tommyds/tommyhash.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010, Andrea Mazzoleni. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "tommyhash.h" 29 | 30 | /******************************************************************************/ 31 | /* hash */ 32 | 33 | tommy_inline tommy_uint32_t tommy_le_uint32_read(const void* ptr) 34 | { 35 | /* allow unaligned read on Intel x86 and x86_64 platforms */ 36 | #if defined(__i386__) || defined(_M_IX86) || defined(_X86_) || defined(__x86_64__) || defined(_M_X64) 37 | /* defines from http://predef.sourceforge.net/ */ 38 | return *(const tommy_uint32_t*)ptr; 39 | #else 40 | const unsigned char* ptr8 = tommy_cast(const unsigned char*, ptr); 41 | return ptr8[0] + ((tommy_uint32_t)ptr8[1] << 8) + ((tommy_uint32_t)ptr8[2] << 16) + ((tommy_uint32_t)ptr8[3] << 24); 42 | #endif 43 | } 44 | 45 | #define tommy_rot(x, k) \ 46 | (((x) << (k)) | ((x) >> (32 - (k)))) 47 | 48 | #define tommy_mix(a, b, c) \ 49 | do { \ 50 | a -= c; a ^= tommy_rot(c, 4); c += b; \ 51 | b -= a; b ^= tommy_rot(a, 6); a += c; \ 52 | c -= b; c ^= tommy_rot(b, 8); b += a; \ 53 | a -= c; a ^= tommy_rot(c, 16); c += b; \ 54 | b -= a; b ^= tommy_rot(a, 19); a += c; \ 55 | c -= b; c ^= tommy_rot(b, 4); b += a; \ 56 | } while (0) 57 | 58 | #define tommy_final(a, b, c) \ 59 | do { \ 60 | c ^= b; c -= tommy_rot(b, 14); \ 61 | a ^= c; a -= tommy_rot(c, 11); \ 62 | b ^= a; b -= tommy_rot(a, 25); \ 63 | c ^= b; c -= tommy_rot(b, 16); \ 64 | a ^= c; a -= tommy_rot(c, 4); \ 65 | b ^= a; b -= tommy_rot(a, 14); \ 66 | c ^= b; c -= tommy_rot(b, 24); \ 67 | } while (0) 68 | 69 | tommy_uint32_t tommy_hash_u32(tommy_uint32_t init_val, const void* void_key, tommy_size_t key_len) 70 | { 71 | const unsigned char* key = tommy_cast(const unsigned char*, void_key); 72 | tommy_uint32_t a, b, c; 73 | 74 | a = b = c = 0xdeadbeef + ((tommy_uint32_t)key_len) + init_val; 75 | 76 | while (key_len > 12) { 77 | a += tommy_le_uint32_read(key + 0); 78 | b += tommy_le_uint32_read(key + 4); 79 | c += tommy_le_uint32_read(key + 8); 80 | 81 | tommy_mix(a, b, c); 82 | 83 | key_len -= 12; 84 | key += 12; 85 | } 86 | 87 | switch (key_len) { 88 | case 0 : 89 | return c; /* used only when called with a zero length */ 90 | case 12 : 91 | c += tommy_le_uint32_read(key + 8); 92 | b += tommy_le_uint32_read(key + 4); 93 | a += tommy_le_uint32_read(key + 0); 94 | break; 95 | case 11 : c += ((tommy_uint32_t)key[10]) << 16; 96 | case 10 : c += ((tommy_uint32_t)key[9]) << 8; 97 | case 9 : c += key[8]; 98 | case 8 : 99 | b += tommy_le_uint32_read(key + 4); 100 | a += tommy_le_uint32_read(key + 0); 101 | break; 102 | case 7 : b += ((tommy_uint32_t)key[6]) << 16; 103 | case 6 : b += ((tommy_uint32_t)key[5]) << 8; 104 | case 5 : b += key[4]; 105 | case 4 : 106 | a += tommy_le_uint32_read(key + 0); 107 | break; 108 | case 3 : a += ((tommy_uint32_t)key[2]) << 16; 109 | case 2 : a += ((tommy_uint32_t)key[1]) << 8; 110 | case 1 : a += key[0]; 111 | } 112 | 113 | tommy_final(a, b, c); 114 | 115 | return c; 116 | } 117 | 118 | tommy_uint64_t tommy_hash_u64(tommy_uint64_t init_val, const void* void_key, tommy_size_t key_len) 119 | { 120 | const unsigned char* key = tommy_cast(const unsigned char*, void_key); 121 | tommy_uint32_t a, b, c; 122 | 123 | a = b = c = 0xdeadbeef + ((tommy_uint32_t)key_len) + (init_val & 0xffffffff); 124 | c += init_val >> 32; 125 | 126 | while (key_len > 12) { 127 | a += tommy_le_uint32_read(key + 0); 128 | b += tommy_le_uint32_read(key + 4); 129 | c += tommy_le_uint32_read(key + 8); 130 | 131 | tommy_mix(a, b, c); 132 | 133 | key_len -= 12; 134 | key += 12; 135 | } 136 | 137 | switch (key_len) { 138 | case 0 : 139 | return c + ((tommy_uint64_t)b << 32); /* used only when called with a zero length */ 140 | case 12 : 141 | c += tommy_le_uint32_read(key + 8); 142 | b += tommy_le_uint32_read(key + 4); 143 | a += tommy_le_uint32_read(key + 0); 144 | break; 145 | case 11 : c += ((tommy_uint32_t)key[10]) << 16; 146 | case 10 : c += ((tommy_uint32_t)key[9]) << 8; 147 | case 9 : c += key[8]; 148 | case 8 : 149 | b += tommy_le_uint32_read(key + 4); 150 | a += tommy_le_uint32_read(key + 0); 151 | break; 152 | case 7 : b += ((tommy_uint32_t)key[6]) << 16; 153 | case 6 : b += ((tommy_uint32_t)key[5]) << 8; 154 | case 5 : b += key[4]; 155 | case 4 : 156 | a += tommy_le_uint32_read(key + 0); 157 | break; 158 | case 3 : a += ((tommy_uint32_t)key[2]) << 16; 159 | case 2 : a += ((tommy_uint32_t)key[1]) << 8; 160 | case 1 : a += key[0]; 161 | } 162 | 163 | tommy_final(a, b, c); 164 | 165 | return c + ((tommy_uint64_t)b << 32); 166 | } 167 | 168 | tommy_uint32_t tommy_strhash_u32(tommy_uint64_t init_val, const void* void_key) 169 | { 170 | const unsigned char* key = tommy_cast(const unsigned char*, void_key); 171 | tommy_uint32_t a, b, c; 172 | tommy_uint32_t m[3] = { 0xff, 0xff00, 0xff0000 }; 173 | 174 | a = b = c = 0xdeadbeef + init_val; 175 | /* this is different than original lookup3 and the result won't match */ 176 | 177 | while (1) { 178 | tommy_uint32_t v = tommy_le_uint32_read(key); 179 | 180 | if (tommy_haszero_u32(v)) { 181 | if (v & m[0]) { 182 | a += v & m[0]; 183 | if (v & m[1]) { 184 | a += v & m[1]; 185 | if (v & m[2]) 186 | a += v & m[2]; 187 | } 188 | } 189 | 190 | break; 191 | } 192 | 193 | a += v; 194 | 195 | v = tommy_le_uint32_read(key + 4); 196 | 197 | if (tommy_haszero_u32(v)) { 198 | if (v & m[0]) { 199 | b += v & m[0]; 200 | if (v & m[1]) { 201 | b += v & m[1]; 202 | if (v & m[2]) 203 | b += v & m[2]; 204 | } 205 | } 206 | 207 | break; 208 | } 209 | 210 | b += v; 211 | 212 | v = tommy_le_uint32_read(key + 8); 213 | 214 | if (tommy_haszero_u32(v)) { 215 | if (v & m[0]) { 216 | c += v & m[0]; 217 | if (v & m[1]) { 218 | c += v & m[1]; 219 | if (v & m[2]) 220 | c += v & m[2]; 221 | } 222 | } 223 | 224 | break; 225 | } 226 | 227 | c += v; 228 | 229 | tommy_mix(a, b, c); 230 | 231 | key += 12; 232 | } 233 | 234 | /* for lengths that are multiplers of 12 we already have called mix */ 235 | /* this is different than the original lookup3 and the result won't match */ 236 | 237 | tommy_final(a, b, c); 238 | 239 | return c; 240 | } 241 | 242 | -------------------------------------------------------------------------------- /tommyds/tommytree.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, Andrea Mazzoleni. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "tommytree.h" 29 | 30 | #include /* for assert */ 31 | 32 | /******************************************************************************/ 33 | /* tree */ 34 | 35 | void tommy_tree_init(tommy_tree* tree, tommy_compare_func* cmp) 36 | { 37 | tree->root = 0; 38 | tree->count = 0; 39 | tree->cmp = cmp; 40 | } 41 | 42 | static int tommy_tree_delta(tommy_tree_node* root) 43 | { 44 | int left_height = root->prev ? root->prev->key : 0; 45 | int right_height = root->next ? root->next->key : 0; 46 | 47 | return left_height - right_height; 48 | } 49 | 50 | /* AVL tree operations */ 51 | static tommy_tree_node* tommy_tree_balance(tommy_tree_node*); 52 | 53 | static tommy_tree_node* tommy_tree_rotate_left(tommy_tree_node* root) 54 | { 55 | tommy_tree_node* next = root->next; 56 | 57 | root->next = next->prev; 58 | 59 | next->prev = tommy_tree_balance(root); 60 | 61 | return tommy_tree_balance(next); 62 | } 63 | 64 | static tommy_tree_node* tommy_tree_rotate_right(tommy_tree_node* root) 65 | { 66 | tommy_tree_node* prev = root->prev; 67 | 68 | root->prev = prev->next; 69 | 70 | prev->next = tommy_tree_balance(root); 71 | 72 | return tommy_tree_balance(prev); 73 | } 74 | 75 | static tommy_tree_node* tommy_tree_move_right(tommy_tree_node* root, tommy_tree_node* node) 76 | { 77 | if (!root) 78 | return node; 79 | 80 | root->next = tommy_tree_move_right(root->next, node); 81 | 82 | return tommy_tree_balance(root); 83 | } 84 | 85 | static tommy_tree_node* tommy_tree_balance(tommy_tree_node* root) 86 | { 87 | int delta = tommy_tree_delta(root); 88 | 89 | if (delta < -1) { 90 | if (tommy_tree_delta(root->next) > 0) 91 | root->next = tommy_tree_rotate_right(root->next); 92 | return tommy_tree_rotate_left(root); 93 | } 94 | 95 | if (delta > 1) { 96 | if (tommy_tree_delta(root->prev) < 0) 97 | root->prev = tommy_tree_rotate_left(root->prev); 98 | return tommy_tree_rotate_right(root); 99 | } 100 | 101 | /* recompute key */ 102 | root->key = 0; 103 | 104 | if (root->prev && root->prev->key > root->key) 105 | root->key = root->prev->key; 106 | 107 | if (root->next && root->next->key > root->key) 108 | root->key = root->next->key; 109 | 110 | /* count itself */ 111 | root->key += 1; 112 | 113 | return root; 114 | } 115 | 116 | static tommy_tree_node* tommy_tree_insert_node(tommy_compare_func* cmp, tommy_tree_node* root, tommy_tree_node** let) 117 | { 118 | int c; 119 | 120 | if (!root) 121 | return *let; 122 | 123 | c = cmp((*let)->data, root->data); 124 | 125 | if (c < 0) { 126 | root->prev = tommy_tree_insert_node(cmp, root->prev, let); 127 | return tommy_tree_balance(root); 128 | } 129 | 130 | if (c > 0) { 131 | root->next = tommy_tree_insert_node(cmp, root->next, let); 132 | return tommy_tree_balance(root); 133 | } 134 | 135 | /* already present, set the return pointer */ 136 | *let = root; 137 | 138 | return root; 139 | } 140 | 141 | void* tommy_tree_insert(tommy_tree* tree, tommy_tree_node* node, void* data) 142 | { 143 | tommy_tree_node* insert = node; 144 | 145 | insert->data = data; 146 | insert->prev = 0; 147 | insert->next = 0; 148 | insert->key = 0; 149 | 150 | tree->root = tommy_tree_insert_node(tree->cmp, tree->root, &insert); 151 | 152 | if (insert == node) 153 | ++tree->count; 154 | 155 | return insert->data; 156 | } 157 | 158 | static tommy_tree_node* tommy_tree_remove_node(tommy_compare_func* cmp, tommy_tree_node* root, void* data, tommy_tree_node** let) 159 | { 160 | int c; 161 | 162 | if (!root) 163 | return 0; 164 | 165 | c = cmp(data, root->data); 166 | 167 | if (c < 0) { 168 | root->prev = tommy_tree_remove_node(cmp, root->prev, data, let); 169 | return tommy_tree_balance(root); 170 | } 171 | 172 | if (c > 0) { 173 | root->next = tommy_tree_remove_node(cmp, root->next, data, let); 174 | return tommy_tree_balance(root); 175 | } 176 | 177 | /* found */ 178 | *let = root; 179 | 180 | return tommy_tree_move_right(root->prev, root->next); 181 | } 182 | 183 | void* tommy_tree_remove(tommy_tree* tree, void* data) 184 | { 185 | tommy_tree_node* node = 0; 186 | 187 | tree->root = tommy_tree_remove_node(tree->cmp, tree->root, data, &node); 188 | 189 | if (!node) 190 | return 0; 191 | 192 | --tree->count; 193 | 194 | return node->data; 195 | } 196 | 197 | static tommy_tree_node* tommy_tree_search_node(tommy_compare_func* cmp, tommy_tree_node* root, void* data) 198 | { 199 | int c; 200 | 201 | if (!root) 202 | return 0; 203 | 204 | c = cmp(data, root->data); 205 | 206 | if (c < 0) 207 | return tommy_tree_search_node(cmp, root->prev, data); 208 | 209 | if (c > 0) 210 | return tommy_tree_search_node(cmp, root->next, data); 211 | 212 | return root; 213 | } 214 | 215 | void* tommy_tree_search(tommy_tree* tree, void* data) 216 | { 217 | tommy_tree_node* node = tommy_tree_search_node(tree->cmp, tree->root, data); 218 | 219 | if (!node) 220 | return 0; 221 | 222 | return node->data; 223 | } 224 | 225 | void* tommy_tree_search_compare(tommy_tree* tree, tommy_compare_func* cmp, void* cmp_arg) 226 | { 227 | tommy_tree_node* node = tommy_tree_search_node(cmp, tree->root, cmp_arg); 228 | 229 | if (!node) 230 | return 0; 231 | 232 | return node->data; 233 | } 234 | 235 | void* tommy_tree_remove_existing(tommy_tree* tree, tommy_tree_node* node) 236 | { 237 | void* data = tommy_tree_remove(tree, node->data); 238 | 239 | assert(data != 0); 240 | 241 | return data; 242 | } 243 | 244 | static void tommy_tree_foreach_node(tommy_tree_node* root, tommy_foreach_func* func) 245 | { 246 | tommy_tree_node* next; 247 | 248 | if (!root) 249 | return; 250 | 251 | tommy_tree_foreach_node(root->prev, func); 252 | 253 | /* make a copy in case func is free() */ 254 | next = root->next; 255 | 256 | func(root->data); 257 | 258 | tommy_tree_foreach_node(next, func); 259 | } 260 | 261 | void tommy_tree_foreach(tommy_tree* tree, tommy_foreach_func* func) 262 | { 263 | tommy_tree_foreach_node(tree->root, func); 264 | } 265 | 266 | static void tommy_tree_foreach_arg_node(tommy_tree_node* root, tommy_foreach_arg_func* func, void* arg) 267 | { 268 | tommy_tree_node* next; 269 | 270 | if (!root) 271 | return; 272 | 273 | tommy_tree_foreach_arg_node(root->prev, func, arg); 274 | 275 | /* make a copy in case func is free() */ 276 | next = root->next; 277 | 278 | func(arg, root->data); 279 | 280 | tommy_tree_foreach_arg_node(next, func, arg); 281 | } 282 | 283 | void tommy_tree_foreach_arg(tommy_tree* tree, tommy_foreach_arg_func* func, void* arg) 284 | { 285 | tommy_tree_foreach_arg_node(tree->root, func, arg); 286 | } 287 | 288 | tommy_size_t tommy_tree_memory_usage(tommy_tree* tree) 289 | { 290 | return tommy_tree_count(tree) * sizeof(tommy_tree_node); 291 | } 292 | 293 | -------------------------------------------------------------------------------- /tommyds/tommytree.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, Andrea Mazzoleni. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | /** \file 29 | * AVL tree. 30 | * 31 | * This tree is a standard AVL tree implementation that stores elements in the 32 | * order defined by the comparison function. 33 | * 34 | * As difference than other tommy containers, duplicate elements cannot be inserted. 35 | * 36 | * To initialize a tree you have to call tommy_tree_init() specifing a comparison 37 | * function that will define the order in the tree. 38 | * 39 | * \code 40 | * tommy_tree tree; 41 | * 42 | * tommy_tree_init(&tree, cmp); 43 | * \endcode 44 | * 45 | * To insert elements in the tree you have to call tommy_tree_insert() for 46 | * each element. 47 | * In the insertion call you have to specify the address of the node and the 48 | * address of the object. 49 | * The address of the object is used to initialize the tommy_node::data field 50 | * of the node. 51 | * 52 | * \code 53 | * struct object { 54 | * int value; 55 | * // other fields 56 | * tommy_tree_node node; 57 | * }; 58 | * 59 | * struct object* obj = malloc(sizeof(struct object)); // creates the object 60 | * 61 | * obj->value = ...; // initializes the object 62 | * 63 | * tommy_tree_insert(&tree, &obj->node, obj); // inserts the object 64 | * \endcode 65 | * 66 | * To find and element in the tree you have to call tommy_tree_search() providing 67 | * the key to search. 68 | * 69 | * \code 70 | * struct object value_to_find = { 1 }; 71 | * struct object* obj = tommy_tree_search(&tree, &value_to_find); 72 | * if (!obj) { 73 | * // not found 74 | * } else { 75 | * // found 76 | * } 77 | * \endcode 78 | * 79 | * To remove an element from the tree you have to call tommy_tree_remove() 80 | * providing the key to search and remove. 81 | * 82 | * \code 83 | * struct object value_to_remove = { 1 }; 84 | * struct object* obj = tommy_tree_remove(&tree, &value_to_remove); 85 | * if (obj) { 86 | * free(obj); // frees the object allocated memory 87 | * } 88 | * \endcode 89 | * 90 | * To destroy the tree you have to remove or destroy all the contained elements. 91 | * The tree itself doesn't have or need a deallocation function. 92 | * 93 | * If you need to iterate over all the elements in the tree, you can use 94 | * tommy_tree_foreach() or tommy_tree_foreach_arg(). 95 | * If you need a more precise control with a real iteration, you have to insert 96 | * all the elements also in a ::tommy_list, and use the list to iterate. 97 | * See the \ref multiindex example for more detail. 98 | */ 99 | 100 | #ifndef __TOMMYTREE_H 101 | #define __TOMMYTREE_H 102 | 103 | #include "tommytypes.h" 104 | 105 | /******************************************************************************/ 106 | /* tree */ 107 | 108 | /** 109 | * Tree node. 110 | * This is the node that you have to include inside your objects. 111 | */ 112 | typedef tommy_node tommy_tree_node; 113 | 114 | /** 115 | * Tree container type. 116 | * \note Don't use internal fields directly, but access the container only using functions. 117 | */ 118 | typedef struct tommy_tree_struct { 119 | tommy_tree_node* root; /**< Root node. */ 120 | tommy_count_t count; /**< Number of elements. */ 121 | tommy_compare_func* cmp; /**< Comparison function. */ 122 | } tommy_tree; 123 | 124 | /** 125 | * Initializes the tree. 126 | * \param cmp The comparison function that defines the orderin the tree. 127 | */ 128 | void tommy_tree_init(tommy_tree* tree, tommy_compare_func* cmp); 129 | 130 | /** 131 | * Inserts an element in the tree. 132 | * If the element is already present, it's not inserted again. 133 | * Check the return value to identify if the element was already present or not. 134 | * You have to provide the pointer of the node embedded into the object and 135 | * the pointer to the object. 136 | * \param node Pointer to the node embedded into the object to insert. 137 | * \param data Pointer to the object to insert. 138 | * \return The element in the tree. Either the already existing one, or the one just inserted. 139 | */ 140 | void* tommy_tree_insert(tommy_tree* tree, tommy_tree_node* node, void* data); 141 | 142 | /** 143 | * Searches and removes an element. 144 | * If the element is not found, 0 is returned. 145 | * \param data Element used for comparison. 146 | * \return The removed element, or 0 if not found. 147 | */ 148 | void* tommy_tree_remove(tommy_tree* tree, void* data); 149 | 150 | /** 151 | * Searches an element in the tree. 152 | * If the element is not found, 0 is returned. 153 | * \param data Element used for comparison. 154 | * \return The first element found, or 0 if none. 155 | */ 156 | void* tommy_tree_search(tommy_tree* tree, void* data); 157 | 158 | /** 159 | * Searches an element in the tree with a specific comparison function. 160 | * 161 | * Like tommy_tree_search() but you can specify a different comparison function. 162 | * Note that this function must define a suborder of the original one. 163 | * 164 | * The ::data argument will be the first argument of the comparison function, 165 | * and it can be of a different type of the objects in the tree. 166 | */ 167 | void* tommy_tree_search_compare(tommy_tree* tree, tommy_compare_func* cmp, void* cmp_arg); 168 | 169 | /** 170 | * Removes an element from the tree. 171 | * You must already have the address of the element to remove. 172 | * \return The tommy_node::data field of the node removed. 173 | */ 174 | void* tommy_tree_remove_existing(tommy_tree* tree, tommy_tree_node* node); 175 | 176 | /** 177 | * Calls the specified function for each element in the tree. 178 | * 179 | * The elements are processed in order. 180 | * 181 | * You cannot add or remove elements from the inside of the callback, 182 | * but can use it to deallocate them. 183 | * 184 | * \code 185 | * tommy_tree tree; 186 | * 187 | * // initializes the tree 188 | * tommy_tree_init(&tree, cmp); 189 | * 190 | * ... 191 | * 192 | * // creates an object 193 | * struct object* obj = malloc(sizeof(struct object)); 194 | * 195 | * ... 196 | * 197 | * // insert it in the tree 198 | * tommy_tree_insert(&tree, &obj->node, obj); 199 | * 200 | * ... 201 | * 202 | * // deallocates all the objects iterating the tree 203 | * tommy_tree_foreach(&tree, free); 204 | * \endcode 205 | */ 206 | void tommy_tree_foreach(tommy_tree* tree, tommy_foreach_func* func); 207 | 208 | /** 209 | * Calls the specified function with an argument for each element in the tree. 210 | */ 211 | void tommy_tree_foreach_arg(tommy_tree* tree, tommy_foreach_arg_func* func, void* arg); 212 | 213 | /** 214 | * Gets the number of elements. 215 | */ 216 | tommy_inline tommy_count_t tommy_tree_count(tommy_tree* tree) 217 | { 218 | return tree->count; 219 | } 220 | 221 | /** 222 | * Gets the size of allocated memory. 223 | * It includes the size of the ::tommy_tree_node of the stored elements. 224 | */ 225 | tommy_size_t tommy_tree_memory_usage(tommy_tree* tree); 226 | 227 | #endif 228 | 229 | -------------------------------------------------------------------------------- /phmap/phmap_dump.h: -------------------------------------------------------------------------------- 1 | #if !defined(phmap_dump_h_guard_) 2 | #define phmap_dump_h_guard_ 3 | 4 | // --------------------------------------------------------------------------- 5 | // Copyright (c) 2019, Gregory Popovitch - greg7mdp@gmail.com 6 | // 7 | // providing dump/load/mmap_load 8 | // 9 | // Licensed under the Apache License, Version 2.0 (the "License"); 10 | // you may not use this file except in compliance with the License. 11 | // You may obtain a copy of the License at 12 | // 13 | // https://www.apache.org/licenses/LICENSE-2.0 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, 17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | // See the License for the specific language governing permissions and 19 | // limitations under the License. 20 | // --------------------------------------------------------------------------- 21 | 22 | #include 23 | #include 24 | #include 25 | #include "phmap.h" 26 | namespace phmap 27 | { 28 | 29 | namespace type_traits_internal { 30 | 31 | #if defined(__GLIBCXX__) && __GLIBCXX__ < 20150801 32 | template struct IsTriviallyCopyable : public std::integral_constant {}; 33 | #else 34 | template struct IsTriviallyCopyable : public std::is_trivially_copyable {}; 35 | #endif 36 | 37 | template 38 | struct IsTriviallyCopyable> { 39 | static constexpr bool value = IsTriviallyCopyable::value && IsTriviallyCopyable::value; 40 | }; 41 | } 42 | 43 | namespace container_internal { 44 | 45 | // ------------------------------------------------------------------------ 46 | // dump/load for raw_hash_set 47 | // ------------------------------------------------------------------------ 48 | template 49 | template 50 | bool raw_hash_set::dump(OutputArchive& ar) { 51 | static_assert(type_traits_internal::IsTriviallyCopyable::value, 52 | "value_type should be trivially copyable"); 53 | 54 | if (!ar.dump(size_)) { 55 | std::cerr << "Failed to dump size_" << std::endl; 56 | return false; 57 | } 58 | if (size_ == 0) { 59 | return true; 60 | } 61 | if (!ar.dump(capacity_)) { 62 | std::cerr << "Failed to dump capacity_" << std::endl; 63 | return false; 64 | } 65 | if (!ar.dump(reinterpret_cast(ctrl_), 66 | sizeof(ctrl_t) * (capacity_ + Group::kWidth + 1))) { 67 | 68 | std::cerr << "Failed to dump ctrl_" << std::endl; 69 | return false; 70 | } 71 | if (!ar.dump(reinterpret_cast(slots_), 72 | sizeof(slot_type) * capacity_)) { 73 | std::cerr << "Failed to dump slot_" << std::endl; 74 | return false; 75 | } 76 | return true; 77 | } 78 | 79 | template 80 | template 81 | bool raw_hash_set::load(InputArchive& ar) { 82 | static_assert(type_traits_internal::IsTriviallyCopyable::value, 83 | "value_type should be trivially copyable"); 84 | raw_hash_set().swap(*this); // clear any existing content 85 | if (!ar.load(&size_)) { 86 | std::cerr << "Failed to load size_" << std::endl; 87 | return false; 88 | } 89 | if (size_ == 0) { 90 | return true; 91 | } 92 | if (!ar.load(&capacity_)) { 93 | std::cerr << "Failed to load capacity_" << std::endl; 94 | return false; 95 | } 96 | 97 | // allocate memory for ctrl_ and slots_ 98 | initialize_slots(); 99 | if (!ar.load(reinterpret_cast(ctrl_), 100 | sizeof(ctrl_t) * (capacity_ + Group::kWidth + 1))) { 101 | std::cerr << "Failed to load ctrl" << std::endl; 102 | return false; 103 | } 104 | if (!ar.load(reinterpret_cast(slots_), 105 | sizeof(slot_type) * capacity_)) { 106 | std::cerr << "Failed to load slot" << std::endl; 107 | return false; 108 | } 109 | return true; 110 | } 111 | 112 | // ------------------------------------------------------------------------ 113 | // dump/load for parallel_hash_set 114 | // ------------------------------------------------------------------------ 115 | template class RefSet, 117 | class Mtx_, 118 | class Policy, class Hash, class Eq, class Alloc> 119 | template 120 | bool parallel_hash_set::dump(OutputArchive& ar) { 121 | static_assert(type_traits_internal::IsTriviallyCopyable::value, 122 | "value_type should be trivially copyable"); 123 | 124 | if (! ar.dump(subcnt())) { 125 | std::cerr << "Failed to dump meta!" << std::endl; 126 | return false; 127 | } 128 | for (size_t i = 0; i < sets_.size(); ++i) { 129 | auto& inner = sets_[i]; 130 | typename Lockable::UniqueLock m(const_cast(inner)); 131 | if (!inner.set_.dump(ar)) { 132 | std::cerr << "Failed to dump submap " << i << std::endl; 133 | return false; 134 | } 135 | } 136 | return true; 137 | } 138 | 139 | template class RefSet, 141 | class Mtx_, 142 | class Policy, class Hash, class Eq, class Alloc> 143 | template 144 | bool parallel_hash_set::load(InputArchive& ar) { 145 | static_assert(type_traits_internal::IsTriviallyCopyable::value, 146 | "value_type should be trivially copyable"); 147 | 148 | size_t submap_count = 0; 149 | if (!ar.load(&submap_count)) { 150 | std::cerr << "Failed to load submap count!" << std::endl; 151 | return false; 152 | } 153 | 154 | if (submap_count != subcnt()) { 155 | std::cerr << "submap count(" << submap_count << ") != N(" << N << ")" << std::endl; 156 | return false; 157 | } 158 | 159 | for (size_t i = 0; i < submap_count; ++i) { 160 | auto& inner = sets_[i]; 161 | typename Lockable::UniqueLock m(const_cast(inner)); 162 | if (!inner.set_.load(ar)) { 163 | std::cerr << "Failed to load submap " << i << std::endl; 164 | return false; 165 | } 166 | } 167 | return true; 168 | } 169 | } // namespace container_internal 170 | 171 | 172 | 173 | // ------------------------------------------------------------------------ 174 | // BinaryArchive 175 | // File is closed when archive object is destroyed 176 | // ------------------------------------------------------------------------ 177 | 178 | // ------------------------------------------------------------------------ 179 | // ------------------------------------------------------------------------ 180 | class BinaryOutputArchive { 181 | public: 182 | BinaryOutputArchive(const char *file_path) { 183 | ofs_.open(file_path, std::ios_base::binary); 184 | } 185 | 186 | bool dump(const char *p, size_t sz) { 187 | ofs_.write(p, sz); 188 | return true; 189 | } 190 | 191 | template 192 | typename std::enable_if::value, bool>::type 193 | dump(const V& v) { 194 | ofs_.write(reinterpret_cast(&v), sizeof(V)); 195 | return true; 196 | } 197 | 198 | private: 199 | std::ofstream ofs_; 200 | }; 201 | 202 | 203 | class BinaryInputArchive { 204 | public: 205 | BinaryInputArchive(const char * file_path) { 206 | ifs_.open(file_path, std::ios_base::binary); 207 | } 208 | 209 | bool load(char* p, size_t sz) { 210 | ifs_.read(p, sz); 211 | return true; 212 | } 213 | 214 | template 215 | typename std::enable_if::value, bool>::type 216 | load(V* v) { 217 | ifs_.read(reinterpret_cast(v), sizeof(V)); 218 | return true; 219 | } 220 | 221 | private: 222 | std::ifstream ifs_; 223 | }; 224 | 225 | } // namespace phmap 226 | 227 | #endif // phmap_dump_h_guard_ 228 | --------------------------------------------------------------------------------