From f9139a6e73e66190c15812e6fa66b930c9ec2c04 Mon Sep 17 00:00:00 2001 From: pancake Date: Fri, 29 Nov 2024 09:35:00 +0100 Subject: [PATCH] Remove shlr/sdb and use the subprojects from make too ##build * Use sdb 2.0.2 the latest release --- .gitignore | 10 +- Makefile | 2 +- binr/rules.mk | 2 +- libr/Makefile | 4 +- libr/anal/d/Makefile | 2 +- libr/arch/p/java.mk | 2 +- libr/asm/Makefile | 5 +- libr/asm/d/Makefile | 2 +- libr/bin/d/Makefile | 2 +- libr/bin/p/cgc.mk | 1 - libr/bin/p/elf.mk | 1 - libr/bin/p/java.mk | 2 +- libr/bin/p/mach0.mk | 2 +- libr/bin/p/mbn.mk | 1 - libr/bin/p/symbols.mk | 2 +- libr/bin/p/te.mk | 1 - libr/core/p/a2f.mk | 2 +- libr/core/p/agD.mk | 2 +- libr/core/p/java.mk | 2 +- libr/do-ar-sh | 2 +- libr/io/p/shm.mk | 2 +- libr/main/radare2.c | 4 +- libr/syscall/d/Makefile | 2 +- libr/util/d/Makefile | 3 +- libr/util/sdb.mk | 5 +- shlr/Makefile | 67 +- shlr/sdb-config.mk | 5 - shlr/sdb.mk | 3 +- shlr/sdb/Makefile | 228 -- shlr/sdb/README.md | 119 - shlr/sdb/config.mk | 145 -- shlr/sdb/include/sdb/asserts.h | 92 - shlr/sdb/include/sdb/buffer.h | 70 - shlr/sdb/include/sdb/cdb.h | 47 - shlr/sdb/include/sdb/cdb_make.h | 40 - shlr/sdb/include/sdb/config.h | 16 - shlr/sdb/include/sdb/cwisstable.h | 3018 ------------------------- shlr/sdb/include/sdb/dict.h | 42 - shlr/sdb/include/sdb/gcc_stdatomic.h | 70 - shlr/sdb/include/sdb/heap.h | 70 - shlr/sdb/include/sdb/ht.h | 61 - shlr/sdb/include/sdb/ht_inc.h | 127 -- shlr/sdb/include/sdb/ht_pp.h | 25 - shlr/sdb/include/sdb/ht_pu.h | 35 - shlr/sdb/include/sdb/ht_su.h | 36 - shlr/sdb/include/sdb/ht_up.h | 26 - shlr/sdb/include/sdb/ht_uu.h | 30 - shlr/sdb/include/sdb/ls.h | 85 - shlr/sdb/include/sdb/msvc_stdatomic.h | 54 - shlr/sdb/include/sdb/rangstr.h | 29 - shlr/sdb/include/sdb/sdb.h | 469 ---- shlr/sdb/include/sdb/set.h | 36 - shlr/sdb/include/sdb/types.h | 166 -- shlr/sdb/include/sdb/version.h | 1 - shlr/sdb/memcache/Makefile | 1 - shlr/sdb/meson.build | 176 -- shlr/sdb/src/Makefile | 101 - shlr/sdb/src/array.c | 709 ------ shlr/sdb/src/base64.c | 111 - shlr/sdb/src/buffer.inc.c | 58 - shlr/sdb/src/cdb.c | 190 -- shlr/sdb/src/cdb_make.c | 197 -- shlr/sdb/src/dict.c | 215 -- shlr/sdb/src/diff.c | 171 -- shlr/sdb/src/disk.c | 176 -- shlr/sdb/src/entry.c | 14 - shlr/sdb/src/fmt.c | 206 -- shlr/sdb/src/heap.c | 424 ---- shlr/sdb/src/ht.c | 68 - shlr/sdb/src/ht.inc.c | 366 --- shlr/sdb/src/ht_pp.c | 48 - shlr/sdb/src/ht_pu.c | 108 - shlr/sdb/src/ht_su.c | 171 -- shlr/sdb/src/ht_up.c | 43 - shlr/sdb/src/ht_uu.c | 110 - shlr/sdb/src/journal.c | 127 -- shlr/sdb/src/json.c | 357 --- shlr/sdb/src/json/Makefile | 37 - shlr/sdb/src/json/README | 20 - shlr/sdb/src/json/api.c | 55 - shlr/sdb/src/json/indent.c | 139 -- shlr/sdb/src/json/js0n.c | 296 --- shlr/sdb/src/json/main.c | 92 - shlr/sdb/src/json/path.c | 219 -- shlr/sdb/src/json/rangstr.c | 110 - shlr/sdb/src/json/test.c | 13 - shlr/sdb/src/json/test.json | 4 - shlr/sdb/src/lock.c | 76 - shlr/sdb/src/ls.c | 397 ---- shlr/sdb/src/main.c | 1088 --------- shlr/sdb/src/match.c | 111 - shlr/sdb/src/ns.c | 252 --- shlr/sdb/src/num.c | 85 - shlr/sdb/src/query.c | 922 -------- shlr/sdb/src/sdb.1 | 72 - shlr/sdb/src/sdb.c | 1276 ----------- shlr/sdb/src/set.c | 78 - shlr/sdb/src/text.c | 492 ---- shlr/sdb/src/util.c | 394 ---- shlr/sdb/test/Makefile | 1 - shlr/sdb/wasi.mk | 7 - shlr/sdb/wasi.sh | 23 - subprojects/sdb.mk | 5 +- subprojects/sdb.wrap | 3 +- sys/sdk.sh | 2 +- test/unit/Makefile | 2 +- 106 files changed, 63 insertions(+), 15632 deletions(-) delete mode 100644 shlr/sdb-config.mk delete mode 100644 shlr/sdb/Makefile delete mode 100644 shlr/sdb/README.md delete mode 100644 shlr/sdb/config.mk delete mode 100644 shlr/sdb/include/sdb/asserts.h delete mode 100644 shlr/sdb/include/sdb/buffer.h delete mode 100644 shlr/sdb/include/sdb/cdb.h delete mode 100644 shlr/sdb/include/sdb/cdb_make.h delete mode 100644 shlr/sdb/include/sdb/config.h delete mode 100644 shlr/sdb/include/sdb/cwisstable.h delete mode 100644 shlr/sdb/include/sdb/dict.h delete mode 100644 shlr/sdb/include/sdb/gcc_stdatomic.h delete mode 100644 shlr/sdb/include/sdb/heap.h delete mode 100644 shlr/sdb/include/sdb/ht.h delete mode 100644 shlr/sdb/include/sdb/ht_inc.h delete mode 100644 shlr/sdb/include/sdb/ht_pp.h delete mode 100644 shlr/sdb/include/sdb/ht_pu.h delete mode 100644 shlr/sdb/include/sdb/ht_su.h delete mode 100644 shlr/sdb/include/sdb/ht_up.h delete mode 100644 shlr/sdb/include/sdb/ht_uu.h delete mode 100644 shlr/sdb/include/sdb/ls.h delete mode 100644 shlr/sdb/include/sdb/msvc_stdatomic.h delete mode 100644 shlr/sdb/include/sdb/rangstr.h delete mode 100644 shlr/sdb/include/sdb/sdb.h delete mode 100644 shlr/sdb/include/sdb/set.h delete mode 100644 shlr/sdb/include/sdb/types.h delete mode 100644 shlr/sdb/include/sdb/version.h delete mode 100644 shlr/sdb/memcache/Makefile delete mode 100644 shlr/sdb/meson.build delete mode 100644 shlr/sdb/src/Makefile delete mode 100644 shlr/sdb/src/array.c delete mode 100644 shlr/sdb/src/base64.c delete mode 100644 shlr/sdb/src/buffer.inc.c delete mode 100644 shlr/sdb/src/cdb.c delete mode 100644 shlr/sdb/src/cdb_make.c delete mode 100644 shlr/sdb/src/dict.c delete mode 100644 shlr/sdb/src/diff.c delete mode 100644 shlr/sdb/src/disk.c delete mode 100644 shlr/sdb/src/entry.c delete mode 100644 shlr/sdb/src/fmt.c delete mode 100644 shlr/sdb/src/heap.c delete mode 100644 shlr/sdb/src/ht.c delete mode 100644 shlr/sdb/src/ht.inc.c delete mode 100644 shlr/sdb/src/ht_pp.c delete mode 100644 shlr/sdb/src/ht_pu.c delete mode 100644 shlr/sdb/src/ht_su.c delete mode 100644 shlr/sdb/src/ht_up.c delete mode 100644 shlr/sdb/src/ht_uu.c delete mode 100644 shlr/sdb/src/journal.c delete mode 100644 shlr/sdb/src/json.c delete mode 100644 shlr/sdb/src/json/Makefile delete mode 100644 shlr/sdb/src/json/README delete mode 100644 shlr/sdb/src/json/api.c delete mode 100644 shlr/sdb/src/json/indent.c delete mode 100644 shlr/sdb/src/json/js0n.c delete mode 100644 shlr/sdb/src/json/main.c delete mode 100644 shlr/sdb/src/json/path.c delete mode 100644 shlr/sdb/src/json/rangstr.c delete mode 100644 shlr/sdb/src/json/test.c delete mode 100644 shlr/sdb/src/json/test.json delete mode 100644 shlr/sdb/src/lock.c delete mode 100644 shlr/sdb/src/ls.c delete mode 100644 shlr/sdb/src/main.c delete mode 100644 shlr/sdb/src/match.c delete mode 100644 shlr/sdb/src/ns.c delete mode 100644 shlr/sdb/src/num.c delete mode 100644 shlr/sdb/src/query.c delete mode 100644 shlr/sdb/src/sdb.1 delete mode 100644 shlr/sdb/src/sdb.c delete mode 100644 shlr/sdb/src/set.c delete mode 100644 shlr/sdb/src/text.c delete mode 100644 shlr/sdb/src/util.c delete mode 100644 shlr/sdb/test/Makefile delete mode 100644 shlr/sdb/wasi.mk delete mode 100755 shlr/sdb/wasi.sh diff --git a/.gitignore b/.gitignore index 4dbe1ceb6e173..f5f5b45a2cb85 100644 --- a/.gitignore +++ b/.gitignore @@ -70,14 +70,8 @@ libr/arch/p/arm/v35/arch-armv7 shlr/capstone/ shlr/java/out shlr/java/out.exe -shlr/sdb/sdb -shlr/sdb/sdb.exe -shlr/sdb/src/sdb -shlr/sdb/src/.sdb -shlr/sdb/src/sdb.exe -shlr/sdb/src/.sdb.exe -shlr/sdb/src/libsdb.so* -shlr/spp/config.h +subprojects/sdb +subprojects/capstone shlr/.cs_tmp.zip sys/travis/*.txt sys/.mark_python-deps diff --git a/Makefile b/Makefile index adcd173c937f7..69cee74e4e75a 100644 --- a/Makefile +++ b/Makefile @@ -159,7 +159,7 @@ windist: mkdir -p "${WINDIST}/include/libr/r_util" mkdir -p "${WINDIST}/include/libr/r_anal" @echo "${C}[WINDIST] Copying development files${R}" - cp -f shlr/sdb/include/*.h "${WINDIST}/include/libr/sdb/" + cp -f subprojects/sdb/include/*.h "${WINDIST}/include/libr/sdb/" cp -f libr/include/r_util/*.h "${WINDIST}/include/libr/r_util/" cp -f libr/include/r_anal/*.h "${WINDIST}/include/libr/r_anal/" cp -f libr/include/*.h "${WINDIST}/include/libr" diff --git a/binr/rules.mk b/binr/rules.mk index 18407476ec48a..2aaaa91ef0436 100644 --- a/binr/rules.mk +++ b/binr/rules.mk @@ -39,7 +39,7 @@ ifeq (${COMPILER},wasi) LINK+=$(SHLR)/zip/librz.a LINK+=$(SHLR)/gdb/lib/libgdbr.a LINK+=$(SHLR)/capstone/libcapstone.a -LINK+=$(SHLR)/sdb/src/libsdb.a +LINK+=$(SHLR)/../subprojects/sdb/src/libsdb.a # instead of libr.a LINK+=$(LIBR)/util/libr_util.a diff --git a/libr/Makefile b/libr/Makefile index 1e40c758b6ab1..a57131a9e4c43 100644 --- a/libr/Makefile +++ b/libr/Makefile @@ -202,7 +202,7 @@ install-includes: done ; \ done) ${INSTALL_DIR} "${DESTDIR}${INCLUDEDIR}/libr/sdb" - (cd ../shlr/sdb/include/sdb && for FILE in *.h ; do \ + (cd ../subprojects/sdb/include/sdb && for FILE in *.h ; do \ ${INSTALL_DATA} $$FILE "${DESTDIR}${INCLUDEDIR}/libr/sdb/$$FILE" ; \ done) for a in r_util r_crypto r_anal ; do \ @@ -218,7 +218,7 @@ symstall install-symlink: "${DESTDIR}${LIBDIR}/pkgconfig" \ "${DESTDIR}${LIBDIR}/radare2/${VERSION}" ; \ rm -rf "${DESTDIR}${INCLUDEDIR}/libr" && ln -fs "${PWD}/include" "${DESTDIR}${INCLUDEDIR}/libr" ; \ - rm -rf "${DESTDIR}${INCLUDEDIR}/libr/sdb" && ln -fs "${PWD}/../shlr/sdb/include/sdb" "${DESTDIR}${INCLUDEDIR}/libr/sdb" ; \ + rm -rf "${DESTDIR}${INCLUDEDIR}/libr/sdb" && ln -fs "${PWD}/../subprojects/sdb/include/sdb" "${DESTDIR}${INCLUDEDIR}/libr/sdb" ; \ $(MAKE) install-pkgconfig-symlink ; \ $(foreach lib,${LIBS}, \ ln -fs "${PWD}/$(lib)/libr_$(lib).${EXT_SO}" \ diff --git a/libr/anal/d/Makefile b/libr/anal/d/Makefile index 1044cc7b369d9..c0a7cffbe22e8 100755 --- a/libr/anal/d/Makefile +++ b/libr/anal/d/Makefile @@ -78,7 +78,7 @@ HOST_CC?=gcc F_SDB=$(addsuffix .sdb,$F) -SDBPATH=$(LTOP)/../shlr/sdb/ +SDBPATH=$(LTOP)/../subprojects/sdb/ ifeq ($(BUILD_OS),windows) BUILD_EXT_EXE=.exe else diff --git a/libr/arch/p/java.mk b/libr/arch/p/java.mk index 404961a6f3911..8daf87ef8ae88 100644 --- a/libr/arch/p/java.mk +++ b/libr/arch/p/java.mk @@ -13,4 +13,4 @@ ${TARGET_JAVA}: ${OBJ_JAVA} -o java.${EXT_SO} \ ${OBJ_JAVA} ${SHARED2_JAVA} \ $(SHLR)/java/libr_java.$(EXT_AR) \ - $(SHLR)/sdb/src/libsdb.$(EXT_AR) + $(SHLR)/../subprojects/sdb/src/libsdb.$(EXT_AR) diff --git a/libr/asm/Makefile b/libr/asm/Makefile index b8e7a5e9e1053..34c12aabd5e75 100644 --- a/libr/asm/Makefile +++ b/libr/asm/Makefile @@ -3,7 +3,8 @@ include ../../global.mk NAME=r_asm R2DEPS=r_syscall r_util r_esil r_crypto R2DEPS+=r_flag r_cons r_reg r_arch -CFLAGS+=-DR2_PLUGIN_INCORE -Iarch/include -Iarch -I../../shlr +CFLAGS+=-DR2_PLUGIN_INCORE -Iarch/include -Iarch +CFLAGS+=-I../../shlr # for spp only CURDIR=p/ include $(TOP)/libr/config.mk @@ -17,7 +18,7 @@ alle: $(MAKE) gperfs $(MAKE) plugins -SDB_PATH=../../../shlr/sdb +SDB_PATH=../../../subprojects/sdb SDB=$(SDB_PATH)/sdb gperfs: diff --git a/libr/asm/d/Makefile b/libr/asm/d/Makefile index 293b71f5c9057..4096d6034e3db 100644 --- a/libr/asm/d/Makefile +++ b/libr/asm/d/Makefile @@ -2,7 +2,7 @@ FILES=6502 8051 m68k x86 arc arm avr bpf LH5801 ppc z80 mips sparc sh xtensa FILES+=i8080 java i4004 dalvik msp430 lm32 s390 tms320 propeller v810 v850 FILES+=pic18c chip8 tricore bf pickle riscv evm sm5xx gb stm8 F_SDB=$(addsuffix .sdb,${FILES}) -SDB=../../../shlr/sdb/sdb +SDB=../../../subprojects/sdb/sdb CFLAGS+=-fvisibility=hidden LDFLAGS+=-fvisibility=hidden diff --git a/libr/bin/d/Makefile b/libr/bin/d/Makefile index d020990271b47..87d3c0be1c23e 100644 --- a/libr/bin/d/Makefile +++ b/libr/bin/d/Makefile @@ -1,7 +1,7 @@ include ../../../global.mk include ../../../config-user.mk -SDBPATH=$(LTOP)/../shlr/sdb/ +SDBPATH=$(LTOP)/../subprojects/sdb/ SDB=$(SDBPATH)/sdb P=${DESTDIR}${DATADIR}/radare2/${VERSION}/format diff --git a/libr/bin/p/cgc.mk b/libr/bin/p/cgc.mk index d0e49819c50ff..d4d9cd28c928f 100644 --- a/libr/bin/p/cgc.mk +++ b/libr/bin/p/cgc.mk @@ -2,7 +2,6 @@ OBJ_CGC=bin_cgc.o STATIC_OBJ+=${OBJ_CGC} TARGET_CGC=bin_cgc.${EXT_SO} -#LINK+=-L../../util -lr_util $(SHLR)/sdb/src/libsdb.a ifeq ($(WITHPIC),1) ALL_TARGETS+=${TARGET_CGC} diff --git a/libr/bin/p/elf.mk b/libr/bin/p/elf.mk index 8f4d33215dfa3..b540a257471c3 100644 --- a/libr/bin/p/elf.mk +++ b/libr/bin/p/elf.mk @@ -1,6 +1,5 @@ OBJ_ELF=bin_elf.o bin_dbginfo_elf.o bin_write_elf.o OBJ_ELF+=../format/elf/elf.o ../format/elf/elf_write.o -#LINK+=-L../../util -lr_util $(SHLR)/sdb/src/libsdb.a STATIC_OBJ+=${OBJ_ELF} TARGET_ELF=bin_elf.${EXT_SO} diff --git a/libr/bin/p/java.mk b/libr/bin/p/java.mk index 577c25f76f841..4d210e3adf7a2 100644 --- a/libr/bin/p/java.mk +++ b/libr/bin/p/java.mk @@ -14,4 +14,4 @@ ${TARGET_JAVA}: ${OBJ_JAVA} ${CC} $(call libname,bin_java) ${CFLAGS} ${OBJ_JAVA} \ $(LINK) $(LDFLAGS) ${SHARED2_JAVA} \ ${SHLR}/java/libr_java.${EXT_AR} \ - ${SHLR}/sdb/src/libsdb.${EXT_AR} + ${SHLR}/../subprojects/sdb/src/libsdb.${EXT_AR} diff --git a/libr/bin/p/mach0.mk b/libr/bin/p/mach0.mk index dcdcf9c7efa7f..526a9113edf1e 100644 --- a/libr/bin/p/mach0.mk +++ b/libr/bin/p/mach0.mk @@ -9,5 +9,5 @@ ALL_TARGETS+=${TARGET_MACH0} ${TARGET_MACH0}: ${OBJ_MACH0} -${CC} $(call libname,bin_mach0) ${CFLAGS} \ - ${OBJ_MACH0} ${SHLR}/sdb/src/libsdb.a \ + ${OBJ_MACH0} ${SHLR}/../subprojects/sdb/src/libsdb.a \ $(LINK) $(LDFLAGS) diff --git a/libr/bin/p/mbn.mk b/libr/bin/p/mbn.mk index 56aa1d5dfa245..af781cc549e5a 100644 --- a/libr/bin/p/mbn.mk +++ b/libr/bin/p/mbn.mk @@ -2,7 +2,6 @@ OBJ_MBN=bin_mbn.o STATIC_OBJ+=${OBJ_MBN} TARGET_MBN=bin_mbn.${EXT_SO} -#LINK+=-L../../util -lr_util $(SHLR)/sdb/src/libsdb.a ifeq ($(WITHPIC),1) ALL_TARGETS+=${TARGET_MBN} diff --git a/libr/bin/p/symbols.mk b/libr/bin/p/symbols.mk index 7b020cef62c6c..e93799087b7f5 100644 --- a/libr/bin/p/symbols.mk +++ b/libr/bin/p/symbols.mk @@ -8,5 +8,5 @@ ALL_TARGETS+=${TARGET_SYMBOLS} ${TARGET_SYMBOLS}: ${OBJ_SYMBOLS} -${CC} $(call libname,bin_mach0) ${CFLAGS} \ - ${OBJ_SYMBOLS} ${SHLR}/sdb/src/libsdb.a \ + ${OBJ_SYMBOLS} ${SHLR}/../subprojects/sdb/src/libsdb.a \ $(LINK) $(LDFLAGS) diff --git a/libr/bin/p/te.mk b/libr/bin/p/te.mk index 5b3d67480c3fd..6771f070914e9 100644 --- a/libr/bin/p/te.mk +++ b/libr/bin/p/te.mk @@ -2,7 +2,6 @@ OBJ_TE=bin_te.o ../format/te/te.o STATIC_OBJ+=${OBJ_TE} TARGET_TE=bin_te.${EXT_SO} -#LINK+=-L../../util -lr_util $(SHLR)/sdb/src/libsdb.a ALL_TARGETS+=${TARGET_TE} diff --git a/libr/core/p/a2f.mk b/libr/core/p/a2f.mk index af9831ef8fd37..a8636e12afb6e 100644 --- a/libr/core/p/a2f.mk +++ b/libr/core/p/a2f.mk @@ -9,7 +9,7 @@ ALL_TARGETS+=${CORE_TARGET_A2F} ${CORE_TARGET_A2F}: ${CORE_OBJ_A2F} ${CC} $(call libname,core_anal) ${CFLAGS} \ -o core_a2f.${EXT_SO} \ - $(SHLR)/sdb/src/libsdb.a \ + $(SHLR)/../subprojects/sdb/src/libsdb.a \ -L$(LIBR)/crypto -lr_crypto \ ${CORE_OBJ_A2F} endif diff --git a/libr/core/p/agD.mk b/libr/core/p/agD.mk index 254d8d1977672..6ce824b81084e 100644 --- a/libr/core/p/agD.mk +++ b/libr/core/p/agD.mk @@ -9,7 +9,7 @@ ALL_TARGETS+=${CORE_TARGET_AGD} ${CORE_TARGET_AGD}: ${CORE_OBJ_AGD} ${CC} $(call libname,core_anal) ${CFLAGS} \ -o core_agD.${EXT_SO} \ - $(SHLR)/sdb/src/libsdb.a \ + $(SHLR)/../subprojects/sdb/src/libsdb.a \ -L$(LIBR)/crypto -lr_crypto \ ${CORE_OBJ_AGD} endif diff --git a/libr/core/p/java.mk b/libr/core/p/java.mk index fd37829fceae9..8137fc5c47277 100644 --- a/libr/core/p/java.mk +++ b/libr/core/p/java.mk @@ -24,6 +24,6 @@ ${CORE_TARGET_JAVA}: ${CORE_OBJ_JAVA} -o core_java.${EXT_SO} \ ${CORE_OBJ_JAVA} ${CORE_SHARED2_JAVA} \ $(SHLR)/java/libr_java.$(EXT_AR) \ - $(SHLR)/sdb/src/libsdb.$(EXT_AR) \ + $(SHLR)/../subprojects/sdb/src/libsdb.$(EXT_AR) \ -L$(LIBR)/crypto -lr_crypto endif diff --git a/libr/do-ar-sh b/libr/do-ar-sh index 8142054ac5dd3..a9e238e72814c 100644 --- a/libr/do-ar-sh +++ b/libr/do-ar-sh @@ -1,6 +1,6 @@ #!/bin/sh -LIBS="libr/cons/libr_cons.a libr/util/libr_util.a libr/bin/libr_bin.a libr/anal/libr_anal.a libr/bp/libr_bp.a libr/crypto/libr_crypto.a libr/debug/libr_debug.a shlr/sdb/src/libsdb.a libr/core/libr_core.a libr/main/libr_main.a libr/fs/libr_fs.a libr/syscall/libr_syscall.a shlr/java/libr_java.a shlr/zip/librz.a libr/socket/libr_socket.a libr/anal/libr_anal.a libr/flag/libr_flag.a libr/search/libr_search.a libr/reg/libr_reg.a libr/config/libr_config.a libr/io/libr_io.a libr/bp/libr_bp.a libr/asm/libr_asm.a libr/bp/libr_bp.a libr/egg/libr_egg.a libr/anal/libr_anal.a libr/magic/libr_magic.a libr/lang/libr_lang.a libr/fs/libr_fs.a shlr/grub/libgrubfs.a shlr/capstone/libcapstone.a shlr/gdb/lib/libgdbr.a" +LIBS="libr/cons/libr_cons.a libr/util/libr_util.a libr/bin/libr_bin.a libr/anal/libr_anal.a libr/bp/libr_bp.a libr/crypto/libr_crypto.a libr/debug/libr_debug.a subprojects/sdb/src/libsdb.a libr/core/libr_core.a libr/main/libr_main.a libr/fs/libr_fs.a libr/syscall/libr_syscall.a shlr/java/libr_java.a shlr/zip/librz.a libr/socket/libr_socket.a libr/anal/libr_anal.a libr/flag/libr_flag.a libr/search/libr_search.a libr/reg/libr_reg.a libr/config/libr_config.a libr/io/libr_io.a libr/bp/libr_bp.a libr/asm/libr_asm.a libr/bp/libr_bp.a libr/egg/libr_egg.a libr/anal/libr_anal.a libr/magic/libr_magic.a libr/lang/libr_lang.a libr/fs/libr_fs.a shlr/grub/libgrubfs.a shlr/capstone/libcapstone.a shlr/gdb/lib/libgdbr.a" cd .. LIB=libr.a diff --git a/libr/io/p/shm.mk b/libr/io/p/shm.mk index 07c0f2c3e4aa3..ca0f5d0fe3233 100644 --- a/libr/io/p/shm.mk +++ b/libr/io/p/shm.mk @@ -24,4 +24,4 @@ R_IO_SHM_LINKFLAGS+=-L.. -lr_io endif $(N) p/${TARGET_SHM}: p/${OBJ_SHM} - cd p && $(CC) $(CFLAGS) -shared -L.. $(CSRC_SHM) -fPIC -o $(TARGET_SHM) -I../../include -I../../../shlr/sdb/src $(R_IO_SHM_LINKFLAGS) + cd p && $(CC) $(CFLAGS) -shared -L.. $(CSRC_SHM) -fPIC -o $(TARGET_SHM) -I../../include -I../../../subprojects/sdb/src $(R_IO_SHM_LINKFLAGS) diff --git a/libr/main/radare2.c b/libr/main/radare2.c index 88030ae94422d..aabbd8056fac5 100644 --- a/libr/main/radare2.c +++ b/libr/main/radare2.c @@ -125,11 +125,11 @@ static int r_main_version_verify(RCore *core, bool show, bool json) { } { pj_ko (pj, "sdb"); - pj_ks (pj, "destdir", "shlr/sdb"); + pj_ks (pj, "destdir", "subprojects/sdb"); pj_ks (pj, "git", "https://github.com/radareorg/sdb"); pj_ks (pj, "branch", "master"); pj_ks (pj, "license", "MIT"); - pj_ks (pj, "commit", "c4db2b24dacd25403ecb084c9b8e7840889ca236"); + pj_ks (pj, "commit", "2e24eb0616dfce5e28130660313b56db9252dd5c"); // TODO SUBPROJECTS pj_end (pj); } { diff --git a/libr/syscall/d/Makefile b/libr/syscall/d/Makefile index c0b69771b1174..1edabb7d05e72 100644 --- a/libr/syscall/d/Makefile +++ b/libr/syscall/d/Makefile @@ -27,7 +27,7 @@ HOST_CC?=gcc F_SDB=$(addsuffix .sdb,$F) -SDBPATH=$(LTOP)/../shlr/sdb/ +SDBPATH=$(LTOP)/../subprojects/sdb/ ifeq ($(BUILD_OS),windows) BUILD_EXT_EXE=.exe else diff --git a/libr/util/d/Makefile b/libr/util/d/Makefile index c7056ea972c79..dd7d75ab989bd 100644 --- a/libr/util/d/Makefile +++ b/libr/util/d/Makefile @@ -8,7 +8,8 @@ FILES+=macintosh big5 iso_646 FILES+=cyrillic_iso cyrillic_windows F_SDB=$(addsuffix .sdb,$(FILES)) -SDB=../../../shlr/sdb/sdb +# SUBPROJECTS TODO: SDB_EXE +SDB=../../../subprojects/sdb/sdb include ../../../config-user.mk include ../../../global.mk diff --git a/libr/util/sdb.mk b/libr/util/sdb.mk index 8a2043a82d797..6539165a3ffcc 100644 --- a/libr/util/sdb.mk +++ b/libr/util/sdb.mk @@ -1,5 +1,6 @@ -SDBPATH=$(SHLR)/sdb/src/ -SDBINCDIR=$(SHLR)/sdb/include +# SUBPROJECTS TODO sdb +SDBPATH=$(SHLR)/../subprojects/sdb/src/ +SDBINCDIR=$(SHLR)/../subprojects/sdb/include SDBLIB=${SDBPATH}/libsdb.a EXTRA_TARGETS+=${SDBLIB} EXTRA_PRE+=$(SDBLIB) diff --git a/shlr/Makefile b/shlr/Makefile index 14efac0b147fd..663b5c1d680c3 100644 --- a/shlr/Makefile +++ b/shlr/Makefile @@ -78,7 +78,6 @@ endif SHLR?=$(shell pwd) AR?=ar RANLIB?=ranlib -# MODS=sdb zip java mpc MODS=zip java mpc MODS+=gdb qnx ar # lz4 @@ -87,11 +86,8 @@ ifeq (1,$(WITH_GPL)) MODS+=grub endif endif -SDB_URL=https://github.com/radareorg/sdb -#SDB_URL=/Users/pancake/prg/sdb SPP_URL=https://github.com/trufae/spp PWD=$(shell pwd) -SDB_CONFIG=${PWD}/sdb-config.mk CFLAGS_SHARED=${PIC_CFLAGS} @@ -107,12 +103,6 @@ preall: libwinkd capstone-build bochs sdbs $(MAKE) -C $$MOD HAVE_VALA= ROOT="${PWD}/../" CC="${CC}" ; \ done -SDBFILES=sdb/src/.sdb${EXT_EXE} sdb/sdb${EXT_EXE} sdb/src/.sdb sdb/sdb -PREMODS=capstone gdb winkd sdb bochs ar - -clean mrproper: - rm -f ${SDBFILES} - @for MOD in ${PREMODS} ${MODS} ; do $(MAKE) -C $$MOD clean ; done ifeq ($(BUILD_OS),windows) BUILD_EXT_EXE=.exe @@ -125,10 +115,18 @@ ifneq ($(CC),cccl) PIC=-fPIC endif -SDB_HOST=sdb/sdb$(BUILD_EXT_EXE) -SDB_LIBA=sdb/src/libsdb.$(EXT_AR) +SDB_ROOT=../subprojects/sdb +SDB_HOST=$(SDB_ROOT)/sdb$(BUILD_EXT_EXE) +SDB_LIBA=$(SDB_ROOT)/src/libsdb.$(EXT_AR) + +SDBFILES=$(SDB_ROOT)/src/.sdb${EXT_EXE} $(SDB_ROOT)/sdb${EXT_EXE} $(SDB_ROOT)/src/.sdb $(SDB_ROOT)/sdb +PREMODS=capstone gdb winkd sdb bochs ar + +clean mrproper: + rm -f ${SDBFILES} + @for MOD in ${PREMODS} ${MODS} ; do $(MAKE) -C $$MOD clean ; done -$(SDB_HOST): +$(SDB_HOST): $(SDB_ROOT) $(MAKE) sdb-host HOST_CC=$(HOST_CC) CC=$(HOST_CC) $(SDB_LIBA): @@ -137,18 +135,21 @@ $(SDB_LIBA): sdbs: $(SDB_HOST) $(MAKE) $(SDB_LIBA) RANLIB="$(RANLIB)" +$(SDB_ROOT): + $(MAKE) -C ../subprojects + sdb-host: @echo @echo ">>>>>>>>" @echo "HOST SDB" @echo ">>>>>>>>" @echo - $(MAKE) -C sdb clean ; rm -f sdb/src/*.o sdb/include/sdb/version.h - $(MAKE) -C sdb/src "CC=${HOST_CC}" LDFLAGS='${HOST_LDFLAGS}' CPPFLAGS='-I$(SHLR)/sdb/include' CFLAGS='${HOST_CFLAGS} ${PIC}' bin - cp -f sdb/src/sdb${BUILD_EXT_EXE} sdb/src/.sdb${BUILD_EXT_EXE} - cp -f sdb/src/sdb${BUILD_EXT_EXE} sdb/sdb$(BUILD_EXT_EXE) + $(MAKE) -C $(SDB_ROOT) clean ; rm -f $(SDB_ROOT)/src/*.o $(SDB_ROOT)/include/sdb/version.h + $(MAKE) -C $(SDB_ROOT)/src "CC=${HOST_CC}" LDFLAGS='${HOST_LDFLAGS}' CPPFLAGS='-I$(SHLR)/sdb/include' CFLAGS='${HOST_CFLAGS} ${PIC}' bin + cp -f $(SDB_ROOT)/src/sdb${BUILD_EXT_EXE} $(SDB_ROOT)/src/.sdb${BUILD_EXT_EXE} + cp -f $(SDB_ROOT)/src/sdb${BUILD_EXT_EXE} $(SDB_ROOT)/sdb$(BUILD_EXT_EXE) rm -f $(SDB_LIBA) - -file sdb/sdb$(BUILD_EXT_EXE) + -file $(SDB_ROOT)/sdb$(BUILD_EXT_EXE) sdb-target: @echo @@ -157,18 +158,18 @@ sdb-target: @echo ">>>>>>>>>>" @echo rm -f src/libsdb.$(EXT_AR) - $(MAKE) -C sdb clean ; rm -f sdb/src/*.o ../include/sdb/version.h - $(MAKE) -C sdb/src ../include/sdb/version.h + $(MAKE) -C $(SDB_ROOT) clean ; rm -f $(SDB_ROOT)/src/*.o ../include/sdb/version.h + $(MAKE) -C $(SDB_ROOT)/src ../include/sdb/version.h ifeq ($(EXT_EXE),.wasm) - $(MAKE) -C sdb/src ARCH=xxx EXT_AR=.$(EXT_AR) RANLIB="${RANLIB}" CPPFLAGS=-I$(SHLR)/sdb/include \ + $(MAKE) -C $(SDB_ROOT)/src ARCH=xxx EXT_AR=.$(EXT_AR) RANLIB="${RANLIB}" CPPFLAGS=-I$(SHLR)/sdb/include \ CFLAGS_SHARED="${CFLAGS_SHARED} -DHAVE_MMAN=0" \ CC="${CC}" AR="${AR}" ARCH=undefined CFLAGS='${CFLAGS} -DHAVE_MMAN=0' LDFLAGS='${LDFLAGS}' libsdb.$(EXT_AR) else - $(MAKE) -C sdb/src ARCH=xxx EXT_AR=.$(EXT_AR) RANLIB="${RANLIB}" CPPFLAGS="-I$(SHLR)/sdb/include -DHAVE_SYSTEM=0" \ + $(MAKE) -C $(SDB_ROOT)/src ARCH=xxx EXT_AR=.$(EXT_AR) RANLIB="${RANLIB}" CPPFLAGS="-I$(SHLR)/sdb/include -DHAVE_SYSTEM=0" \ CFLAGS_SHARED="${CFLAGS_SHARED}" \ CC="${CC}" AR="${AR}" ARCH=undefined LDFLAGS='${LDFLAGS}' libsdb.$(EXT_AR) endif - $(RANLIB) sdb/src/libsdb.$(EXT_AR) + $(RANLIB) $(SDB_ROOT)/src/libsdb.$(EXT_AR) .PHONY: sdb-sync sync-sdb sdbclean sdb-native sdb-target SDB_F=README.md config.mk src include Makefile meson.build wasi.mk wasi.sh @@ -185,23 +186,9 @@ bochs: $(MAKE) -C bochs all sdb-clean clean-sdb: - $(MAKE) -C sdb clean - rm -f sdb/sdb.exe - rm -f sdb/src/libsdb.${EXT_AR} - -sdb-sync sync-sdb: - rm -rf sdb sdb.vc - git clone --depth 1 ${SDB_URL} sdb.vc - mkdir -p sdb - cp -rf ${SDB_SYNCFILES} sdb - rm -rf sdb.vc - rm -f include/sdb/version.h - $(MAKE) -C sdb include/sdb/version.h - mkdir -p sdb/test sdb/memcache - sed -e 's,HAVE_VALA=,HAVE_VALA=#,' sdb/config.mk > .t - mv .t sdb/config.mk - echo all clean mrproper: | tee sdb/test/Makefile > sdb/memcache/Makefile - git add sdb + $(MAKE) -C $(SDB_ROOT) clean + rm -f $(SDB_ROOT)/sdb.exe + rm -f $(SDB_ROOT)/src/libsdb.${EXT_AR} ifeq ($(WITH_LIBR),1) install: libr_shlr.${EXT_AR} diff --git a/shlr/sdb-config.mk b/shlr/sdb-config.mk deleted file mode 100644 index c257b4dfb8956..0000000000000 --- a/shlr/sdb-config.mk +++ /dev/null @@ -1,5 +0,0 @@ -include ${ROOT}/config-user.mk -HOST_CC?=gcc -#CC=${CC} -OS=${OSTYPE} -CFLAGS_SHARED=-shared -fPIC diff --git a/shlr/sdb.mk b/shlr/sdb.mk index 55eab31a65e78..02650e8f62b8f 100644 --- a/shlr/sdb.mk +++ b/shlr/sdb.mk @@ -1 +1,2 @@ -CFLAGS+=-I$(SHLR)/sdb/include +# deprecate.. move into subprojects/sdb-deps.mk +CFLAGS+=-I$(SHLR)/../subprojects/sdb/include diff --git a/shlr/sdb/Makefile b/shlr/sdb/Makefile deleted file mode 100644 index 201a387c36f56..0000000000000 --- a/shlr/sdb/Makefile +++ /dev/null @@ -1,228 +0,0 @@ -include config.mk -VALADIR=bindings/vala - -PWD=$(shell pwd) -PFX=${DESTDIR}${PREFIX} -HGFILES=`find sdb-${SDBVER} -type f | grep -v hg | grep -v swp` -ASANOPTS=address undefined signed-integer-overflow -LEAKOPTS=leak -CFLAGS_ASAN=$(addprefix -fsanitize=,$(ASANOPTS)) $(CFLAGS) -CFLAGS_LEAK=$(addprefix -fsanitize=,$(LEAKOPTS)) -MKDIR=mkdir - -all: pkgconfig include/sdb/version.h - ${MAKE} -C src -ifeq ($(BUILD_MEMCACHE),1) - ${MAKE} -C memcache -endif - -vala: -ifneq (${HAVE_VALA},) - $(MAKE) -C $(VALADIR) - $(MAKE) -C $(VALADIR)/types -else - @echo Nothing to do. -endif - -.PHONY: test sdb.js pkgconfig dist w32dista asan - -include wasi.mk - -x xxx cxx: - # $(MAKE) CC="gcc -x c++ -Wall -fpermissive" - $(MAKE) CC=g++ CFLAGS="-fPIC -x c++ -Wall -fpermissive -I../include -Werror" - -o xo xoxo ox: - g++ -o sdb $(filter-out src/ht.inc.c, src/*.c) -I include/ - -wasi wasm: $(WASI_SDK) - ${MAKE} include/sdb/version.h - CC=$(WASI_CC) CFLAGS="$(WASI_CFLAGS)" $(MAKE) CC=$(WASI_CC) -C src all WITHPIC=0 - mv src/sdb src/sdb.wasm - file src/sdb.wasm - -test: - ${MAKE} -C test - -heap: - CFLAGS=-DUSE_SDB_HEAP=1 $(MAKE) -C src all - -asan: - $(MAKE) include/sdb/version.h - CC=gcc LDFLAGS="$(CFLAGS_ASAN)" CFLAGS="$(CFLAGS_ASAN)" ${MAKE} -C src all - -asantest: - export ASAN_OPTIONS=detect_leaks=0 ; \ - CC=gcc CFLAGS="$(CFLAGS_ASAN)" ${MAKE} -C test - -leak: - $(MAKE) include/sdb/version.h - CC=gcc LDFLAGS="$(CFLAGS_LEAK)" CFLAGS="$(CFLAGS_LEAK)" $(MAKE) -C src all - -leaktest: - CC=gcc CFLAGS="$(CFLAGS_LEAK)" LDFLAGS="$(CFLAGS_LEAK)" $(MAKE) -C test - -pkgconfig: - [ -d pkgconfig ] && ${MAKE} -C pkgconfig || true - -include/sdb/version.h: - echo '#define SDB_VERSION "${SDBVER}"' > include/sdb/version.h - -CFILES=cdb.c cdb_make.c ls.c ht.c sdb.c num.c base64.c text.c -CFILES+=json.c ns.c lock.c util.c disk.c query.c array.c fmt.c main.c -EMCCFLAGS=-O2 -s EXPORTED_FUNCTIONS="['_sdb_querys','_sdb_new0']" -#EMCCFLAGS+=--embed-file sdb.data - -sdb.js: include/sdb/version.h - cd src ; emcc ${EMCCFLAGS} -I../include -o ../sdb.js ${CFILES} - -clean: - rm -f include/sdb/version.h - $(MAKE) -C src clean - $(MAKE) -C memcache clean - $(MAKE) -C test clean -ifneq (${HAVE_VALA},) - ${MAKE} -C $(VALADIR) clean -endif - -dist: - rm -f sdb-${SDBVER}.tar.gz - rm -rf sdb-${SDBVER} - git clone . sdb-${SDBVER} - rm -rf sdb-${SDBVER}/.git* - tar czvf sdb-${SDBVER}.tar.gz sdb-${SDBVER} - pub sdb-${SDBVER}.tar.gz - rm -rf sdb-${SDBVER} - -w32dist: - rm -f sdb-${SDBVER}.zip - rm -rf sdb-${SDBVER} - mkdir -p sdb-${SDBVER} - cp src/sdb.exe sdb-${SDBVER} - zip -r sdb-${SDBVER}.zip sdb-${SDBVER} - rm -rf sdb-${SDBVER} - -install-dirs: - $(INSTALL_DIR) ${DESTDIR}${MANDIR} ${DESTDIR}${LIBDIR}/pkgconfig ${DESTDIR}${BINDIR} - $(INSTALL_DIR) ${DESTDIR}${DATADIR}/vala/vapi ${DESTDIR}${INCDIR}/sdb - -INCFLS=sdb.h version.h cdb.h ht_uu.h ht_up.h ht_pp.h types.h heap.h -INCFLS+=ls.h cdb_make.h buffer.h config.h ht.h dict.h set.h ht_inc.h -INCFLS+=rangstr.h asserts.h cwisstable.h gcc_stdatomic.h msvc_stdatomic.h -INCFILES=$(addprefix include/sdb/,$(INCFLS)) - -install: pkgconfig install-dirs - $(INSTALL_MAN) src/sdb.1 ${DESTDIR}${MANDIR} - $(INSTALL_LIB) src/libsdb$(EXT_SO) ${DESTDIR}${LIBDIR} - $(INSTALL_DATA) src/libsdb$(EXT_AR) ${DESTDIR}${LIBDIR} - -if [ "$(EXT_SO)" != "$(SOVER)" ]; then \ - cd ${DESTDIR}${LIBDIR} ; \ - mv libsdb$(EXT_SO) libsdb$(SOVER) ; \ - ln -s libsdb$(SOVER) libsdb$(EXT_SO) ; \ - ln -s libsdb$(SOVER) libsdb$(EXT_SO).$(SOVERSION) ; \ - fi - mkdir -p $(DESTDIR)/$(INCDIR)/sdb - $(INSTALL_DATA) $(INCFILES) $(DESTDIR)$(INCDIR)/sdb - $(INSTALL_PROGRAM) src/sdb $(DESTDIR)$(BINDIR) -ifeq ($(BUILD_MEMCACHE),1) - $(INSTALL_DATA) memcache/libmcsdb.a ${DESTDIR}${LIBDIR} - $(INSTALL_DATA) memcache/mcsdb.h ${DESTDIR}${INCDIR}/sdb - $(INSTALL_PROGRAM) memcache/mcsdbd ${DESTDIR}${BINDIR} - $(INSTALL_PROGRAM) memcache/mcsdbc ${DESTDIR}${BINDIR} - $(INSTALL_DATA) pkgconfig/mcsdb.pc ${DESTDIR}${LIBDIR}/pkgconfig -endif - $(INSTALL_DATA) pkgconfig/sdb.pc ${DESTDIR}${LIBDIR}/pkgconfig -ifneq (${HAVE_VALA},) - test -f ${VALADIR}/types/sdbtypes.h || $(MAKE) -C $(VALADIR)/types - $(INSTALL_DATA) ${VALADIR}/sdb.vapi ${DESTDIR}${DATADIR}/vala/vapi - cd ${VALADIR}/types && ${MAKE} install DESTDIR=${DESTDIR} PREFIX=${PREFIX} -ifeq ($(BUILD_MEMCACHE),1) - $(INSTALL_DATA) ${VALADIR}/mcsdb.vapi ${DESTDIR}${DATADIR}/vala/vapi -endif -endif - - -PGOFLAG=-fprofile-instr-generate -# PGOFLAG=-fcs-profile-generate -# PGOFLAG=-fprofile-generate -# PROFDATA=/opt/homebrew/Cellar//llvm/16.0.4/bin/llvm-profdata -PROFDATA=xcrun llvm-profdata -pgo: - $(MAKE) clean - $(MAKE) CFLAGS="-O3 $(PGOFLAG)" LDFLAGS="$(PGOFLAG)" - rm -f test/test-*.prof - export LLVM_PROFILE_FILE="code-%p.prof" ; $(MAKE) -C test \ - CFLAGS="-O3 $(PGOFLAG)" LDFLAGS="$(PGOFLAG)" - $(PROFDATA) merge -sparse -output=code.prof test/co*.prof - rm -f test/test-*.prof - $(MAKE) clean - $(MAKE) CFLAGS="-O3 -fprofile-use=$(shell pwd)/code.prof" - touch code.prof -# xcrun llvm-cov show src/sdb -instr-profile=$(shell pwd)/code.prof - -deinstall uninstall: - rm -rf ${DESTDIR}${INCDIR}/sdb - rm -f ${DESTDIR}${BINDIR}/sdb - rm -f ${DESTDIR}${BINDIR}/mcsdbc - rm -f ${DESTDIR}${BINDIR}/mcsdbd - rm -f ${DESTDIR}${LIBDIR}/libsdb.* - rm -f ${DESTDIR}${LIBDIR}/libmcsdb.a - rm -f ${DESTDIR}${LIBDIR}/pkgconfig/sdb.pc - rm -f ${DESTDIR}${LIBDIR}/pkgconfig/mcsdb.pc - rm -f ${DESTDIR}${MANDIR}/sdb.1 -ifneq (${HAVE_VALA},) - rm -f ${DESTDIR}${DATADIR}/vala/vapi/sdb.vapi - rm -f ${DESTDIR}${DATADIR}/vala/vapi/mcsdb.vapi - cd ${VALADIR}/types && ${MAKE} uninstall DESTDIR=${DESTDIR} PREFIX=${PREFIX} -endif - -symstall: install-dirs - cd src && for a in libsdb.* ; do ln -fs ${PWD}/src/$$a ${DESTDIR}${LIBDIR}/$$a ; done - ln -fs ${PWD}/src/sdb.1 ${DESTDIR}${MANDIR}/sdb.1 - ln -fs ${PWD}/src/sdb ${DESTDIR}${BINDIR} - mkdir -p ${DESTDIR}${INCDIR}/sdb - ln -fs ${PWD}/include/sdb/sdb.h ${DESTDIR}${INCDIR}/sdb - ln -fs ${PWD}/include/sdb/version.h ${DESTDIR}${INCDIR}/sdb - ln -fs ${PWD}/include/sdb/cdb.h ${DESTDIR}${INCDIR}/sdb - ln -fs ${PWD}/include/sdb/ht_uu.h ${DESTDIR}${INCDIR}/sdb - ln -fs ${PWD}/include/sdb/ht_up.h ${DESTDIR}${INCDIR}/sdb - ln -fs ${PWD}/include/sdb/ht_pp.h ${DESTDIR}${INCDIR}/sdb - ln -fs ${PWD}/include/sdb/types.h ${DESTDIR}${INCDIR}/sdb - ln -fs ${PWD}/include/sdb/ls.h ${DESTDIR}${INCDIR}/sdb - ln -fs ${PWD}/include/sdb/cdb_make.h ${DESTDIR}${INCDIR}/sdb - ln -fs ${PWD}/include/sdb/buffer.h ${DESTDIR}${INCDIR}/sdb - ln -fs ${PWD}/include/sdb/config.h ${DESTDIR}${INCDIR}/sdb -ifneq (${HAVE_VALA},) - $(MKDIR) -p ${DESTDIR}$(VAPIDIR) - ln -fs ${PWD}/bindings/vala/sdb.pc ${DESTDIR}${LIBDIR}/pkgconfig - ln -fs ${PWD}/bindings/vala/mcsdb.pc ${DESTDIR}${LIBDIR}/pkgconfig - ln -fs ${PWD}/bindings/vala/sdb.vapi ${DESTDIR}$(VAPIDIR) - ln -fs ${PWD}/bindings/vala/mcsdb.vapi ${DESTDIR}$(VAPIDIR) - ln -fs ${PWD}/bindings/vala/sdb.vapi ${DESTDIR}$(VAPIDIR) - ln -fs ${PWD}/bindings/vala/mcsdb.vapi ${DESTDIR}$(VAPIDIR) - cd ${VALADIR}/types && ${MAKE} symstall DESTDIR=${DESTDIR} PREFIX=${PREFIX} -endif - -# windows compiler prefix -# travis/debian -WCP=i386-mingw32 -# mxe -#WCP=i686-pc-mingw32 - -w32: include/sdb/version.h - cd src ; \ - ${MAKE} OS=w32 WCP=${WCP} CC=${WCP}-gcc AR=${WCP}-ar RANLIB=${WCP}-ranlib sdb.exe - -# ios toolchain -IOS_CC=$(shell xcrun --sdk iphoneos --find clang) -isysroot $(shell xcrun --sdk iphoneos --show-sdk-path) -arch armv7 -arch arm64 -IOS_AR=$(shell xcrun --sdk iphoneos --find ar) -IOS_RL=$(shell xcrun --sdk iphoneos --find ranlib) - -ios: include/sdb/version.h - ${MAKE} CFLAGS=-DUSE_DLSYSTEM=1 OS=Darwin ARCH=arm CC="${IOS_CC}" AR="${IOS_AR}" RANLIB="${IOS_RL}" HAVE_VALA= all - -v version: - @echo $(SDBVER) - -.PHONY: all ${VALADIR} clean dist w32 ios v version -.PHONY: install-dirs install uninstall deinstall symstall diff --git a/shlr/sdb/README.md b/shlr/sdb/README.md deleted file mode 100644 index 5d8384e416d92..0000000000000 --- a/shlr/sdb/README.md +++ /dev/null @@ -1,119 +0,0 @@ -SDB (string database) -===================== - -sdb is a simple string key/value database based on djb's cdb -disk storage and supports JSON and arrays introspection. - -mcsdbd is a memcache server with disk storage based on sdb. -It is distributed as a standalone binary and a library. - -There's also the sdbtypes: a vala library that implements -several data structures on top of an sdb or a memcache instance. - -[![GHA](https://github.com/radareorg/sdb/workflows/ci/badge.svg)](https://github.com/radareorg/sdb/actions?query=workflow%3Aci) -[![COV](https://scan.coverity.com/projects/1651/badge.svg)](https://scan.coverity.com/projects/1651) - -Author ------- -pancake - -Contains --------- -* namespaces (multiple sdb paths) -* atomic database sync (never corrupted) -* bindings for vala, luvit, newlisp and nodejs -* command-line frontend for sdb databases -* memcache client and server with sdb backend -* arrays support (syntax sugar) -* json parser/getter (js0n.c) - -Rips ----- -* disk storage based on cdb code -* linked lists from r2 api - -Compilation ------------ -For native builds just type `make`. Everything will be compiled twice to get the .dylib and .a and sdb in PIC and nonPIC modes. - -To compile with Emscripten for Javascript: - - make CC=emcc EXT_EXE=.js - -To crosscompile with meson: - -``` -$ cat > cross-file.txt <=0.6): - -``` -$ sdb - '[]list=1,2' '[0]list' '[0]list=foo' '[]list' '[+1]list=bar' -1 -foo -2 -``` - -Let's play with json: - -``` -$ sdb d g='{"foo":1,"bar":{"cow":3}}' -$ sdb d g:bar.cow -3 -$ sdb - user='{"id":123}' user:id=99 user:id -99 -``` - -Using the command-line without any disk database: - -``` -$ sdb - foo=bar foo a=3 +a -a -bar -4 -3 - -$ sdb - -foo=bar -foo -bar -a=3 -+a -4 --a -3 -``` - -Remove the database - -``` -$ rm -f d -``` diff --git a/shlr/sdb/config.mk b/shlr/sdb/config.mk deleted file mode 100644 index 96a381dc1277f..0000000000000 --- a/shlr/sdb/config.mk +++ /dev/null @@ -1,145 +0,0 @@ -PREFIX?=/usr -BINDIR=${PREFIX}/bin -LIBDIR=${PREFIX}/lib -DATADIR=${PREFIX}/share -INCDIR=${PREFIX}/include -VAPIDIR=${DATADIR}/vala/vapi/ -MANDIR=${DATADIR}/man/man1 - -SDBVER=2.0.1 - -BUILD_MEMCACHE=0 - -INSTALL?=install - -ifeq ($(INSTALL),cp) -INSTALL_DIR=mkdir -p -INSTALL_DATA=cp -f -INSTALL_PROGRAM=cp -f -INSTALL_SCRIPT=cp -f -INSTALL_MAN=cp -f -INSTALL_LIB=cp -f -else -INSTALL_DIR=$(INSTALL) -d -INSTALL_DATA=$(INSTALL) -m 644 -INSTALL_PROGRAM=$(INSTALL) -m 755 -INSTALL_SCRIPT=$(INSTALL) -m 755 -INSTALL_MAN=$(INSTALL) -m 444 -INSTALL_LIB=$(INSTALL) -c -endif - -OS=$(shell uname) -OSTYPE?=$(shell uname -s) -ARCH?=$(shell uname -m) - -# link time optimization -#CFLAGS_STD=-std=gnu99 -flto -O2 - -CFLAGS_STD=-std=gnu99 -ifeq (,$(findstring AIX,${OSTYPE})) -CFLAGS_STD+=-D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -endif - -#CFLAGS+=-Wno-initializer-overrides -CFLAGS:=${CFLAGS_STD} $(CFLAGS) - -# Hack to fix clang warnings -ifeq ($(CC),cc) -CFLAGS+=$(shell gcc -v 2>&1 | grep -q LLVM && echo '-Wno-initializer-overrides') -endif -CFLAGS+=-Wall -CFLAGS+=-fPIC -CFLAGS+=-Wsign-compare -# some old gcc doesnt support this -# CFLAGS+=-Wmissing-field-initializers -#CFLAGS+=-O3 -# CFLAGS+=-g -Wall -O0 -#CFLAGS+=-g -#LDFLAGS+=-g -flto - -HAVE_VALA=#$(shell valac --version 2> /dev/null) -# This is hacky -HOST_CC?=gcc -RANLIB?=ranlib - -AR?=ar -CC?=gcc -EXT_EXE= -EXT_SO=.so -EXT_AR=.a - -ifneq (,$(findstring MINGW32,${OSTYPE})) -OS=w32 -CC=gcc -else -ifeq (${OS},w32) -WCP?=i386-mingw32 -CC=${WCP}-gcc -AR?=${WCP}-ar -endif -endif - -#LDFLAGS_SHARED?=-fPIC -shared -LDFLAGS_SHARED?=-shared - -ifeq (${OS},w32) -EXT_EXE=.exe -EXT_AR=.lib -EXT_SO=.dll -LDFLAGS_SHARED=-shared -endif - -# create .d files -ifeq (,$(findstring tcc,${CC})) -CFLAGS+=-MMD -else -CFLAGS+=-MD -endif - -ifeq (${OS},w32) -OSTYPE=MINGW32 -endif - -ifneq (,$(findstring MINGW,${OSTYPE})$(findstring MSYS,${OSTYPE})$(findstring CYGWIN,${OSTYPE})) -EXT_SO=.dll -EXT_AR=.a -SOVER=${EXT_SO} -CFLAGS+=-DUNICODE -D_UNICODE -else -EXT_SO=.so -SOVER=${EXT_SO}.${SDBVER} -endif -ifeq (${OS},Darwin) -EXT_SO=.dylib -SOVER=.dylib -LDFLAGS+=-dynamic -LDFLAGS_SHARED+=-dynamiclib - ifeq (${ARCH},i386) -#CC+=-arch i386 -CC+=-arch x86_64 - endif -else - ifneq (,$(findstring CYGWIN,${OSTYPE})) -CFLAGS+=-D__CYGWIN__=1 -LDFLAGS_SHARED?=-shared - else - ifneq (,$(findstring MINGW32,${OSTYPE})) -CFLAGS+=-DMINGW32=1 - else -CFLAGS+=-fPIC -SOVERSION=0 -LDFLAGS_SHARED?=-fPIC - endif - endif -LDFLAGS_SHARED+=-Wl,-soname,libsdb.so.$(SOVERSION) -endif - -ifeq ($(MAKEFLAGS),s) -SILENT=1 -else -SILENT= -endif - -ifneq (${SDB_CONFIG},) -include ${SDB_CONFIG} -endif diff --git a/shlr/sdb/include/sdb/asserts.h b/shlr/sdb/include/sdb/asserts.h deleted file mode 100644 index c160ad7949f00..0000000000000 --- a/shlr/sdb/include/sdb/asserts.h +++ /dev/null @@ -1,92 +0,0 @@ -#ifndef SDB_ASSERTS_H -#define SDB_ASSERTS_H - -#if defined (__cplusplus) -extern "C" { -#endif - -#if defined (__GNUC__) && defined (__cplusplus) -#define SDB_FUNCTION ((const char*) (__PRETTY_FUNCTION__)) -#elif defined(__STDC__) && defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L -#define SDB_FUNCTION ((const char*) (__func__)) -#elif defined (__GNUC__) || (defined(_MSC_VER) && (_MSC_VER > 1300)) -#define SDB_FUNCTION ((const char*) (__FUNCTION__)) -#else -#warning Do not know how to get function name in this setup -#define SDB_FUNCTION ((const char*) ("???")) -#endif - -/* - * SDB_CHECKS_LEVEL determines the behaviour of the sdb_return_* set of functions. - * - * 0: completely disable every function and make them like no-operation - * 1: silently enable checks. Check expressions and do return, but do not log anything - * 2: enable checks and logging (DEFAULT) - * 3: transform them into real assertion - */ -#ifndef SDB_CHECKS_LEVEL -#define SDB_CHECKS_LEVEL 2 -#endif - -#if SDB_CHECKS_LEVEL == 0 - -#define sdb_return_if_fail(expr) do { ; } while(0) -#define sdb_return_val_if_fail(expr, val) do { ; } while(0) - -#elif SDB_CHECKS_LEVEL == 1 || SDB_CHECKS_LEVEL == 2 // SDB_CHECKS_LEVEL - -#if SDB_CHECKS_LEVEL == 1 -#define SDB_LOG_(fmt, ...) -#else -#define SDB_LOG_(fmt, ...) eprintf (fmt, __VA_ARGS__) -#endif - -/** - * sdb_return_if_fail: - * @expr: the expression to check - * - * Verifies that the expression @expr, usually representing a precondition, - * evaluates to `true`. If the function returns a value, use - * sdb_return_val_if_fail() instead. - * - * If @expr evaluates to %FALSE, the current function should be considered to - * have undefined behaviour (a programmer error). The only correct solution - * to such an error is to change the module that is calling the current - * function, so that it avoids this incorrect call. - * - * To make this undefined behaviour visible, if @expr evaluates to %FALSE, - * the result is usually that a critical message is logged and the current - * function returns. - */ -#define sdb_return_if_fail(expr) \ - do { \ - if (!(expr)) { \ - SDB_LOG_ ("%s: assertion '%s' failed (line %d)", SDB_FUNCTION, #expr, __LINE__); \ - return; \ - } \ - } while (0) - -#define sdb_return_val_if_fail(expr, val) \ - do { \ - if (!(expr)) { \ - SDB_LOG_ ("%s: assertion '%s' failed (line %d)", SDB_FUNCTION, #expr, __LINE__); \ - return (val); \ - } \ - } while (0) - -#else // SDB_CHECKS_LEVEL - -#include - -#define sdb_return_if_fail(expr) do { assert (expr); } while(0) -#define sdb_return_val_if_fail(expr, val) do { assert (expr); } while(0) -#define sdb_return_if_reached() do { assert (false); } while(0) -#define sdb_return_val_if_reached(val) do { assert (false); } while(0) - -#endif // SDB_CHECKS_LEVEL - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/shlr/sdb/include/sdb/buffer.h b/shlr/sdb/include/sdb/buffer.h deleted file mode 100644 index f26a6832ad226..0000000000000 --- a/shlr/sdb/include/sdb/buffer.h +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef BUFFER_H -#define BUFFER_H - -#include "types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef int (*BufferOp)(int, const char *, int); - -typedef struct buffer { - char *x; - unsigned int p; - unsigned int n; - int fd; - BufferOp op; -} buffer; - -#define BUFFER_INIT(op,fd,buf,len) { (buf), 0, (len), (fd), (op) } -#define BUFFER_INSIZE 8192 -#define BUFFER_OUTSIZE 8192 - -#if 0 -void buffer_initialize(buffer *,BufferOp,int,char *,unsigned int); - -int buffer_flush(buffer *); -int buffer_put(buffer *,const char *,unsigned int); -int buffer_putalign(buffer *,const char *,unsigned int); -int buffer_putflush(buffer *,const char *,unsigned int); -int buffer_get(buffer *,char *,unsigned int); -int buffer_bget(buffer *,char *,unsigned int); -int buffer_feed(buffer *); - -char *buffer_peek(buffer *); -void buffer_seek(buffer *,unsigned int); - -#endif - -#define buffer_PUTC(s,c) \ - ( ((s)->n != (s)->p) \ - ? ( (s)->x[(s)->p++] = (c), 0 ) \ - : buffer_put((s),&(c),1) \ - ) - -#define buffer_PEEK(s) ( (s)->x + (s)->n ) -#define buffer_SEEK(s,len) ( ( (s)->p -= (len) ) , ( (s)->n += (len) ) ) - -#define buffer_GETC(s,c) \ - ( ((s)->p > 0) \ - ? ( *(c) = (s)->x[(s)->n], buffer_SEEK((s),1), 1 ) \ - : buffer_get((s),(c),1) \ - ) - -int buffer_copy(buffer *,buffer *); - -// WTF GLOBALS -#if 0 -extern buffer *buffer_0; -extern buffer *buffer_0small; -extern buffer *buffer_1; -extern buffer *buffer_1small; -extern buffer *buffer_2; -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/shlr/sdb/include/sdb/cdb.h b/shlr/sdb/include/sdb/cdb.h deleted file mode 100644 index 565530e8df02d..0000000000000 --- a/shlr/sdb/include/sdb/cdb.h +++ /dev/null @@ -1,47 +0,0 @@ -/* Public domain. */ - -#ifndef CDB_H -#define CDB_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include "types.h" - -#define KVLSZ 4 -#define CDB_MAX_KEY 0xff -#define CDB_MAX_VALUE 0xffffff - -#define CDB_HASHSTART 5381 - -struct cdb { - char *map; /* 0 if no map is available */ - int fd; /* filedescriptor */ - ut32 size; /* initialized if map is nonzero */ - ut32 loop; /* number of hash slots searched under this key */ - ut32 khash; /* initialized if loop is nonzero */ - ut32 kpos; /* initialized if loop is nonzero */ - ut32 hpos; /* initialized if loop is nonzero */ - ut32 hslots; /* initialized if loop is nonzero */ - ut32 dpos; /* initialized if cdb_findnext() returns 1 */ - ut32 dlen; /* initialized if cdb_findnext() returns 1 */ -}; - -/* TODO THIS MUST GTFO! */ -bool cdb_getkvlen(struct cdb *db, ut32 *klen, ut32 *vlen, ut32 pos); -void cdb_free(struct cdb *); -bool cdb_init(struct cdb *, int fd); -void cdb_findstart(struct cdb *); -bool cdb_read(struct cdb *, char *, unsigned int, ut32); -int cdb_findnext(struct cdb *, ut32 u, const char *, ut32); - -#define cdb_datapos(c) ((c)->dpos) -#define cdb_datalen(c) ((c)->dlen) - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/shlr/sdb/include/sdb/cdb_make.h b/shlr/sdb/include/sdb/cdb_make.h deleted file mode 100644 index d226bcfa4cd21..0000000000000 --- a/shlr/sdb/include/sdb/cdb_make.h +++ /dev/null @@ -1,40 +0,0 @@ -/* Public domain. */ - -#ifndef CDB_MAKE_H -#define CDB_MAKE_H - -#include "buffer.h" -#include "types.h" - -#define CDB_HPLIST 1000 - -struct cdb_hp { ut32 h; ut32 p; } ; - -struct cdb_hplist { - struct cdb_hp hp[CDB_HPLIST]; - struct cdb_hplist *next; - int num; -}; - -struct cdb_make { - char bspace[8192]; - char final[1024]; - ut32 count[256]; - ut32 start[256]; - struct cdb_hplist *head; - struct cdb_hp *split; /* includes space for hash */ - struct cdb_hp *hash; - ut32 numentries; - ut32 memsize; - buffer b; - ut32 pos; - int fd; -}; - -int cdb_make_start(struct cdb_make *, int); -int cdb_make_addbegin(struct cdb_make *, unsigned int, unsigned int); -int cdb_make_addend(struct cdb_make *, unsigned int, unsigned int,ut32); -int cdb_make_add(struct cdb_make *, const char *, unsigned int, const char *, unsigned int); -int cdb_make_finish(struct cdb_make *); - -#endif diff --git a/shlr/sdb/include/sdb/config.h b/shlr/sdb/include/sdb/config.h deleted file mode 100644 index 7eaa88c7d95dd..0000000000000 --- a/shlr/sdb/include/sdb/config.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef CONFIG_H -#define CONFIG_H - -#define SDB_KEYSIZE 32 -/* only available on linux, and some distros require -lrt */ -#define USE_MONOTONIC_CLOCK 0 - -#if SDB_KEYSIZE == 32 -#define SDB_KT ut32 -#elif SDB_KEYSIZE == 64 -#define SDB_KT ut64 -#else -#error Invalid key size -#endif - -#endif diff --git a/shlr/sdb/include/sdb/cwisstable.h b/shlr/sdb/include/sdb/cwisstable.h deleted file mode 100644 index 9efacbc57406c..0000000000000 --- a/shlr/sdb/include/sdb/cwisstable.h +++ /dev/null @@ -1,3018 +0,0 @@ -// Copyright 2022 Google LLC -// Copyright 2024 radare2 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// THIS IS A GENERATED FILE! DO NOT EDIT DIRECTLY! -// Generated using unify.py, by concatenating, in order: -// #include "cwisstable/internal/base.h" -// #include "cwisstable/internal/bits.h" -// #include "cwisstable/internal/control_byte.h" -// #include "cwisstable/internal/capacity.h" -// #include "cwisstable/internal/probe.h" -// #include "cwisstable/internal/absl_hash.h" -// #include "cwisstable/hash.h" -// #include "cwisstable/policy.h" -// #include "cwisstable/internal/raw_table.h" -// #include "cwisstable/declare.h" - -#ifndef CWISSTABLE_H_ -#define CWISSTABLE_H_ - -#if defined(__APPLE__) && (defined(__ppc__) || defined(__powerpc__)) -#define CWISS_IS_MACPPC 1 -#define CWISS_THREAD_LOCAL -#else -#define CWISS_IS_MACPPC 0 -#endif - -#include -#include -#if !CWISS_IS_MACPPC -#include -#endif -#include -#include -#include -#include -#include -#include - -// #if __STDC_VERSION__ < 201112L -// This requires C11 -#undef static_assert -#define static_assert(x,y) -// #endif - -/// cwisstable/internal/base.h ///////////////////////////////////////////////// -/// Feature detection and basic helper macros. - -/// C++11 compatibility macros. -/// -/// Atomic support, due to incompatibilities between C++ and C11 atomic syntax. -/// - `CWISS_ATOMIC_T(Type)` names an atomic version of `Type`. We must use this -/// instead of `_Atomic(Type)` to name an atomic type. -/// - `CWISS_ATOMIC_INC(value)` will atomically increment `value` without -/// performing synchronization. This is used as a weak entropy source -/// elsewhere. -/// -/// `extern "C"` support via `CWISS_END_EXTERN` and `CWISS_END_EXTERN`, -/// which open and close an `extern "C"` block in C++ mode. -#ifdef __cplusplus -#include - -#define CWISS_BEGIN_EXTERN extern "C" { -#define CWISS_END_EXTERN } -#else -#if _MSC_VER -// #include "msvc_stdatomic.h" -#else -#if __STDC_VERSION__ >= 201112L -#include -#else -#include "gcc_stdatomic.h" -#endif -#endif - -#define CWISS_BEGIN_EXTERN -#define CWISS_END_EXTERN -#endif - -/// Compiler detection macros. -/// -/// The following macros are defined: -/// - `CWISS_IS_CLANG` detects Clang. -/// - `CWISS_IS_GCC` detects GCC (and *not* Clang pretending to be GCC). -/// - `CWISS_IS_MSVC` detects MSCV (and *not* clang-cl). -/// - `CWISS_IS_GCCISH` detects GCC and GCC-mode Clang. -/// - `CWISS_IS_MSVCISH` detects MSVC and clang-cl. -#ifdef __clang__ -#define CWISS_IS_CLANG 1 -#else -#define CWISS_IS_CLANG 0 -#endif -#if defined(__GNUC__) -#define CWISS_IS_GCCISH 1 -#else -#define CWISS_IS_GCCISH 0 -#endif -#if defined(_MSC_VER) -#define CWISS_IS_MSVCISH 1 -#else -#define CWISS_IS_MSVCISH 0 -#endif -#define CWISS_IS_GCC (CWISS_IS_GCCISH && !CWISS_IS_CLANG) -#define CWISS_IS_MSVC (CWISS_IS_MSVCISH && !CWISS_IS_CLANG) - -#define CWISS_PRAGMA(pragma_) _Pragma(#pragma_) - -#if CWISS_IS_GCCISH -#define CWISS_GCC_PUSH CWISS_PRAGMA(GCC diagnostic push) -#define CWISS_GCC_ALLOW(w_) CWISS_PRAGMA(GCC diagnostic ignored w_) -#define CWISS_GCC_POP CWISS_PRAGMA(GCC diagnostic pop) -#else -#define CWISS_GCC_PUSH -#define CWISS_GCC_ALLOW(w_) -#define CWISS_GCC_POP -#endif - -/// Atomic support, due to incompatibilities between C++ and C11 atomic syntax. -/// - `CWISS_ATOMIC_T(Type)` names an atomic version of `Type`. We must use this -/// instead of `_Atomic(Type)` to name an atomic type. -/// - `CWISS_ATOMIC_INC(value)` will atomically increment `value` without -/// performing synchronization. This is used as a weak entropy source -/// elsewhere. -/// -/// MSVC, of course, being that it does not support _Atomic in C mode, forces us -/// into `volatile`. This is *wrong*, but MSVC certainly won't miscompile it any -/// worse than it would a relaxed atomic. It doesn't matter for our use of -/// atomics. -#ifdef __cplusplus -#include -#define CWISS_ATOMIC_T(Type_) volatile std::atomic -#define CWISS_ATOMIC_INC(val_) (val_).fetch_add(1, std::memory_order_relaxed) -#elif CWISS_IS_MSVC || CWISS_IS_MACPPC -#define CWISS_ATOMIC_T(Type_) volatile Type_ -#define CWISS_ATOMIC_INC(val_) (val_ += 1) -#else -#define CWISS_ATOMIC_T(Type_) volatile _Atomic(Type_) -#define CWISS_ATOMIC_INC(val_) \ - atomic_fetch_add_explicit(&(val_), 1, memory_order_relaxed) -#endif - -/// Warning control around `CWISS` symbol definitions. These macros will -/// disable certain false-positive warnings that `CWISS` definitions tend to -/// emit. -#define CWISS_BEGIN \ - CWISS_GCC_PUSH \ - CWISS_GCC_ALLOW("-Wunused-function") \ - CWISS_GCC_ALLOW("-Wunused-parameter") \ - CWISS_GCC_ALLOW("-Wcast-qual") \ - CWISS_GCC_ALLOW("-Wmissing-field-initializers") -#define CWISS_END CWISS_GCC_POP - -/// `CWISS_HAVE_SSE2` is nonzero if we have SSE2 support. -/// -/// `-DCWISS_HAVE_SSE2` can be used to override it; it is otherwise detected -/// via the usual non-portable feature-detection macros. -#ifndef CWISS_HAVE_SSE2 -#if defined(__SSE2__) || \ - (CWISS_IS_MSVCISH && \ - (defined(_M_X64) || (defined(_M_IX86) && _M_IX86_FP >= 2))) -#define CWISS_HAVE_SSE2 1 -#else -#define CWISS_HAVE_SSE2 0 -#endif -#endif - -/// `CWISS_HAVE_SSSE2` is nonzero if we have SSSE2 support. -/// -/// `-DCWISS_HAVE_SSSE2` can be used to override it; it is otherwise detected -/// via the usual non-portable feature-detection macros. -#ifndef CWISS_HAVE_SSSE3 -#ifdef __SSSE3__ -#define CWISS_HAVE_SSSE3 1 -#else -#define CWISS_HAVE_SSSE3 0 -#endif -#endif - -#if CWISS_HAVE_SSE2 -#include -#endif - -#if CWISS_HAVE_SSSE3 -#if !CWISS_HAVE_SSE2 -#error "Bad configuration: SSSE3 implies SSE2!" -#endif -#include -#endif - -/// `CWISS_HAVE_MUL128` is nonzero if there is compiler-specific -/// intrinsics for 128-bit multiplication. -/// -/// `-DCWISS_HAVE_MUL128=0` can be used to explicitly fall back onto the pure -/// C implementation. -#ifndef DCWISS_HAVE_MUL128 -#if defined(__SIZEOF_INT128__) && \ - ((CWISS_IS_CLANG && !CWISS_IS_MSVC) || CWISS_IS_GCC) -#define DCWISS_HAVE_MUL128 1 -#else -#define DCWISS_HAVE_MUL128 0 -#endif -#endif - -#ifdef __aarch64__ -#define USE_128_MIX 0 -#elif DCWISS_HAVE_MUL128 -#define USE_128_MIX 1 -#else -#define USE_128_MIX 0 -#endif - -/// `CWISS_ALIGN` is a cross-platform `alignas()`: specifically, MSVC doesn't -/// quite believe in it. -#if CWISS_IS_MSVC -#define CWISS_alignas(align_) __declspec(align(align_)) - -#else -#if !CWISS_IS_MACPPC -#include -#endif - -#ifdef alignas -#define CWISS_alignas(align_) alignas(align_) -#else -#define CWISS_alignas(align_) __attribute__((aligned(align_))) -#endif - -#endif - -#ifndef alignof -#define alignof __alignof -#endif - -#ifdef _MSC_VER -#define SDB_MAYBE_UNUSED -#else -#define SDB_MAYBE_UNUSED __attribute__((unused)) -#endif - -/// `CWISS_HAVE_BUILTIN` will, in Clang, detect whether a Clang language -/// extension is enabled. -/// -/// See https://clang.llvm.org/docs/LanguageExtensions.html. -#ifdef __has_builtin -#define CWISS_HAVE_CLANG_BUILTIN(x_) __has_builtin(x_) -#else -#define CWISS_HAVE_CLANG_BUILTIN(x_) 0 -#endif - -/// `CWISS_HAVE_GCC_ATTRIBUTE` detects if a particular `__attribute__(())` is -/// present. -/// -/// GCC: https://gcc.gnu.org/gcc-5/changes.html -/// Clang: https://clang.llvm.org/docs/LanguageExtensions.html -#ifdef __has_attribute -#define CWISS_HAVE_GCC_ATTRIBUTE(x_) __has_attribute(x_) -#else -#define CWISS_HAVE_GCC_ATTRIBUTE(x_) 0 -#endif - -#ifdef __has_feature -#define CWISS_HAVE_FEATURE(x_) __has_feature(x_) -#else -#define CWISS_HAVE_FEATURE(x_) 0 -#endif - -/// `CWISS_THREAD_LOCAL` expands to the appropriate TLS annotation, if one is -/// available. -#if CWISS_IS_GCCISH && !CWISS_IS_MACPPC -#define CWISS_THREAD_LOCAL __thread -#elif CWISS_IS_MSVC -#define CWISS_THREAD_LOCAL -#endif - -/// `CWISS_CHECK` will evaluate `cond_` and, if false, print an error and crash -/// the program. -/// -/// This is like `assert()` but unconditional. -#define CWISS_CHECK(cond_, ...) \ - do { \ - if (cond_) break; \ - fprintf(stderr, "CWISS_CHECK failed at %s:%d\n", __FILE__, __LINE__); \ - fprintf(stderr, __VA_ARGS__); \ - fprintf(stderr, "\n"); \ - fflush(stderr); \ - abort(); \ - } while (false) - -/// `CWISS_DCHECK` is like `CWISS_CHECK` but is disabled by `NDEBUG`. -#ifdef NDEBUG -#define CWISS_DCHECK(cond_, ...) ((void)0) -#else -#define CWISS_DCHECK CWISS_CHECK -#endif - -/// `CWISS_LIKELY` and `CWISS_UNLIKELY` provide a prediction hint to the -/// compiler to encourage branches to be scheduled in a particular way. -#if CWISS_HAVE_CLANG_BUILTIN(__builtin_expect) || CWISS_IS_GCC -#define CWISS_LIKELY(cond_) (__builtin_expect(false || (cond_), true)) -#define CWISS_UNLIKELY(cond_) (__builtin_expect(false || (cond_), false)) -#else -#define CWISS_LIKELY(cond_) (cond_) -#define CWISS_UNLIKELY(cond_) (cond_) -#endif - -/// `CWISS_INLINE_ALWAYS` informs the compiler that it should try really hard -/// to inline a function. -#if CWISS_HAVE_GCC_ATTRIBUTE(always_inline) -#define CWISS_INLINE_ALWAYS __attribute__((always_inline)) -#else -#define CWISS_INLINE_ALWAYS -#endif - -/// `CWISS_INLINE_NEVER` informs the compiler that it should avoid inlining a -/// function. -#if CWISS_HAVE_GCC_ATTRIBUTE(noinline) -#define CWISS_INLINE_NEVER __attribute__((noinline)) -#else -#define CWISS_INLINE_NEVER -#endif - -/// `CWISS_PREFETCH` informs the compiler that it should issue prefetch -/// instructions. -#if CWISS_HAVE_CLANG_BUILTIN(__builtin_prefetch) || CWISS_IS_GCC -#define CWISS_HAVE_PREFETCH 1 -#define CWISS_PREFETCH(addr_, locality_) \ - __builtin_prefetch(addr_, 0, locality_); -#else -#define CWISS_HAVE_PREFETCH 0 -#define CWISS_PREFETCH(addr_, locality_) ((void)0) -#endif - -/// `CWISS_HAVE_ASAN` and `CWISS_HAVE_MSAN` detect the presence of some of the -/// sanitizers. -#if defined(__SANITIZE_ADDRESS__) || CWISS_HAVE_FEATURE(address_sanitizer) -#define CWISS_HAVE_ASAN 1 -#else -#define CWISS_HAVE_ASAN 0 -#endif -#if defined(__SANITIZE_MEMORY__) || \ - (CWISS_HAVE_FEATURE(memory_sanitizer) && !defined(__native_client__)) -#define CWISS_HAVE_MSAN 1 -#else -#define CWISS_HAVE_MSAN 0 -#endif - -#if CWISS_HAVE_ASAN -#include -#endif - -#if CWISS_HAVE_MSAN -#include -#endif - -/// Maximally careful endianness detection. -/// Assume LITTLE_ENDIAN by default. -#if defined(__has_include) -# if __has_include() -# include -# if defined(__BYTE_ORDER) && (__BYTE_ORDER == __BIG_ENDIAN) -# define CWISS_IS_BIG_ENDIAN 1 -# endif -# endif -#elif defined(__BYTE_ORDER__) -# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ -# define CWISS_IS_BIG_ENDIAN 1 -# endif -#elif defined(__ppc__) || defined(__powerpc__) -# define CWISS_IS_BIG_ENDIAN 1 -#elif defined(_AIX) -# define CWISS_IS_BIG_ENDIAN 1 -#else -# warning "Cannot detect endianness; assuming little-endian." -#endif -#ifndef CWISS_IS_BIG_ENDIAN -# define CWISS_IS_BIG_ENDIAN 0 -#endif - -CWISS_BEGIN -CWISS_BEGIN_EXTERN -/// Informs a sanitizer runtime that this memory is invalid. -static inline void CWISS_PoisonMemory(const void* m, size_t s) { -#if CWISS_HAVE_ASAN - ASAN_POISON_MEMORY_REGION(m, s); -#endif -#if CWISS_HAVE_MSAN - __msan_poison(m, s); -#endif - (void)m; - (void)s; -} - -/// Informs a sanitizer runtime that this memory is no longer invalid. -static inline void CWISS_UnpoisonMemory(const void* m, size_t s) { -#if CWISS_HAVE_ASAN - ASAN_UNPOISON_MEMORY_REGION(m, s); -#endif -#if CWISS_HAVE_MSAN - __msan_unpoison(m, s); -#endif - (void)m; - (void)s; -} -CWISS_END_EXTERN -CWISS_END -/// cwisstable/internal/base.h ///////////////////////////////////////////////// - -/// cwisstable/internal/bits.h ///////////////////////////////////////////////// -/// Bit manipulation utilities. - -CWISS_BEGIN -CWISS_BEGIN_EXTERN - -/// Counts the number of trailing zeroes in the binary representation of `x`. -CWISS_INLINE_ALWAYS -static inline uint32_t CWISS_TrailingZeroes64(uint64_t x) { -#if CWISS_HAVE_CLANG_BUILTIN(__builtin_ctzll) || CWISS_IS_GCC -#if defined( __STDC_VERSION__ ) && __STDC_VERSION__ >= 201112L - static_assert(sizeof(unsigned long long) == sizeof(x), - "__builtin_ctzll does not take 64-bit arg"); -#endif - return __builtin_ctzll(x); -#elif CWISS_IS_MSVC - unsigned long result = 0; -#if defined(_M_X64) || defined(_M_ARM64) - _BitScanForward64(&result, x); -#else - if (((uint32_t)x) == 0) { - _BitScanForward(&result, (unsigned long)(x >> 32)); - return result + 32; - } - _BitScanForward(&result, (unsigned long)(x)); -#endif - return result; -#else - uint32_t c = 63; - x &= ~x + 1; - if (x & 0x00000000FFFFFFFF) c -= 32; - if (x & 0x0000FFFF0000FFFF) c -= 16; - if (x & 0x00FF00FF00FF00FF) c -= 8; - if (x & 0x0F0F0F0F0F0F0F0F) c -= 4; - if (x & 0x3333333333333333) c -= 2; - if (x & 0x5555555555555555) c -= 1; - return c; -#endif -} - -/// Counts the number of leading zeroes in the binary representation of `x`. -CWISS_INLINE_ALWAYS -static inline uint32_t CWISS_LeadingZeroes64(uint64_t x) { -#if CWISS_HAVE_CLANG_BUILTIN(__builtin_clzll) || CWISS_IS_GCC -#if defined( __STDC_VERSION__ ) && __STDC_VERSION__ >= 201112L - static_assert(sizeof(unsigned long long) == sizeof(x), - "__builtin_clzll does not take 64-bit arg"); -#endif - // Handle 0 as a special case because __builtin_clzll(0) is undefined. - return x == 0 ? 64 : __builtin_clzll(x); -#elif CWISS_IS_MSVC - unsigned long result = 0; -#if defined(_M_X64) || defined(_M_ARM64) - if (_BitScanReverse64(&result, x)) { - return 63 - result; - } -#else - if ((x >> 32) && _BitScanReverse(&result, (unsigned long)(x >> 32))) { - return 31 - result; - } - if (_BitScanReverse(&result, (unsigned long)(x))) { - return 63 - result; - } -#endif - return 64; -#else - uint32_t zeroes = 60; - if (x >> 32) { - zeroes -= 32; - x >>= 32; - } - if (x >> 16) { - zeroes -= 16; - x >>= 16; - } - if (x >> 8) { - zeroes -= 8; - x >>= 8; - } - if (x >> 4) { - zeroes -= 4; - x >>= 4; - } - return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[x] + zeroes; -#endif -} - -/// Counts the number of trailing zeroes in the binary representation of `x_` in -/// a type-generic fashion. -#define CWISS_TrailingZeros(x_) (CWISS_TrailingZeroes64(x_)) - -/// Counts the number of leading zeroes in the binary representation of `x_` in -/// a type-generic fashion. -#define CWISS_LeadingZeros(x_) \ - (CWISS_LeadingZeroes64(x_) - \ - (uint32_t)((sizeof(unsigned long long) - sizeof(x_)) * 8)) - -/// Computes the number of bits necessary to represent `x_`, i.e., the bit index -/// of the most significant one. -#define CWISS_BitWidth(x_) \ - (((uint32_t)(sizeof(x_) * 8)) - CWISS_LeadingZeros(x_)) - -#define CWISS_RotateLeft(x_, bits_) \ - (((x_) << bits_) | ((x_) >> (sizeof(x_) * 8 - bits_))) - -/// The return type of `CWISS_Mul128`. -typedef struct { - uint64_t lo, hi; -} CWISS_U128; - -/// Computes a double-width multiplication operation. -static inline CWISS_U128 CWISS_Mul128(uint64_t a, uint64_t b) { -#ifdef __SIZEOF_INT128__ - // TODO: de-intrinsics-ize this. - __uint128_t p = a; - p *= b; - return (CWISS_U128) { (uint64_t)p, (uint64_t)(p >> 64) }; -#else - /* - * https://stackoverflow.com/questions/25095741/how-can-i-multiply-64-bit-operands-and-get-128-bit-result-portably - * - * Fast yet simple grade school multiply that avoids - * 64-bit carries with the properties of multiplying by 11 - * and takes advantage of UMAAL on ARMv6 to only need 4 - * calculations. - */ - - /* First calculate all of the cross products. */ - const uint64_t lo_lo = (a & 0xFFFFFFFF) * (b & 0xFFFFFFFF); - const uint64_t hi_lo = (a >> 32) * (b & 0xFFFFFFFF); - const uint64_t lo_hi = (a & 0xFFFFFFFF) * (b >> 32); - const uint64_t hi_hi = (a >> 32) * (b >> 32); - - /* Now add the products together. These will never overflow. */ - const uint64_t cross = (lo_lo >> 32) + (hi_lo & 0xFFFFFFFF) + lo_hi; - const uint64_t high = (hi_lo >> 32) + (cross >> 32) + hi_hi; - const uint64_t low = (cross << 32) | (lo_lo & 0xFFFFFFFF); - CWISS_U128 result = { .lo = low, .hi = high }; - return result; -#endif -} - -/// Loads an unaligned u32. -static inline uint32_t CWISS_Load32(const void* p) { - uint32_t v; - memcpy(&v, p, sizeof(v)); - return v; -} - -/// Loads an unaligned u64. -static inline uint64_t CWISS_Load64(const void* p) { - uint64_t v; - memcpy(&v, p, sizeof(v)); - return v; -} - -/// Reads 9 to 16 bytes from p. -static inline CWISS_U128 CWISS_Load9To16(const void* p, size_t len) { - const unsigned char* p8 = (const unsigned char*)p; - uint64_t lo = CWISS_Load64(p8); - uint64_t hi = CWISS_Load64(p8 + len - 8); - return (CWISS_U128) { lo, hi >> (128 - len * 8) }; -} - -/// Reads 4 to 8 bytes from p. -static inline uint64_t CWISS_Load4To8(const void* p, size_t len) { - const unsigned char* p8 = (const unsigned char*)p; - uint64_t lo = CWISS_Load32(p8); - uint64_t hi = CWISS_Load32(p8 + len - 4); - return lo | (hi << (len - 4) * 8); -} - -/// Reads 1 to 3 bytes from p. -static inline uint32_t CWISS_Load1To3(const void* p, size_t len) { - const unsigned char* p8 = (const unsigned char*)p; - uint32_t mem0 = p8[0]; - uint32_t mem1 = p8[len / 2]; - uint32_t mem2 = p8[len - 1]; - return (mem0 | (mem1 << (len / 2 * 8)) | (mem2 << ((len - 1) * 8))); -} - -/// A abstract bitmask, such as that emitted by a SIMD instruction. -/// -/// Specifically, this type implements a simple bitset whose representation is -/// controlled by `width` and `shift`. `width` is the number of abstract bits in -/// the bitset, while `shift` is the log-base-two of the width of an abstract -/// bit in the representation. -/// -/// For example, when `width` is 16 and `shift` is zero, this is just an -/// ordinary 16-bit bitset occupying the low 16 bits of `mask`. When `width` is -/// 8 and `shift` is 3, abstract bits are represented as the bytes `0x00` and -/// `0x80`, and it occupies all 64 bits of the bitmask. -typedef struct { - /// The mask, in the representation specified by `width` and `shift`. - uint64_t mask; - /// The number of abstract bits in the mask. - uint32_t width; - /// The log-base-two width of an abstract bit. - uint32_t shift; -} CWISS_BitMask; - -/// Returns the index of the lowest abstract bit set in `self`. -static inline uint32_t CWISS_BitMask_LowestBitSet(const CWISS_BitMask* self) { - return CWISS_TrailingZeros(self->mask) >> self->shift; -} - -/// Returns the index of the highest abstract bit set in `self`. -static inline uint32_t CWISS_BitMask_HighestBitSet(const CWISS_BitMask* self) { - return (uint32_t)(CWISS_BitWidth(self->mask) - 1) >> self->shift; -} - -/// Return the number of trailing zero abstract bits. -static inline uint32_t CWISS_BitMask_TrailingZeros(const CWISS_BitMask* self) { - return CWISS_TrailingZeros(self->mask) >> self->shift; -} - -/// Return the number of leading zero abstract bits. -static inline uint32_t CWISS_BitMask_LeadingZeros(const CWISS_BitMask* self) { - uint32_t total_significant_bits = self->width << self->shift; - uint32_t extra_bits = sizeof(self->mask) * 8 - total_significant_bits; - return (uint32_t)(CWISS_LeadingZeros(self->mask << extra_bits)) >> - self->shift; -} - -/// Iterates over the one bits in the mask. -/// -/// If the mask is empty, returns `false`; otherwise, returns the index of the -/// lowest one bit in the mask, and removes it from the set. -static inline bool CWISS_BitMask_next(CWISS_BitMask* self, uint32_t* bit) { - if (self->mask == 0) { - return false; - } - - *bit = CWISS_BitMask_LowestBitSet(self); - self->mask &= (self->mask - 1); - return true; -} - -CWISS_END_EXTERN -CWISS_END -/// cwisstable/internal/bits.h ///////////////////////////////////////////////// - -/// cwisstable/internal/control_byte.h ///////////////////////////////////////// -CWISS_BEGIN -CWISS_BEGIN_EXTERN - -/// Control bytes and groups: the core of SwissTable optimization. -/// -/// Control bytes are bytes (collected into groups of a platform-specific size) -/// that define the state of the corresponding slot in the slot array. Group -/// manipulation is tightly optimized to be as efficient as possible. - -/// A `CWISS_ControlByte` is a single control byte, which can have one of four -/// states: empty, deleted, full (which has an associated seven-bit hash) and -/// the sentinel. They have the following bit patterns: -/// -/// ``` -/// empty: 1 0 0 0 0 0 0 0 -/// deleted: 1 1 1 1 1 1 1 0 -/// full: 0 h h h h h h h // h represents the hash bits. -/// sentinel: 1 1 1 1 1 1 1 1 -/// ``` -/// -/// These values are specifically tuned for SSE-flavored SIMD; future ports to -/// other SIMD platforms may require choosing new values. The static_asserts -/// below detail the source of these choices. -typedef int8_t CWISS_ControlByte; -#define CWISS_kEmpty (INT8_C(-128)) -#define CWISS_kDeleted (INT8_C(-2)) -#define CWISS_kSentinel (INT8_C(-1)) -// TODO: Wrap CWISS_ControlByte in a single-field struct to get strict-aliasing -// benefits. - -#if defined( __STDC_VERSION__ ) && __STDC_VERSION__ >= 201112L -static_assert( - (CWISS_kEmpty & CWISS_kDeleted & CWISS_kSentinel & 0x80) != 0, - "Special markers need to have the MSB to make checking for them efficient"); -static_assert( - CWISS_kEmpty < CWISS_kSentinel && CWISS_kDeleted < CWISS_kSentinel, - "CWISS_kEmpty and CWISS_kDeleted must be smaller than " - "CWISS_kSentinel to make the SIMD test of IsEmptyOrDeleted() efficient"); -static_assert( - CWISS_kSentinel == -1, - "CWISS_kSentinel must be -1 to elide loading it from memory into SIMD " - "registers (pcmpeqd xmm, xmm)"); -static_assert(CWISS_kEmpty == -128, - "CWISS_kEmpty must be -128 to make the SIMD check for its " - "existence efficient (psignb xmm, xmm)"); -static_assert( - (~CWISS_kEmpty & ~CWISS_kDeleted & CWISS_kSentinel & 0x7F) != 0, - "CWISS_kEmpty and CWISS_kDeleted must share an unset bit that is not " - "shared by CWISS_kSentinel to make the scalar test for " - "MatchEmptyOrDeleted() efficient"); -static_assert(CWISS_kDeleted == -2, - "CWISS_kDeleted must be -2 to make the implementation of " - "ConvertSpecialToEmptyAndFullToDeleted efficient"); -#endif - -/// Returns a pointer to a control byte group that can be used by empty tables. -static inline CWISS_ControlByte* CWISS_EmptyGroup(void) { - // A single block of empty control bytes for tables without any slots - // allocated. This enables removing a branch in the hot path of find(). - CWISS_alignas(16) static const CWISS_ControlByte kEmptyGroup[16] = { - CWISS_kSentinel, CWISS_kEmpty, CWISS_kEmpty, CWISS_kEmpty, - CWISS_kEmpty, CWISS_kEmpty, CWISS_kEmpty, CWISS_kEmpty, - CWISS_kEmpty, CWISS_kEmpty, CWISS_kEmpty, CWISS_kEmpty, - CWISS_kEmpty, CWISS_kEmpty, CWISS_kEmpty, CWISS_kEmpty, - }; - - // Const must be cast away here; no uses of this function will actually write - // to it, because it is only used for empty tables. - return (CWISS_ControlByte*)&kEmptyGroup; -} - -/// Returns a hash seed. -/// -/// The seed consists of the ctrl_ pointer, which adds enough entropy to ensure -/// non-determinism of iteration order in most cases. -static inline size_t CWISS_HashSeed(const CWISS_ControlByte* ctrl) { - // The low bits of the pointer have little or no entropy because of - // alignment. We shift the pointer to try to use higher entropy bits. A - // good number seems to be 12 bits, because that aligns with page size. - return ((uintptr_t)ctrl) >> 12; -} - -/// Extracts the H1 portion of a hash: the high 57 bits mixed with a per-table -/// salt. -static inline size_t CWISS_H1(size_t hash, const CWISS_ControlByte* ctrl) { - return (hash >> 7) ^ CWISS_HashSeed(ctrl); -} - -/// Extracts the H2 portion of a hash: the low 7 bits, which can be used as -/// control byte. -typedef uint8_t CWISS_h2_t; -static inline CWISS_h2_t CWISS_H2(size_t hash) { return hash & 0x7F; } - -/// Returns whether `c` is empty. -static inline bool CWISS_IsEmpty(CWISS_ControlByte c) { - return c == CWISS_kEmpty; -} - -/// Returns whether `c` is full. -static inline bool CWISS_IsFull(CWISS_ControlByte c) { return c >= 0; } - -/// Returns whether `c` is deleted. -static inline bool CWISS_IsDeleted(CWISS_ControlByte c) { - return c == CWISS_kDeleted; -} - -/// Returns whether `c` is empty or deleted. -static inline bool CWISS_IsEmptyOrDeleted(CWISS_ControlByte c) { - return c < CWISS_kSentinel; -} - -/// Asserts that `ctrl` points to a full control byte. -#define CWISS_AssertIsFull(ctrl) \ - CWISS_CHECK((ctrl) != NULL && CWISS_IsFull(*(ctrl)), \ - "Invalid operation on iterator (%p/%d). The element might have " \ - "been erased, or the table might have rehashed.", \ - (ctrl), (ctrl) ? *(ctrl) : -1) - -/// Asserts that `ctrl` is either null OR points to a full control byte. -#define CWISS_AssertIsValid(ctrl) \ - CWISS_CHECK((ctrl) == NULL || CWISS_IsFull(*(ctrl)), \ - "Invalid operation on iterator (%p/%d). The element might have " \ - "been erased, or the table might have rehashed.", \ - (ctrl), (ctrl) ? *(ctrl) : -1) - -/// Constructs a `BitMask` with the correct parameters for whichever -/// implementation of `CWISS_Group` is in use. -#define CWISS_Group_BitMask(x) \ - (CWISS_BitMask){(uint64_t)(x), CWISS_Group_kWidth, CWISS_Group_kShift}; - -// TODO(#4): Port this to NEON. -#if CWISS_HAVE_SSE2 -// Reference guide for intrinsics used below: -// -// * __m128i: An XMM (128-bit) word. -// -// * _mm_setzero_si128: Returns a zero vector. -// * _mm_set1_epi8: Returns a vector with the same i8 in each lane. -// -// * _mm_subs_epi8: Saturating-subtracts two i8 vectors. -// * _mm_and_si128: Ands two i128s together. -// * _mm_or_si128: Ors two i128s together. -// * _mm_andnot_si128: And-nots two i128s together. -// -// * _mm_cmpeq_epi8: Component-wise compares two i8 vectors for equality, -// filling each lane with 0x00 or 0xff. -// * _mm_cmpgt_epi8: Same as above, but using > rather than ==. -// -// * _mm_loadu_si128: Performs an unaligned load of an i128. -// * _mm_storeu_si128: Performs an unaligned store of a u128. -// -// * _mm_sign_epi8: Retains, negates, or zeroes each i8 lane of the first -// argument if the corresponding lane of the second -// argument is positive, negative, or zero, respectively. -// * _mm_movemask_epi8: Selects the sign bit out of each i8 lane and produces a -// bitmask consisting of those bits. -// * _mm_shuffle_epi8: Selects i8s from the first argument, using the low -// four bits of each i8 lane in the second argument as -// indices. -typedef __m128i CWISS_Group; -#define CWISS_Group_kWidth ((size_t)16) -#define CWISS_Group_kShift 0 - -// https://github.com/abseil/abseil-cpp/issues/209 -// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87853 -// _mm_cmpgt_epi8 is broken under GCC with -funsigned-char -// Work around this by using the portable implementation of Group -// when using -funsigned-char under GCC. -static inline CWISS_Group CWISS_mm_cmpgt_epi8_fixed(CWISS_Group a, - CWISS_Group b) { - if (CWISS_IS_GCC && CHAR_MIN == 0) { // std::is_unsigned_v - const CWISS_Group mask = _mm_set1_epi8(0x80); - const CWISS_Group diff = _mm_subs_epi8(b, a); - return _mm_cmpeq_epi8(_mm_and_si128(diff, mask), mask); - } - return _mm_cmpgt_epi8(a, b); -} - -static inline CWISS_Group CWISS_Group_new(const CWISS_ControlByte* pos) { - return _mm_loadu_si128((const CWISS_Group*)pos); -} - -// Returns a bitmask representing the positions of slots that match hash. -static inline CWISS_BitMask CWISS_Group_Match(const CWISS_Group* self, - CWISS_h2_t hash) { - return CWISS_Group_BitMask( - _mm_movemask_epi8(_mm_cmpeq_epi8(_mm_set1_epi8(hash), *self))) -} - -// Returns a bitmask representing the positions of empty slots. -static inline CWISS_BitMask CWISS_Group_MatchEmpty(const CWISS_Group* self) { -#if CWISS_HAVE_SSSE3 - // This only works because ctrl_t::kEmpty is -128. - return CWISS_Group_BitMask(_mm_movemask_epi8(_mm_sign_epi8(*self, *self))); -#else - return CWISS_Group_Match(self, CWISS_kEmpty); -#endif -} - -// Returns a bitmask representing the positions of empty or deleted slots. -static inline CWISS_BitMask CWISS_Group_MatchEmptyOrDeleted(const CWISS_Group* self) { - CWISS_Group special = _mm_set1_epi8((uint8_t)CWISS_kSentinel); - return CWISS_Group_BitMask(_mm_movemask_epi8(CWISS_mm_cmpgt_epi8_fixed(special, *self))); -} - -// Returns the number of trailing empty or deleted elements in the group. -static inline uint32_t CWISS_Group_CountLeadingEmptyOrDeleted( - const CWISS_Group* self) { - CWISS_Group special = _mm_set1_epi8((uint8_t)CWISS_kSentinel); - return CWISS_TrailingZeros((uint32_t)(_mm_movemask_epi8(CWISS_mm_cmpgt_epi8_fixed(special, *self)) + 1)); -} - -static inline void CWISS_Group_ConvertSpecialToEmptyAndFullToDeleted(const CWISS_Group* self, CWISS_ControlByte* dst) { - CWISS_Group msbs = _mm_set1_epi8((char)-128); - CWISS_Group x126 = _mm_set1_epi8(126); -#if CWISS_HAVE_SSSE3 - CWISS_Group res = _mm_or_si128(_mm_shuffle_epi8(x126, *self), msbs); -#else - CWISS_Group zero = _mm_setzero_si128(); - CWISS_Group special_mask = CWISS_mm_cmpgt_epi8_fixed(zero, *self); - CWISS_Group res = _mm_or_si128(msbs, _mm_andnot_si128(special_mask, x126)); -#endif - _mm_storeu_si128((CWISS_Group*)dst, res); -} -#else // CWISS_HAVE_SSE2 -typedef uint64_t CWISS_Group; -#define CWISS_Group_kWidth ((size_t)8) -#define CWISS_Group_kShift 3 - -#if CWISS_HAVE_CLANG_BUILTIN(__builtin_bswap64) -# define bswap64 __builtin_bswap64 -#else -static inline uint64_t bswap64(uint64_t v) { - return ((v & ((uint64_t)0xff << (7 * 8))) >> (7 * 8)) | - ((v & ((uint64_t)0xff << (6 * 8))) >> (5 * 8)) | - ((v & ((uint64_t)0xff << (5 * 8))) >> (3 * 8)) | - ((v & ((uint64_t)0xff << (4 * 8))) >> (1 * 8)) | - ((v & ((uint64_t)0xff << (3 * 8))) << (1 * 8)) | - ((v & ((uint64_t)0xff << (2 * 8))) << (3 * 8)) | - ((v & ((uint64_t)0xff << (1 * 8))) << (5 * 8)) | - ((v & ((uint64_t)0xff << (0 * 8))) << (7 * 8)); -} -#endif - -static inline CWISS_Group CWISS_Group_new(const CWISS_ControlByte* pos) { - CWISS_Group val; - memcpy(&val, pos, sizeof(val)); -#if CWISS_IS_BIG_ENDIAN - val = bswap64(val); -#endif - return val; -} - -static inline CWISS_BitMask CWISS_Group_Match(const CWISS_Group* self, - CWISS_h2_t hash) { - // For the technique, see: - // http://graphics.stanford.edu/~seander/bithacks.html##ValueInWord - // (Determine if a word has a byte equal to n). - // - // Caveat: there are false positives but: - // - they only occur if there is a real match - // - they never occur on ctrl_t::kEmpty, ctrl_t::kDeleted, ctrl_t::kSentinel - // - they will be handled gracefully by subsequent checks in code - // - // Example: - // v = 0x1716151413121110 - // hash = 0x12 - // retval = (v - lsbs) & ~v & msbs = 0x0000000080800000 - uint64_t msbs = 0x8080808080808080ULL; - uint64_t lsbs = 0x0101010101010101ULL; - uint64_t x = *self ^ (lsbs * hash); - return CWISS_Group_BitMask((x - lsbs) & ~x & msbs); -} - -static inline CWISS_BitMask CWISS_Group_MatchEmpty(const CWISS_Group* self) { - uint64_t msbs = 0x8080808080808080ULL; - return CWISS_Group_BitMask((*self & (~*self << 6)) & msbs); -} - -static inline CWISS_BitMask CWISS_Group_MatchEmptyOrDeleted( - const CWISS_Group* self) { - uint64_t msbs = 0x8080808080808080ULL; - return CWISS_Group_BitMask((*self & (~*self << 7)) & msbs); -} - -static inline uint32_t CWISS_Group_CountLeadingEmptyOrDeleted( - const CWISS_Group* self) { - uint64_t gaps = 0x00FEFEFEFEFEFEFEULL; - return (CWISS_TrailingZeros(((~*self & (*self >> 7)) | gaps) + 1) + 7) >> 3; -} - -static inline void CWISS_Group_ConvertSpecialToEmptyAndFullToDeleted( - const CWISS_Group* self, CWISS_ControlByte* dst) { - uint64_t msbs = 0x8080808080808080ULL; - uint64_t lsbs = 0x0101010101010101ULL; - uint64_t x = *self & msbs; - uint64_t res = (~x + (x >> 7)) & ~lsbs; - memcpy(dst, &res, sizeof(res)); -} -#endif // CWISS_HAVE_SSE2 - -CWISS_END_EXTERN -CWISS_END -/// cwisstable/internal/control_byte.h ///////////////////////////////////////// - -/// cwisstable/internal/capacity.h ///////////////////////////////////////////// -/// Capacity, load factor, and allocation size computations for a SwissTable. -/// -/// A SwissTable's backing array consists of control bytes followed by slots -/// that may or may not contain objects. -/// -/// The layout of the backing array, for `capacity` slots, is thus, as a -/// pseudo-struct: -/// ``` -/// struct CWISS_BackingArray { -/// // Control bytes for the "real" slots. -/// CWISS_ControlByte ctrl[capacity]; -/// // Always `CWISS_kSentinel`. This is used by iterators to find when to -/// // stop and serves no other purpose. -/// CWISS_ControlByte sentinel; -/// // A copy of the first `kWidth - 1` elements of `ctrl`. This is used so -/// // that if a probe sequence picks a value near the end of `ctrl`, -/// // `CWISS_Group` will have valid control bytes to look at. -/// // -/// // As an interesting special-case, such probe windows will never choose -/// // the zeroth slot as a candidate, because they will see `kSentinel` -/// // instead of the correct H2 value. -/// CWISS_ControlByte clones[kWidth - 1]; -/// // Alignment padding equal to `alignof(slot_type)`. -/// char padding_; -/// // The actual slot data. -/// char slots[capacity * sizeof(slot_type)]; -/// }; -/// ``` -/// -/// The length of this array is computed by `CWISS_AllocSize()`. - -CWISS_BEGIN -CWISS_BEGIN_EXTERN - -/// Returns he number of "cloned control bytes". -/// -/// This is the number of control bytes that are present both at the beginning -/// of the control byte array and at the end, such that we can create a -/// `CWISS_Group_kWidth`-width probe window starting from any control byte. -static inline size_t CWISS_NumClonedBytes(void) { - return CWISS_Group_kWidth - 1; -} - -/// Returns whether `n` is a valid capacity (i.e., number of slots). -/// -/// A valid capacity is a non-zero integer `2^m - 1`. -static inline bool CWISS_IsValidCapacity(size_t n) { - return ((n + 1) & n) == 0 && n > 0; -} - -/// Returns some per-call entropy. -/// -/// Currently, the entropy is produced by XOR'ing the address of a (preferably -/// thread-local) value with a perpetually-incrementing value. -static inline size_t RandomSeed(void) { -#ifdef CWISS_THREAD_LOCAL - static CWISS_THREAD_LOCAL size_t counter; - size_t value = counter++; -#else - static CWISS_ATOMIC_T(size_t) counter; - size_t value = CWISS_ATOMIC_INC (counter); -#endif - return value ^ ((size_t)&counter); -} - -/// Mixes a randomly generated per-process seed with `hash` and `ctrl` to -/// randomize insertion order within groups. -CWISS_INLINE_NEVER static bool CWISS_ShouldInsertBackwards( - size_t hash, const CWISS_ControlByte* ctrl) { - // To avoid problems with weak hashes and single bit tests, we use % 13. - // TODO(kfm,sbenza): revisit after we do unconditional mixing - return (CWISS_H1(hash, ctrl) ^ RandomSeed()) % 13 > 6; -} - -/// Applies the following mapping to every byte in the control array: -/// * kDeleted -> kEmpty -/// * kEmpty -> kEmpty -/// * _ -> kDeleted -/// -/// Preconditions: `CWISS_IsValidCapacity(capacity)`, -/// `ctrl[capacity]` == `kSentinel`, `ctrl[i] != kSentinel for i < capacity`. -CWISS_INLINE_NEVER static void CWISS_ConvertDeletedToEmptyAndFullToDeleted( CWISS_ControlByte* ctrl, size_t capacity) { - CWISS_DCHECK(ctrl[capacity] == CWISS_kSentinel, "bad ctrl value at %zu: %02x", capacity, ctrl[capacity]); - CWISS_DCHECK(CWISS_IsValidCapacity(capacity), "invalid capacity: %zu", capacity); - - CWISS_ControlByte* pos; - for (pos = ctrl; pos < ctrl + capacity; pos += CWISS_Group_kWidth) { - CWISS_Group g = CWISS_Group_new(pos); - CWISS_Group_ConvertSpecialToEmptyAndFullToDeleted(&g, pos); - } - // Copy the cloned ctrl bytes. - memcpy(ctrl + capacity + 1, ctrl, CWISS_NumClonedBytes()); - ctrl[capacity] = CWISS_kSentinel; -} - -/// Sets `ctrl` to `{kEmpty, ..., kEmpty, kSentinel}`, marking the entire -/// array as deleted. -static inline void CWISS_ResetCtrl(size_t capacity, CWISS_ControlByte* ctrl, const void* slots, size_t slot_size) { - memset(ctrl, CWISS_kEmpty, capacity + 1 + CWISS_NumClonedBytes()); - ctrl[capacity] = CWISS_kSentinel; - CWISS_PoisonMemory(slots, slot_size * capacity); -} - -/// Sets `ctrl[i]` to `h`. -/// -/// Unlike setting it directly, this function will perform bounds checks and -/// mirror the value to the cloned tail if necessary. -static inline void CWISS_SetCtrl(size_t i, CWISS_ControlByte h, size_t capacity, CWISS_ControlByte* ctrl, const void* slots, size_t slot_size) { - CWISS_DCHECK(i < capacity, "CWISS_SetCtrl out-of-bounds: %zu >= %zu", i, capacity); - - const char* slot = ((const char*)slots) + i * slot_size; - if (CWISS_IsFull(h)) { - CWISS_UnpoisonMemory(slot, slot_size); - } else { - CWISS_PoisonMemory(slot, slot_size); - } - - // This is intentionally branchless. If `i < kWidth`, it will write to the - // cloned bytes as well as the "real" byte; otherwise, it will store `h` - // twice. - size_t mirrored_i = ((i - CWISS_NumClonedBytes()) & capacity) + (CWISS_NumClonedBytes() & capacity); - ctrl[i] = h; - ctrl[mirrored_i] = h; -} - -/// Converts `n` into the next valid capacity, per `CWISS_IsValidCapacity`. -static inline size_t CWISS_NormalizeCapacity(size_t n) { - return n ? SIZE_MAX >> CWISS_LeadingZeros(n) : 1; -} - -// General notes on capacity/growth methods below: -// - We use 7/8th as maximum load factor. For 16-wide groups, that gives an -// average of two empty slots per group. -// - For (capacity+1) >= Group::kWidth, growth is 7/8*capacity. -// - For (capacity+1) < Group::kWidth, growth == capacity. In this case, we -// never need to probe (the whole table fits in one group) so we don't need a -// load factor less than 1. - -/// Given `capacity`, applies the load factor; i.e., it returns the maximum -/// number of values we should put into the table before a rehash. -static inline size_t CWISS_CapacityToGrowth(size_t capacity) { - CWISS_DCHECK(CWISS_IsValidCapacity(capacity), "invalid capacity: %zu", - capacity); - // `capacity*7/8` - if (CWISS_Group_kWidth == 8 && capacity == 7) { - // x-x/8 does not work when x==7. - return 6; - } - return capacity - capacity / 8; -} - -/// Given `growth`, "unapplies" the load factor to find how large the capacity -/// should be to stay within the load factor. -/// -/// This might not be a valid capacity and `CWISS_NormalizeCapacity()` may be -/// necessary. -static inline size_t CWISS_GrowthToLowerboundCapacity(size_t growth) { - // `growth*8/7` - if (CWISS_Group_kWidth == 8 && growth == 7) { - // x+(x-1)/7 does not work when x==7. - return 8; - } - return growth + (size_t)((((int64_t)growth) - 1) / 7); -} - -// The allocated block consists of `capacity + 1 + NumClonedBytes()` control -// bytes followed by `capacity` slots, which must be aligned to `slot_align`. -// SlotOffset returns the offset of the slots into the allocated block. - -/// Given the capacity of a table, computes the offset (from the start of the -/// backing allocation) at which the slots begin. -static inline size_t CWISS_SlotOffset(size_t capacity, size_t slot_align) { - CWISS_DCHECK(CWISS_IsValidCapacity(capacity), "invalid capacity: %zu", - capacity); - const size_t num_control_bytes = capacity + 1 + CWISS_NumClonedBytes(); - return (num_control_bytes + slot_align - 1) & (~slot_align + 1); -} - -/// Given the capacity of a table, computes the total size of the backing -/// array. -static inline size_t CWISS_AllocSize(size_t capacity, size_t slot_size, - size_t slot_align) { - return CWISS_SlotOffset(capacity, slot_align) + capacity * slot_size; -} - -/// Whether a table is "small". A small table fits entirely into a probing -/// group, i.e., has a capacity equal to the size of a `CWISS_Group`. -/// -/// In small mode we are able to use the whole capacity. The extra control -/// bytes give us at least one "empty" control byte to stop the iteration. -/// This is important to make 1 a valid capacity. -/// -/// In small mode only the first `capacity` control bytes after the sentinel -/// are valid. The rest contain dummy ctrl_t::kEmpty values that do not -/// represent a real slot. This is important to take into account on -/// `CWISS_FindFirstNonFull()`, where we never try -/// `CWISS_ShouldInsertBackwards()` for small tables. -static inline bool CWISS_IsSmall(size_t capacity) { - return capacity < CWISS_Group_kWidth - 1; -} - -CWISS_END_EXTERN -CWISS_END -/// cwisstable/internal/capacity.h ///////////////////////////////////////////// - -/// cwisstable/internal/probe.h //////////////////////////////////////////////// -/// Table probing functions. -/// -/// "Probing" refers to the process of trying to find the matching entry for a -/// given lookup by repeatedly searching for values throughout the table. - -CWISS_BEGIN -CWISS_BEGIN_EXTERN - -/// The state for a probe sequence. -/// -/// Currently, the sequence is a triangular progression of the form -/// ``` -/// p(i) := kWidth/2 * (i^2 - i) + hash (mod mask + 1) -/// ``` -/// -/// The use of `kWidth` ensures that each probe step does not overlap groups; -/// the sequence effectively outputs the addresses of *groups* (although not -/// necessarily aligned to any boundary). The `CWISS_Group` machinery allows us -/// to check an entire group with minimal branching. -/// -/// Wrapping around at `mask + 1` is important, but not for the obvious reason. -/// As described in capacity.h, the first few entries of the control byte array -/// is mirrored at the end of the array, which `CWISS_Group` will find and use -/// for selecting candidates. However, when those candidates' slots are -/// actually inspected, there are no corresponding slots for the cloned bytes, -/// so we need to make sure we've treated those offsets as "wrapping around". -typedef struct { - size_t mask_; - size_t offset_; - size_t index_; -} CWISS_ProbeSeq; - -/// Creates a new probe sequence using `hash` as the initial value of the -/// sequence and `mask` (usually the capacity of the table) as the mask to -/// apply to each value in the progression. -static inline CWISS_ProbeSeq CWISS_ProbeSeq_new(size_t hash, size_t mask) { - return (CWISS_ProbeSeq) { - .mask_ = mask, - .offset_ = hash & mask, - }; -} - -/// Returns the slot `i` indices ahead of `self` within the bounds expressed by -/// `mask`. -static inline size_t CWISS_ProbeSeq_offset(const CWISS_ProbeSeq* self, - size_t i) { - return (self->offset_ + i) & self->mask_; -} - -/// Advances the sequence; the value can be obtained by calling -/// `CWISS_ProbeSeq_offset()` or inspecting `offset_`. -static inline void CWISS_ProbeSeq_next(CWISS_ProbeSeq* self) { - self->index_ += CWISS_Group_kWidth; - self->offset_ += self->index_; - self->offset_ &= self->mask_; -} - -/// Begins a probing operation on `ctrl`, using `hash`. -static inline CWISS_ProbeSeq CWISS_ProbeSeq_Start(const CWISS_ControlByte* ctrl, - size_t hash, - size_t capacity) { - return CWISS_ProbeSeq_new(CWISS_H1(hash, ctrl), capacity); -} - -// The return value of `CWISS_FindFirstNonFull()`. -typedef struct { - size_t offset; - size_t probe_length; -} CWISS_FindInfo; - -/// Probes an array of control bits using a probe sequence derived from `hash`, -/// and returns the offset corresponding to the first deleted or empty slot. -/// -/// Behavior when the entire table is full is undefined. -/// -/// NOTE: this function must work with tables having both empty and deleted -/// slots in the same group. Such tables appear during -/// `CWISS_RawTable_DropDeletesWithoutResize()`. -static inline CWISS_FindInfo CWISS_FindFirstNonFull( - const CWISS_ControlByte* ctrl, size_t hash, size_t capacity) { - CWISS_ProbeSeq seq = CWISS_ProbeSeq_Start(ctrl, hash, capacity); - while (true) { - CWISS_Group g = CWISS_Group_new(ctrl + seq.offset_); - CWISS_BitMask mask = CWISS_Group_MatchEmptyOrDeleted(&g); - if (mask.mask) { -#ifndef NDEBUG - // We want to add entropy even when ASLR is not enabled. - // In debug build we will randomly insert in either the front or back of - // the group. - // TODO(kfm,sbenza): revisit after we do unconditional mixing - if (!CWISS_IsSmall(capacity) && CWISS_ShouldInsertBackwards(hash, ctrl)) { - return (CWISS_FindInfo) { - CWISS_ProbeSeq_offset(&seq, CWISS_BitMask_HighestBitSet(&mask)), - seq.index_ - }; - } -#endif - return (CWISS_FindInfo) { - CWISS_ProbeSeq_offset(&seq, CWISS_BitMask_TrailingZeros(&mask)), - seq.index_ - }; - } - CWISS_ProbeSeq_next(&seq); - CWISS_DCHECK(seq.index_ <= capacity, "full table!"); - } -} - -CWISS_END_EXTERN -CWISS_END -/// cwisstable/internal/probe.h //////////////////////////////////////////////// - -/// cwisstable/internal/absl_hash.h //////////////////////////////////////////// -/// Implementation details of AbslHash. - -CWISS_BEGIN -CWISS_BEGIN_EXTERN - -static inline uint64_t CWISS_AbslHash_LowLevelMix(uint64_t v0, uint64_t v1) { -#if USE_128_MIX - // The default bit-mixer uses 64x64->128-bit multiplication. - CWISS_U128 p = CWISS_Mul128(v0, v1); - return p.hi ^ p.lo; -#else - // The default bit-mixer above would perform poorly on some ARM microarchs, - // where calculating a 128-bit product requires a sequence of two - // instructions with a high combined latency and poor throughput. - // Instead, we mix bits using only 64-bit arithmetic, which is faster. - uint64_t p = v0 ^ CWISS_RotateLeft(v1, 40); - p *= v1 ^ CWISS_RotateLeft(v0, 39); - return p ^ (p >> 11); -#endif -} - -CWISS_INLINE_NEVER -static uint64_t CWISS_AbslHash_LowLevelHash(const void* data, size_t len, - uint64_t seed, - const uint64_t salt[5]) { - const char* ptr = (const char*)data; - uint64_t starting_length = (uint64_t)len; - uint64_t current_state = seed ^ salt[0]; - - if (len > 64) { - // If we have more than 64 bytes, we're going to handle chunks of 64 - // bytes at a time. We're going to build up two separate hash states - // which we will then hash together. - uint64_t duplicated_state = current_state; - - do { - uint64_t chunk[8]; - memcpy(chunk, ptr, sizeof(chunk)); - - uint64_t cs0 = CWISS_AbslHash_LowLevelMix(chunk[0] ^ salt[1], - chunk[1] ^ current_state); - uint64_t cs1 = CWISS_AbslHash_LowLevelMix(chunk[2] ^ salt[2], - chunk[3] ^ current_state); - current_state = (cs0 ^ cs1); - - uint64_t ds0 = CWISS_AbslHash_LowLevelMix(chunk[4] ^ salt[3], - chunk[5] ^ duplicated_state); - uint64_t ds1 = CWISS_AbslHash_LowLevelMix(chunk[6] ^ salt[4], - chunk[7] ^ duplicated_state); - duplicated_state = (ds0 ^ ds1); - - ptr += 64; - len -= 64; - } while (len > 64); - - current_state = current_state ^ duplicated_state; - } - - // We now have a data `ptr` with at most 64 bytes and the current state - // of the hashing state machine stored in current_state. - while (len > 16) { - uint64_t a = CWISS_Load64(ptr); - uint64_t b = CWISS_Load64(ptr + 8); - - current_state = CWISS_AbslHash_LowLevelMix(a ^ salt[1], b ^ current_state); - - ptr += 16; - len -= 16; - } - - // We now have a data `ptr` with at most 16 bytes. - uint64_t a = 0; - uint64_t b = 0; - if (len > 8) { - // When we have at least 9 and at most 16 bytes, set A to the first 64 - // bits of the input and B to the last 64 bits of the input. Yes, they will - // overlap in the middle if we are working with less than the full 16 - // bytes. - a = CWISS_Load64(ptr); - b = CWISS_Load64(ptr + len - 8); - } - else if (len > 3) { - // If we have at least 4 and at most 8 bytes, set A to the first 32 - // bits and B to the last 32 bits. - a = CWISS_Load32(ptr); - b = CWISS_Load32(ptr + len - 4); - } - else if (len > 0) { - // If we have at least 1 and at most 3 bytes, read all of the provided - // bits into A, with some adjustments. - a = CWISS_Load1To3(ptr, len); - } - - uint64_t w = CWISS_AbslHash_LowLevelMix(a ^ salt[1], b ^ current_state); - uint64_t z = salt[1] ^ starting_length; - return CWISS_AbslHash_LowLevelMix(w, z); -} - -// A non-deterministic seed. -// -// The current purpose of this seed is to generate non-deterministic results -// and prevent having users depend on the particular hash values. -// It is not meant as a security feature right now, but it leaves the door -// open to upgrade it to a true per-process random seed. A true random seed -// costs more and we don't need to pay for that right now. -// -// On platforms with ASLR, we take advantage of it to make a per-process -// random value. -// See https://en.wikipedia.org/wiki/Address_space_layout_randomization -// -// On other platforms this is still going to be non-deterministic but most -// probably per-build and not per-process. -static const void* const CWISS_AbslHash_kSeed = &CWISS_AbslHash_kSeed; - -// The salt array used by LowLevelHash. This array is NOT the mechanism used to -// make absl::Hash non-deterministic between program invocations. See `Seed()` -// for that mechanism. -// -// Any random values are fine. These values are just digits from the decimal -// part of pi. -// https://en.wikipedia.org/wiki/Nothing-up-my-sleeve_number -static const uint64_t CWISS_AbslHash_kHashSalt[5] = { - 0x243F6A8885A308D3ULL, 0x13198A2E03707344, 0xA4093822299F31D0ULL, - 0x082EFA98EC4E6C89ULL, 0x452821E638D01377ULL, -}; - -#define CWISS_AbslHash_kPiecewiseChunkSize ((size_t)1024) - -typedef uint64_t CWISS_AbslHash_State_; -#define CWISS_AbslHash_kInit_ ((CWISS_AbslHash_State_)(uintptr_t)CWISS_AbslHash_kSeed) - -static inline void CWISS_AbslHash_Mix(CWISS_AbslHash_State_* state, uint64_t v) { - const uint64_t kMul = (sizeof (size_t) == 4) ? 0xcc9e2d51ULL : 0x9ddfea08eb382d69ULL; - *state = CWISS_AbslHash_LowLevelMix (*state + v, kMul); -} - -CWISS_INLINE_NEVER -static uint64_t CWISS_AbslHash_Hash64(const void* val, size_t len) { - return CWISS_AbslHash_LowLevelHash (val, len, CWISS_AbslHash_kInit_, CWISS_AbslHash_kHashSalt); -} - -CWISS_END_EXTERN -CWISS_END -/// cwisstable/internal/absl_hash.h //////////////////////////////////////////// - -/// cwisstable/hash.h ////////////////////////////////////////////////////////// -/// Hash functions. -/// -/// This file provides some hash functions to use with cwisstable types. -/// -/// Every hash function defines four symbols: -/// - `CWISS__State`, the state of the hash function. -/// - `CWISS__kInit`, the initial value of the hash state. -/// - `void CWISS__Write(State*, const void*, size_t)`, write some more -/// data into the hash state. -/// - `size_t CWISS__Finish(State)`, digest the state into a final hash -/// value. -/// -/// Currently available are two hashes: `FxHash`, which is small and fast, and -/// `AbslHash`, the hash function used by Abseil. -/// -/// `AbslHash` is the default hash function. - -CWISS_BEGIN -CWISS_BEGIN_EXTERN - -typedef size_t CWISS_FxHash_State; -#define CWISS_FxHash_kInit ((CWISS_FxHash_State)0) -static inline void CWISS_FxHash_Write(CWISS_FxHash_State* state, - const void* val, size_t len) { - const size_t kSeed = (size_t)(0x517cc1b727220a95ULL); - const uint32_t kRotate = 5; - - const char* p = (const char*)val; - CWISS_FxHash_State state_ = *state; - while (len > 0) { - size_t word = 0; - size_t to_read = len >= sizeof(state_) ? sizeof(state_) : len; - memcpy(&word, p, to_read); - - state_ = CWISS_RotateLeft(state_, kRotate); - state_ ^= word; - state_ *= kSeed; - - len -= to_read; - p += to_read; - } - *state = state_; -} -static inline size_t CWISS_FxHash_Finish(CWISS_FxHash_State state) { - return state; -} - -typedef CWISS_AbslHash_State_ CWISS_AbslHash_State; -#define CWISS_AbslHash_kInit CWISS_AbslHash_kInit_ -static inline void CWISS_AbslHash_Write(CWISS_AbslHash_State* state, - const void* val, size_t len) { - const char* val8 = (const char*)val; - if (CWISS_LIKELY(len < CWISS_AbslHash_kPiecewiseChunkSize)) { - goto CWISS_AbslHash_Write_small; - } - - while (len >= CWISS_AbslHash_kPiecewiseChunkSize) { - CWISS_AbslHash_Mix( - state, CWISS_AbslHash_Hash64(val8, CWISS_AbslHash_kPiecewiseChunkSize)); - len -= CWISS_AbslHash_kPiecewiseChunkSize; - val8 += CWISS_AbslHash_kPiecewiseChunkSize; - } - -CWISS_AbslHash_Write_small:; - uint64_t v; - if (len > 16) { - v = CWISS_AbslHash_Hash64(val8, len); - } - else if (len > 8) { - CWISS_U128 p = CWISS_Load9To16(val8, len); - CWISS_AbslHash_Mix(state, p.lo); - v = p.hi; - } - else if (len >= 4) { - v = CWISS_Load4To8(val8, len); - } - else if (len > 0) { - v = CWISS_Load1To3(val8, len); - } - else { - // Empty ranges have no effect. - return; - } - - CWISS_AbslHash_Mix(state, v); -} -static inline size_t CWISS_AbslHash_Finish(CWISS_AbslHash_State state) { - return state; -} - -CWISS_END_EXTERN -CWISS_END -/// cwisstable/hash.h ////////////////////////////////////////////////////////// - -/// cwisstable/policy.h //////////////////////////////////////////////////////// -/// Hash table policies. -/// -/// Table policies are `cwisstable`'s generic code mechanism. All code in -/// `cwisstable`'s internals is completely agnostic to: -/// - The layout of the elements. -/// - The storage strategy for the elements (inline, indirect in the heap). -/// - Hashing, comparison, and allocation. -/// -/// This information is provided to `cwisstable`'s internals by way of a -/// *policy*: a vtable describing how to move elements around, hash them, -/// compare them, allocate storage for them, and so on and on. This design is -/// inspired by Abseil's equivalent, which is a template parameter used for -/// sharing code between all the SwissTable-backed containers. -/// -/// Unlike Abseil, policies are part of `cwisstable`'s public interface. Due to -/// C's lack of any mechanism for detecting the gross properties of types, -/// types with unwritten invariants, such as C strings (NUL-terminated byte -/// arrays), users must be able to carefully describe to `cwisstable` how to -/// correctly do things to their type. DESIGN.md goes into detailed rationale -/// for this polymorphism strategy. -/// -/// # Defining a Policy -/// -/// Policies are defined as read-only globals and passed around by pointer to -/// different `cwisstable` functions; macros are provided for doing this, since -/// most of these functions will not vary significantly from one type to -/// another. There are four of them: -/// -/// - `CWISS_DECLARE_FLAT_SET_POLICY(kPolicy, Type, ...)` -/// - `CWISS_DECLARE_FLAT_MAP_POLICY(kPolicy, Key, Value, ...)` -/// - `CWISS_DECLARE_NODE_SET_POLICY(kPolicy, Type, ...)` -/// - `CWISS_DECLARE_NODE_MAP_POLICY(kPolicy, Key, Value, ...)` -/// -/// These correspond to the four SwissTable types in Abseil: two map types and -/// two set types; "flat" means that elements are stored inline in the backing -/// array, whereas "node" means that the element is stored in its own heap -/// allocation, making it stable across rehashings (which SwissTable does more -/// or less whenever it feels like it). -/// -/// Each macro expands to a read-only global variable definition (with the name -/// `kPolicy`, i.e, the first variable) dedicated for the specified type(s). -/// The arguments that follow are overrides for the default values of each field -/// in the policy; all but the size and alignment fields of `CWISS_ObjectPolicy` -/// may be overridden. To override the field `kPolicy.foo.bar`, pass -/// `(foo_bar, value)` to the macro. If multiple such pairs are passed in, the -/// first one found wins. `examples/stringmap.c` provides an example of how to -/// use this functionality. -/// -/// For "common" uses, where the key and value are plain-old-data, `declare.h` -/// has dedicated macros, and fussing with policies directly is unnecessary. - -CWISS_BEGIN -CWISS_BEGIN_EXTERN - -/// A policy describing the basic laying properties of a type. -/// -/// This type describes how to move values of a particular type around. -typedef struct { - /// The layout of the stored object. - size_t size, align; - - /// Performs a deep copy of `src` onto a fresh location `dst`. - void (*copy)(void* dst, const void* src); - - /// Destroys an object. - /// - /// This member may, as an optimization, be null. This will cause it to - /// behave as a no-op, and may be more efficient than making this an empty - /// function. - void (*dtor)(void* val); -} CWISS_ObjectPolicy; - -/// A policy describing the hashing properties of a type. -/// -/// This type describes the necessary information for putting a value into a -/// hash table. -/// -/// A *heterogenous* key policy is one whose equality function expects different -/// argument types, which can be used for so-called heterogenous lookup: finding -/// an element of a table by comparing it to a somewhat different type. If the -/// table element is, for example, a `std::string`[1]-like type, it could still -/// be found via a non-owning version like a `std::string_view`[2]. This is -/// important for making efficient use of a SwissTable. -/// -/// [1]: For non C++ programmers: a growable string type implemented as a -/// `struct { char* ptr; size_t size, capacity; }`. -/// [2]: Similarly, a `std::string_view` is a pointer-length pair to a string -/// *somewhere*; unlike a C-style string, it might be a substring of a -/// larger allocation elsewhere. -typedef struct { - /// Computes the hash of a value. - /// - /// This function must be such that if two elements compare equal, they must - /// have the same hash (but not vice-versa). - /// - /// If this policy is heterogenous, this function must be defined so that - /// given the original key policy of the table's element type, if - /// `hetero->eq(a, b)` holds, then `hetero->hash(a) == original->hash(b)`. - /// In other words, the obvious condition for a hash table to work correctly - /// with this policy. - size_t(*hash)(const void* val); - - /// Compares two values for equality. - /// - /// This function is actually not symmetric: the first argument will always be - /// the value being searched for, and the second will be a pointer to the - /// candidate entry. In particular, this means they can be different types: - /// in C++ parlance, `needle` could be a `std::string_view`, while `candidate` - /// could be a `std::string`. - bool (*eq)(const void* needle, const void* candidate); -} CWISS_KeyPolicy; - -/// A policy for allocation. -/// -/// This type provides access to a custom allocator. -typedef struct { - /// Allocates memory. - /// - /// This function must never fail and never return null, unlike `malloc`. This - /// function does not need to tolerate zero sized allocations. - void* (*alloc)(size_t size, size_t align); - - /// Deallocates memory allocated by `alloc`. - /// - /// This function is passed the same size/alignment as was passed to `alloc`, - /// allowing for sized-delete optimizations. - void (*free)(void* array, size_t size, size_t align); -} CWISS_AllocPolicy; - -/// A policy for allocating space for slots. -/// -/// This allows us to distinguish between inline storage (more cache-friendly) -/// and outline (pointer-stable). -typedef struct { - /// The layout of a slot value. - /// - /// Usually, this will be the same as for the object type, *or* the layout - /// of a pointer (for outline storage). - size_t size, align; - - /// Initializes a new slot at the given location. - /// - /// This function does not initialize the value *in* the slot; it simply sets - /// up the slot so that a value can be `memcpy`'d or otherwise emplaced into - /// the slot. - void (*init)(void* slot); - - /// Destroys a slot, including the destruction of the value it contains. - /// - /// This function may, as an optimization, be null. This will cause it to - /// behave as a no-op. - void (*del)(void* slot); - - /// Transfers a slot. - /// - /// `dst` must be uninitialized; `src` must be initialized. After this - /// function, their roles will be switched: `dst` will be initialized and - /// contain the value from `src`; `src` will be initialized. - /// - /// This function need not actually copy the underlying value. - void (*transfer)(void* dst, void* src); - - /// Extracts a pointer to the value inside the a slot. - /// - /// This function does not need to tolerate nulls. - void* (*get)(void* slot); -} CWISS_SlotPolicy; - -/// A hash table policy. -/// -/// See the header documentation for more information. -typedef struct { - const CWISS_ObjectPolicy* obj; - const CWISS_KeyPolicy* key; - const CWISS_AllocPolicy* alloc; - const CWISS_SlotPolicy* slot; -} CWISS_Policy; - -/// Declares a hash set policy with inline storage for the given type. -/// -/// See the header documentation for more information. -#define CWISS_DECLARE_FLAT_SET_POLICY(kPolicy_, Type_, obj_copy, obj_dtor, key_hash, key_eq) \ - CWISS_DECLARE_FLAT_POLICY_(kPolicy_, Type_, Type_, obj_copy, obj_dtor, key_hash, key_eq) - -/// Declares a hash set policy with pointer-stable storage for the given type. -/// -/// See the header documentation for more information. -#define CWISS_DECLARE_NODE_SET_POLICY(kPolicy_, Type_, obj_copy, obj_dtor, key_hash, key_eq) \ - CWISS_DECLARE_NODE_POLICY_(kPolicy_, Type_, Type_, obj_copy, obj_dtor, key_hash, key_eq) - -/// Declares a hash map policy with pointer-stable storage for the given key and -/// value types. -/// -/// See the header documentation for more information. -#define CWISS_DECLARE_NODE_MAP_POLICY(kPolicy_, K_, V_, obj_copy, obj_dtor, key_hash, key_eq) \ - typedef struct kPolicy_##_entry_t { \ - K_ k; \ - V_ v; \ - } kPolicy_##_Entry; \ - CWISS_DECLARE_NODE_POLICY_(kPolicy_, kPolicy_##_Entry, K_, obj_copy, obj_dtor, key_hash, key_eq) - -// ---- PUBLIC API ENDS HERE! ---- - -/// Declares a hash map policy with inline storage for the given key and value -/// types. -/// -/// See the header documentation for more information. -#define CWISS_DECLARE_FLAT_MAP_POLICY(kPolicy_, K_, V_, obj_copy, obj_dtor, key_hash, key_eq) \ - typedef struct kPolicy_##_entry_t { \ - K_ k; \ - V_ v; \ - } kPolicy_##_Entry; \ - CWISS_DECLARE_FLAT_POLICY_(kPolicy_, kPolicy_##_Entry, K_, obj_copy, obj_dtor, key_hash, key_eq) - -#define CWISS_DECLARE_FLAT_POLICY_(kPolicy_, Type_, Key_, obj_copy, obj_dtor, key_hash, key_eq) \ - CWISS_BEGIN \ - static inline void kPolicy_##_DefaultSlotInit(void* slot) {} \ - static inline void kPolicy_##_DefaultSlotTransfer(void* dst, void* src) { \ - memcpy(dst, src, sizeof(Type_)); \ - } \ - static inline void* kPolicy_##_DefaultSlotGet(void* slot) { return slot; } \ - static inline void kPolicy_##_DefaultSlotDtor(void* slot){ \ - obj_dtor (slot); \ - } \ - \ - static const CWISS_ObjectPolicy kPolicy_##_ObjectPolicy = { \ - sizeof(Type_), \ - alignof(Type_), \ - obj_copy, \ - obj_dtor \ - }; \ - static const CWISS_KeyPolicy kPolicy_##_KeyPolicy = { \ - key_hash, key_eq, \ - }; \ - static const CWISS_AllocPolicy kPolicy_##_AllocPolicy = { \ - CWISS_DefaultMalloc, \ - CWISS_DefaultFree, \ - }; \ - static const CWISS_SlotPolicy kPolicy_##_SlotPolicy = { \ - sizeof(Type_), \ - sizeof(Type_), \ - kPolicy_##_DefaultSlotInit, \ - kPolicy_##_DefaultSlotDtor, \ - kPolicy_##_DefaultSlotTransfer, \ - kPolicy_##_DefaultSlotGet, \ - }; \ - CWISS_END \ - static const CWISS_Policy kPolicy_ = { \ - &kPolicy_##_ObjectPolicy, \ - &kPolicy_##_KeyPolicy, \ - &kPolicy_##_AllocPolicy, \ - &kPolicy_##_SlotPolicy, \ - } - -static inline void* CWISS_DefaultMalloc(size_t size, size_t align) { - void* p = malloc(size); // TODO: Check alignment. - CWISS_CHECK(p != NULL, "malloc() returned null"); - return p; -} -static inline void CWISS_DefaultFree(void* array, size_t size, size_t align) { - free(array); -} - -#define CWISS_DECLARE_NODE_POLICY_(kPolicy_, Type_, Key_, obj_copy, obj_dtor, key_hash, key_eq) \ - CWISS_BEGIN \ - static inline void kPolicy_##_NodeSlotInit(void* slot) { \ - void* node = CWISS_DefaultMalloc(sizeof(Type_), alignof(Type_)); \ - memcpy(slot, &node, sizeof(node)); \ - } \ - static inline void kPolicy_##_NodeSlotDtor(void* slot) { \ - obj_dtor(*(void**)slot); \ - CWISS_DefaultFree(*(void**)slot, sizeof(Type_), alignof(Type_)); \ - } \ - static inline void kPolicy_##_NodeSlotTransfer(void* dst, void* src) { \ - memcpy(dst, src, sizeof(void*)); \ - } \ - static inline void* kPolicy_##_NodeSlotGet(void* slot) { \ - return *((void**)slot); \ - } \ - static const CWISS_ObjectPolicy kPolicy_##_ObjectPolicy = { \ - sizeof(Type_), \ - alignof(Type_), \ - obj_copy, \ - obj_dtor \ - }; \ - static const CWISS_KeyPolicy kPolicy_##_KeyPolicy = { \ - key_hash, key_eq, \ - }; \ - static const CWISS_AllocPolicy kPolicy_##_AllocPolicy = { \ - CWISS_DefaultMalloc, \ - CWISS_DefaultFree, \ - }; \ - static const CWISS_SlotPolicy kPolicy_##_SlotPolicy = { \ - sizeof(void*), \ - alignof(void*), \ - kPolicy_##_NodeSlotInit, \ - kPolicy_##_NodeSlotDtor, \ - kPolicy_##_NodeSlotTransfer, \ - kPolicy_##_NodeSlotGet, \ - }; \ - CWISS_END \ - static const CWISS_Policy kPolicy_ = { \ - &kPolicy_##_ObjectPolicy, \ - &kPolicy_##_KeyPolicy, \ - &kPolicy_##_AllocPolicy, \ - &kPolicy_##_SlotPolicy, \ - } - -CWISS_END_EXTERN -CWISS_END -/// cwisstable/policy.h //////////////////////////////////////////////////////// - -/// cwisstable/internal/raw_table.h //////////////////////////////////////////// -/// The SwissTable implementation. -/// -/// `CWISS_RawTable` is the core data structure that all SwissTables wrap. -/// -/// All functions in this header take a `const CWISS_Policy*`, which describes -/// how to manipulate the elements in a table. The same pointer (i.e., same -/// address and provenance) passed to the function that created the -/// `CWISS_RawTable` MUST be passed to all subsequent function calls, and it -/// must not be mutated at any point between those calls. Failure to adhere to -/// these requirements is UB. -/// -/// It is STRONGLY recommended that this pointer point to a const global. - -CWISS_BEGIN -CWISS_BEGIN_EXTERN - -/// A SwissTable. -/// -/// This is absl::container_internal::raw_hash_set in Abseil. -typedef struct { - /// The control bytes (and, also, a pointer to the base of the backing array). - /// - /// This contains `capacity_ + 1 + CWISS_NumClonedBytes()` entries. - CWISS_ControlByte* ctrl_; - /// The beginning of the slots, located at `CWISS_SlotOffset()` bytes after - /// `ctrl_`. May be null for empty tables. - char* slots_; - /// The number of filled slots. - size_t size_; - /// The total number of available slots. - size_t capacity_; - /// The number of slots we can still fill before a rehash. See - /// `CWISS_CapacityToGrowth()`. - size_t growth_left_; -} CWISS_RawTable; - - -/// An iterator into a SwissTable. -/// -/// Unlike a C++ iterator, there is no "end" to compare to. Instead, -/// `CWISS_RawIter_get()` will yield a null pointer once the iterator is -/// exhausted. -/// -/// Invariants: -/// - `ctrl_` and `slot_` are always in sync (i.e., the pointed to control byte -/// corresponds to the pointed to slot), or both are null. `set_` may be null -/// in the latter case. -/// - `ctrl_` always points to a full slot. -typedef struct { - CWISS_RawTable* set_; - CWISS_ControlByte* ctrl_; - char* slot_; -} CWISS_RawIter; - -/// Fixes up `ctrl_` to point to a full by advancing it and `slot_` until they -/// reach one. -/// -/// If a sentinel is reached, we null both of them out instead. -static inline void CWISS_RawIter_SkipEmptyOrDeleted(const CWISS_Policy* policy, - CWISS_RawIter* self) { - while (CWISS_IsEmptyOrDeleted(*self->ctrl_)) { - CWISS_Group g = CWISS_Group_new(self->ctrl_); - uint32_t shift = CWISS_Group_CountLeadingEmptyOrDeleted(&g); - self->ctrl_ += shift; - self->slot_ += shift * policy->slot->size; - } - - // Not sure why this is a branch rather than a cmov; Abseil uses a branch. - if (CWISS_UNLIKELY(*self->ctrl_ == CWISS_kSentinel)) { - self->ctrl_ = NULL; - self->slot_ = NULL; - } -} - -/// Creates a valid iterator starting at the `index`th slot. -static inline CWISS_RawIter CWISS_RawTable_iter_at(const CWISS_Policy* policy, - CWISS_RawTable* self, - size_t index) { - CWISS_RawIter iter = { - self, - self->ctrl_ + index, - self->slots_ ? self->slots_ + index * policy->slot->size : NULL, - }; - CWISS_RawIter_SkipEmptyOrDeleted(policy, &iter); - CWISS_AssertIsValid(iter.ctrl_); - return iter; -} - -/// Creates an iterator for `self`. -static inline CWISS_RawIter CWISS_RawTable_iter(const CWISS_Policy* policy, - CWISS_RawTable* self) { - return CWISS_RawTable_iter_at(policy, self, 0); -} - -/// Creates a valid iterator starting at the `index`th slot, accepting a `const` -/// pointer instead. -static inline CWISS_RawIter CWISS_RawTable_citer_at(const CWISS_Policy* policy, - const CWISS_RawTable* self, - size_t index) { - return CWISS_RawTable_iter_at(policy, (CWISS_RawTable*)self, index); -} - -/// Creates an iterator for `self`, accepting a `const` pointer instead. -static inline CWISS_RawIter CWISS_RawTable_citer(const CWISS_Policy* policy, - const CWISS_RawTable* self) { - return CWISS_RawTable_iter(policy, (CWISS_RawTable*)self); -} - -/// Returns a pointer into the currently pointed-to slot (*not* to the slot -/// itself, but rather its contents). -/// -/// Returns null if the iterator has been exhausted. -static inline void* CWISS_RawIter_get(const CWISS_Policy* policy, - const CWISS_RawIter* self) { - CWISS_AssertIsValid(self->ctrl_); - if (self->slot_ == NULL) { - return NULL; - } - - return policy->slot->get(self->slot_); -} - -/// Advances the iterator and returns the result of `CWISS_RawIter_get()`. -/// -/// Calling on an empty iterator is UB. -static inline void* CWISS_RawIter_next(const CWISS_Policy* policy, - CWISS_RawIter* self) { - CWISS_AssertIsFull(self->ctrl_); - self->ctrl_++; - self->slot_ += policy->slot->size; - - CWISS_RawIter_SkipEmptyOrDeleted(policy, self); - return CWISS_RawIter_get(policy, self); -} - -/// Erases, but does not destroy, the value pointed to by `it`. -static inline void CWISS_RawTable_EraseMetaOnly(const CWISS_Policy* policy, - CWISS_RawIter it) { - CWISS_DCHECK(CWISS_IsFull(*it.ctrl_), "erasing a dangling iterator"); - --it.set_->size_; - const size_t index = (size_t)(it.ctrl_ - it.set_->ctrl_); - const size_t index_before = (index - CWISS_Group_kWidth) & it.set_->capacity_; - CWISS_Group g_after = CWISS_Group_new(it.ctrl_); - CWISS_BitMask empty_after = CWISS_Group_MatchEmpty(&g_after); - CWISS_Group g_before = CWISS_Group_new(it.set_->ctrl_ + index_before); - CWISS_BitMask empty_before = CWISS_Group_MatchEmpty(&g_before); - - // We count how many consecutive non empties we have to the right and to the - // left of `it`. If the sum is >= kWidth then there is at least one probe - // window that might have seen a full group. - bool was_never_full = - empty_before.mask && empty_after.mask && - (size_t)(CWISS_BitMask_TrailingZeros(&empty_after) + - CWISS_BitMask_LeadingZeros(&empty_before)) < CWISS_Group_kWidth; - - CWISS_SetCtrl(index, was_never_full ? CWISS_kEmpty : CWISS_kDeleted, - it.set_->capacity_, it.set_->ctrl_, it.set_->slots_, - policy->slot->size); - it.set_->growth_left_ += was_never_full; - // infoz().RecordErase(); -} - -/// Computes a lower bound for the expected available growth and applies it to -/// `self_`. -static inline void CWISS_RawTable_ResetGrowthLeft(const CWISS_Policy* policy, - CWISS_RawTable* self) { - self->growth_left_ = CWISS_CapacityToGrowth(self->capacity_) - self->size_; -} - -/// Allocates a backing array for `self` and initializes its control bits. This -/// reads `capacity_` and updates all other fields based on the result of the -/// allocation. -/// -/// This does not free the currently held array; `capacity_` must be nonzero. -static inline void CWISS_RawTable_InitializeSlots(const CWISS_Policy* policy, - CWISS_RawTable* self) { - CWISS_DCHECK(self->capacity_, "capacity should be nonzero"); - // Folks with custom allocators often make unwarranted assumptions about the - // behavior of their classes vis-a-vis trivial destructability and what - // calls they will or wont make. Avoid sampling for people with custom - // allocators to get us out of this mess. This is not a hard guarantee but - // a workaround while we plan the exact guarantee we want to provide. - // - // People are often sloppy with the exact type of their allocator (sometimes - // it has an extra const or is missing the pair, but rebinds made it work - // anyway). To avoid the ambiguity, we work off SlotAlloc which we have - // bound more carefully. - // - // NOTE(mcyoung): Not relevant in C but kept in case we decide to do custom - // alloc. - /*if (std::is_same>::value && - slots_ == nullptr) { - infoz() = Sample(sizeof(slot_type)); - }*/ - - char* mem = - (char*) // Cast for C++. - policy->alloc->alloc(CWISS_AllocSize(self->capacity_, policy->slot->size, - policy->slot->align), - policy->slot->align); - - self->ctrl_ = (CWISS_ControlByte*)mem; - self->slots_ = mem + CWISS_SlotOffset(self->capacity_, policy->slot->align); - CWISS_ResetCtrl(self->capacity_, self->ctrl_, self->slots_, - policy->slot->size); - CWISS_RawTable_ResetGrowthLeft(policy, self); - - // infoz().RecordStorageChanged(size_, capacity_); -} - -/// Destroys all slots in the backing array, frees the backing array, and clears -/// all top-level book-keeping data. -static inline void CWISS_RawTable_DestroySlots(const CWISS_Policy* policy, - CWISS_RawTable* self) { - if (!self->capacity_) return; - - if (policy->slot->del != NULL) { - size_t i; - for (i = 0; i != self->capacity_; i++) { - if (CWISS_IsFull(self->ctrl_[i])) { - policy->slot->del(self->slots_ + i * policy->slot->size); - } - } - } - - policy->alloc->free( - self->ctrl_, - CWISS_AllocSize(self->capacity_, policy->slot->size, policy->slot->align), - policy->slot->align); - self->ctrl_ = CWISS_EmptyGroup(); - self->slots_ = NULL; - self->size_ = 0; - self->capacity_ = 0; - self->growth_left_ = 0; -} - -/// Grows the table to the given capacity, triggering a rehash. -static inline void CWISS_RawTable_Resize(const CWISS_Policy* policy, - CWISS_RawTable* self, - size_t new_capacity) { - CWISS_DCHECK(CWISS_IsValidCapacity(new_capacity), "invalid capacity: %zu", - new_capacity); - - CWISS_ControlByte* old_ctrl = self->ctrl_; - char* old_slots = self->slots_; - const size_t old_capacity = self->capacity_; - self->capacity_ = new_capacity; - CWISS_RawTable_InitializeSlots(policy, self); - - size_t i; - for (i = 0; i != old_capacity; i++) { - if (CWISS_IsFull(old_ctrl[i])) { - size_t hash = policy->key->hash( - policy->slot->get(old_slots + i * policy->slot->size)); - CWISS_FindInfo target = - CWISS_FindFirstNonFull(self->ctrl_, hash, self->capacity_); - size_t new_i = target.offset; - CWISS_SetCtrl(new_i, CWISS_H2(hash), self->capacity_, self->ctrl_, - self->slots_, policy->slot->size); - policy->slot->transfer(self->slots_ + new_i * policy->slot->size, - old_slots + i * policy->slot->size); - } - } - if (old_capacity) { - CWISS_UnpoisonMemory(old_slots, policy->slot->size * old_capacity); - policy->alloc->free( - old_ctrl, - CWISS_AllocSize(old_capacity, policy->slot->size, policy->slot->align), - policy->slot->align); - } -} - -/// Prunes control bits to remove as many tombstones as possible. -/// -/// See the comment on `CWISS_RawTable_rehash_and_grow_if_necessary()`. -CWISS_INLINE_NEVER -static void CWISS_RawTable_DropDeletesWithoutResize(const CWISS_Policy* policy, - CWISS_RawTable* self) { - CWISS_DCHECK(CWISS_IsValidCapacity(self->capacity_), "invalid capacity: %zu", - self->capacity_); - CWISS_DCHECK(!CWISS_IsSmall(self->capacity_), - "unexpected small capacity: %zu", self->capacity_); - // Algorithm: - // - mark all DELETED slots as EMPTY - // - mark all FULL slots as DELETED - // - for each slot marked as DELETED - // hash = Hash(element) - // target = find_first_non_full(hash) - // if target is in the same group - // mark slot as FULL - // else if target is EMPTY - // transfer element to target - // mark slot as EMPTY - // mark target as FULL - // else if target is DELETED - // swap current element with target element - // mark target as FULL - // repeat procedure for current slot with moved from element (target) - CWISS_ConvertDeletedToEmptyAndFullToDeleted(self->ctrl_, self->capacity_); - // Unfortunately because we do not know this size statically, we need to take - // a trip to the allocator. Alternatively we could use a variable length - // alloca... - void* slot = policy->alloc->alloc(policy->slot->size, policy->slot->align); - - size_t i; - for (i = 0; i != self->capacity_; i++) { - if (!CWISS_IsDeleted(self->ctrl_[i])) continue; - - char* old_slot = self->slots_ + i * policy->slot->size; - size_t hash = policy->key->hash(policy->slot->get(old_slot)); - - const CWISS_FindInfo target = - CWISS_FindFirstNonFull(self->ctrl_, hash, self->capacity_); - const size_t new_i = target.offset; - - char* new_slot = self->slots_ + new_i * policy->slot->size; - - // Verify if the old and new i fall within the same group wrt the hash. - // If they do, we don't need to move the object as it falls already in the - // best probe we can. - const size_t probe_offset = - CWISS_ProbeSeq_Start(self->ctrl_, hash, self->capacity_).offset_; -#define CWISS_ProbeIndex(pos_) \ - (((pos_ - probe_offset) & self->capacity_) / CWISS_Group_kWidth) - - // Element doesn't move. - if (CWISS_LIKELY(CWISS_ProbeIndex(new_i) == CWISS_ProbeIndex(i))) { - CWISS_SetCtrl(i, CWISS_H2(hash), self->capacity_, self->ctrl_, - self->slots_, policy->slot->size); - continue; - } - if (CWISS_IsEmpty(self->ctrl_[new_i])) { - // Transfer element to the empty spot. - // SetCtrl poisons/unpoisons the slots so we have to call it at the - // right time. - CWISS_SetCtrl(new_i, CWISS_H2(hash), self->capacity_, self->ctrl_, - self->slots_, policy->slot->size); - policy->slot->transfer(new_slot, old_slot); - CWISS_SetCtrl(i, CWISS_kEmpty, self->capacity_, self->ctrl_, self->slots_, - policy->slot->size); - } - else { - CWISS_DCHECK(CWISS_IsDeleted(self->ctrl_[new_i]), - "bad ctrl value at %zu: %02x", new_i, self->ctrl_[new_i]); - CWISS_SetCtrl(new_i, CWISS_H2(hash), self->capacity_, self->ctrl_, - self->slots_, policy->slot->size); - // Until we are done rehashing, DELETED marks previously FULL slots. - // Swap i and new_i elements. - - policy->slot->transfer(slot, old_slot); - policy->slot->transfer(old_slot, new_slot); - policy->slot->transfer(new_slot, slot); - --i; // repeat - } -#undef CWISS_ProbeSeq_Start_index - } - CWISS_RawTable_ResetGrowthLeft(policy, self); - policy->alloc->free(slot, policy->slot->size, policy->slot->align); -} - -/// Called whenever the table *might* need to conditionally grow. -/// -/// This function is an optimization opportunity to perform a rehash even when -/// growth is unnecessary, because vacating tombstones is beneficial for -/// performance in the long-run. -static inline void CWISS_RawTable_rehash_and_grow_if_necessary( - const CWISS_Policy* policy, CWISS_RawTable* self) { - if (self->capacity_ == 0) { - CWISS_RawTable_Resize(policy, self, 1); - } - else if (self->capacity_ > CWISS_Group_kWidth && - // Do these calculations in 64-bit to avoid overflow. - self->size_ * UINT64_C(32) <= self->capacity_ * UINT64_C(25)) { - // Squash DELETED without growing if there is enough capacity. - // - // Rehash in place if the current size is <= 25/32 of capacity_. - // Rationale for such a high factor: 1) drop_deletes_without_resize() is - // faster than resize, and 2) it takes quite a bit of work to add - // tombstones. In the worst case, seems to take approximately 4 - // insert/erase pairs to create a single tombstone and so if we are - // rehashing because of tombstones, we can afford to rehash-in-place as - // long as we are reclaiming at least 1/8 the capacity without doing more - // than 2X the work. (Where "work" is defined to be size() for rehashing - // or rehashing in place, and 1 for an insert or erase.) But rehashing in - // place is faster per operation than inserting or even doubling the size - // of the table, so we actually afford to reclaim even less space from a - // resize-in-place. The decision is to rehash in place if we can reclaim - // at about 1/8th of the usable capacity (specifically 3/28 of the - // capacity) which means that the total cost of rehashing will be a small - // fraction of the total work. - // - // Here is output of an experiment using the BM_CacheInSteadyState - // benchmark running the old case (where we rehash-in-place only if we can - // reclaim at least 7/16*capacity_) vs. this code (which rehashes in place - // if we can recover 3/32*capacity_). - // - // Note that although in the worst-case number of rehashes jumped up from - // 15 to 190, but the number of operations per second is almost the same. - // - // Abridged output of running BM_CacheInSteadyState benchmark from - // raw_hash_set_benchmark. N is the number of insert/erase operations. - // - // | OLD (recover >= 7/16 | NEW (recover >= 3/32) - // size | N/s LoadFactor NRehashes | N/s LoadFactor NRehashes - // 448 | 145284 0.44 18 | 140118 0.44 19 - // 493 | 152546 0.24 11 | 151417 0.48 28 - // 538 | 151439 0.26 11 | 151152 0.53 38 - // 583 | 151765 0.28 11 | 150572 0.57 50 - // 628 | 150241 0.31 11 | 150853 0.61 66 - // 672 | 149602 0.33 12 | 150110 0.66 90 - // 717 | 149998 0.35 12 | 149531 0.70 129 - // 762 | 149836 0.37 13 | 148559 0.74 190 - // 807 | 149736 0.39 14 | 151107 0.39 14 - // 852 | 150204 0.42 15 | 151019 0.42 15 - CWISS_RawTable_DropDeletesWithoutResize(policy, self); - } - else { - // Otherwise grow the container. - CWISS_RawTable_Resize(policy, self, self->capacity_ * 2 + 1); - } -} - -/// Prefetches the backing array to dodge potential TLB misses. -/// This is intended to overlap with execution of calculating the hash for a -/// key. -static inline void CWISS_RawTable_PrefetchHeapBlock( - const CWISS_Policy* policy, const CWISS_RawTable* self) { - CWISS_PREFETCH(self->ctrl_, 1); -} - -/// Issues CPU prefetch instructions for the memory needed to find or insert -/// a key. -/// -/// NOTE: This is a very low level operation and should not be used without -/// specific benchmarks indicating its importance. -static inline void CWISS_RawTable_Prefetch(const CWISS_Policy* policy, - const CWISS_RawTable* self, - const void* key) { - (void)key; -#if CWISS_HAVE_PREFETCH - CWISS_RawTable_PrefetchHeapBlock(policy, self); - CWISS_ProbeSeq seq = CWISS_ProbeSeq_Start(self->ctrl_, policy->key->hash(key), - self->capacity_); - CWISS_PREFETCH(self->ctrl_ + seq.offset_, 3); - CWISS_PREFETCH(self->ctrl_ + seq.offset_ * policy->slot->size, 3); -#endif -} - -/// The return type of `CWISS_RawTable_PrepareInsert()`. -typedef struct { - size_t index; - bool inserted; -} CWISS_PrepareInsert; - -/// Given the hash of a value not currently in the table, finds the next viable -/// slot index to insert it at. -/// -/// If the table does not actually have space, UB. -CWISS_INLINE_NEVER -static size_t CWISS_RawTable_PrepareInsert(const CWISS_Policy* policy, - CWISS_RawTable* self, size_t hash) { - CWISS_FindInfo target = - CWISS_FindFirstNonFull(self->ctrl_, hash, self->capacity_); - if (CWISS_UNLIKELY(self->growth_left_ == 0 && - !CWISS_IsDeleted(self->ctrl_[target.offset]))) { - CWISS_RawTable_rehash_and_grow_if_necessary(policy, self); - target = CWISS_FindFirstNonFull(self->ctrl_, hash, self->capacity_); - } - self->size_++; - self->growth_left_ -= CWISS_IsEmpty(self->ctrl_[target.offset]); - CWISS_SetCtrl(target.offset, CWISS_H2(hash), self->capacity_, self->ctrl_, - self->slots_, policy->slot->size); - // infoz().RecordInsert(hash, target.probe_length); - return target.offset; -} - -/// Attempts to find `key` in the table; if it isn't found, returns where to -/// insert it, instead. -static inline CWISS_PrepareInsert CWISS_RawTable_FindOrPrepareInsert( - const CWISS_Policy* policy, const CWISS_KeyPolicy* key_policy, - CWISS_RawTable* self, const void* key) { - CWISS_RawTable_PrefetchHeapBlock(policy, self); - size_t hash = key_policy->hash(key); - CWISS_ProbeSeq seq = CWISS_ProbeSeq_Start(self->ctrl_, hash, self->capacity_); - while (true) { - CWISS_Group g = CWISS_Group_new(self->ctrl_ + seq.offset_); - CWISS_BitMask match = CWISS_Group_Match(&g, CWISS_H2(hash)); - uint32_t i; - while (CWISS_BitMask_next(&match, &i)) { - size_t idx = CWISS_ProbeSeq_offset(&seq, i); - char* slot = self->slots_ + idx * policy->slot->size; - if (CWISS_LIKELY(key_policy->eq(key, policy->slot->get(slot)))) - return (CWISS_PrepareInsert) { idx, false }; - } - if (CWISS_LIKELY(CWISS_Group_MatchEmpty(&g).mask)) break; - CWISS_ProbeSeq_next(&seq); - CWISS_DCHECK(seq.index_ <= self->capacity_, "full table!"); - } - return (CWISS_PrepareInsert) { - CWISS_RawTable_PrepareInsert(policy, self, hash), - true - }; -} - -/// Prepares a slot to insert an element into. -/// -/// This function does all the work of calling the appropriate policy functions -/// to initialize the slot. -static inline void* CWISS_RawTable_PreInsert(const CWISS_Policy* policy, - CWISS_RawTable* self, size_t i) { - void* dst = self->slots_ + i * policy->slot->size; - policy->slot->init(dst); - return policy->slot->get(dst); -} - -/// Creates a new empty table with the given capacity. -static inline CWISS_RawTable CWISS_RawTable_new(const CWISS_Policy* policy, - size_t capacity) { - CWISS_RawTable self = { - .ctrl_ = CWISS_EmptyGroup(), - }; - - if (capacity != 0) { - self.capacity_ = CWISS_NormalizeCapacity(capacity); - CWISS_RawTable_InitializeSlots(policy, &self); - } - - return self; -} - -/// Ensures that at least `n` more elements can be inserted without a resize -/// (although this function my itself resize and rehash the table). -static inline void CWISS_RawTable_reserve(const CWISS_Policy* policy, - CWISS_RawTable* self, size_t n) { - if (n <= self->size_ + self->growth_left_) { - return; - } - - n = CWISS_NormalizeCapacity(CWISS_GrowthToLowerboundCapacity(n)); - CWISS_RawTable_Resize(policy, self, n); - - // This is after resize, to ensure that we have completed the allocation - // and have potentially sampled the hashtable. - // infoz().RecordReservation(n); -} - -/// Creates a duplicate of this table. -static inline CWISS_RawTable CWISS_RawTable_dup(const CWISS_Policy* policy, - const CWISS_RawTable* self) { - CWISS_RawTable copy = CWISS_RawTable_new(policy, 0); - - CWISS_RawTable_reserve(policy, ©, self->size_); - // Because the table is guaranteed to be empty, we can do something faster - // than a full `insert`. In particular we do not need to take a trip to - // `CWISS_RawTable_rehash_and_grow_if_necessary()` because we are already - // big enough (since `self` is a priori) and tombstones cannot be created - // during this process. - CWISS_RawIter iter; - for (iter = CWISS_RawTable_citer(policy, self); - CWISS_RawIter_get(policy, &iter); CWISS_RawIter_next(policy, &iter)) { - void* v = CWISS_RawIter_get(policy, &iter); - size_t hash = policy->key->hash(v); - - CWISS_FindInfo target = - CWISS_FindFirstNonFull(copy.ctrl_, hash, copy.capacity_); - CWISS_SetCtrl(target.offset, CWISS_H2(hash), copy.capacity_, copy.ctrl_, - copy.slots_, policy->slot->size); - void* slot = CWISS_RawTable_PreInsert(policy, ©, target.offset); - policy->obj->copy(slot, v); - // infoz().RecordInsert(hash, target.probe_length); - } - copy.size_ = self->size_; - copy.growth_left_ -= self->size_; - return copy; -} - -/// Destroys this table, destroying its elements and freeing the backing array. -static inline void CWISS_RawTable_destroy(const CWISS_Policy* policy, - CWISS_RawTable* self) { - CWISS_RawTable_DestroySlots(policy, self); -} - -/// Returns whether the table is empty. -static inline bool CWISS_RawTable_empty(const CWISS_Policy* policy, - const CWISS_RawTable* self) { - return !self->size_; -} - -/// Returns the number of elements in the table. -static inline size_t CWISS_RawTable_size(const CWISS_Policy* policy, - const CWISS_RawTable* self) { - return self->size_; -} - -/// Returns the total capacity of the table, which is different from the number -/// of elements that would cause it to get resized. -static inline size_t CWISS_RawTable_capacity(const CWISS_Policy* policy, - const CWISS_RawTable* self) { - return self->capacity_; -} - -/// Clears the table, erasing every element contained therein. -static inline void CWISS_RawTable_clear(const CWISS_Policy* policy, CWISS_RawTable* self) { - // Iterating over this container is O(bucket_count()). When bucket_count() - // is much greater than size(), iteration becomes prohibitively expensive. - // For clear() it is more important to reuse the allocated array when the - // container is small because allocation takes comparatively long time - // compared to destruction of the elements of the container. So we pick the - // largest bucket_count() threshold for which iteration is still fast and - // past that we simply deallocate the array. - if (self->capacity_ > 127) { - CWISS_RawTable_DestroySlots(policy, self); - - // infoz().RecordClearedReservation(); - } else if (self->capacity_) { - if (policy->slot->del != NULL) { - size_t i; - for (i = 0; i != self->capacity_; i++) { - if (CWISS_IsFull(self->ctrl_[i])) { - policy->slot->del(self->slots_ + i * policy->slot->size); - } - } - } - - self->size_ = 0; - CWISS_ResetCtrl(self->capacity_, self->ctrl_, self->slots_, - policy->slot->size); - CWISS_RawTable_ResetGrowthLeft(policy, self); - } - CWISS_DCHECK(!self->size_, "size was still nonzero"); - // infoz().RecordStorageChanged(0, capacity_); -} - -/// The return type of `CWISS_RawTable_insert()`. -typedef struct { - /// An iterator referring to the relevant element. - CWISS_RawIter iter; - /// True if insertion actually occurred; false if the element was already - /// present. - bool inserted; -} CWISS_Insert; - -/// "Inserts" `val` into the table if it isn't already present. -/// -/// This function does not perform insertion; it behaves exactly like -/// `CWISS_RawTable_insert()` up until it would copy-initialize the new -/// element, instead returning a valid iterator pointing to uninitialized data. -/// -/// This allows, for example, lazily constructing the parts of the element that -/// do not figure into the hash or equality. -/// -/// If this function returns `true` in `inserted`, the caller has *no choice* -/// but to insert, i.e., they may not change their minds at that point. -/// -/// `key_policy` is a possibly heterogenous key policy for comparing `key`'s -/// type to types in the map. `key_policy` may be `&policy->key`. -static inline CWISS_Insert CWISS_RawTable_deferred_insert( - const CWISS_Policy* policy, const CWISS_KeyPolicy* key_policy, - CWISS_RawTable* self, const void* key) { - CWISS_PrepareInsert res = - CWISS_RawTable_FindOrPrepareInsert(policy, key_policy, self, key); - - if (res.inserted) { - CWISS_RawTable_PreInsert(policy, self, res.index); - } - return (CWISS_Insert) { - CWISS_RawTable_citer_at(policy, self, res.index), - res.inserted - }; -} - -/// Inserts `val` (by copy) into the table if it isn't already present. -/// -/// Returns an iterator pointing to the element in the map and whether it was -/// just inserted or was already present. -static inline CWISS_Insert CWISS_RawTable_insert(const CWISS_Policy* policy, - CWISS_RawTable* self, - const void* val) { - CWISS_PrepareInsert res = - CWISS_RawTable_FindOrPrepareInsert(policy, policy->key, self, val); - - if (res.inserted) { - void* slot = CWISS_RawTable_PreInsert(policy, self, res.index); - policy->obj->copy(slot, val); - } - return (CWISS_Insert) { - CWISS_RawTable_citer_at(policy, self, res.index), - res.inserted - }; -} - -/// Tries to find the corresponding entry for `key` using `hash` as a hint. -/// If not found, returns a null iterator. -/// -/// `key_policy` is a possibly heterogenous key policy for comparing `key`'s -/// type to types in the map. `key_policy` may be `&policy->key`. -/// -/// If `hash` is not actually the hash of `key`, UB. -static inline CWISS_RawIter CWISS_RawTable_find_hinted( - const CWISS_Policy* policy, const CWISS_KeyPolicy* key_policy, - const CWISS_RawTable* self, const void* key, size_t hash) { - CWISS_ProbeSeq seq = CWISS_ProbeSeq_Start(self->ctrl_, hash, self->capacity_); - while (true) { - CWISS_Group g = CWISS_Group_new(self->ctrl_ + seq.offset_); - CWISS_BitMask match = CWISS_Group_Match(&g, CWISS_H2(hash)); - uint32_t i; - while (CWISS_BitMask_next(&match, &i)) { - char* slot = - self->slots_ + CWISS_ProbeSeq_offset(&seq, i) * policy->slot->size; - if (CWISS_LIKELY(key_policy->eq(key, policy->slot->get(slot)))) - return CWISS_RawTable_citer_at(policy, self, - CWISS_ProbeSeq_offset(&seq, i)); - } - if (CWISS_LIKELY(CWISS_Group_MatchEmpty(&g).mask)) - return (CWISS_RawIter) { 0 }; - CWISS_ProbeSeq_next(&seq); - CWISS_DCHECK(seq.index_ <= self->capacity_, "full table!"); - } -} - -/// Tries to find the corresponding entry for `key`. -/// If not found, returns a null iterator. -/// -/// `key_policy` is a possibly heterogenous key policy for comparing `key`'s -/// type to types in the map. `key_policy` may be `&policy->key`. -static inline CWISS_RawIter CWISS_RawTable_find( - const CWISS_Policy* policy, const CWISS_KeyPolicy* key_policy, - const CWISS_RawTable* self, const void* key) { - return CWISS_RawTable_find_hinted(policy, key_policy, self, key, - key_policy->hash(key)); -} - -/// Erases the element pointed to by the given valid iterator. -/// This function will invalidate the iterator. -static inline void CWISS_RawTable_erase_at(const CWISS_Policy* policy, - CWISS_RawIter it) { - CWISS_AssertIsFull(it.ctrl_); - if (policy->slot->del != NULL) { - policy->slot->del(it.slot_); - } - CWISS_RawTable_EraseMetaOnly(policy, it); -} - -/// Erases the entry corresponding to `key`, if present. Returns true if -/// deletion occured. -/// -/// `key_policy` is a possibly heterogenous key policy for comparing `key`'s -/// type to types in the map. `key_policy` may be `&policy->key`. -static inline bool CWISS_RawTable_erase(const CWISS_Policy* policy, - const CWISS_KeyPolicy* key_policy, - CWISS_RawTable* self, const void* key) { - CWISS_RawIter it = CWISS_RawTable_find(policy, key_policy, self, key); - if (it.slot_ == NULL) return false; - CWISS_RawTable_erase_at(policy, it); - return true; -} - -/// Triggers a rehash, growing to at least a capacity of `n`. -static inline void CWISS_RawTable_rehash(const CWISS_Policy* policy, - CWISS_RawTable* self, size_t n) { - if (n == 0 && self->capacity_ == 0) return; - if (n == 0 && self->size_ == 0) { - CWISS_RawTable_DestroySlots(policy, self); - // infoz().RecordStorageChanged(0, 0); - // infoz().RecordClearedReservation(); - return; - } - - // bitor is a faster way of doing `max` here. We will round up to the next - // power-of-2-minus-1, so bitor is good enough. - size_t m = CWISS_NormalizeCapacity( - n | CWISS_GrowthToLowerboundCapacity(self->size_)); - // n == 0 unconditionally rehashes as per the standard. - if (n == 0 || m > self->capacity_) { - CWISS_RawTable_Resize(policy, self, m); - - // This is after resize, to ensure that we have completed the allocation - // and have potentially sampled the hashtable. - // infoz().RecordReservation(n); - } -} - -/// Returns whether `key` is contained in this table. -/// -/// `key_policy` is a possibly heterogenous key policy for comparing `key`'s -/// type to types in the map. `key_policy` may be `&policy->key`. -static inline bool CWISS_RawTable_contains(const CWISS_Policy* policy, - const CWISS_KeyPolicy* key_policy, - const CWISS_RawTable* self, - const void* key) { - return CWISS_RawTable_find(policy, key_policy, self, key).slot_ != NULL; -} - -CWISS_END_EXTERN -CWISS_END -/// cwisstable/internal/raw_table.h //////////////////////////////////////////// - -/// cwisstable/declare.h /////////////////////////////////////////////////////// -/// SwissTable code generation macros. -/// -/// This file is the entry-point for users of `cwisstable`. It exports six -/// macros for generating different kinds of tables. Four correspond to Abseil's -/// four SwissTable containers: -/// -/// - `CWISS_DECLARE_FLAT_HASHSET(Set, Type)` -/// - `CWISS_DECLARE_FLAT_HASHMAP(Map, Key, Value)` -/// - `CWISS_DECLARE_NODE_HASHSET(Set, Type)` -/// - `CWISS_DECLARE_NODE_HASHMAP(Map, Key, Value)` -/// -/// These expand to a type (with the same name as the first argument) and and -/// a collection of strongly-typed functions associated to it (the generated -/// API is described below). These macros use the default policy (see policy.h) -/// for each of the four containers; custom policies may be used instead via -/// the following macros: -/// -/// - `CWISS_DECLARE_HASHSET_WITH(Set, Type, kPolicy)` -/// - `CWISS_DECLARE_HASHMAP_WITH(Map, Key, Value, kPolicy)` -/// -/// `kPolicy` must be a constant global variable referring to an appropriate -/// property for the element types of the container. -/// -/// The generated API is safe: the functions are well-typed and automatically -/// pass the correct policy pointer. Because the pointer is a constant -/// expression, it promotes devirtualization when inlining. -/// -/// # Generated API -/// -/// See `set_api.h` and `map_api.h` for detailed listings of what the generated -/// APIs look like. - -CWISS_BEGIN -CWISS_BEGIN_EXTERN - -/// Generates a new hash set type with inline storage and the default -/// plain-old-data policies. -/// -/// See header documentation for examples of generated API. -#define CWISS_DECLARE_FLAT_HASHSET(HashSet_, Type_,obj_copy, obj_dtor, key_hash, key_eq) \ - CWISS_DECLARE_FLAT_SET_POLICY(HashSet_##_kPolicy, Type_, obj_copy, obj_dtor, key_hash, key_eq); \ - CWISS_DECLARE_HASHSET_WITH(HashSet_, Type_, HashSet_##_kPolicy) - -#define CWISS_DECLARE_FLAT_HASHSET_DEFAULT(HashSet_, Type_) \ - static inline void HashSet_##_default_dtor(void* val) { } \ - static inline void HashSet_##_default_copy(void* dst_, const void* src_) { \ - memcpy(dst_, src_, sizeof(Type_)); \ - } \ - static inline size_t HashSet_##_default_hash(const void* val) { \ - CWISS_AbslHash_State state = CWISS_AbslHash_kInit; \ - CWISS_AbslHash_Write(&state, val, sizeof(Type_)); \ - return CWISS_AbslHash_Finish(state); \ - } \ - static inline bool HashSet_##_default_eq(const void* a, const void* b) { return memcmp (a,b,sizeof(Type_)) == 0; } \ - CWISS_DECLARE_FLAT_HASHSET(HashSet_, Type_, \ - HashSet_##_default_copy, \ - HashSet_##_default_dtor, \ - HashSet_##_default_hash, \ - HashSet_##_default_eq); - -/// Generates a new hash set type with outline storage and the default -/// plain-old-data policies. -/// -/// See header documentation for examples of generated API. -#define CWISS_DECLARE_NODE_HASHSET(HashSet_, Type_, obj_copy, obj_dtor, key_hash, key_eq) \ - CWISS_DECLARE_NODE_SET_POLICY(HashSet_##_kPolicy, Type_, obj_copy, obj_dtor, key_hash, key_eq); \ - CWISS_DECLARE_HASHSET_WITH(HashSet_, Type_, HashSet_##_kPolicy) - -#define CWISS_DECLARE_NODE_HASHSET_DEFAULT(HashSet_, Type_) \ - static inline void HashSet_##_default_dtor(void* val) { } \ - static inline void HashSet_##_default_copy(void* dst_, const void* src_) { \ - memcpy(dst_, src_, sizeof(Type_)); \ - } \ - static inline size_t HashSet_##_default_hash(const void* val) { \ - CWISS_AbslHash_State state = CWISS_AbslHash_kInit; \ - CWISS_AbslHash_Write(&state, val, sizeof(Type_)); \ - return CWISS_AbslHash_Finish(state); \ - } \ - static inline bool HashSet_##_default_eq(const void* a, const void* b) { return memcmp (a,b,sizeof(Type_)) == 0; } \ - CWISS_DECLARE_NODE_HASHSET(HashSet_, Type_, \ - HashSet_##_default_copy, \ - HashSet_##_default_dtor, \ - HashSet_##_default_hash, \ - HashSet_##_default_eq); - -/// Generates a new hash map type with inline storage and the default -/// plain-old-data policies. -/// -/// See header documentation for examples of generated API. -#define CWISS_DECLARE_FLAT_HASHMAP(HashMap_, K_, V_, obj_copy, obj_dtor, key_hash, key_eq) \ - CWISS_DECLARE_FLAT_MAP_POLICY(HashMap_##_kPolicy, K_, V_, obj_copy, obj_dtor, key_hash, key_eq); \ - CWISS_DECLARE_HASHMAP_WITH(HashMap_, K_, V_, HashMap_##_kPolicy) - -#define CWISS_DECLARE_FLAT_HASHMAP_DEFAULT(HashMap_, K_, V_) \ - static inline void HashMap_##_default_dtor(void* val) { } \ - typedef struct { \ - K_ k; \ - V_ v; \ - } HashMap_##_EntryInternal; \ - static inline void HashMap_##_default_copy(void* dst_, const void* src_) { \ - memcpy(dst_, src_, sizeof(HashMap_##_EntryInternal)); \ - } \ - static inline size_t HashMap_##_default_hash(const void* val) { \ - CWISS_AbslHash_State state = CWISS_AbslHash_kInit; \ - CWISS_AbslHash_Write(&state, val, sizeof(K_)); \ - return CWISS_AbslHash_Finish(state); \ - } \ - static inline bool HashMap_##_default_eq(const void* a, const void* b) { return memcmp (a,b,sizeof(K_)) == 0; } \ - CWISS_DECLARE_FLAT_HASHMAP(HashMap_, K_, V_, \ - HashMap_##_default_copy, \ - HashMap_##_default_dtor, \ - HashMap_##_default_hash, \ - HashMap_##_default_eq); - -/// Generates a new hash map type with outline storage and the default -/// plain-old-data policies. -/// -/// See header documentation for examples of generated API. -#define CWISS_DECLARE_NODE_HASHMAP(HashMap_, K_, V_, a,b,c,d) \ - CWISS_DECLARE_NODE_MAP_POLICY(HashMap_##_kPolicy, K_, V_, a,b,c,d); \ - CWISS_DECLARE_HASHMAP_WITH(HashMap_, K_, V_, HashMap_##_kPolicy) - -#define CWISS_DECLARE_NODE_HASHMAP_DEFAULT(HashMap_, K_, V_) \ - typedef struct { \ - K_ k; \ - V_ v; \ - } HashMap_##_EntryInternal; \ - static inline void HashMap_##_default_dtor(void* val) { } \ - static inline void HashMap_##_default_copy(void* dst_, const void* src_) { \ - memcpy(dst_, src_, sizeof(HashMap_##_EntryInternal)); \ - } \ - static inline size_t HashMap_##_default_hash(const void* val) { \ - CWISS_AbslHash_State state = CWISS_AbslHash_kInit; \ - CWISS_AbslHash_Write(&state, val, sizeof(K_)); \ - return CWISS_AbslHash_Finish(state); \ - } \ - static inline bool HashMap_##_default_eq(const void* a, const void* b) { return memcmp (a,b,sizeof(K_)) == 0; } \ - CWISS_DECLARE_NODE_HASHMAP(HashMap_, K_, V_, \ - HashMap_##_default_copy, \ - HashMap_##_default_dtor, \ - HashMap_##_default_hash, \ - HashMap_##_default_eq); - -/// Generates a new hash set type using the given policy. -/// -/// See header documentation for examples of generated API. -#define CWISS_DECLARE_HASHSET_WITH(HashSet_, Type_, kPolicy_) \ - typedef Type_ HashSet_##_Entry; \ - typedef Type_ HashSet_##_Key; \ - CWISS_DECLARE_COMMON_(HashSet_, HashSet_##_Entry, HashSet_##_Key, kPolicy_) - -/// Generates a new hash map type using the given policy. -/// -/// See header documentation for examples of generated API. -#define CWISS_DECLARE_HASHMAP_WITH(HashMap_, K_, V_, kPolicy_) \ - typedef struct HashMap_##_entry_t { \ - K_ key; \ - V_ val; \ - } HashMap_##_Entry; \ - typedef K_ HashMap_##_Key; \ - CWISS_DECLARE_COMMON_(HashMap_, HashMap_##_Entry, HashMap_##_Key, kPolicy_) - -/// Declares a heterogenous lookup for an existing SwissTable type. -/// -/// This macro will expect to find the following functions: -/// - size_t __hash(const Key*); -/// - bool
__eq(const Key*, const
_Key*); -/// -/// These functions will be used to build the heterogenous key policy. -#define CWISS_DECLARE_LOOKUP(HashSet_, Key_) \ - CWISS_DECLARE_LOOKUP_NAMED(HashSet_, Key_, Key_) - -/// Declares a heterogenous lookup for an existing SwissTable type. -/// -/// This is like `CWISS_DECLARE_LOOKUP`, but allows customizing the name used -/// in the `_by_` prefix on the names, as well as the names of the extension -/// point functions. -#define CWISS_DECLARE_LOOKUP_NAMED(HashSet_, LookupName_, Key_) \ - CWISS_BEGIN \ -static inline size_t HashSet_##_##LookupName_##_SyntheticHash( \ - const void* val) { \ - return HashSet_##_##LookupName_##_hash((const Key_*)val); \ - } \ - static inline bool HashSet_##_##LookupName_##_SyntheticEq(const void* a, \ - const void* b) { \ - return HashSet_##_##LookupName_##_eq((const Key_*)a, \ - (const HashSet_##_Entry*)b); \ - } \ - static const CWISS_KeyPolicy HashSet_##_##LookupName_##_kPolicy = { \ - HashSet_##_##LookupName_##_SyntheticHash, \ - HashSet_##_##LookupName_##_SyntheticEq, \ - }; \ - \ - static inline const CWISS_KeyPolicy* HashSet_##_##LookupName_##_policy( \ - void) { \ - return &HashSet_##_##LookupName_##_kPolicy; \ - } \ - \ - static inline HashSet_##_Insert HashSet_##_deferred_insert_by_##LookupName_( \ - HashSet_* self, const Key_* key) { \ - CWISS_Insert ret = CWISS_RawTable_deferred_insert( \ - HashSet_##_policy(), &HashSet_##_##LookupName_##_kPolicy, &self->set_, \ - key); \ - return (HashSet_##_Insert){{ret.iter}, ret.inserted}; \ - } \ - static inline HashSet_##_CIter HashSet_##_cfind_hinted_by_##LookupName_( \ - const HashSet_* self, const Key_* key, size_t hash) { \ - return (HashSet_##_CIter){CWISS_RawTable_find_hinted( \ - HashSet_##_policy(), &HashSet_##_##LookupName_##_kPolicy, &self->set_, \ - key, hash)}; \ - } \ - static inline HashSet_##_Iter HashSet_##_find_hinted_by_##LookupName_( \ - HashSet_* self, const Key_* key, size_t hash) { \ - return (HashSet_##_Iter){CWISS_RawTable_find_hinted( \ - HashSet_##_policy(), &HashSet_##_##LookupName_##_kPolicy, &self->set_, \ - key, hash)}; \ - } \ - \ - static inline HashSet_##_CIter HashSet_##_cfind_by_##LookupName_( \ - const HashSet_* self, const Key_* key) { \ - return (HashSet_##_CIter){CWISS_RawTable_find( \ - HashSet_##_policy(), &HashSet_##_##LookupName_##_kPolicy, &self->set_, \ - key)}; \ - } \ - static inline HashSet_##_Iter HashSet_##_find_by_##LookupName_( \ - HashSet_* self, const Key_* key) { \ - return (HashSet_##_Iter){CWISS_RawTable_find( \ - HashSet_##_policy(), &HashSet_##_##LookupName_##_kPolicy, &self->set_, \ - key)}; \ - } \ - \ - static inline bool HashSet_##_contains_by_##LookupName_( \ - const HashSet_* self, const Key_* key) { \ - return CWISS_RawTable_contains(HashSet_##_policy(), \ - &HashSet_##_##LookupName_##_kPolicy, \ - &self->set_, key); \ - } \ - \ - static inline bool HashSet_##_erase_by_##LookupName_(HashSet_* self, \ - const Key_* key) { \ - return CWISS_RawTable_erase(HashSet_##_policy(), \ - &HashSet_##_##LookupName_##_kPolicy, \ - &self->set_, key); \ - } \ - \ - CWISS_END \ - /* Force a semicolon. */ \ - struct HashSet_##_##LookupName_##_NeedsTrailingSemicolon_ { \ - int x; \ - } - -// ---- PUBLIC API ENDS HERE! ---- - -#define CWISS_DECLARE_COMMON_(HashSet_, Type_, Key_, kPolicy_) \ - CWISS_BEGIN \ - static inline SDB_MAYBE_UNUSED const CWISS_Policy* HashSet_##_policy(void) { \ - return &kPolicy_; \ - } \ - \ - typedef struct HashSet_##_t { \ - CWISS_RawTable set_; \ - } HashSet_; \ - \ - static inline SDB_MAYBE_UNUSED HashSet_ HashSet_##_new(size_t bucket_count) { \ - return (HashSet_){CWISS_RawTable_new(&kPolicy_, bucket_count)}; \ - } \ - static inline SDB_MAYBE_UNUSED HashSet_ HashSet_##_dup(const HashSet_* that) { \ - return (HashSet_){CWISS_RawTable_dup(&kPolicy_, &that->set_)}; \ - } \ - static inline SDB_MAYBE_UNUSED void HashSet_##_destroy(HashSet_* self) { \ - CWISS_RawTable_destroy(&kPolicy_, &self->set_); \ - } \ - \ - typedef struct { \ - CWISS_RawIter it_; \ - } HashSet_##_Iter; \ - static inline SDB_MAYBE_UNUSED HashSet_##_Iter HashSet_##_iter(HashSet_* self) { \ - return (HashSet_##_Iter){CWISS_RawTable_iter(&kPolicy_, &self->set_)}; \ - } \ - static inline SDB_MAYBE_UNUSED Type_* HashSet_##_Iter_get(const HashSet_##_Iter* it) { \ - return (Type_*)CWISS_RawIter_get(&kPolicy_, &it->it_); \ - } \ - static inline SDB_MAYBE_UNUSED Type_* HashSet_##_Iter_next(HashSet_##_Iter* it) { \ - return (Type_*)CWISS_RawIter_next(&kPolicy_, &it->it_); \ - } \ - \ - typedef struct { \ - CWISS_RawIter it_; \ - } HashSet_##_CIter; \ - static inline SDB_MAYBE_UNUSED HashSet_##_CIter HashSet_##_citer(const HashSet_* self) { \ - return (HashSet_##_CIter){CWISS_RawTable_citer(&kPolicy_, &self->set_)}; \ - } \ - static inline SDB_MAYBE_UNUSED const Type_* HashSet_##_CIter_get( \ - const HashSet_##_CIter* it) { \ - return (const Type_*)CWISS_RawIter_get(&kPolicy_, &it->it_); \ - } \ - static inline SDB_MAYBE_UNUSED const Type_* HashSet_##_CIter_next(HashSet_##_CIter* it) { \ - return (const Type_*)CWISS_RawIter_next(&kPolicy_, &it->it_); \ - } \ - static inline SDB_MAYBE_UNUSED HashSet_##_CIter HashSet_##_Iter_const(HashSet_##_Iter it) { \ - return (HashSet_##_CIter){it.it_}; \ - } \ - \ - static inline SDB_MAYBE_UNUSED void HashSet_##_reserve(HashSet_* self, size_t n) { \ - CWISS_RawTable_reserve(&kPolicy_, &self->set_, n); \ - } \ - static inline SDB_MAYBE_UNUSED void HashSet_##_rehash(HashSet_* self, size_t n) { \ - CWISS_RawTable_rehash(&kPolicy_, &self->set_, n); \ - } \ - \ - static inline SDB_MAYBE_UNUSED bool HashSet_##_empty(const HashSet_* self) { \ - return CWISS_RawTable_empty(&kPolicy_, &self->set_); \ - } \ - static inline SDB_MAYBE_UNUSED size_t HashSet_##_size(const HashSet_* self) { \ - return CWISS_RawTable_size(&kPolicy_, &self->set_); \ - } \ - static inline SDB_MAYBE_UNUSED size_t HashSet_##_capacity(const HashSet_* self) { \ - return CWISS_RawTable_capacity(&kPolicy_, &self->set_); \ - } \ - \ - static inline SDB_MAYBE_UNUSED void HashSet_##_clear(HashSet_* self) { \ - CWISS_RawTable_clear(&kPolicy_, &self->set_); \ - } \ - \ - typedef struct { \ - HashSet_##_Iter iter; \ - bool inserted; \ - } HashSet_##_Insert; \ - static inline SDB_MAYBE_UNUSED HashSet_##_Insert HashSet_##_deferred_insert( \ - HashSet_* self, const Key_* key) { \ - CWISS_Insert ret = CWISS_RawTable_deferred_insert(&kPolicy_, kPolicy_.key, \ - &self->set_, key); \ - return (HashSet_##_Insert){{ret.iter}, ret.inserted}; \ - } \ - static inline SDB_MAYBE_UNUSED HashSet_##_Insert HashSet_##_insert(HashSet_* self, \ - const Type_* val) { \ - CWISS_Insert ret = CWISS_RawTable_insert(&kPolicy_, &self->set_, val); \ - return (HashSet_##_Insert){{ret.iter}, ret.inserted}; \ - } \ - \ - static inline SDB_MAYBE_UNUSED HashSet_##_CIter HashSet_##_cfind_hinted( \ - const HashSet_* self, const Key_* key, size_t hash) { \ - return (HashSet_##_CIter){CWISS_RawTable_find_hinted( \ - &kPolicy_, kPolicy_.key, &self->set_, key, hash)}; \ - } \ - static inline SDB_MAYBE_UNUSED HashSet_##_Iter HashSet_##_find_hinted( \ - HashSet_* self, const Key_* key, size_t hash) { \ - return (HashSet_##_Iter){CWISS_RawTable_find_hinted( \ - &kPolicy_, kPolicy_.key, &self->set_, key, hash)}; \ - } \ - static inline SDB_MAYBE_UNUSED HashSet_##_CIter HashSet_##_cfind(const HashSet_* self, \ - const Key_* key) { \ - return (HashSet_##_CIter){ \ - CWISS_RawTable_find(&kPolicy_, kPolicy_.key, &self->set_, key)}; \ - } \ - static inline SDB_MAYBE_UNUSED HashSet_##_Iter HashSet_##_find(HashSet_* self, \ - const Key_* key) { \ - return (HashSet_##_Iter){ \ - CWISS_RawTable_find(&kPolicy_, kPolicy_.key, &self->set_, key)}; \ - } \ - \ - static inline bool SDB_MAYBE_UNUSED HashSet_##_contains(const HashSet_* self, \ - const Key_* key) { \ - return CWISS_RawTable_contains(&kPolicy_, kPolicy_.key, &self->set_, key); \ - } \ - \ - static inline void SDB_MAYBE_UNUSED HashSet_##_erase_at(HashSet_##_Iter it) { \ - CWISS_RawTable_erase_at(&kPolicy_, it.it_); \ - } \ - static inline bool SDB_MAYBE_UNUSED HashSet_##_erase(HashSet_* self, const Key_* key) { \ - return CWISS_RawTable_erase(&kPolicy_, kPolicy_.key, &self->set_, key); \ - } \ - \ - CWISS_END \ - /* Force a semicolon. */ struct HashSet_##_NeedsTrailingSemicolon_ { int x; } - -CWISS_END_EXTERN -CWISS_END -/// cwisstable/declare.h /////////////////////////////////////////////////////// - -#endif // CWISSTABLE_H_ diff --git a/shlr/sdb/include/sdb/dict.h b/shlr/sdb/include/sdb/dict.h deleted file mode 100644 index e924316644f5b..0000000000000 --- a/shlr/sdb/include/sdb/dict.h +++ /dev/null @@ -1,42 +0,0 @@ - -#define MHTSZ 32 - -typedef ut64 dicti; - -typedef struct { - dicti k; - dicti v; - void *u; -} dictkv; - -// 4 + 4 + 4 = 12 .. missing 4 more -// 8 + 8 + 4 = 20 .. missing 16, what about 32 ? -// 8 + 8 + 8 = 24 .. still not there, missing 8 -// 4 + 4 + 8 = 16 .. lgtm - -typedef void (*dict_freecb)(void *); -typedef int (*dictkv_cb)(dictkv *, void *); - -typedef struct { - void **table; - dict_freecb f; - ut32 size; -} dict; - -typedef dict SdbMini; - -SDB_API dict *dict_new(ut32 size, dict_freecb f); -SDB_API void dict_free(dict*); -SDB_API bool dict_init(dict *m, ut32, dict_freecb f); -SDB_API void dict_fini(dict *m); -SDB_API ut32 dict_stats(dict *m, ut32 nb); -SDB_API dicti dict_hash(const char *s); -SDB_API bool dict_set(dict *m, dicti k, dicti v, void *u); -SDB_API dictkv *dict_getr(dict *m, dicti k); -SDB_API dictkv *dict_getr(dict *m, dicti k); -SDB_API dicti dict_get(dict *m, dicti k); -SDB_API dicti dict_get(dict *m, dicti k); -SDB_API void *dict_getu(dict *m, dicti k); -SDB_API bool dict_add(dict *m, dicti k, dicti v, void *u); -SDB_API bool dict_del(dict *m, dicti k); -SDB_API void dict_foreach(dict *m, dictkv_cb cb, void *u); diff --git a/shlr/sdb/include/sdb/gcc_stdatomic.h b/shlr/sdb/include/sdb/gcc_stdatomic.h deleted file mode 100644 index 313feff3af9ab..0000000000000 --- a/shlr/sdb/include/sdb/gcc_stdatomic.h +++ /dev/null @@ -1,70 +0,0 @@ -/* -* Copyright © 2018, VideoLAN and dav1d authors -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this -* list of conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, -* this list of conditions and the following disclaimer in the documentation -* and/or other materials provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef GCCVER_STDATOMIC_H_ -#define GCCVER_STDATOMIC_H_ - -#if !defined(__cplusplus) - -typedef int atomic_int; -typedef unsigned int atomic_uint; - -#ifndef __ATOMIC_RELAXED -#define __ATOMIC_RELAXED 0 -#endif -#ifndef __ATOMIC_CONSUME -#define __ATOMIC_CONSUME 1 -#endif -#ifndef __ATOMIC_ACQUIRE -#define __ATOMIC_ACQUIRE 2 -#endif -#ifndef __ATOMIC_RELEASE -#define __ATOMIC_RELEASE 3 -#endif -#ifndef __ATOMIC_ACQ_REL -#define __ATOMIC_ACQ_REL 4 -#endif -#ifndef __ATOMIC_SEQ_CST -#define __ATOMIC_SEQ_CST 5 -#endif - -#define memory_order_relaxed __ATOMIC_RELAXED -#define memory_order_acquire __ATOMIC_ACQUIRE - -#define atomic_init(p_a, v) do { *(p_a) = (v); } while(0) -#define atomic_store(p_a, v) __atomic_store_n(p_a, v, __ATOMIC_SEQ_CST) -#define atomic_load(p_a) __atomic_load_n(p_a, __ATOMIC_SEQ_CST) -#define atomic_load_explicit(p_a, mo) __atomic_load_n(p_a, mo) -#define atomic_fetch_add(p_a, inc) __atomic_fetch_add(p_a, inc, __ATOMIC_SEQ_CST) -#define atomic_fetch_add_explicit(p_a, inc, mo) __atomic_fetch_add(p_a, inc, mo) -#define atomic_fetch_sub(p_a, dec) __atomic_fetch_sub(p_a, dec, __ATOMIC_SEQ_CST) -#define atomic_exchange(p_a, v) __atomic_exchange_n(p_a, v, __ATOMIC_SEQ_CST) -#define atomic_fetch_or(p_a, v) __atomic_fetch_or(p_a, v, __ATOMIC_SEQ_CST) -#define atomic_compare_exchange_strong(p_a, expected, desired) __atomic_compare_exchange_n(p_a, expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) - -#endif /* !defined(__cplusplus) */ - -#endif /* GCCVER_STDATOMIC_H_ */ diff --git a/shlr/sdb/include/sdb/heap.h b/shlr/sdb/include/sdb/heap.h deleted file mode 100644 index 774f0c2808abc..0000000000000 --- a/shlr/sdb/include/sdb/heap.h +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef SDB_HEAP_H -#define SDB_HEAP_H 1 - -typedef void *(*SdbHeapRealloc)(void *data, void *ptr, size_t size); -typedef void (*SdbHeapFini)(void *data); - -// global heap apis -typedef struct sdb_global_heap_t { - SdbHeapRealloc realloc; - // SdbHeapInit init; - SdbHeapFini fini; - void *data; -} SdbGlobalHeap; - -extern SdbGlobalHeap Gheap; -extern const SdbGlobalHeap sdb_gh_custom; // custom heap allocator -extern const SdbGlobalHeap sdb_gh_libc; // use libc's heap - -static inline void sdb_gh_use(const SdbGlobalHeap *gh) { - if (gh) { - memcpy (&Gheap, gh, sizeof (SdbGlobalHeap)); - } else { - memset (&Gheap, 0, sizeof (SdbGlobalHeap)); - } -} - -static inline void sdb_gh_fini(void) { - if (Gheap.fini) { - Gheap.fini (Gheap.data); - } -} - -static inline void *sdb_gh_malloc(size_t size) { - if (Gheap.realloc) { - void *ptr = Gheap.realloc (Gheap.data, NULL, size); -// eprintf ("malloc %p\n" , ptr); - return ptr; - } - return malloc (size); -} - -static inline void *sdb_gh_realloc(void *ptr, size_t size) { - if (Gheap.realloc) { - return Gheap.realloc (Gheap.data, ptr, size); - } - return realloc (ptr, size); -} - -static inline void sdb_gh_free(void *ptr) { - if (!ptr) { - return; - } - if (Gheap.realloc) { -// eprintf ("free ptr %p\n" , ptr); - Gheap.realloc (Gheap.data, ptr, 0); - } else { - free (ptr); - } -} - -static inline void *sdb_gh_calloc(size_t count, size_t size) { - size_t total = count * size; // TODO: detect overflow - void *res = sdb_gh_malloc (total); - if (res) { - memset (res, 0, total); - } - return res; -} - -#endif diff --git a/shlr/sdb/include/sdb/ht.h b/shlr/sdb/include/sdb/ht.h deleted file mode 100644 index b411f99a44d1c..0000000000000 --- a/shlr/sdb/include/sdb/ht.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef SDB_HT_H -#define SDB_HT_H - -#include "ht_pp.h" -#include "heap.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** keyvalue pair **/ -typedef struct sdb_kv { - //sub of HtPPKv so we can cast safely - HtPPKv base; - ut32 cas; - ut64 expire; -} SdbKv; - -static inline char *sdbkv_key(const SdbKv *kv) { - return (char *)kv->base.key; -} - -static inline char *sdbkv_value(const SdbKv *kv) { - return (char *)kv->base.value; -} - -static inline ut32 sdbkv_key_len(const SdbKv *kv) { - return kv->base.key_len; -} - -static inline ut32 sdbkv_value_len(const SdbKv *kv) { - return kv->base.value_len; -} - -SDB_API SdbKv* sdbkv_new2(const char *k, int kl, const char *v, int vl); -SDB_API SdbKv* sdbkv_new(const char *k, const char *v); -extern SDB_API void sdbkv_free(SdbKv *kv); - -// extern SDB_API ut32 sdb_hash(const char *key); - -SDB_API HtPP* sdb_ht_new(void); -// Destroy a hashtable and all of its entries. -SDB_API void sdb_ht_free(HtPP* ht); -// Insert a new Key-Value pair into the hashtable. If the key already exists, returns false. -SDB_API bool sdb_ht_insert(HtPP* ht, const char* key, const char* value); -// Insert a new Key-Value pair into the hashtable, or updates the value if the key already exists. -SDB_API bool sdb_ht_insert_kvp(HtPP* ht, SdbKv *kvp, bool update); -// Insert a new Key-Value pair into the hashtable, or updates the value if the key already exists. -SDB_API bool sdb_ht_update(HtPP* ht, const char* key, const char* value); -// Delete a key from the hashtable. -SDB_API bool sdb_ht_delete(HtPP* ht, const char* key); -// Find the value corresponding to the matching key. -SDB_API char* sdb_ht_find(HtPP* ht, const char* key, bool* found); -// Find the KeyValuePair corresponding to the matching key. -SDB_API SdbKv* sdb_ht_find_kvp(HtPP* ht, const char* key, bool* found); - -#ifdef __cplusplus -} -#endif - -#endif // SDB_HT_H diff --git a/shlr/sdb/include/sdb/ht_inc.h b/shlr/sdb/include/sdb/ht_inc.h deleted file mode 100644 index 722346c9124af..0000000000000 --- a/shlr/sdb/include/sdb/ht_inc.h +++ /dev/null @@ -1,127 +0,0 @@ -/* radare2 - BSD 3 Clause License - 2016-2022 - crowell, pancake */ - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef HT_TYPE -#error HT_TYPE should be defined before including this header -#endif - -#undef HtName_ -#undef Ht_ -#undef HT_ -#undef KEY_TYPE -#undef VALUE_TYPE -#undef KEY_TO_HASH -#undef HT_NULL_VALUE - -#if HT_TYPE == 1 -#define HtName_(name) name##PP -#define Ht_(name) ht_pp_##name -#define HT_(name) HtPP##name -#define KEY_TYPE void * -#define VALUE_TYPE void * -#define KEY_TO_HASH(x) ((ut32)(uintptr_t)(x)) -#define HT_NULL_VALUE NULL -#elif HT_TYPE == 2 -#define HtName_(name) name##UP -#define Ht_(name) ht_up_##name -#define HT_(name) HtUP##name -#define KEY_TYPE ut64 -#define VALUE_TYPE void * -#define KEY_TO_HASH(x) ((ut32)(x)) -#define HT_NULL_VALUE 0 -#elif HT_TYPE == 3 -#define HtName_(name) name##UU -#define Ht_(name) ht_uu_##name -#define HT_(name) HtUU##name -#define KEY_TYPE ut64 -#define VALUE_TYPE ut64 -#define KEY_TO_HASH(x) ((ut32)(x)) -#define HT_NULL_VALUE 0 -#else -#define HtName_(name) name##PU -#define Ht_(name) ht_pu_##name -#define HT_(name) HtPU##name -#define KEY_TYPE void * -#define VALUE_TYPE ut64 -#define KEY_TO_HASH(x) ((ut32)(uintptr_t)(x)) -#define HT_NULL_VALUE 0 -#endif - -#include "ls.h" -#include "types.h" - -/* Kv represents a single key/value element in the hashtable */ -typedef struct Ht_(kv) { - KEY_TYPE key; - VALUE_TYPE value; - ut32 key_len; - ut32 value_len; -} HT_(Kv); - -typedef void (*HT_(KvFreeFunc))(HT_(Kv) *); -typedef KEY_TYPE (*HT_(DupKey))(const KEY_TYPE); -typedef VALUE_TYPE (*HT_(DupValue))(const VALUE_TYPE); -typedef ut32 (*HT_(CalcSizeK))(const KEY_TYPE); -typedef ut32 (*HT_(CalcSizeV))(const VALUE_TYPE); -typedef ut32 (*HT_(HashFunction))(const KEY_TYPE); -typedef int (*HT_(ListComparator))(const KEY_TYPE, const KEY_TYPE); -typedef bool (*HT_(ForeachCallback))(void *user, const KEY_TYPE, const VALUE_TYPE); - -typedef struct Ht_(bucket_t) { - HT_(Kv) *arr; - ut32 count; - ut32 size; -} HT_(Bucket); - -/* Options contain all the settings of the hashtable */ -typedef struct Ht_(options_t) { - HT_(ListComparator) cmp; // Function for comparing values. Returns 0 if eq. - HT_(HashFunction) hashfn; // Function for hashing items in the hash table. - HT_(DupKey) dupkey; // Function for making a copy of key - HT_(DupValue) dupvalue; // Function for making a copy of value - HT_(CalcSizeK) calcsizeK; // Function to determine the key's size - HT_(CalcSizeV) calcsizeV; // Function to determine the value's size - HT_(KvFreeFunc) freefn; // Function to free the keyvalue store - size_t elem_size; // Size of each HtKv element (useful for subclassing like SdbKv) -} HT_(Options); - -/* Ht is the hashtable structure */ -typedef struct Ht_(t) { - HT_(Bucket) *table; // Actual table. - HT_(Options) opt; - ut32 size; // size of the hash table in buckets. - ut32 count; // number of stored elements. - ut32 prime_idx; -} HtName_(Ht); - -// Create a new Ht with the provided Options -SDB_API HtName_(Ht)* Ht_(new_opt)(HT_(Options) *opt); -// Destroy a hashtable and all of its entries. -SDB_API void Ht_(free)(HtName_(Ht)* ht); -// Insert a new Key-Value pair into the hashtable. If the key already exists, returns false. -SDB_API bool Ht_(insert)(HtName_(Ht)* ht, const KEY_TYPE key, VALUE_TYPE value); -// Insert a new Key-Value pair into the hashtable, or updates the value if the key already exists. -SDB_API bool Ht_(update)(HtName_(Ht)* ht, const KEY_TYPE key, VALUE_TYPE value); -// Update the key of an element in the hashtable -SDB_API bool Ht_(update_key)(HtName_(Ht)* ht, const KEY_TYPE old_key, const KEY_TYPE new_key); -// Delete a key from the hashtable. -SDB_API bool Ht_(delete)(HtName_(Ht)* ht, const KEY_TYPE key); -// Find the value corresponding to the matching key. -SDB_API VALUE_TYPE Ht_(find)(HtName_(Ht)* ht, const KEY_TYPE key, bool* found); -// Iterates over all elements in the hashtable, calling the cb function on each Kv. -// If the cb returns false, the iteration is stopped. -// cb should not modify the hashtable. -// NOTE: cb can delete the current element, but it should be avoided -SDB_API void Ht_(foreach)(HtName_(Ht) *ht, HT_(ForeachCallback) cb, void *user); - -SDB_API HT_(Kv)* Ht_(find_kv)(HtName_(Ht)* ht, const KEY_TYPE key, bool* found); -SDB_API bool Ht_(insert_kv)(HtName_(Ht) *ht, HT_(Kv) *kv, bool update); - -#ifdef __cplusplus -} -#endif - -#undef HT_TYPE diff --git a/shlr/sdb/include/sdb/ht_pp.h b/shlr/sdb/include/sdb/ht_pp.h deleted file mode 100644 index 08ec5f08a4996..0000000000000 --- a/shlr/sdb/include/sdb/ht_pp.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef SDB_HT_PP_H -#define SDB_HT_PP_H - -/* - * This header provides an hashtable HtPP that has void* as key and void* as - * value. The API functions starts with "ht_pp_" and the types starts with "HtPP". - */ -#undef HT_TYPE -#define HT_TYPE 1 -//#include "sdbht.h" -#include "ht_inc.h" - -#ifdef __cplusplus -extern "C" { -#endif - -SDB_API HtName_(Ht)* Ht_(new0)(void); -SDB_API HtName_(Ht)* Ht_(new)(HT_(DupValue) valdup, HT_(KvFreeFunc) pair_free, HT_(CalcSizeV) valueSize); -SDB_API HtName_(Ht)* Ht_(new_size)(ut32 initial_size, HT_(DupValue) valdup, HT_(KvFreeFunc) pair_free, HT_(CalcSizeV) valueSize); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/shlr/sdb/include/sdb/ht_pu.h b/shlr/sdb/include/sdb/ht_pu.h deleted file mode 100644 index 0e2d80c444015..0000000000000 --- a/shlr/sdb/include/sdb/ht_pu.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef SDB_HT_PU_H -#define SDB_HT_PU_H - -/* - * This header provides a hashtable HtPU that has void* as key and ut64 as - * value. The hashtable does not take ownership of the keys, and so will not - * free the pointers once they are removed from the hashtable. - */ - -#include "sdb/types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef uint64_t ut64; - -typedef struct HtPU_t HtPU; - -typedef bool (*HtPUForEachCallback)(void *user, const void *key, const ut64 value); - -SDB_API HtPU* ht_pu_new0(void); -SDB_API void ht_pu_free(HtPU *hm); -SDB_API bool ht_pu_insert(HtPU *hm, void *key, ut64 value); -SDB_API bool ht_pu_update(HtPU *hm, void *key, ut64 value); -SDB_API bool ht_pu_update_key(HtPU *hm, void *old_key, void *new_key); -SDB_API bool ht_pu_delete(HtPU *hm, void *key); -SDB_API ut64 ht_pu_find(HtPU *hm, void *key, bool* found); -SDB_API void ht_pu_foreach(HtPU *hm, HtPUForEachCallback cb, void *user); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/shlr/sdb/include/sdb/ht_su.h b/shlr/sdb/include/sdb/ht_su.h deleted file mode 100644 index 7f02fe34d1833..0000000000000 --- a/shlr/sdb/include/sdb/ht_su.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef SDB_HT_SU_H -#define SDB_HT_SU_H - -/* - * This header provides a hashtable HtSU that has char* as key and ut64 as - * value (a "stringmap"). The hashtable takes ownership of the keys by making a - * copy of the key, and will free the pointers once they are removed from the - * hashtable. - */ - -#include "sdb/types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef uint64_t ut64; - -typedef struct HtSU_t HtSU; - -typedef bool (*HtSUForEachCallback)(void *user, const char *key, const ut64 value); - -SDB_API HtSU* ht_su_new0(void); -SDB_API void ht_su_free(HtSU *hm); -SDB_API bool ht_su_insert(HtSU *hm, const char *key, ut64 value); -SDB_API bool ht_su_update(HtSU *hm, const char *key, ut64 value); -SDB_API bool ht_su_update_key(HtSU *hm, const char *old_key, const char *new_key); -SDB_API bool ht_su_delete(HtSU *hm, const char *key); -SDB_API ut64 ht_su_find(HtSU *hm, const char *key, bool* found); -SDB_API void ht_su_foreach(HtSU *hm, HtSUForEachCallback cb, void *user); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/shlr/sdb/include/sdb/ht_up.h b/shlr/sdb/include/sdb/ht_up.h deleted file mode 100644 index 23bde02e2d6f3..0000000000000 --- a/shlr/sdb/include/sdb/ht_up.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef SDB_HT_UP_H -#define SDB_HT_UP_H - -/* - * This header provides an hashtable HtUP that has ut64 as key and void* as - * value. The API functions starts with "ht_up_" and the types starts with "HtUP". - */ -#undef HT_TYPE -#define HT_TYPE 2 -#include "ht_inc.h" -#include "sdb/ht.h" - -#ifdef __cplusplus -extern "C" { -#endif - -SDB_API HtName_(Ht)* Ht_(new0)(void); -SDB_API HtName_(Ht)* Ht_(new)(HT_(DupValue) valdup, HT_(KvFreeFunc) pair_free, HT_(CalcSizeV) valueSize); -SDB_API HtName_(Ht)* Ht_(new_size)(ut32 initial_size, HT_(DupValue) valdup, HT_(KvFreeFunc) pair_free, HT_(CalcSizeV) valueSize); -#undef HT_TYPE - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/shlr/sdb/include/sdb/ht_uu.h b/shlr/sdb/include/sdb/ht_uu.h deleted file mode 100644 index cf5f5153cd5ec..0000000000000 --- a/shlr/sdb/include/sdb/ht_uu.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef SDB_HT_UU_H_ -#define SDB_HT_UU_H_ - -/* - * This header provides a hashtable Ht that has ut64 as key and ut64 as value. - */ - -#include "sdb/types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct HtUU_t HtUU; -typedef bool (*HtUUForEachCallback)(void *user, const ut64 key, const ut64 value); - -SDB_API HtUU* ht_uu_new0(void); -SDB_API void ht_uu_free(HtUU *hm); -SDB_API bool ht_uu_insert(HtUU *hm, const ut64 key, ut64 value); -SDB_API bool ht_uu_update(HtUU *hm, const ut64 key, ut64 value); -SDB_API bool ht_uu_update_key(HtUU *hm, const ut64 old_key, const ut64 new_key); -SDB_API bool ht_uu_delete(HtUU *hm, const ut64 key); -SDB_API ut64 ht_uu_find(HtUU *hm, const ut64 key, bool* found); -SDB_API void ht_uu_foreach(HtUU *hm, HtUUForEachCallback cb, void *user); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/shlr/sdb/include/sdb/ls.h b/shlr/sdb/include/sdb/ls.h deleted file mode 100644 index 742a4bbba0fff..0000000000000 --- a/shlr/sdb/include/sdb/ls.h +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef LS_H -#define LS_H - -#include -#include "types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void (*SdbListFree)(void *ptr); -typedef int (*SdbListComparator)(const void *a, const void *b); - -typedef struct ls_iter_t { - void *data; - struct ls_iter_t *n, *p; -} SdbListIter; - -typedef struct ls_t { - size_t length; - SdbListIter *head; - SdbListIter *tail; - SdbListFree free; - SdbListComparator cmp; - bool sorted; -} SdbList; - -#define ls_foreach(list, it, pos) \ - if ((list)) for (it = (list)->head; it && (pos = it->data); it = it->n) - -#define ls_foreach_cast(list, it, T, pos) \ - if ((list)) for (it = (list)->head; it && (pos = (T)((it)->data)); it = (it)->n) - -#define ls_foreach_safe(list, it, tmp, pos) \ - if ((list)) for (it = list->head; it && (pos = it->data) && ((tmp = it->n) || 1); it = tmp) - -#define ls_foreach_prev(list, it, pos) \ - if ((list)) for (it = list->tail; it && (pos = it->data); it = it->p) - -#define ls_iterator(x) ((x)? (x)->head: NULL) - -// #define ls_empty(x) (!x || (!x->head && !x->tail)) -#define ls_empty(x) (!x || !x->length) -#define ls_head(x) x->head -#define ls_tail(x) x->tail -#define ls_unref(x) x -#define ls_iter_get(x) x->data; x=x->n -#define ls_iter_next(x) (x?1:0) -#define ls_iter_cur(x) x->p -#define ls_iter_unref(x) x -#define ls_length(x) x->length -SDB_API SdbList *ls_new(void); -SDB_API SdbList *ls_newf(SdbListFree freefn); -SDB_API SdbListIter *ls_append(SdbList *list, void *data); -SDB_API SdbListIter *ls_prepend(SdbList *list, void *data); -//SDB_API void ls_add_sorted(SdbList *list, void *data, SdbListComparator cmp); -SDB_API bool ls_sort(SdbList *list, SdbListComparator cmp); -SDB_API bool ls_merge_sort(SdbList *list, SdbListComparator cmp); - -SDB_API void ls_delete(SdbList *list, SdbListIter *iter); -SDB_API bool ls_delete_data(SdbList *list, void *ptr); -SDB_API void ls_iter_init(SdbListIter *iter, SdbList *list); -SDB_API void ls_destroy(SdbList *list); -SDB_API void ls_free(SdbList *list); -SDB_API SdbListIter *ls_item_new(void *data); -SDB_API void ls_unlink(SdbList *list, void *ptr); -SDB_API void ls_split(SdbList *list, void *ptr); -// Removes element `iter` from `list`. -SDB_API void ls_split_iter(SdbList *list, SdbListIter *iter); -SDB_API void *ls_get_n(SdbList *list, int n); -SDB_API void *ls_get_top(SdbList *list); -#define ls_push(x,y) ls_append(x,y) -SDB_API void *ls_pop(SdbList *list); -SDB_API void ls_reverse(SdbList *list); -SDB_API SdbList *ls_clone(SdbList *list); -SDB_API int ls_join(SdbList *first, SdbList *second); -SDB_API int ls_del_n(SdbList *list, int n); -SDB_API SdbListIter *ls_insert(SdbList *list, int n, void *data); -SDB_API void *ls_pop_head(SdbList *list); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/shlr/sdb/include/sdb/msvc_stdatomic.h b/shlr/sdb/include/sdb/msvc_stdatomic.h deleted file mode 100644 index f086bab5d52b0..0000000000000 --- a/shlr/sdb/include/sdb/msvc_stdatomic.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef MSCVER_STDATOMIC_H_ -#define MSCVER_STDATOMIC_H_ - -#if !defined(__cplusplus) && defined(_MSC_VER) - -#pragma warning(push) -#pragma warning(disable:4067) /* newline for __has_include_next */ - -#if defined(__clang__) && __has_include_next() - /* use the clang stdatomic.h with clang-cl*/ -# include_next -#else /* ! stdatomic.h */ - -#include - -typedef volatile LONG atomic_int; -typedef volatile ULONG atomic_uint; - -typedef enum { - memory_order_relaxed, - memory_order_acquire -} msvc_atomic_memory_order; - -#define atomic_init(p_a, v) do { *(p_a) = (v); } while(0) -#define atomic_store(p_a, v) InterlockedExchange((LONG*)p_a, v) -#define atomic_load(p_a) InterlockedCompareExchange((LONG*)p_a, 0, 0) -#define atomic_exchange(p_a, v) InterlockedExchange(p_a, v) -#define atomic_load_explicit(p_a, mo) atomic_load(p_a) - -static inline int atomic_compare_exchange_strong_int(LONG *obj, LONG *expected, - LONG desired) -{ - LONG orig = *expected; - *expected = InterlockedCompareExchange(obj, desired, orig); - return *expected == orig; -} -#define atomic_compare_exchange_strong(p_a, expected, desired) atomic_compare_exchange_strong_int((LONG *)p_a, (LONG *)expected, (LONG)desired) - -/* - * TODO use a special call to increment/decrement - * using InterlockedIncrement/InterlockedDecrement - */ -#define atomic_fetch_add(p_a, inc) InterlockedExchangeAdd(p_a, inc) -#define atomic_fetch_sub(p_a, dec) InterlockedExchangeAdd(p_a, -(dec)) -#define atomic_fetch_or(p_a, v) InterlockedOr(p_a, v) -#define atomic_fetch_add_explicit(p_a, inc, mo) atomic_fetch_add(p_a, inc) - -#endif /* ! stdatomic.h */ - -#pragma warning(pop) - -#endif /* !defined(__cplusplus) && defined(_MSC_VER) */ - -#endif /* MSCVER_STDATOMIC_H_ */ diff --git a/shlr/sdb/include/sdb/rangstr.h b/shlr/sdb/include/sdb/rangstr.h deleted file mode 100644 index d50671edf80ed..0000000000000 --- a/shlr/sdb/include/sdb/rangstr.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef SDB_INCLUDE_RANGSTR_H -#define SDB_INCLUDE_RANGSTR_H - -#include -#include "sdb/types.h" - -#define RangstrType unsigned int - -typedef struct { - int type; - int next; - size_t f, t; - const char *p; -} Rangstr; - -#if 1 -SDB_IPI void rangstr_print (Rangstr *s); -SDB_IPI Rangstr rangstr_new (const char *s); -SDB_IPI Rangstr rangstr_null(void); -SDB_IPI int rangstr_int (Rangstr *s); -SDB_IPI char *rangstr_dup (Rangstr *rs); -SDB_IPI Rangstr rangstr_news (const char *s, RangstrType *res, int i); -SDB_IPI int rangstr_cmp (Rangstr *a, Rangstr *b); -SDB_IPI const char *rangstr_str (Rangstr* rs); -SDB_IPI int rangstr_length (Rangstr* rs); -SDB_IPI int rangstr_find (Rangstr* rs, char ch); -#endif - -#endif diff --git a/shlr/sdb/include/sdb/sdb.h b/shlr/sdb/include/sdb/sdb.h deleted file mode 100644 index e4a685d279c74..0000000000000 --- a/shlr/sdb/include/sdb/sdb.h +++ /dev/null @@ -1,469 +0,0 @@ -#ifndef SDB_H -#define SDB_H - -#if !defined(O_BINARY) && !defined(_MSC_VER) -#undef O_BINARY -#define O_BINARY 0 -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#include "asserts.h" -#include "types.h" -#include "ht.h" -#include "ls.h" -#include "dict.h" -#include "cdb.h" -#include "cdb_make.h" -#include "version.h" -#include "rangstr.h" -#include "heap.h" - -/* Key value sizes */ -#define SDB_MIN_VALUE 1 -#define SDB_MAX_VALUE 0xffffff -#define SDB_MIN_KEY 1 -#define SDB_MAX_KEY 0xff - -#define SDB_HASH_FAST 0 -#define SDB_INLINE_HASH 1 - -// ftp://ftp.gnu.org/old-gnu/Manuals/gperf-2.7/html_node/gperf_17.es.html -#define SDB_MAX_GPERF_KEYS 15000 - -#if !defined(SZT_ADD_OVFCHK) -#define SZT_ADD_OVFCHK(x, y) ((SIZE_MAX - (x)) <= (y)) -#endif - -#if defined(__GNUC__) -#define SDB_LIKELY(x) __builtin_expect((size_t)(x),1) -#define SDB_UNLIKELY(x) __builtin_expect((size_t)(x),0) -#define SDB_INLINE __attribute__((always_inline)) -#else -#define SDB_LIKELY(x) (x) -#define SDB_UNLIKELY(x) (x) -#define SDB_INLINE -#endif - -/* printf format check attributes */ -#if defined(__clang__) || defined(__GNUC__) -#define SDB_PRINTF_CHECK(fmt, dots) __attribute__ ((format (printf, fmt, dots))) -#else -#define SDB_PRINTF_CHECK(fmt, dots) -#endif - -#if __SDB_WINDOWS__ && !__CYGWIN__ -#include -#include -#include -#include -#include -#include -#ifndef _MSC_VER -extern __attribute__((dllimport)) void *__cdecl _aligned_malloc(size_t, size_t); -extern __attribute__((dllimport)) void __cdecl _aligned_free(void *memblock); -extern char *strdup (const char *); -#else -#include -#include -#include // for _aligned_malloc -#define ftruncate _chsize -#endif - -//#define SDB_MODE 0 -#define SDB_MODE _S_IWRITE | _S_IREAD -#else -#define SDB_MODE 0644 -//#define SDB_MODE 0600 -#endif - -//#define SDB_RS '\x1e' -#define SDB_RS ',' -#define SDB_SS "," -#define SDB_MAX_PATH 256 -#define SDB_NUM_BASE 16 -#define SDB_NUM_BUFSZ 64 - -#define SDB_OPTION_NONE 0 -#define SDB_OPTION_ALL 0xff -#define SDB_OPTION_SYNC (1 << 0) -#define SDB_OPTION_NOSTAMP (1 << 1) -#define SDB_OPTION_FS (1 << 2) -#define SDB_OPTION_JOURNAL (1 << 3) - -#define SDB_LIST_UNSORTED 0 -#define SDB_LIST_SORTED 1 - -// This size implies trailing zero terminator, this is 254 chars + 0 -#define SDB_KSZ 0xff -#define SDB_VSZ 0xffffff - -typedef int (*GperfForeachCallback)(void *user, const char *k, const char *v); -typedef struct sdb_gperf_t { - const char *name; - const char *(*get)(const char *k); - unsigned int *(*hash)(const char *k); - bool (*foreach)(GperfForeachCallback cb, void *user); -} SdbGperf; - -typedef struct sdb_t { - char *dir; // path+name - char *path; - char *name; - int fd; - int refs; // reference counter - int lock; - int journal; - struct cdb db; - struct cdb_make m; - HtPP *ht; - ut32 eod; - ut32 pos; - SdbGperf *gp; - int fdump; - char *ndump; - ut64 expire; - ut64 last; // timestamp of last change - int options; - int ns_lock; // TODO: merge into options? - SdbList *ns; - SdbList *hooks; - SdbKv tmpkv; - ut32 depth; - bool timestamped; - SdbMini mht; -} Sdb; - -typedef struct sdb_ns_t { - char *name; - ut32 hash; - Sdb *sdb; -} SdbNs; - -SDB_API Sdb* sdb_new0(void); -SDB_API Sdb* sdb_new(const char *path, const char *file, int lock); - -SDB_API int sdb_open(Sdb *s, const char *file); -SDB_API int sdb_open_gperf(Sdb *s, SdbGperf *g); -SDB_API void sdb_close(Sdb *s); - -SDB_API void sdb_config(Sdb *s, int options); -SDB_API bool sdb_free(Sdb* s); -SDB_API void sdb_file(Sdb* s, const char *dir); -SDB_API bool sdb_merge(Sdb* d, Sdb *s); -SDB_API int sdb_count(Sdb* s); -SDB_API void sdb_reset(Sdb* s); -SDB_API void sdb_setup(Sdb* s, int options); -SDB_API void sdb_drain(Sdb*, Sdb*); - -// Copy everything, including namespaces, from src to dst -SDB_API void sdb_copy(Sdb *src, Sdb *dst); - -SDB_API bool sdb_stats(Sdb *s, ut32 *disk, ut32 *mem); -SDB_API bool sdb_dump_hasnext (Sdb* s); - -typedef bool (*SdbForeachCallback)(void *user, const char *k, const char *v); -SDB_API bool sdb_foreach(Sdb* s, SdbForeachCallback cb, void *user); -SDB_API SdbList *sdb_foreach_list(Sdb* s, bool sorted); -SDB_API SdbList *sdb_foreach_list_filter(Sdb* s, SdbForeachCallback filter, bool sorted); -SDB_API SdbList *sdb_foreach_match(Sdb* s, const char *expr, bool sorted); - -SDB_API int sdb_main(int argc, const char **argv); -SDB_API bool sdb_query(Sdb* s, const char *cmd); -SDB_API int sdb_queryf(Sdb* s, const char *fmt, ...); -SDB_API int sdb_query_lines(Sdb *s, const char *cmd); -SDB_API char *sdb_querys(Sdb* s, char *buf, size_t len, const char *cmd); -SDB_API char *sdb_querysf(Sdb* s, char *buf, size_t buflen, const char *fmt, ...); -SDB_API int sdb_query_file(Sdb *s, const char* file); -SDB_API bool sdb_exists(Sdb*, const char *key); -SDB_API bool sdb_remove(Sdb*, const char *key, ut32 cas); -SDB_API int sdb_unset(Sdb*, const char *key, ut32 cas); -SDB_API int sdb_nunset(Sdb*, ut64 nkey, ut32 cas); -SDB_API int sdb_unset_like(Sdb *s, const char *k); -SDB_API char** sdb_like(Sdb *s, const char *k, const char *v, SdbForeachCallback cb); - -// diffing -typedef struct sdb_diff_t { - const SdbList *path; - const char *k; - const char *v; // if null, k is a namespace - bool add; -} SdbDiff; - -// Format diff in a readable form into str. str, size and return are like in snprintf. -SDB_API int sdb_diff_format(char *str, int size, const SdbDiff *diff); - -typedef void (*SdbDiffCallback)(const SdbDiff *diff, void *user); - -// Returns true iff the contents of a and b are equal including contained namespaces -// If cb is non-null, it will be called subsequently with differences. -SDB_API bool sdb_diff(Sdb *a, Sdb *b, SdbDiffCallback cb, void *cb_user); - -// Gets a pointer to the value associated with `key`. -SDB_API char *sdb_get(Sdb*, const char *key, ut32 *cas); -SDB_API char *sdb_nget(Sdb*, ut64 nkey, ut32 *cas); - -// Gets a pointer to the value associated with `key` and returns in `vlen` the -// length of the value string. -SDB_API char *sdb_get_len(Sdb*, const char *key, int *vlen, ut32 *cas); - -// Gets a const pointer to the value associated with `key` -SDB_API const char *sdb_const_get(Sdb*, const char *key, ut32 *cas); - -// Gets a const pointer to the value associated with `key` and returns in -// `vlen` the length of the value string. -SDB_API const char *sdb_const_get_len(Sdb* s, const char *key, int *vlen, ut32 *cas); -SDB_API int sdb_set(Sdb*, const char *key, const char *data, ut32 cas); -SDB_API int sdb_nset(Sdb*, ut64 nkey, const char *data, ut32 cas); -SDB_API ut64 sdb_num_nget(Sdb *s, ut64 nkey, ut32 *cas); -SDB_API int sdb_num_nset(Sdb* s, ut64 nkey, ut64 nval, ut32 cas); -SDB_API int sdb_set_owned(Sdb* s, const char *key, char *val, ut32 cas); -SDB_API int sdb_concat(Sdb *s, const char *key, const char *value, ut32 cas); -SDB_API int sdb_uncat(Sdb *s, const char *key, const char *value, ut32 cas); -SDB_API int sdb_add(Sdb* s, const char *key, const char *val, ut32 cas); -SDB_API int sdb_nadd(Sdb* s, ut64 nkey, const char *val, ut32 cas); -SDB_API bool sdb_sync(Sdb*); -SDB_API void sdbkv_free(SdbKv *kv); - -/* num.c */ -SDB_API bool sdb_num_exists(Sdb*, const char *key); -SDB_API int sdb_num_base(const char *s); -SDB_API ut64 sdb_num_get(Sdb* s, const char *key, ut32 *cas); -SDB_API int sdb_num_set(Sdb* s, const char *key, ut64 v, ut32 cas); -SDB_API int sdb_num_add(Sdb *s, const char *key, ut64 v, ut32 cas); -SDB_API ut64 sdb_num_inc(Sdb* s, const char *key, ut64 n, ut32 cas); -SDB_API ut64 sdb_num_dec(Sdb* s, const char *key, ut64 n, ut32 cas); -SDB_API int sdb_num_min(Sdb* s, const char *key, ut64 v, ut32 cas); -SDB_API int sdb_num_max(Sdb* s, const char *key, ut64 v, ut32 cas); - -/* ptr */ -SDB_API int sdb_ptr_set(Sdb *db, const char *key, void *p, ut32 cas); -SDB_API void* sdb_ptr_get(Sdb *db, const char *key, ut32 *cas); - -/* create db */ -SDB_API bool sdb_disk_create(Sdb* s); -SDB_API bool sdb_disk_insert(Sdb* s, const char *key, const char *val); -SDB_API bool sdb_disk_finish(Sdb* s); -SDB_API bool sdb_disk_unlink(Sdb* s); - -/* plaintext sdb files */ -SDB_API bool sdb_text_save_fd(Sdb *s, int fd, bool sort); -SDB_API bool sdb_text_save(Sdb *s, const char *file, bool sort); -SDB_API bool sdb_text_load_buf(Sdb *s, char *buf, size_t sz); -SDB_API bool sdb_text_load(Sdb *s, const char *file); -SDB_API bool sdb_text_check(Sdb *s, const char *file); - -/* iterate */ -SDB_API void sdb_dump_begin(Sdb* s); -SDB_API SdbKv *sdb_dump_next(Sdb* s); -SDB_API bool sdb_dump_dupnext(Sdb* s, char *key, char **value, int *_vlen); - -/* journaling */ -SDB_API bool sdb_journal_close(Sdb *s); -SDB_API bool sdb_journal_open(Sdb *s); -SDB_API int sdb_journal_load(Sdb *s); -SDB_API bool sdb_journal_log(Sdb *s, const char *key, const char *val); -SDB_API bool sdb_journal_clear(Sdb *s); -SDB_API bool sdb_journal_unlink(Sdb *s); - -/* numeric */ -SDB_API char *sdb_itoa(ut64 n, int base, char *s, int slen); -SDB_API char *sdb_itoas(ut64 n, int base); -SDB_API ut64 sdb_atoi(const char *s); - -/* locking */ -SDB_API bool sdb_lock(const char *s); -SDB_API bool sdb_lock_file(const char *f, char *buf, size_t buf_size); -SDB_API void sdb_unlock(const char *s); -SDB_API bool sdb_unlink(Sdb* s); -SDB_API int sdb_lock_wait(const char *s UNUSED); - -/* expiration */ -SDB_API bool sdb_expire_set(Sdb* s, const char *key, ut64 expire, ut32 cas); -SDB_API ut64 sdb_expire_get(Sdb* s, const char *key, ut32 *cas); -SDB_API ut64 sdb_now(void); -SDB_API ut64 sdb_unow(void); -SDB_API ut8 sdb_hash_byte(const char *s); - -#if !SDB_INLINE_HASH -SDB_API ut32 sdb_hash(const char *key); -SDB_API ut32 sdb_hash_len(const char *key, ut32 *len); -#else -#if SDB_HASH_FAST -#define SDB_HASH_ONELINER h = (h ^ (h << 1)) + *s++ // 2.14s -#else -#define SDB_HASH_ONELINER h = (h + (h << 5)) ^ *s++ // 2.25 -#endif -SDB_INLINE static inline ut32 sdb_hash_len(const char *s, ut32 *len) { - ut32 h = CDB_HASHSTART; - if (SDB_UNLIKELY (!s)) { - return h; - } - if (len) { // comptime because its inlined - ut32 count = 0; - while (*s) { - SDB_HASH_ONELINER; - count++; - } - *len = count; - } else { - while (*s) { - SDB_HASH_ONELINER; - } - } - return h; -} - -SDB_INLINE static inline ut32 sdb_hash(const char *s) { - return sdb_hash_len (s, NULL); -} -#endif - -/* json api */ -SDB_API int sdb_js0n(const unsigned char *js, RangstrType len, RangstrType *out); -SDB_API bool sdb_isjson(const char *k); -SDB_API char *sdb_json_get_str (const char *json, const char *path); -SDB_API bool sdb_json_get_bool(const char *json, const char *path); - -SDB_API char *sdb_json_get(Sdb* s, const char *key, const char *p, ut32 *cas); -SDB_API bool sdb_json_set(Sdb* s, const char *k, const char *p, const char *v, ut32 cas); -SDB_API int sdb_json_num_get(Sdb* s, const char *k, const char *p, ut32 *cas); -SDB_API int sdb_json_num_set(Sdb* s, const char *k, const char *p, int v, ut32 cas); -SDB_API int sdb_json_num_dec(Sdb* s, const char *k, const char *p, int n, ut32 cas); -SDB_API int sdb_json_num_inc(Sdb* s, const char *k, const char *p, int n, ut32 cas); - -SDB_API char *sdb_json_indent(const char *s, const char *tab); -SDB_API char *sdb_json_unindent(const char *s); - -typedef struct { - char *buf; - size_t blen; - size_t len; -} SdbJsonString; - -SDB_API const char *sdb_json_format(SdbJsonString* s, const char *fmt, ...); -#define sdb_json_format_free(x) free ((x)->buf) - -// namespace -SDB_API Sdb* sdb_ns(Sdb *s, const char *name, int create); -SDB_API Sdb *sdb_ns_path(Sdb *s, const char *path, int create); -SDB_API void sdb_ns_init(Sdb* s); -SDB_API void sdb_ns_free(Sdb* s); -SDB_API void sdb_ns_lock(Sdb *s, int lock, int depth); -SDB_API void sdb_ns_sync(Sdb* s); -SDB_API int sdb_ns_set(Sdb *s, const char *name, Sdb *r); -SDB_API bool sdb_ns_unset(Sdb *s, const char *name, Sdb *r); - -// array -SDB_API bool sdb_array_contains(Sdb* s, const char *key, const char *val, ut32 *cas); -SDB_API bool sdb_array_contains_num(Sdb *s, const char *key, ut64 val, ut32 *cas); -SDB_API int sdb_array_indexof(Sdb *s, const char *key, const char *val, ut32 cas); -SDB_API int sdb_array_set(Sdb* s, const char *key, int idx, const char *val, ut32 cas); -SDB_API int sdb_array_set_num(Sdb* s, const char *key, int idx, ut64 val, ut32 cas); -SDB_API bool sdb_array_append(Sdb *s, const char *key, const char *val, ut32 cas); -SDB_API bool sdb_array_append_num(Sdb *s, const char *key, ut64 val, ut32 cas); -SDB_API bool sdb_array_prepend(Sdb *s, const char *key, const char *val, ut32 cas); -SDB_API bool sdb_array_prepend_num(Sdb *s, const char *key, ut64 val, ut32 cas); -SDB_API char *sdb_array_get(Sdb* s, const char *key, int idx, ut32 *cas); -SDB_API ut64 sdb_array_get_num(Sdb* s, const char *key, int idx, ut32 *cas); -SDB_API int sdb_array_get_idx(Sdb *s, const char *key, const char *val, ut32 cas); // agetv -SDB_API int sdb_array_insert(Sdb* s, const char *key, int idx, const char *val, ut32 cas); -SDB_API int sdb_array_insert_num(Sdb* s, const char *key, int idx, ut64 val, ut32 cas); -SDB_API int sdb_array_unset(Sdb* s, const char *key, int n, ut32 cas); // leaves empty bucket -SDB_API int sdb_array_delete(Sdb* s, const char *key, int n, ut32 cas); -SDB_API void sdb_array_sort(Sdb* s, const char *key, ut32 cas); -SDB_API void sdb_array_sort_num(Sdb* s, const char *key, ut32 cas); -// set - -// Adds string `val` at the end of array `key`. -SDB_API int sdb_array_add(Sdb* s, const char *key, const char *val, ut32 cas); - -// Adds number `val` at the end of array `key`. -SDB_API int sdb_array_add_num(Sdb* s, const char *key, ut64 val, ut32 cas); - -// Adds string `val` in the sorted array `key`. -SDB_API int sdb_array_add_sorted(Sdb *s, const char *key, const char *val, ut32 cas); - -// Adds number `val` in the sorted array `key`. -SDB_API int sdb_array_add_sorted_num(Sdb *s, const char *key, ut64 val, ut32 cas); - -// Removes the string `val` from the array `key`. -SDB_API int sdb_array_remove(Sdb *s, const char *key, const char *val, ut32 cas); - -// Removes the number `val` from the array `key`. -SDB_API int sdb_array_remove_num(Sdb* s, const char *key, ut64 val, ut32 cas); - -// helpers -SDB_API char *sdb_anext(char *str, char **next); -SDB_API const char *sdb_const_anext(const char *str); -SDB_API int sdb_alen(const char *str); -SDB_API int sdb_alen_ignore_empty(const char *str); -SDB_API int sdb_array_size(Sdb* s, const char *key); -SDB_API int sdb_array_length(Sdb* s, const char *key); - -int sdb_array_list(Sdb* s, const char *key); - -// Adds the string `val` to the start of array `key`. -SDB_API bool sdb_array_push(Sdb *s, const char *key, const char *val, ut32 cas); - -// Returns the string at the start of array `key` or -// NULL if there are no elements. -SDB_API char *sdb_array_pop(Sdb *s, const char *key, ut32 *cas); - -// Adds the number `val` to the start of array `key`. -SDB_API int sdb_array_push_num(Sdb *s, const char *key, ut64 num, ut32 cas); - -// Returns the number at the start of array `key`. -SDB_API ut64 sdb_array_pop_num(Sdb *s, const char *key, ut32 *cas); - -SDB_API char *sdb_array_pop_head(Sdb *s, const char *key, ut32 *cas); -SDB_API char *sdb_array_pop_tail(Sdb *s, const char *key, ut32 *cas); - -typedef void (*SdbHook)(Sdb *s, void *user, const char *k, const char *v); - -SDB_API bool sdb_hook(Sdb* s, SdbHook cb, void* user); -SDB_API bool sdb_unhook(Sdb* s, SdbHook h); -SDB_API int sdb_hook_call(Sdb *s, const char *k, const char *v); -SDB_API void sdb_hook_free(Sdb *s); -/* Util.c */ -SDB_API int sdb_isnum(const char *s); -SDB_API bool sdb_isempty(Sdb *s); - -SDB_API const char *sdb_type(const char *k); -SDB_API bool sdb_match(const char *str, const char *glob); -SDB_API int sdb_bool_set(Sdb *db, const char *str, bool v, ut32 cas); -SDB_API bool sdb_bool_get(Sdb *db, const char *str, ut32 *cas); - -// base64 -SDB_API ut8 *sdb_decode(const char *in, int *len); -SDB_API char *sdb_encode(const ut8 *bin, int len); -SDB_API void sdb_encode_raw(char *bout, const ut8 *bin, int len); -SDB_API int sdb_decode_raw(ut8 *bout, const char *bin, int len); - -// binfmt -SDB_API int sdb_fmt_init(void *p, const char *fmt); -SDB_API void sdb_fmt_free(void *p, const char *fmt); -SDB_API int sdb_fmt_tobin(const char *_str, const char *fmt, void *stru); -SDB_API char *sdb_fmt_tostr(void *stru, const char *fmt); -SDB_API char** sdb_fmt_array(const char *list); -SDB_API ut64* sdb_fmt_array_num(const char *list); - -// raw array helpers -SDB_API char *sdb_array_compact(char *p); -SDB_API char *sdb_aslice(char *out, int from, int to); -#define sdb_aforeach(x,y) \ - { char *next; \ - if (y) for (x=y;;) { \ - x = sdb_anext (x, &next); -#define sdb_aforeach_next(x) \ - if (!next) break; \ - *(next-1) = ','; \ - x = next; } } - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/shlr/sdb/include/sdb/set.h b/shlr/sdb/include/sdb/set.h deleted file mode 100644 index 7202a59e5795e..0000000000000 --- a/shlr/sdb/include/sdb/set.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef SDB_SET_H -#define SDB_SET_H - -#include "ht_pp.h" -#include "ht_up.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef HtPP SetP; -typedef bool (*set_p_foreach_cb)(void *userdata, const void *p); -typedef bool (*set_u_foreach_cb)(void *userdata, const ut64 u); - -SDB_API SetP *set_p_new(void); -SDB_API void set_p_add(SetP *p, void *u); -SDB_API bool set_p_contains(SetP *s, void *u); -SDB_API void set_p_delete(SetP *s, void *u); -SDB_API void set_p_free(SetP *p); -SDB_API void set_p_foreach(SetP *p, set_p_foreach_cb cb, void *u); - -typedef HtUP SetU; - -SDB_API SetU *set_u_new(void); -SDB_API void set_u_add(SetU *p, ut64 u); -SDB_API bool set_u_contains(SetU *s, ut64 u); -SDB_API void set_u_delete(SetU *s, ut64 u); -SDB_API void set_u_free(SetU *p); - -SDB_API void set_u_foreach(SetU *s, set_u_foreach_cb cb, void *u); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/shlr/sdb/include/sdb/types.h b/shlr/sdb/include/sdb/types.h deleted file mode 100644 index 29788372a647c..0000000000000 --- a/shlr/sdb/include/sdb/types.h +++ /dev/null @@ -1,166 +0,0 @@ -#ifndef SDB_TYPES_H -#define SDB_TYPES_H - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#undef eprintf -#define eprintf(...) fprintf(stderr,__VA_ARGS__) - -// Inspired in https://gcc.gnu.org/wiki/Visibility -#ifndef SDB_API - #undef SDB_IPI - #if defined _WIN32 || defined __CYGWIN__ - #ifdef __GNUC__ - #define SDB_API __attribute__ ((dllexport)) - #else - #define SDB_API __declspec(dllexport) // Note: actually gcc seems to also supports this syntax. - #endif - #define SDB_IPI - #else - #if __GNUC__ >= 4 - #define SDB_API __attribute__ ((visibility ("default"))) - #define SDB_IPI __attribute__ ((visibility ("hidden"))) - #else - #define SDB_API - #define SDB_IPI - #endif - #endif -#endif - -#if MINGW || __MINGW32__ || __MINGW64__ -#define __MINGW__ 1 -#endif - -#ifndef INT32_MAX -#define INT32_MAX (0x7fffffff) -#endif - -#if defined __WIN32__ || __MINGW__ > 0 || R2__WINDOWS__ || __WINDOWS__ > 0 || _MSC_VER > 0 -#define __SDB_WINDOWS__ 1 -#undef DIRSEP -#define DIRSEP '\\' -#undef lseek -#define lseek _lseek -#include -#include -#if __MINGW32__ -#define ULLFMT PRIx64 -#else -#define ULLFMT "I64" -#endif -#undef HAVE_MMAN -#define HAVE_MMAN 0 -#else -// CYGWIN AND UNIX -#define __SDB_WINDOWS__ 0 -#undef DIRSEP -#define DIRSEP '/' -#include -#undef HAVE_MMAN -#define HAVE_MMAN 1 -#define ULLFMT PRIx64 -#endif - -#if __wasi__ || EMSCRIPTEN -#undef HAVE_MMAN -#define HAVE_MMAN 0 -#endif - -#ifndef USE_MMAN -#define USE_MMAN HAVE_MMAN -#endif - -#ifndef UNUSED -# define UNUSED -# ifdef __GNUC__ -# if __GNUC__ >= 4 -# undef UNUSED -# define UNUSED __attribute__((__unused__)) -# endif -# endif -#endif - -#ifndef ut8 -#define ut8 uint8_t -#define ut32 uint32_t -#define ut64 uint64_t -#define st64 int64_t - -// TODO: deprecate R_NEW -#ifndef R_NEW -//it means we are within sdb -#define R_NEW(x) (x*)sdb_gh_malloc(sizeof(x)) -#endif -#ifndef R_NEW0 -#define R_NEW0(x) (x*)sdb_gh_calloc(1, sizeof(x)) -#endif -#ifndef R_FREE -#define R_FREE(x) { sdb_gh_free (x); x = NULL; } -#endif -#define UT32_MAX ((ut32)0xffffffff) -#define UT64_MAX ((ut64)(0xffffffffffffffffLL)) -#endif -#ifndef R_MAX_DEFINED -#define R_MAX(x,y) (((x)>(y))?(x):(y)) -#define R_MAX_DEFINED 1 -#endif - -#ifndef R_MIN_DEFINED -#define R_MIN(x,y) (((x)>(y))?(y):(x)) -#define R_MIN_DEFINED 1 -#endif - -#include "config.h" - -static inline int seek_set(int fd, off_t pos) { - return ((fd == -1) || (lseek (fd, (off_t) pos, SEEK_SET) == -1))? 0:1; -} - -static inline void ut32_pack(char s[4], ut32 u) { - s[0] = u & 255; - u >>= 8; - s[1] = u & 255; - u >>= 8; - s[2] = u & 255; - s[3] = u >> 8; -} - -static inline void ut32_pack_big(char s[4], ut32 u) { - s[3] = u & 255; - u >>= 8; - s[2] = u & 255; - u >>= 8; - s[1] = u & 255; - s[0] = u >> 8; -} - -static inline void ut32_unpack(char s[4], ut32 *u) { - ut32 result = 0; - result = (ut8) s[3]; - result <<= 8; - result += (ut8) s[2]; - result <<= 8; - result += (ut8) s[1]; - result <<= 8; - result += (ut8) s[0]; - *u = result; -} - -SDB_API char *sdb_strdup(const char *s); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/shlr/sdb/include/sdb/version.h b/shlr/sdb/include/sdb/version.h deleted file mode 100644 index 892f1c4edcc5c..0000000000000 --- a/shlr/sdb/include/sdb/version.h +++ /dev/null @@ -1 +0,0 @@ -#define SDB_VERSION "2.0.1" diff --git a/shlr/sdb/memcache/Makefile b/shlr/sdb/memcache/Makefile deleted file mode 100644 index 6b0684547e06e..0000000000000 --- a/shlr/sdb/memcache/Makefile +++ /dev/null @@ -1 +0,0 @@ -all clean mrproper: diff --git a/shlr/sdb/meson.build b/shlr/sdb/meson.build deleted file mode 100644 index 996e629759f3f..0000000000000 --- a/shlr/sdb/meson.build +++ /dev/null @@ -1,176 +0,0 @@ -project('sdb', 'c', meson_version: '>=0.60.0') - -py3_exe = import('python').find_installation('python3') -pkgconfig_mod = import('pkgconfig') - -version_cmd = '''from sys import argv -with open(argv[1]) as fd: - for line in fd: - if line.startswith('SDBVER='): - version_tuple = line.split('=')[1] - print(version_tuple) - break -''' -sdb_version = '0.0.1' -config_mk = files('config.mk')[0] -r = run_command(py3_exe, '-c', version_cmd, config_mk) -if r.returncode() == 0 - sdb_version = r.stdout().strip() -else - warning('Cannot determine SDB version') -endif -message('SDB version = ' + sdb_version) - - -is_windows = host_machine.system() == 'windows' ? true: false - -if is_windows - libsdb_name = 'libsdb' - sdb_libversion = '' -else - sdb_libversion = sdb_version - libsdb_name = 'sdb' -endif - -# Create include/sdb/version.h -conf_data = configuration_data() -conf_data.set_quoted('SDB_VERSION', sdb_version, description : 'From config.mk') -configure_file( - output : 'version.h', - configuration : conf_data, - install_dir : join_paths(get_option('includedir'), 'sdb') -) - -libsdb_sources = [ - 'src/array.c', - 'src/set.c', - 'src/base64.c', - 'src/cdb.c', - 'src/cdb_make.c', - 'src/dict.c', - 'src/diff.c', - 'src/disk.c', - 'src/fmt.c', - 'src/heap.c', - 'src/main.c', - 'src/ht_uu.c', - 'src/ht_up.c', - 'src/ht_pp.c', - 'src/ht_pu.c', - 'src/ht_su.c', - 'src/journal.c', - 'src/json.c', - 'src/lock.c', - 'src/ls.c', - 'src/match.c', - 'src/ns.c', - 'src/num.c', - 'src/query.c', - 'src/sdb.c', - 'src/ht.c', - 'src/util.c', - 'src/text.c' -] - -# . = b/version.h -sdb_inc = include_directories(['.', 'include']) -rpath_lib = '' -rpath_exe = '' -if get_option('local') and get_option('default_library') == 'shared' - rpath_lib = '$ORIGIN' - rpath_exe = '$ORIGIN/../' + get_option('libdir') -endif - -libsdb = both_libraries(libsdb_name, libsdb_sources, - include_directories: sdb_inc, - implicit_include_directories: false, - soversion: sdb_libversion, - install: not meson.is_subproject(), - install_rpath: rpath_lib -) - -if is_windows - link_with = libsdb.get_static_lib() -else - link_with = libsdb.get_shared_lib() -endif - -sdb_dep = declare_dependency( - link_with: libsdb.get_static_lib(), - include_directories: sdb_inc -) - -if not meson.is_subproject() - include_files = [ - 'include/sdb/buffer.h', - 'include/sdb/cdb.h', - 'include/sdb/cdb_make.h', - 'include/sdb/config.h', - 'include/sdb/dict.h', - 'include/sdb/heap.h', - 'include/sdb/ht_inc.h', - 'include/sdb/ht_pp.h', - 'include/sdb/ht_up.h', - 'include/sdb/ht_uu.h', - 'include/sdb/ht_pu.h', - 'include/sdb/ht_su.h', - 'include/sdb/ls.h', - 'include/sdb/sdb.h', - 'include/sdb/ht.h', - 'include/sdb/set.h', - 'include/sdb/types.h', - 'include/sdb/asserts.h', - 'include/sdb/cwisstable.h', - 'include/sdb/gcc_stdatomic.h', - 'include/sdb/msvc_stdatomic.h', - ] - install_headers(include_files, subdir: 'sdb') -endif - -sdb_exe = executable('sdb', join_paths('src','entry.c'), - include_directories: sdb_inc, - link_with: [link_with], - install: not meson.is_subproject(), - install_rpath: rpath_exe, - implicit_include_directories: false -) - -if meson.is_cross_build() - sdb_native_exe = executable('sdb_native', join_paths('src','entry.c'), - include_directories: sdb_inc, - link_with: [link_with], - install: false, - implicit_include_directories: false - ) -else - sdb_native_exe = sdb_exe -endif - -if not meson.is_subproject() - install_man([join_paths('src','sdb.1')]) -endif - -pkgconfig_mod.generate( - name: 'sdb', - filebase: 'sdb', - libraries: [libsdb.get_shared_lib()], - description: 'Simple DataBase', - subdirs: ['sdb'], - version: sdb_version, - url: 'https://github.com/radareorg/sdb' -) - -if not meson.is_subproject() - make_exe = find_program('make', required: false) - if make_exe.found() - test('run tests', make_exe, - args: 'test', - env: ['BASEDIR=' + meson.current_build_dir()], - workdir: join_paths(meson.current_build_dir(), '..'), - depends: [sdb_exe, libsdb] - ) - endif - - subdir(join_paths('test','bench')) - subdir(join_paths('test','unit')) -endif diff --git a/shlr/sdb/src/Makefile b/shlr/sdb/src/Makefile deleted file mode 100644 index 0b9bb1f081458..0000000000000 --- a/shlr/sdb/src/Makefile +++ /dev/null @@ -1,101 +0,0 @@ -include ../config.mk - -# CFLAGS:=-g $(CFLAGS) -OBJ=cdb.o cdb_make.o ls.o ht.o ht_uu.o sdb.o num.o base64.o match.o -OBJ+=json.o ns.o lock.o util.o disk.o query.o array.o fmt.o journal.o text.o -OBJ+=dict.o ht_pp.o ht_up.o ht_pu.o ht_su.o set.o diff.o heap.o main.o -SDB_CFLAGS+=-I../include -SDB_CXXFLAGS+=-I../include -SOBJ=$(subst .o,.o.o,${OBJ}) -WITHPIC?=1 -BIN=sdb${EXT_EXE} - -.PHONY: all static shared clean mrproper install - -all: $(BIN) - $(MAKE) static -ifeq ($(WITHPIC),1) - $(MAKE) shared -endif - -json.o: json/api.c json/js0n.c json/path.c json/rangstr.c json/indent.c - -install: - $(MAKE) -C .. install - -../include/sdb/version.h: - $(MAKE) -C .. include/sdb/version.h - -shared: ../include/sdb/version.h - $(MAKE) libsdb${SOVER} - -static: ../include/sdb/version.h - $(MAKE) libsdb$(EXT_AR) - -sdb_objs: ../include/sdb/version.h - $(MAKE) ${OBJ} - -sdb_objs2: ../include/sdb/version.h - $(MAKE) ${SOBJ} - -libsdb.lib libsdb$(EXT_AR): sdb_objs -ifneq ($(SILENT),) - @echo AR libsdb$(EXT_AR) -endif - rm -f libsdb$(EXT_AR) - ${AR} q libsdb$(EXT_AR) ${OBJ} - ${RANLIB} libsdb$(EXT_AR) - -ifeq ($(CC),tcc) -libsdb${SOVER}: - @echo TCC doesnt support shared libs on macos -else -libsdb${SOVER}: sdb_objs2 -endif -ifneq ($(EXT_SO),${SOVER}) - ln -fs libsdb${SOVER} libsdb${EXT_SO} -endif -ifneq ($(SILENT),) - @echo LIB libsdb${SOVER} -endif - $(CC) ${LDFLAGS} $(LDFLAGS_SHARED) -o $@ ${SOBJ} - -bin_deps: ../include/sdb/version.h - $(MAKE) libsdb.a entry.o - -bin $(BIN): bin_deps -ifneq ($(SILENT),) - @echo BIN ${BIN} -endif - $(CC) ${LDFLAGS} -o ${BIN} entry.o ${OBJ} - -mrproper clean: - rm -rf ${OBJ} ${SOBJ} entry.o libsdb.a a.out ${BIN} sdb.dSYM - rm -rf *.d *._d json/*.d json/*._d *.sdb *.db *.dylib *.dll *.so *.so.* - -# rules # -.c: -ifneq ($(SILENT),) - @echo LD $< -endif - $(CC) $(LDFLAGS) -c $(CFLAGS) $(SDB_CFLAGS) -o $@ $< - -S=$ - -%.o: %.c -ifneq ($(SILENT),) - @echo CC $< -endif - $(CC) -c ${CPPFLAGS} ${CFLAGS} $(SDB_CFLAGS) ${CFLAGS_SHARED} -o $@ $< - -%.o.o: %.c -ifneq ($(SILENT),) - @echo CC PIC $< -endif - @mv `echo $<|sed -e 's,\.c$S,\.d,g'` $<.tmp 2>/dev/null || true - $(CC) -c ${CPPFLAGS} ${CFLAGS} $(SDB_CFLAGS) ${CFLAGS_SHARED} -o $@ $< - @mv `echo $<|sed -e 's,\.c$S,\.d,g'` `echo $<|sed -e 's,\.c$S,\._d,g'` 2>/dev/null || true - @mv $<.tmp `echo $<|sed -e 's,\.c$S,\.d,g'` 2>/dev/null ||true - --include ${OBJ:.o=.d} --include ${OBJ:.o=._d} diff --git a/shlr/sdb/src/array.c b/shlr/sdb/src/array.c deleted file mode 100644 index e4570d1c65204..0000000000000 --- a/shlr/sdb/src/array.c +++ /dev/null @@ -1,709 +0,0 @@ -/* sdb - MIT - Copyright 2011-2022 - pancake */ - -#include "sdb/sdb.h" -#include - -// TODO: Push should always prepend. do not make this configurable -#define PUSH_PREPENDS 1 - -// TODO: missing num_{inc/dec} functions - -static const char *Aindexof(const char *str, int idx) { - int len = 0; - const char *n, *p = str; - for (len = 0; ; len++) { - if (len == idx) { - return p; - } - if (!(n = strchr (p, SDB_RS))) { - break; - } - p = n + 1; - } - return NULL; -} - -static int astrcmp(const char *a, const char *b) { - char va = *a; - char vb = *b; - for (;;) { - if (va == '\0' || va == SDB_RS) { - if (vb == '\0' || vb == SDB_RS) { - return 0; - } - return -1; - } - if (vb == '\0' || vb == SDB_RS) { - return 1; - } - if (va != vb) { - return (va > vb) ? 1 : -1; - } - va = *(++a); - vb = *(++b); - } -} - -static inline int cstring_cmp(const void *a, const void *b) { - const char **va = (const char **)a; - const char **vb = (const char **)b; - return astrcmp (*va, *vb); -} - -static inline int int_cmp(const void *a, const void *b) { - const ut64 va = *(const ut64 *)a; - const ut64 vb = *(const ut64 *)b; - if (va > vb) { - return 1; - } - if (va < vb) { - return -1; - } - return 0; -} - -SDB_API ut64 sdb_array_get_num(Sdb *s, const char *key, int idx, ut32 *cas) { - int i; - const char *n, *str = sdb_const_get (s, key, cas); - if (!str || !*str) { - return 0LL; - } - if (idx) { - for (i = 0; i < idx; i++) { - n = strchr (str, SDB_RS); - if (!n) { - return 0LL; - } - str = n + 1; - } - } - return sdb_atoi (str); -} - -SDB_API char *sdb_array_get(Sdb *s, const char *key, int idx, ut32 *cas) { - const char *str = sdb_const_get (s, key, cas); - const char *p = str; - char *o, *n; - int i, len; - if (!str || !*str) { - return NULL; - } - if (idx < 0) { - int alen = sdb_alen (str); - if (-idx > alen) { - return NULL; - } - idx += alen; - } - if (!idx) { - n = strchr ((char *)str, SDB_RS); - if (!n) { - return sdb_strdup (str); - } - len = n - str; - o = (char *)sdb_gh_malloc (len + 1); - if (!o) { - return NULL; - } - memcpy (o, str, len); - o[len] = 0; - return o; - } - for (i = 0; i < idx; i++) { - n = strchr ((char *)p, SDB_RS); - if (!n) return NULL; - p = n + 1; - } - n = strchr ((char *)p, SDB_RS); - if (!n) { - return sdb_strdup (p); - } - len = n - p; - o = (char *)sdb_gh_malloc (len + 1); - if (o) { - memcpy (o, p, len); - o[len] = 0; - return o; - } - return NULL; -} - -SDB_API int sdb_array_insert_num(Sdb *s, const char *key, int idx, ut64 val, ut32 cas) { - char valstr[SDB_NUM_BUFSZ]; - sdb_itoa (val, 0, valstr, sizeof (valstr)); - return sdb_array_insert (s, key, idx, valstr, cas); -} - -// TODO: done, but there's room for improvement -SDB_API int sdb_array_insert(Sdb *s, const char *key, int idx, const char *val, ut32 cas) { - int lnstr, lstr; - size_t lval; - char *x, *ptr; - const char *str = sdb_const_get_len (s, key, &lstr, 0); - if (!str || !*str) { - return sdb_set (s, key, val, cas); - } - lval = strlen (val); - lstr--; - // XXX: lstr is wrongly computed in sdb_const_get_with an off-by-one - // we can optimize this by caching value len in memory . add - // sdb_const_get_size() - lstr = strlen (str); - - // When removing strlen this conversion should be checked - size_t lstr_tmp = lstr; - if (SZT_ADD_OVFCHK (lval, lstr_tmp) || SZT_ADD_OVFCHK (lval + lstr_tmp, 2)) { - return false; - } - x = (char *)sdb_gh_malloc (lval + lstr_tmp + 2); - if (!x) { - return false; - } - - if (idx == -1) { - memcpy (x, str, lstr); - x[lstr] = SDB_RS; - memcpy (x + lstr + 1, val, lval + 1); - } else if (!idx) { - memcpy (x, val, lval); - x[lval] = SDB_RS; - memcpy (x + lval + 1, str, lstr + 1); - } else { - char *nstr = (char *)sdb_gh_malloc (lstr + 1); - if (!nstr) { - sdb_gh_free (x); - return false; - } - memcpy (nstr, str, lstr + 1); - ptr = (char *)Aindexof (nstr, idx); - if (ptr) { - int lptr = (nstr + lstr + 1) - ptr; - char *p_1 = ptr > nstr? ptr - 1: ptr; - *p_1 = 0; - lnstr = ptr - nstr - 1; - memcpy (x, nstr, lnstr); - x[lnstr] = SDB_RS; - memcpy (x + lnstr + 1, val, lval); - x[lnstr + lval + 1] = SDB_RS; - // TODO: this strlen hurts performance - memcpy (x + lval + 2 + lnstr, ptr, lptr); //strlen (ptr)+1); - sdb_gh_free (nstr); - } else { - // this is not efficient - sdb_gh_free (nstr); - sdb_gh_free (x); - // fallback for empty buckets - return sdb_array_set (s, key, idx, val, cas); - } - } - return sdb_set_owned (s, key, x, cas); -} - -SDB_API int sdb_array_set_num(Sdb *s, const char *key, int idx, ut64 val, ut32 cas) { - char valstr[SDB_NUM_BUFSZ]; - sdb_itoa (val, 0, valstr, sizeof (valstr)); - return sdb_array_set (s, key, idx, valstr, cas); -} - -SDB_API int sdb_array_add_num(Sdb *s, const char *key, ut64 val, ut32 cas) { - char buf[SDB_NUM_BUFSZ]; - char *v = sdb_itoa (val, 0, buf, sizeof (buf)); - if (!sdb_array_contains (s, key, v, NULL)) { - if (val < 256) { - v = sdb_itoa (val, 10, buf, sizeof (buf)); - } - } - return sdb_array_add (s, key, v, cas); -} - -// XXX: index should be supressed here? if its a set we shouldnt change the index -SDB_API int sdb_array_add(Sdb *s, const char *key, const char *val, ut32 cas) { - if (sdb_array_contains (s, key, val, NULL)) { - return 0; - } - return sdb_array_insert (s, key, -1, val, cas); -} - -SDB_API int sdb_array_add_sorted(Sdb *s, const char *key, const char *val, ut32 cas) { - int lstr, lval, i, j; - const char *str_e, *str_lp, *str_p, *str = sdb_const_get_len (s, key, &lstr, 0); - char *nstr, *nstr_p, **vals; - const char null = '\0'; - if (!str || !*str) { - str = &null; - lstr = 0; - } - str_e = str + lstr; - str_lp = str_p = str; - if (!val || !*val) { - return 1; - } - lval = strlen (val); - vals = sdb_fmt_array (val); - for (i = 0; vals[i]; i++) { - /* empty */ - } - if (i > 1) { - qsort (vals, i, sizeof (ut64*), cstring_cmp); - } - nstr_p = nstr = (char *)sdb_gh_malloc (lstr + lval + 3); - if (!nstr) { - return 1; - } - for (i = 0; vals[i]; i++) { - while (str_p < str_e) { - if (astrcmp (vals[i], str_p) < 0) { - break; - } - str_p = sdb_const_anext (str_p); - if (!str_p) { - str_p = str_e; - } - } - memcpy (nstr_p, str_lp, str_p - str_lp); - nstr_p += str_p - str_lp; - if (str_p == str_e && str_lp != str_e) { - *(nstr_p++) = SDB_RS; - } - str_lp = str_p; - j = strlen (vals[i]); - memcpy (nstr_p, vals[i], j); - nstr_p += j; - *(nstr_p++) = SDB_RS; - } - if (str_lp < str_e) { - memcpy (nstr_p, str_lp, str_e - str_lp); - nstr_p += str_e - str_lp; - *(nstr_p) = '\0'; - } else { - *(--nstr_p) = '\0'; - } - sdb_set_owned (s, key, nstr, cas); - sdb_gh_free (vals); - return 0; -} - -SDB_API int sdb_array_add_sorted_num(Sdb *s, const char *key, ut64 val, ut32 cas) { - int i; - char valstr[SDB_NUM_BUFSZ]; - const char *str = sdb_const_get (s, key, 0); - const char *n = str; - if (!str || !*str) { - return sdb_set (s, key, sdb_itoa (val, 0, valstr, sizeof (valstr)), cas); - } - for (i = 0; n; i++) { - if (val <= sdb_atoi (n)) { - break; - } - n = sdb_const_anext (n); - } - return sdb_array_insert_num (s, key, n? i: -1, val, cas); -} - -SDB_API int sdb_array_unset(Sdb *s, const char *key, int idx, ut32 cas) { - return sdb_array_set (s, key, idx, "", cas); -} - -SDB_API bool sdb_array_append(Sdb *s, const char *key, const char *val, - ut32 cas) { -#if SLOW - return sdb_array_set (s, key, -1, val, cas); -#else - int str_len = 0; - ut32 kas = cas; - const char *str = sdb_const_get_len (s, key, &str_len, &kas); - if (!val || (cas && cas != kas)) { - return false; - } - cas = kas; - if (str && *str && str_len > 0) { - int val_len = strlen (val); - char *newval = (char *)sdb_gh_malloc (str_len + val_len + 2); - if (!newval) { - return false; - } - memcpy (newval, str, str_len); - newval[str_len] = SDB_RS; - memcpy (newval+str_len+1, val, val_len); - newval[str_len+val_len+1] = 0; - sdb_set_owned (s, key, newval, cas); - } else { - sdb_set (s, key, val, cas); - } - return true; -#endif -} - -SDB_API bool sdb_array_append_num(Sdb *s, const char *key, ut64 val, ut32 cas) { - return sdb_array_set_num (s, key, -1, val, cas); -} - -SDB_API int sdb_array_set(Sdb *s, const char *key, int idx, const char *val, - ut32 cas) { - int lstr, lval, len; - const char *usr, *str = sdb_const_get_len (s, key, &lstr, 0); - char *ptr; - - if (!str || !*str) { - return sdb_set (s, key, val, cas); - } - // XXX: should we cache sdb_alen value inside kv? - len = sdb_alen (str); - lstr--; - if (idx < 0 || idx == len) { // append - return sdb_array_insert (s, key, -1, val, cas); - } - lval = strlen (val); - if (idx > len) { - int ret, i, ilen = idx-len; - char *newkey = (char *)sdb_gh_malloc (ilen + lval + 1); - if (!newkey) { - return 0; - } - for (i = 0; i < ilen; i++) { - newkey [i] = SDB_RS; - } - memcpy (newkey + i, val, lval + 1); - ret = sdb_array_insert (s, key, -1, newkey, cas); - sdb_gh_free (newkey); - return ret; - } - //lstr = strlen (str); - ptr = (char*)Aindexof (str, idx); - if (ptr) { - int diff = ptr - str; - char *nstr = (char *)sdb_gh_malloc (lstr + lval + 2); - if (!nstr) { - return false; - } - ptr = nstr + diff; - //memcpy (nstr, str, lstr+1); - memcpy (nstr, str, diff); - memcpy (ptr, val, lval + 1); - usr = Aindexof (str, idx + 1); - if (usr) { - ptr[lval] = SDB_RS; - strcpy (ptr + lval + 1, usr); - } - int ret = sdb_set (s, key, nstr, cas); - sdb_gh_free (nstr); - return ret; - } - return 0; -} - -SDB_API int sdb_array_remove_num(Sdb *s, const char *key, ut64 val, ut32 cas) { - const char *n, *p, *str = sdb_const_get (s, key, 0); - int idx = 0; - ut64 num; - if (str) { - for (p = str; ; idx++) { - num = sdb_atoi (p); - if (num == val) { - return sdb_array_delete (s, key, idx, cas); - } - n = strchr (p, SDB_RS); - if (!n) { - break; - } - p = n + 1; - } - } - return 0; -} - -/* get array index of given value */ -SDB_API int sdb_array_indexof(Sdb *s, const char *key, const char *val, - ut32 cas) { - const char *str = sdb_const_get (s, key, 0); - const char *n, *p = str; - int i; - for (i = 0; ; i++) { - if (!p) { - break; - } - if (!astrcmp (p, val)) { - return i; - } - n = strchr (p, SDB_RS); - if (!n) break; - p = n + 1; - } - return -1; -} - -// previously named del_str... pair with _add -SDB_API int sdb_array_remove (Sdb *s, const char *key, const char *val, - ut32 cas) { - const char *str = sdb_const_get (s, key, 0); - const char *n, *p = str; - int idx; - if (p) { - for (idx = 0; ; idx++) { - if (!astrcmp (p, val)) { - return sdb_array_delete (s, key, idx, cas); - } - n = strchr (p, SDB_RS); - if (!n) { - break; - } - p = n + 1; - } - } - return 0; -} - -SDB_API int sdb_array_delete(Sdb *s, const char *key, int idx, ut32 cas) { - int i; - char *p, *n, *str = sdb_get (s, key, 0); - p = str; - if (!str || !*str) { - sdb_gh_free (str); - return 0; - } - if (idx < 0) { - idx = sdb_alen (str); - if (idx) idx--; - } - for (i = 0; i < idx; i++) { - if ( (n = strchr (p, SDB_RS)) ) { - p = n + 1; - } else { - sdb_gh_free (str); - return 0; - } - } - n = strchr (p, SDB_RS); - if (n) { - memmove (p, n + 1, strlen (n)); - } else { - if (p != str) { - p--; // remove tailing SDB_RS - } - *p = 0; - p[1] = 0; - } - sdb_set_owned (s, key, str, cas); - return 1; -} - -// XXX Doesnt work if numbers are stored in different base -SDB_API bool sdb_array_contains_num(Sdb *s, const char *key, ut64 num, ut32 *cas) { - char val[SDB_NUM_BUFSZ]; - char *nval = sdb_itoa (num, 0, val, sizeof (val)); - return sdb_array_contains (s, key, nval, cas); -} - -SDB_API bool sdb_array_contains(Sdb *s, const char *key, const char *val, ut32 *cas) { - if (!s || !key || !val) { - return false; - } - const char *next, *ptr = sdb_const_get (s, key, cas); - if (ptr && *ptr) { - size_t vlen = strlen (val); - while (1) { - next = strchr (ptr, SDB_RS); - size_t len = next ? (size_t)(next - ptr) : strlen (ptr); - if (len == vlen && !memcmp (ptr, val, len)) { - return true; - } - if (!next) { - break; - } - ptr = next + 1; - } - } - return false; -} - -SDB_API int sdb_array_size(Sdb *s, const char *key) { - return sdb_alen (sdb_const_get (s, key, 0)); -} - -// NOTE: ignore empty buckets -SDB_API int sdb_array_length(Sdb *s, const char *key) { - return sdb_alen_ignore_empty (sdb_const_get (s, key, 0)); -} - -SDB_API int sdb_array_push_num(Sdb *s, const char *key, ut64 num, ut32 cas) { - char buf[SDB_NUM_BUFSZ]; - char *n = sdb_itoa (num, 0, buf, sizeof (buf)); - return sdb_array_push (s, key, n, cas); -} - -SDB_API bool sdb_array_push(Sdb *s, const char *key, const char *val, ut32 cas) { -#if PUSH_PREPENDS - return sdb_array_prepend (s, key, val, cas); -#else - return sdb_array_append (s, key, val, cas); -#endif -} - -SDB_API bool sdb_array_prepend_num(Sdb *s, const char *key, ut64 num, ut32 cas) { - char buf[SDB_NUM_BUFSZ]; - char *n = sdb_itoa (num, 0, buf, sizeof (buf)); - return sdb_array_push (s, key, n, cas); -} - -SDB_API bool sdb_array_prepend (Sdb *s, const char *key, const char *val, ut32 cas) { - if (!s || !key || !val) { - return false; - } - int str_len = 0; - ut32 kas = cas; - const char *str = sdb_const_get_len (s, key, &str_len, &kas); - if (!val || (cas && cas != kas)) { - return false; - } - cas = kas; - if (str && *str) { - int val_len = strlen (val); - char *newval = (char *)sdb_gh_malloc (str_len + val_len + 2); - if (!newval) { - return false; - } - memcpy (newval, val, val_len); - newval[val_len] = SDB_RS; - memcpy (newval + val_len + 1, str, str_len); - newval[str_len + val_len + 1] = 0; - // TODO: optimize this because we already have allocated and strlened everything - sdb_set_owned (s, key, newval, cas); - } else { - sdb_set (s, key, val, cas); - } - return true; -} - -SDB_API ut64 sdb_array_pop_num(Sdb *s, const char *key, ut32 *cas) { - ut64 ret; - char *a = sdb_array_pop (s, key, cas); - if (!a) { - if (cas) { - *cas = UT32_MAX; // invalid - } - return UT64_MAX; - } - if (cas) { - *cas = 0; - } - ret = sdb_atoi (a); - sdb_gh_free (a); - return ret; -} - -SDB_API char *sdb_array_pop(Sdb *s, const char *key, ut32 *cas) { -#if PUSH_PREPENDS - return sdb_array_pop_head (s, key, cas); -#else - return sdb_array_pop_tail (s, key, cas); -#endif -} - -SDB_API char *sdb_array_pop_head(Sdb *s, const char *key, ut32 *cas) { - // remove last element in - ut32 kas; - char *end, *str = sdb_get (s, key, &kas); - if (!str || !*str) { - sdb_gh_free (str); - return NULL; - } - if (cas && *cas != kas) { - *cas = kas; - } - end = strchr (str, SDB_RS); - if (end) { - *end = 0; - sdb_set (s, key, end + 1, 0); - } else { - sdb_unset (s, key, 0); - } - return str; -} - -SDB_API char *sdb_array_pop_tail(Sdb *s, const char *key, ut32 *cas) { - ut32 kas; - char *end, *str = sdb_get (s, key, &kas); - if (!str || !*str) { - sdb_gh_free (str); - return NULL; - } - if (cas && *cas != kas) { - *cas = kas; - } - for (end = str + strlen (str) - 1; end > str && *end != SDB_RS; end--) { - //nothing to see here - } - if (*end == SDB_RS) { - *end++ = 0; - } - sdb_set_owned (s, key, str, 0); - // XXX: probably wrong - return sdb_strdup (end); -} - -SDB_API void sdb_array_sort(Sdb *s, const char *key, ut32 cas) { - char *nstr, *str, **strs; - int lstr, j, i; - str = sdb_get_len (s, key, &lstr, 0); - if (!str) { - return; - } - if (!*str) { - sdb_gh_free (str); - return; - } - strs = sdb_fmt_array (str); - for (i = 0; strs[i]; i++) { - //nothing to see here - } - qsort (strs, i, sizeof (char*), cstring_cmp); - nstr = str; - for (i = 0; strs[i]; i++) { - j = strlen (strs[i]); - memcpy (nstr, strs[i], j); - nstr += j; - *(nstr++) = SDB_RS; - } - if (nstr > str) { - *(--nstr) = '\0'; - } else { - *nstr = '\0'; - } - sdb_set_owned (s, key, str, cas); - sdb_gh_free (strs); -} - -SDB_API void sdb_array_sort_num(Sdb *s, const char *key, ut32 cas) { - char *ret, *nstr; - - char *str = sdb_get (s, key, 0); - if (!str) { - return; - } - if (!*str) { - sdb_gh_free (str); - return; - } - ut64 *nums = sdb_fmt_array_num (str); - sdb_gh_free (str); - if (!nums) { - return; - } - - qsort (nums + 1, (int)*nums, sizeof (ut64), int_cmp); - - nstr = (char *)sdb_gh_malloc (*nums + 1); - if (!nstr) { - sdb_gh_free (nums); - return; - } - memset (nstr, 'q', *nums); - nstr[*nums] = '\0'; - - ret = sdb_fmt_tostr (nums + 1, nstr); - sdb_set_owned (s, key, ret, cas); - - sdb_gh_free (nstr); - sdb_gh_free (nums); - return; -} diff --git a/shlr/sdb/src/base64.c b/shlr/sdb/src/base64.c deleted file mode 100644 index 758c6c5d27281..0000000000000 --- a/shlr/sdb/src/base64.c +++ /dev/null @@ -1,111 +0,0 @@ -/* base64 enc/dec - MIT - Copyright 2011-2022 - pancake */ - -#include "sdb/sdb.h" - -#define SZ 1024 -static const char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -static const char cd64[]="|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq"; - -static void sdb_b64_encode(const ut8 in[3], char out[4], int len) { - if (len < 1) { - return; - } - out[0] = cb64[ in[0] >> 2 ]; - out[1] = cb64[ ((in[0] & 0x03) << 4) | ((len>1)?((in[1] & 0xf0) >> 4):0) ]; - out[2] = (len > 1 ? cb64[ ((in[1] & 0x0f) << 2) | (len > 2 ? ((in[2] & 0xc0) >> 6) : 0) ] : '='); - out[3] = (len > 2 ? cb64[ in[2] & 0x3f ] : '='); -} - -static int sdb_b64_decode(const char in[4], ut8 out[3]) { - int len = 3; - ut8 i, v[4] = {0}; - for (i = 0; i < 4; i++) { - if (in[i] < '+' || in[i] > 'z') { - return -1; - } - v[i] = cd64[in[i] - '+']; - if (v[i] == '$') { - len = i ? i - 1: -1; - break; - } - v[i] -= 62; - } - out[0] = v[0] << 2 | v[1] >> 4; - out[1] = v[1] << 4 | v[2] >> 2; - out[2] = ((v[2] << 6) & 0xc0) | v[3]; - return len; -} - -SDB_API void sdb_encode_raw(char *bout, const ut8 *bin, int len) { - int in, out; - for (in = out = 0; in < len; in += 3,out+=4) { - sdb_b64_encode (bin + in, bout + out, - (len - in) > 3? 3: (len - in)); - } - bout[out] = 0; -} - -SDB_API int sdb_decode_raw(ut8 *bout, const char *bin, int len) { - int in, out, ret; - for (in = out = 0; in < len; in += 4) { - ret = sdb_b64_decode (bin + in, bout + out); - if (ret < 1) { - break; - } - out += ret; - } - return (in != out)? out: 0; -} - -SDB_API char *sdb_encode(const ut8 *bin, int len) { - char *out; - if (!bin) { - return NULL; - } - if (len < 0) { - len = strlen ((const char *)bin); - } - if (!len) { - return sdb_strdup (""); - } - out = (char *)sdb_gh_calloc (8 + (len * 2), sizeof (char)); - if (!out) { - return NULL; - } - sdb_encode_raw (out, bin, len); - return out; -} - -SDB_API ut8 *sdb_decode(const char *in, int *len) { - ut8 *out; - ut32 size; - int olen, ilen; - if (len) { - *len = 0; - } - if (!in) { - return NULL; - } - ilen = (int)strlen (in); - if (!ilen) { - return NULL; - } - size = (ilen * 3) + 16; - if (size < (ut32)ilen) { - return NULL; - } - out = (ut8 *)sdb_gh_calloc (1, size); - if (!out) { - return NULL; - } - olen = sdb_decode_raw (out, in, ilen); - if (!olen) { - sdb_gh_free (out); - return NULL; - } - out[olen] = 0; - if (len) { - *len = olen; - } - return out; -} diff --git a/shlr/sdb/src/buffer.inc.c b/shlr/sdb/src/buffer.inc.c deleted file mode 100644 index 83b0fb799caf9..0000000000000 --- a/shlr/sdb/src/buffer.inc.c +++ /dev/null @@ -1,58 +0,0 @@ -/* Public Domain */ - -#include "sdb/buffer.h" - -void buffer_initialize(buffer *s, BufferOp op, int fd, char *buf, ut32 len) { - s->x = buf; - s->fd = fd; - s->op = op; - s->p = 0; - s->n = len; -} - -static int allwrite(BufferOp op, int fd, const char *buf, ut32 len) { - ut32 w; - while (len > 0) { - w = op (fd, buf, len); - if (w != len) { - return 0; - } - buf += w; - len -= w; - } - return 1; -} - -int buffer_flush(buffer *s) { - int p = s->p; - if (!p) { - return 1; - } - s->p = 0; - return allwrite (s->op, s->fd, s->x, p); -} - -int buffer_putalign(buffer *s, const char *buf, ut32 len) { - ut32 n; - if (!s || !s->x || !buf) { - return 0; - } - while (len > (n = s->n - s->p)) { - memcpy (s->x + s->p, buf, n); - s->p += n; buf += n; len -= n; - if (!buffer_flush (s)) { - return 0; - } - } - /* now len <= s->n - s->p */ - memcpy (s->x + s->p, buf, len); - s->p += len; - return 1; -} - -int buffer_putflush(buffer *s, const char *buf, ut32 len) { - if (!buffer_flush (s)) { - return 0; - } - return allwrite (s->op, s->fd, buf, len); -} diff --git a/shlr/sdb/src/cdb.c b/shlr/sdb/src/cdb.c deleted file mode 100644 index ebed315701dd6..0000000000000 --- a/shlr/sdb/src/cdb.c +++ /dev/null @@ -1,190 +0,0 @@ -/* Public domain - author D. J. Bernstein, modified by pancake - 2014-2016 */ - -#include -#include "sdb/cdb.h" -#include "sdb/heap.h" -#if USE_MMAN -#include -#endif - -/* XXX: this code must be rewritten . too slow */ -bool cdb_getkvlen(struct cdb *c, ut32 *klen, ut32 *vlen, ut32 pos) { - ut8 buf[4] = { 0 }; - *klen = *vlen = 0; - if (!cdb_read (c, (char *)buf, sizeof (buf), pos)) { - return false; - } - *klen = (ut32)buf[0]; - *vlen = (ut32)(buf[1] | ((ut32)buf[2] << 8) | ((ut32)buf[3] << 16)); - if (*vlen > CDB_MAX_VALUE) { - *vlen = CDB_MAX_VALUE; // untaint value for coverity - return false; - } - return true; -} - -void cdb_free(struct cdb *c) { - if (!c->map) { - return; - } -#if USE_MMAN - (void)munmap (c->map, c->size); -#else - sdb_gh_free (c->map); -#endif - c->map = NULL; -} - -void cdb_findstart(struct cdb *c) { - c->loop = 0; -#if !USE_MMAN - if (c->fd != -1) { - lseek (c->fd, 0, SEEK_SET); - } -#endif -} - -bool cdb_init(struct cdb *c, int fd) { - struct stat st; - if (fd != c->fd && c->fd != -1) { - close (c->fd); - } - c->fd = fd; - cdb_findstart (c); - if (fd != -1 && !fstat (fd, &st) && st.st_size > 4 && st.st_size != (off_t)UT64_MAX) { -#if USE_MMAN - char *x = (char *)mmap (0, st.st_size, PROT_READ, MAP_SHARED, fd, 0); - if (x == MAP_FAILED) { - // eprintf ("Cannot mmap %d\n", (int)st.st_size); - return false; - } - if (c->map) { - munmap (c->map, c->size); - } -#else - char *x = sdb_gh_calloc (1, st.st_size); - if (!x) { - // eprintf ("Cannot malloc %d\n", (int)st.st_size); - return false; - } - /* TODO: read by chunks instead of a big huge syscall */ - if (read (fd, x, st.st_size) != st.st_size) { - /* handle read error */ - } - sdb_gh_free (c->map); -#endif - c->map = x; - c->size = st.st_size; - return true; - } - c->map = NULL; - c->size = 0; - return false; -} - -bool cdb_read(struct cdb *c, char *buf, ut32 len, ut32 pos) { - if (c->map) { - if ((pos > c->size) || (c->size - pos < len)) { - return false; - } - if (!buf) { - return false; - } - memcpy (buf, c->map + pos, len); - return true; - } - if (c->fd == -1 || !seek_set (c->fd, pos)) { - return false; - } - while (len > 0) { - int r = (int)read (c->fd, buf, len); - if (r < 1 || (ut32)r != len) { - return false; - } - buf += r; - len -= r; - } - return true; -} - -static int match(struct cdb *c, const char *key, ut32 len, ut32 pos) { - char buf[32]; - const size_t szb = sizeof buf; - while (len > 0) { - int n = (szb > len)? len: szb; - if (!cdb_read (c, buf, n, pos)) { - return -1; - } - if (memcmp (buf, key, n)) { - return 0; - } - pos += n; - key += n; - len -= n; - } - return 1; -} - -int cdb_findnext(struct cdb *c, ut32 u, const char *key, ut32 len) { - char buf[8]; - ut32 pos; - int m; - len++; - if (c->fd == -1) { - return -1; - } - c->hslots = 0; - if (!c->loop) { - const int bufsz = ((u + 1) & 0xFF) ? sizeof (buf) : sizeof (buf) / 2; - if (!cdb_read (c, buf, bufsz, (u << 2) & 1023)) { - return -1; - } - /* hslots = (hpos_next - hpos) / 8 */ - ut32_unpack (buf, &c->hpos); - if (bufsz == sizeof (buf)) { - ut32_unpack (buf + 4, &pos); - } else { - pos = c->size; - } - if (pos < c->hpos) { - return -1; - } - c->hslots = (pos - c->hpos) / (2 * sizeof (ut32)); - if (!c->hslots) { - return 0; - } - c->khash = u; - u = ((u >> 8) % c->hslots) << 3; - c->kpos = c->hpos + u; - } - while (c->loop < c->hslots) { - if (!cdb_read (c, buf, sizeof (buf), c->kpos)) { - return 0; - } - ut32_unpack (buf + 4, &pos); - if (!pos) { - return 0; - } - c->loop++; - c->kpos += sizeof (buf); - if (c->kpos == c->hpos + (c->hslots << 3)) { - c->kpos = c->hpos; - } - ut32_unpack (buf, &u); - if (u == c->khash) { - if (!cdb_getkvlen (c, &u, &c->dlen, pos) || !u) { - return -1; - } - if (u == len) { - if ((m = match (c, key, len, pos + KVLSZ)) == -1) { - return 0; - } - if (m == 1) { - c->dpos = pos + KVLSZ + len; - return 1; - } - } - } - } - return 0; -} diff --git a/shlr/sdb/src/cdb_make.c b/shlr/sdb/src/cdb_make.c deleted file mode 100644 index 6f89c4762e9fe..0000000000000 --- a/shlr/sdb/src/cdb_make.c +++ /dev/null @@ -1,197 +0,0 @@ -/* Public domain. */ - -#include "sdb/sdb.h" -#include "sdb/cdb.h" -#include "sdb/cdb_make.h" -#include "buffer.inc.c" - -#define ALIGNMENT sizeof (void*) -#define USE_GHA 1 - -static char *cdb_alloc(ut32 n) { -#if USE_GHA - return (char *)sdb_gh_malloc (n); -#else -#if __APPLE__ && !__POWERPC__ - void *ret = NULL; - return (char *)(posix_memalign (&ret, ALIGNMENT, n)? NULL: ret); -#elif __SDB_WINDOWS__ && !__CYGWIN__ - return (char *)_aligned_malloc (n, ALIGNMENT); -#else - return (char *)sdb_gh_malloc (n); -#endif -#endif -} - -static void cdb_alloc_free(void *x) { -#if USE_GHA - sdb_gh_free (x); -#else -#if __SDB_WINDOWS__ && !__CYGWIN__ - _aligned_free (x); -#else - sdb_gh_free (x); -#endif -#endif -} - -int cdb_make_start(struct cdb_make *c, int fd) { - int i; - c->head = 0; - c->split = 0; - c->hash = 0; - c->numentries = 0; - c->fd = fd; - c->pos = sizeof (c->final); - buffer_initialize (&c->b, (BufferOp)write, fd, c->bspace, sizeof (c->bspace)); - c->memsize = 1; - for (i = 0; i < 256; i++) { - c->count[i] = 0; - } - return seek_set (fd, c->pos); -} - -static inline int incpos(struct cdb_make *c, ut32 len) { - ut32 newpos = c->pos + len; - if (newpos < len) { - return 0; - } - c->pos = newpos; - return 1; -} - -int cdb_make_addend(struct cdb_make *c, ut32 keylen, ut32 datalen, ut32 h) { - ut32 u; - struct cdb_hplist *head = c->head; - if (!head || (head->num >= CDB_HPLIST)) { - head = (struct cdb_hplist*)cdb_alloc (sizeof (struct cdb_hplist)); - if (!head) { - return 0; - } - head->num = 0; - head->next = c->head; - c->head = head; - } - head->hp[head->num].h = h; - head->hp[head->num].p = c->pos; - head->num++; - c->numentries++; - c->count[255 & h] ++; - u = c->count[255 & h] * 2; - if (u > c->memsize) { - c->memsize = u; - } - return incpos (c, KVLSZ + keylen + datalen); -} - -static int pack_kvlen(ut8 *buf, ut32 klen, ut32 vlen) { - if (klen > SDB_MAX_KEY) { - return 0; // 0xff = 254 chars+trailing zero - } - if (vlen >= SDB_MAX_VALUE) { - return 0; - } - buf[0] = (ut8)klen; - buf[1] = (ut8)((vlen ) & 0xff); - buf[2] = (ut8)((vlen >> 8 ) & 0xff); - buf[3] = (ut8)((vlen >> 16) & 0xff); - return 1; -} - -int cdb_make_addbegin(struct cdb_make *c, ut32 keylen, ut32 datalen) { - ut8 buf[KVLSZ]; - if (!pack_kvlen (buf, keylen, datalen)) { - return 0; - } - return buffer_putalign (&c->b, (const char *)buf, KVLSZ); -} - -int cdb_make_add(struct cdb_make *c, const char *key, ut32 keylen, const char *data, ut32 datalen) { - /* add tailing \0 to allow mmap to work later */ - keylen++; - datalen++; - if (!cdb_make_addbegin (c, keylen, datalen)) { - return 0; - } - if (!buffer_putalign (&c->b, key, keylen)) { - return 0; - } - if (!buffer_putalign (&c->b, data, datalen)) { - return 0; - } - return cdb_make_addend (c, keylen, datalen, sdb_hash (key)); -} - -int cdb_make_finish(struct cdb_make *c) { - int i; - char buf[8]; - struct cdb_hp *hp; - struct cdb_hplist *x, *n; - ut32 len, u, memsize, count, where; - - memsize = c->memsize + c->numentries; - if (memsize > (UT32_MAX / sizeof (struct cdb_hp))) { - return 0; - } - c->split = (struct cdb_hp *) cdb_alloc (memsize * sizeof (struct cdb_hp)); - if (!c->split) { - return 0; - } - c->hash = c->split + c->numentries; - - for (u = i = 0; i<256; i++) { - u += c->count[i]; /* bounded by numentries, so no overflow */ - c->start[i] = u; - } - - for (x = c->head; x; x=x->next) { - i = x->num; - while (i--) { - c->split[--c->start[255 & x->hp[i].h]] = x->hp[i]; - } - } - - for (i = 0; i < 256; i++) { - count = c->count[i]; - len = count << 1; - ut32_pack (c->final + 4 * i, c->pos); - for (u = 0; uhash[u].h = c->hash[u].p = 0; - } - hp = c->split + c->start[i]; - for (u = 0; u < count; u++) { - where = (hp->h >> 8) % len; - while (c->hash[where].p) { - if (++where == len) { - where = 0; - } - } - c->hash[where] = *hp++; - } - for (u = 0; u < len; u++) { - ut32_pack (buf, c->hash[u].h); - ut32_pack (buf + 4, c->hash[u].p); - if (!buffer_putalign (&c->b, buf, 8)) { - return 0; - } - if (!incpos (c, 8)) { - return 0; - } - } - } - - if (!buffer_flush (&c->b)) { - return 0; - } - if (!seek_set (c->fd, 0)) { - return 0; - } - // free childs - for (x = c->head; x;) { - n = x->next; - cdb_alloc_free (x); - x = n; - } - cdb_alloc_free (c->split); - return buffer_putflush (&c->b, c->final, sizeof c->final); -} diff --git a/shlr/sdb/src/dict.c b/shlr/sdb/src/dict.c deleted file mode 100644 index eee8f46928cb1..0000000000000 --- a/shlr/sdb/src/dict.c +++ /dev/null @@ -1,215 +0,0 @@ -/* sdb - MIT - Copyright 2017-2022 - pancake */ - -#include "sdb/sdb.h" - -SDB_API dict *dict_new(ut32 size, dict_freecb f) { - dict *m = (dict *)sdb_gh_calloc (1, sizeof (dict)); - if (!dict_init (m, R_MAX (size, 1), f)) { - sdb_gh_free (m); - m = NULL; - } - return m; -} - -// maybe internal? -static ut32 dict_bucket(dict *m, dicti k) { - if (m->size > 0) { - return k % m->size; - } - return 0; -} - -SDB_API bool dict_init(dict *m, ut32 size, dict_freecb f) { - if (m) { - memset (m, 0, sizeof (dict)); - if (size > 0) { - m->table = (void **)sdb_gh_calloc (size, sizeof (dictkv)); - if (!m->table) { - return false; - } - m->size = size; - } - m->f = f; - } - return true; -} - -SDB_API void dict_fini(dict *m) { - if (m) { - ut32 i; - if (m->f) { - for (i = 0; i < m->size; i++) { - dictkv *kv = (dictkv *)m->table[i]; - if (kv) { - while (kv->k != 0) { - m->f (kv->u); - kv++; - } - } - sdb_gh_free (m->table[i]); - } - } else { - for (i = 0; i < m->size; i++) { - sdb_gh_free (m->table[i]); - } - } - sdb_gh_free (m->table); - dict_init (m, 0, NULL); - } -} - -SDB_API void dict_free(dict *m) { - if (m) { - dict_fini (m); - sdb_gh_free (m); - } -} - -// collisions are not handled in a dict. use a hashtable if you want to use strings as keys. -SDB_API dicti dict_hash(const char *s) { - return (dicti)sdb_hash (s); -} - -SDB_API bool dict_set(dict *m, dicti k, dicti v, void *u) { - if (!m || !m->size || k == 0) { - return false; - } - const int bucket = dict_bucket (m, k); - dictkv *kv = (dictkv *)m->table[bucket]; - if (!kv) { - kv = (dictkv *)sdb_gh_calloc (sizeof (dictkv), 2); - if (kv) { - m->table[bucket] = kv; - kv->k = 0; - kv->v = 0; - kv->u = NULL; - return dict_set (m, k, v, u); - } - return false; - } - dictkv *tmp = kv; - while (kv->k != 0) { - if (kv->k == k) { - kv->v = v; - kv->u = u; - return true; - } - kv++; - } - int curln = (kv - tmp); - dictkv *newkv = (dictkv *)sdb_gh_realloc (tmp, (curln + 2) * sizeof (dictkv)); - if (newkv) { - kv = newkv; - m->table[bucket] = newkv; - kv += curln; - kv->k = k; - kv->v = v; - kv->u = u; - kv++; - kv->k = 0; - kv->v = 0; - kv->u = NULL; - return true; - } - return false; -} - -SDB_API ut32 dict_stats(dict *m, ut32 nb) { - if (((int)nb) < 0) { - return m->size - 1; - } - if (nb < m->size) { - ut32 j = 0; - dictkv *kv = (dictkv *)m->table[nb]; - if (kv) { - while (kv->k != 0) { - j++; - kv++; - } - } - return j; - } - return 0; -} - -SDB_API dictkv *dict_getr(dict *m, dicti k) { - if (!m->size) { - return NULL; - } - int bucket = dict_bucket (m, k); - dictkv *kv = (dictkv *)m->table[bucket]; - if (kv) { - while (kv->k != 0) { - if (kv->k == k) { - return kv; - } - kv++; - } - } - return NULL; -} - -SDB_API dicti dict_get(dict *m, dicti k) { - dictkv *kv = dict_getr (m, k); - return kv ? kv->v : 0; -} - -SDB_API void *dict_getu(dict *m, dicti k) { - dictkv *kv = dict_getr (m, k); - return kv ? kv->u : NULL; -} - -SDB_API bool dict_add(dict *m, dicti k, dicti v, void *u) { - return dict_getr (m, k) - ? dict_set (m, k, v, u) - : false; -} - -SDB_API bool dict_del(dict *m, dicti k) { - int bucket = dict_bucket (m, k); - if (k == 0) { - return false; - } - dictkv *kv = (dictkv *)m->table[bucket]; - if (kv) { - while (kv->k != 0) { - if (kv->k == k) { - if (m->f) { - m->f (kv->u); - } - dictkv *n = (dictkv *)(kv + 1); - while (n->k != 0) { - *kv++ = *n++; - } - kv->k = 0; - return true; - } - kv++; - } - } - return false; -} - -// call the cb callback on each element of the dictionary -// m : dict to iterate -// cb : function that accept a dictkv. When it returns a value != 0, the -// iteration stops -// u : additional information to pass to cb together with the dictkv -SDB_API void dict_foreach(dict *m, dictkv_cb cb, void *u) { - bool iterate = true; - ut32 i; - - for (i = 0; i < m->size && iterate; i++) { - dictkv *kv = (dictkv *)m->table[i]; - if (kv) { - while (kv->k) { - int res = cb (kv, u); - if (res) { - iterate = false; - break; - } - kv++; - } - } - } -} diff --git a/shlr/sdb/src/diff.c b/shlr/sdb/src/diff.c deleted file mode 100644 index 2be35fb517f2c..0000000000000 --- a/shlr/sdb/src/diff.c +++ /dev/null @@ -1,171 +0,0 @@ -/* sdb - MIT - Copyright 2019 - thestr4ng3r */ - -#include "sdb/sdb.h" - -SDB_API int sdb_diff_format(char *str, int size, const SdbDiff *diff) { - int r = 0; -#define APPENDF(...) do { \ - int sr = snprintf (str, size, __VA_ARGS__); \ - if (sr < 0) { \ - return sr; \ - } \ - r += sr; \ - if (sr >= size) { \ - /* no space left, only measure from now on */ \ - str = NULL; \ - size = 0; \ - } else { \ - str += sr; \ - size -= sr; \ - } \ - } while(0) - - APPENDF ("%c%s ", diff->add ? '+' : '-', diff->v ? " " : "NS"); - - SdbListIter *it; - const char *component; - ls_foreach_cast (diff->path, it, const char *, component) { - APPENDF ("%s/", component); - } - - if (diff->v) { - APPENDF ("%s=%s", diff->k, diff->v); - } else { - APPENDF ("%s", diff->k); - } - -#undef APPENDF - return r; -} - -typedef struct sdb_diff_ctx_t { - Sdb *a; - Sdb *b; - bool equal; - SdbList *path; - SdbDiffCallback cb; - void *cb_user; -} SdbDiffCtx; - -#define DIFF(ctx, c, ret) do { \ - (ctx)->equal = false; \ - if ((ctx)->cb) { \ - c \ - } else { \ - /* we already know it's not equal and don't care about the rest of the diff */ \ - return ret; \ - } \ -} while(0) - - -static void sdb_diff_report_ns(SdbDiffCtx *ctx, SdbNs *ns, bool add) { - SdbDiff diff = { ctx->path, ns->name, NULL, add }; - ctx->cb (&diff, ctx->cb_user); -} - -static void sdb_diff_report_kv(SdbDiffCtx *ctx, const char *k, const char *v, bool add) { - SdbDiff diff = { ctx->path, k, v, add }; - ctx->cb (&diff, ctx->cb_user); -} - -typedef struct sdb_diff_kv_cb_ctx { - SdbDiffCtx *ctx; - bool add; -} SdbDiffKVCbCtx; - -static bool sdb_diff_report_kv_cb(void *user, const char *k, const char *v) { - const SdbDiffKVCbCtx *ctx = (const SdbDiffKVCbCtx *)user; - sdb_diff_report_kv (ctx->ctx, k, v, ctx->add); - return true; -} - -/** - * just report everything from sdb to buf with prefix - */ -static void sdb_diff_report(SdbDiffCtx *ctx, Sdb *sdb, bool add) { - SdbListIter *it; - SdbNs *ns; - ls_foreach_cast (sdb->ns, it, SdbNs*, ns) { - sdb_diff_report_ns (ctx, ns, add); - ls_push (ctx->path, ns->name); - sdb_diff_report (ctx, ns->sdb, add); - ls_pop (ctx->path); - } - SdbDiffKVCbCtx cb_ctx = { ctx, add }; - sdb_foreach (sdb, sdb_diff_report_kv_cb, &cb_ctx); -} - -static bool sdb_diff_kv_cb(void *user, const char *k, const char *v) { - const SdbDiffKVCbCtx *ctx = (SdbDiffKVCbCtx *)user; - Sdb *other = ctx->add ? ctx->ctx->a : ctx->ctx->b; - const char *other_val = sdb_const_get (other, k, NULL); - if (!other_val || !*other_val) { - DIFF (ctx->ctx, - sdb_diff_report_kv (ctx->ctx, k, v, ctx->add); - , false); - } else if (!ctx->add && strcmp (v, other_val) != 0) { - DIFF (ctx->ctx, - sdb_diff_report_kv (ctx->ctx, k, v, false); - sdb_diff_report_kv (ctx->ctx, k, other_val, true); - , false); - } - return true; -} - -static void sdb_diff_ctx(SdbDiffCtx *ctx) { - SdbListIter *it; - SdbNs *ns; - ls_foreach_cast (ctx->a->ns, it, SdbNs*, ns) { - Sdb *b_ns = sdb_ns (ctx->b, ns->name, false); - if (!b_ns) { - DIFF (ctx, - sdb_diff_report_ns (ctx, ns, false); - ls_push (ctx->path, ns->name); - sdb_diff_report (ctx, ns->sdb, false); - ls_pop (ctx->path); - ,); - continue; - } - Sdb *a = ctx->a; - Sdb *b = ctx->b; - ctx->a = ns->sdb; - ctx->b = b_ns; - ls_push (ctx->path, ns->name); - sdb_diff_ctx (ctx); - ls_pop (ctx->path); - ctx->a = a; - ctx->b = b; - } - ls_foreach_cast (ctx->b->ns, it, SdbNs*, ns) { - if (!sdb_ns (ctx->a, ns->name, false)) { - DIFF (ctx, - sdb_diff_report_ns (ctx, ns, true); - ls_push (ctx->path, ns->name); - sdb_diff_report (ctx, ns->sdb, true); - ls_pop (ctx->path); - ,); - } - } - SdbDiffKVCbCtx kv_ctx = { ctx, false }; - if (!sdb_foreach (ctx->a, sdb_diff_kv_cb, &kv_ctx)) { - return; - } - kv_ctx.add = true; - sdb_foreach (ctx->b, sdb_diff_kv_cb, &kv_ctx); -} - -SDB_API bool sdb_diff(Sdb *a, Sdb *b, SdbDiffCallback cb, void *cb_user) { - SdbDiffCtx ctx; - ctx.a = a; - ctx.b = b; - ctx.equal = true; - ctx.cb = cb; - ctx.cb_user = cb_user; - ctx.path = ls_new (); - if (!ctx.path) { - return false; - } - sdb_diff_ctx (&ctx); - ls_free (ctx.path); - return ctx.equal; -} diff --git a/shlr/sdb/src/disk.c b/shlr/sdb/src/disk.c deleted file mode 100644 index 4b337a5e3d58c..0000000000000 --- a/shlr/sdb/src/disk.c +++ /dev/null @@ -1,176 +0,0 @@ -/* sdb - MIT - Copyright 2013-2024 - pancake */ - -#include -#include -#include -#include "sdb/sdb.h" - -#if __SDB_WINDOWS__ - -#if UNICODE - -static wchar_t *r_utf8_to_utf16_l(const char *cstring, int len) { - if (!cstring || !len || len < -1) { - return NULL; - } - wchar_t *rutf16 = NULL; - int wcsize; - - if ((wcsize = MultiByteToWideChar (CP_UTF8, 0, cstring, len, NULL, 0))) { - wcsize += 1; - if ((rutf16 = (wchar_t *) sdb_gh_calloc (wcsize, sizeof (wchar_t)))) { - MultiByteToWideChar (CP_UTF8, 0, cstring, len, rutf16, wcsize); - if (len != -1) { - rutf16[wcsize - 1] = L'\0'; - } - } - } - return rutf16; -} - -#define r_sys_conv_utf8_to_utf16(buf) r_utf8_to_utf16_l ((buf), -1) - -static bool r_sys_mkdir(const char *path) { - LPTSTR path_ = r_sys_conv_utf8_to_utf16 (path); - bool ret = CreateDirectory (path_, NULL); - sdb_gh_free (path_); - return ret; -} -#else -#define r_sys_conv_utf8_to_utf16(buf) sdb_strdup (buf) -#define r_sys_mkdir(x) CreateDirectory (x, NULL) -#endif -#ifndef ERROR_ALREADY_EXISTS -#define ERROR_ALREADY_EXISTS 183 -#endif -#define r_sys_mkdir_failed() (GetLastError () != 183) -#else -#define r_sys_mkdir(x) (mkdir (x,0755)!=-1) -#define r_sys_mkdir_failed() (errno != EEXIST) -#endif - -static inline bool mkdirp(char *dir) { - const char slash = DIRSEP; - char *path = dir; - char *ptr = path; - if (*ptr == slash) { - ptr++; - } -#if __SDB_WINDOWS__ - char *p = strstr (ptr, ":\\"); - if (p) { - ptr = p + 2; - } -#endif - while ((ptr = strchr (ptr, slash))) { - *ptr = 0; - if (!r_sys_mkdir (path) && r_sys_mkdir_failed ()) { - // eprintf ("cannot make directory r_sys_mkdirp: fail '%s' of '%s'\n", path, dir); - *ptr = slash; - return false; - } - *ptr = slash; - ptr++; - } - return true; -} - -SDB_API bool sdb_disk_create(Sdb* s) { - int nlen; - char *str; - const char *dir; - if (!s || s->fdump >= 0) { - return false; // cannot re-create - } - if (!s->dir && s->name) { - s->dir = sdb_strdup (s->name); - } - dir = s->dir ? s->dir : "./"; - R_FREE (s->ndump); - nlen = strlen (dir); - str = (char *)sdb_gh_malloc (nlen + 5); - if (!str) { - return false; - } - memcpy (str, dir, nlen + 1); - mkdirp (str); - memcpy (str + nlen, ".tmp", 5); - if (s->fdump != -1) { - close (s->fdump); - } -#if __SDB_WINDOWS__ && UNICODE - wchar_t *wstr = r_sys_conv_utf8_to_utf16 (str); - if (wstr) { - s->fdump = _wopen (wstr, O_BINARY | O_RDWR | O_CREAT | O_TRUNC, SDB_MODE); - sdb_gh_free (wstr); - } else { - s->fdump = -1; - } -#else - s->fdump = open (str, O_BINARY | O_RDWR | O_CREAT | O_TRUNC, SDB_MODE); -#endif - if (s->fdump == -1) { - // eprintf ("sdb: Cannot open '%s' for writing.\n", str); - sdb_gh_free (str); - return false; - } - cdb_make_start (&s->m, s->fdump); - s->ndump = str; - return true; -} - -SDB_API bool sdb_disk_insert(Sdb* s, const char *key, const char *val) { - struct cdb_make *c = &s->m; - if (!key || !val) { - return false; - } - //if (!*val) return 0; //undefine variable if no value - return cdb_make_add (c, key, strlen (key), val, strlen (val)); -} - -#define IFRET(x) if (x) ret = 0 -SDB_API bool sdb_disk_finish(Sdb* s) { - bool reopen = false, ret = true; - IFRET (!cdb_make_finish (&s->m)); -#if USE_MMAN - IFRET (fsync (s->fdump)); -#endif - IFRET (close (s->fdump)); - s->fdump = -1; - // close current fd to avoid sharing violations - if (s->fd != -1) { - close (s->fd); - s->fd = -1; - reopen = true; - } -#if __SDB_WINDOWS__ - LPTSTR ndump_ = r_sys_conv_utf8_to_utf16 (s->ndump); - LPTSTR dir_ = r_sys_conv_utf8_to_utf16 (s->dir); - - if (MoveFileEx (ndump_, dir_, MOVEFILE_REPLACE_EXISTING)) { - //eprintf ("Error 0x%02x\n", GetLastError ()); - } - sdb_gh_free (ndump_); - sdb_gh_free (dir_); -#else - if (s->ndump && s->dir) { - IFRET (rename (s->ndump, s->dir)); - } -#endif - sdb_gh_free (s->ndump); - s->ndump = NULL; - // reopen if was open before - reopen = true; // always reopen if possible - if (reopen) { - int rr = sdb_open (s, s->dir); - if (ret && rr < 0) { - ret = false; - } - cdb_init (&s->db, s->fd); - } - return ret; -} - -SDB_API bool sdb_disk_unlink(Sdb *s) { - return (s->dir && *(s->dir) && unlink (s->dir) != -1); -} diff --git a/shlr/sdb/src/entry.c b/shlr/sdb/src/entry.c deleted file mode 100644 index a281a4a1e68b6..0000000000000 --- a/shlr/sdb/src/entry.c +++ /dev/null @@ -1,14 +0,0 @@ -#include - -#ifndef SDB_CUSTOM_HEAP -#define SDB_CUSTOM_HEAP sdb_gh_custom -#endif - -int main(int argc, const char **argv) { -#if USE_SDB_HEAP - sdb_gh_use (&SDB_CUSTOM_HEAP); -#else - sdb_gh_use (&sdb_gh_libc); -#endif - return sdb_main (argc, argv); -} diff --git a/shlr/sdb/src/fmt.c b/shlr/sdb/src/fmt.c deleted file mode 100644 index 545de8fa8ecba..0000000000000 --- a/shlr/sdb/src/fmt.c +++ /dev/null @@ -1,206 +0,0 @@ -/* sdb - MIT - Copyright 2014-2022 - pancake */ - -#include "sdb/sdb.h" - -// TODO: convert into a function -// TODO: Add 'a' format for array of pointers null terminated?? -// XXX SLOW CONCAT -#define concat(x) if (x) { \ - int size = 2 + strlen (x? x: "")+(out? strlen (out) + 4: 0); \ - if (out) { \ - char *o = (char *)sdb_gh_realloc (out, size); \ - if (o) { \ - strcat (o, ","); \ - strcat (o, x); \ - out = o; \ - } \ - } else { \ - out = sdb_strdup (x); \ - } \ -} - -SDB_API char *sdb_fmt_tostr(void *p, const char *fmt) { - char buf[SDB_NUM_BUFSZ], *e_str, *out = NULL; - int n, len = 0; - if (!p || !fmt) { - return NULL; - } - for (; *fmt; fmt++) { - n = 4; - const ut8 *nbuf = ((ut8*)p) + len; - switch (*fmt) { - case 'b': - concat (sdb_itoa ((ut64)*(nbuf), 10, buf, sizeof (buf))); - break; - case 'h': - concat (sdb_itoa ((ut64)*((short*)nbuf), 10, buf, sizeof (buf))); - break; - case 'd': - concat (sdb_itoa ((ut64)*((int*)nbuf), 10, buf, sizeof (buf))); - break; - case 'q': - concat (sdb_itoa (*((ut64*)nbuf), 10, buf, sizeof (buf))); - n = 8; - break; - case 'z': - concat ((char*)p + len); - break; - case 's': - e_str = sdb_encode ((const ut8*)*((char**)nbuf), -1); - concat (e_str); - sdb_gh_free (e_str); - break; - case 'p': - concat (sdb_itoa ((ut64)*((size_t*)(nbuf)), 16, buf, sizeof (buf))); - n = sizeof (size_t); - break; - } - len += R_MAX ((long)sizeof (void*), n); // align - } - return out; -} - -// TODO: return false if array length != fmt length -SDB_API int sdb_fmt_tobin(const char *_str, const char *fmt, void *stru) { - int n, idx = 0, items = 0; - char *stru8 = (char*)stru; - char *next, *str, *ptr, *word, *e_str; - if (!_str || !*_str || !fmt) { - return 0; - } - str = ptr = sdb_strdup (_str); - for (; *fmt; fmt++) { - word = sdb_anext (ptr, &next); - if (!word || !*word) { - break; - } - items++; - n = 4; // ALIGN - switch (*fmt) { - case 'b': *((ut8*)(stru8 + idx)) = (ut8)sdb_atoi (word); break; - case 'd': *((int*)(stru8 + idx)) = (int)sdb_atoi (word); break; - case 'q': *((ut64*)(stru8 + idx)) = sdb_atoi (word); n = 8; break; - case 'h': *((short*)(stru8 + idx)) = (short)sdb_atoi (word); break; - case 's': - e_str = (char*)sdb_decode (word, 0); - *((char**)(stru8 + idx)) = e_str? e_str: sdb_strdup (word); - break; - case 'z': - *((char**)(stru8 + idx)) = (char*)sdb_strdup (word); - break; - case 'p': - *((void**)(stru8 + idx)) = (void*)(size_t)sdb_atoi (word); - break; - } - idx += R_MAX ((long)sizeof (void*), n); // align - if (!next) { - break; - } - ptr = next; - } - free (str); - return items; -} - -SDB_API void sdb_fmt_free (void *stru, const char *fmt) { - int n, len = 0; - for (; *fmt; fmt++) { - n = 4; - switch (*fmt) { - case 'p': // TODO: leak or wat - case 'b': - case 'h': - case 'd': - /* do nothing */ - break; - case 'q': - n = 8; - break; - case 'z': - case 's': - sdb_gh_free ((void*)*((char**)((ut8*)stru + len))); - break; - } - len += R_MAX ((long)sizeof (void*), n); // align - } -} - -SDB_API int sdb_fmt_init (void *p, const char *fmt) { - int len = 0; - for (; *fmt; fmt++) { - switch (*fmt) { - case 'b': len += sizeof (ut8); break; // 1 - case 'h': len += sizeof (short); break; // 2 - case 'd': len += sizeof (ut32); break; // 4 - case 'q': len += sizeof (ut64); break; // 8 - case 'z': len += sizeof (char*); break; // void* - case 's': len += sizeof (char*); break; // void* - case 'p': len += sizeof (char*); break; // void * - } - } - if (p) { - memset (p, 0, len); - } - return len; -} - -static const char *sdb_anext2(const char *str, const char **next) { - const char *p = strchr (str, SDB_RS); - const char *nxt = (p) ? p + 1: NULL; - if (next) { - *next = nxt; - } - return str; -} - -// TODO: move this into fmt? -SDB_API ut64* sdb_fmt_array_num(const char *list) { - ut64 *retp, *ret = NULL; - ut32 size; - const char *next, *ptr = list; - if (list && *list) { - ut32 len = (ut32) sdb_alen (list); - size = sizeof (ut64) * (len + 1); - if (size < len) { - return NULL; - } - retp = ret = (ut64*) sdb_gh_malloc (size); - if (!ret) { - return NULL; - } - *retp++ = len; - do { - const char *str = sdb_anext2 (ptr, &next); - ut64 n = sdb_atoi (str); - *retp++ = n; - ptr = next; - } while (next); - } - return ret; -} - -SDB_API char** sdb_fmt_array(const char *list) { - char *_s, **retp, **ret = NULL; - const char *next, *ptr = list; - if (list && *list) { - int len = sdb_alen (list); - retp = ret = (char**) sdb_gh_malloc (2 * strlen (list) + - ((len + 1) * sizeof (char *)) + 1); - _s = (char *)ret + ((len + 1) * sizeof (char *)); - if (!ret) { - return NULL; - } - do { - const char *str = sdb_anext2 (ptr, &next); - int slen = next? (next - str) - 1: - (int)strlen (str) + 1; - memcpy (_s, str, slen); - _s[slen] = 0; - *retp++ = _s; - _s += slen + 1; - ptr = next; - } while (next); - *retp = NULL; - } - return ret; -} diff --git a/shlr/sdb/src/heap.c b/shlr/sdb/src/heap.c deleted file mode 100644 index c390efb56dce4..0000000000000 --- a/shlr/sdb/src/heap.c +++ /dev/null @@ -1,424 +0,0 @@ -// https://github.com/YeonwooSung/MemoryAllocation - -#include -#include -#include -#include -#include "sdb/sdb.h" -#include "sdb/heap.h" - -const SdbGlobalHeap sdb_gh_libc = { NULL, NULL, NULL }; -SdbGlobalHeap Gheap = {NULL, NULL}; - -SDB_API char *sdb_strdup(const char *s) { - size_t sl = strlen (s) + 1; - char *p = (char *)sdb_gh_malloc (sl); - if (p) { - memcpy (p, s, sl); - } - return p; -} - -#if USE_MMAN -// #include - -#if !defined(MAP_ANONYMOUS) -#if __MACH__ - #define MAP_ANONYMOUS 0x1000 -#else - #define MAP_ANONYMOUS 0x20 -#endif -#endif - -#if __SDB_WINDOWS__ -#include -#else -#include -#include -#include - -// Size 16 -typedef struct free_list { - struct free_list *next; - struct free_list *prev; -} free_list; - -typedef struct sdb_heap_t { - // Globals - int *last_address; - free_list *free_list_start; - // To reduce number of mmap calls. - int last_mapped_size; // 1; -} SdbHeap; - -SDB_API void sdb_heap_fini(SdbHeap *heap); -SDB_API void *sdb_heap_realloc(SdbHeap *heap, void *ptr, int size); - -static SdbHeap sdb_gh_custom_data = { NULL, NULL, 1}; -const SdbGlobalHeap sdb_gh_custom = { - (SdbHeapRealloc)sdb_heap_realloc, - (SdbHeapFini)sdb_heap_fini, - &sdb_gh_custom_data -}; - -#define USED false -#define FREE true - -typedef struct Header { - int size; - bool free : 1; - bool has_prev : 1; - bool has_next : 1; -} Header; - -// Size field is not necessary in used blocks. -typedef struct Footer { - int size; - bool free : 1; -} Footer; - - -#define ALIGNMENT 8 -#define ALIGN(size) (((size) + (ALIGNMENT - 1)) & ~(ALIGNMENT - 1)) -#define SDB_PAGE_SIZE 131072 // 96096*2 //sysconf(_SC_PAGESIZE) -#define CEIL(X) ((X - (int)(X)) > 0 ? (int)(X + 1) : (int)(X)) -#define PAGES(size) (CEIL(size / (double)SDB_PAGE_SIZE)) -#define MIN_SIZE (ALIGN(sizeof(free_list) + META_SIZE)) -#define MAX(X, Y) (((X) > (Y)) ? (X) : (Y)) - -// Meta sizes. -#define META_SIZE ALIGN(sizeof(Header) + sizeof(Footer)) -#define HEADER_SIZE ALIGN(sizeof(Header)) -#define FOOTER_SIZE ALIGN(sizeof(Footer)) - -// Get pointer to the payload (passing the pointer to the header). -static void *add_offset(void *ptr) { - return (void *)((const ut8*)ptr + HEADER_SIZE); -} - -// Get poiner to the header (passing pointer to the payload). -static void *remove_offset(void *ptr) { - return (void *)((const ut8*)ptr - HEADER_SIZE); -} - -static Footer *getFooter(void *header_ptr) { - return (Footer*)((ut8*)header_ptr + ((Header *)header_ptr)->size - FOOTER_SIZE); -} - -static void setFree(void *ptr, int val) { - ((Header *)ptr)->free = val; - Footer *footer = (Footer *)getFooter(ptr); - footer->free = val; - // Copy size to footer size field. - footer->size = ((Header *)ptr)->size; -} - -// Set size in the header. -static inline void setSizeHeader(void *ptr, int size) { - ((Header *)ptr)->size = size; -} - -#if 0 -// Set size in the header. -static inline void setSizeFooter(void *ptr, int size) { - ((Footer *)getFooter(ptr))->size = size; -} -#endif - -// Get size of the free list item. -static inline int getSize(void *ptr) { - return ((Header *)remove_offset (ptr))->size; -} - -static void remove_from_free_list(SdbHeap *heap, void *block) { - setFree (block, USED); - - free_list *free_block = (free_list *)add_offset(block); - free_list *next = free_block->next; - free_list *prev = free_block->prev; - if (!prev) { - if (!next) { - // free_block is the only block in the free list. - heap->free_list_start = NULL; - } else { - // Remove first element in the free list. - heap->free_list_start = next; - next->prev = NULL; - } - } else { - if (!next) { - // Remove last element of the free list. - prev->next = NULL; - } else { - // Remove element in the middle. - prev->next = next; - next->prev = prev; - } - } -} - -static void append_to_free_list(SdbHeap *heap, void *ptr) { - setFree (ptr, FREE); - - free_list eew = {}; - free_list *new_ptr = (free_list *)add_offset (ptr); - *new_ptr = eew; - - if (heap->free_list_start) { - // Insert in the beginning. - new_ptr->next = heap->free_list_start; - new_ptr->prev = NULL; - heap->free_list_start->prev = new_ptr; - heap->free_list_start = new_ptr; - } else { - // No elements in the free list - heap->free_list_start = new_ptr; - new_ptr->prev = NULL; - new_ptr->next = NULL; - } -} - -// Find a free block that is large enough to store 'size' bytes. -// Returns NULL if not found. -static free_list *find_free_block(SdbHeap *heap, int size) { - free_list *current = heap->free_list_start; - while (current) { - if (getSize (current) >= size) { - // Return a pointer to the free block. - return current; - } - current = current->next; - } - return NULL; -} - -// Split memory into multiple blocks after some part of it was requested -// (requested + the rest). -static void split(SdbHeap *heap, void *start_ptr, int total, int requested) { - void *new_block_ptr = (void*)((ut8*)start_ptr + requested); - int block_size = total - requested; - - // Size that was left after allocating memory. - // Needs to be large enough to store another block (min size is needed in order - // to store free list element there after it is freed). - if (block_size < (int)MIN_SIZE) { - // Not enough size to split. - return; - } - // Change size of the prev (recently allocated) block. - setSizeHeader(start_ptr, requested); - ((Header *)start_ptr)->has_next = true; - - // Add a header for newly created block (right block). - Header header = {block_size, FREE, true, ((Header *)start_ptr)->has_next}; - Header *new_block_header = (Header *)new_block_ptr; - *new_block_header = header; - Footer footer = {block_size, FREE}; - *((Footer *)getFooter(new_block_header)) = footer; - append_to_free_list (heap, new_block_header); -} - -static void *sdb_heap_malloc(SdbHeap *heap, int size) { - if (size <= 0) { - return NULL; - } - // Size of the block can't be smaller than MIN_SIZE, as we need to store - // free list in the body + header and footer on each side respectively. - int required_size = MAX (ALIGN (size + META_SIZE), MIN_SIZE); - // Try to find a block big enough in already allocated memory. - free_list *free_block = find_free_block (heap, required_size); - - if (free_block) { - // Header ptr - void *address = remove_offset (free_block); - // Mark block as used. - setFree (address, USED); - // Split the block into two, where the second is free. - split (heap, address, ((Header *)address)->size, required_size); - remove_from_free_list (heap, address); - return add_offset (address); - } - - // No free block was found. Allocate size requested + header (in full pages). - // Each next allocation will be doubled in size from the previous one - // (to decrease the number of mmap sys calls we make). - // int bytes = MAX (PAGES (required_size), heap->last_mapped_size) * SDB_PAGE_SIZE; - size_t bytes = PAGES (MAX (PAGES (required_size), heap->last_mapped_size)) * SDB_PAGE_SIZE; - heap->last_mapped_size *= 2; - - // last_address my not be returned by mmap, but makes it more efficient if it happens. - void *new_region = mmap (NULL, bytes, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - if (new_region == MAP_FAILED) { - perror ("mmap"); - return NULL; - } - // Create a header/footer for new block. - Header header = {(int)bytes, USED, false, false}; - Header *header_ptr = (Header *)new_region; - *header_ptr = header; - Footer footer = {}; - footer.free = USED; - *((Footer *)getFooter (new_region)) = footer; - - if (new_region == heap->last_address && heap->last_address != 0) { - // if we got a block of memory after the last block, as we requested. - header_ptr->has_prev = true; - // change has_next of the prev block - Footer *prev_footer = (Footer *)(header_ptr - FOOTER_SIZE); - ((Header *)header_ptr - (prev_footer->size))->has_next = true; - } - // Split new region. - split (heap, new_region, bytes, required_size); - // Update last_address for the next allocation. - heap->last_address = (int*)((ut8*)new_region + bytes); - // Return address behind the header (i.e. header is hidden). - return add_offset (new_region); -} - -static void coalesce(SdbHeap *heap, void *ptr) { - Header *current_header = (Header *)ptr; - Footer *current_footer = getFooter (ptr); - if (current_header->has_prev && ((Footer *)((ut8*)ptr - FOOTER_SIZE))->free) { - int prev_size = ((Footer *)((ut8*)ptr - FOOTER_SIZE))->size; - Header *prev_header = (Header *)((ut8*)ptr - prev_size); - Footer *prev_footer = (Footer *)((ut8*)ptr - FOOTER_SIZE); - - // Merge with previous block. - remove_from_free_list (heap, current_header); - // Add size of prev block to the size of current block - prev_header->size += current_header->size; - prev_footer->size = prev_header->size; - current_header = prev_header; - } - void *next = (void*)((ut8*)ptr + current_header->size); - if (current_header->has_next && ((Header *)next)->free) { - int size = ((Header *)next)->size; - // merge with next block. - remove_from_free_list (heap, (ut8*)ptr + current_header->size); - // Add size of next block to the size of current block. - current_header->size += size; - current_footer->size = current_header->size; - } -} - -static int unmap(SdbHeap *heap, void *start_address, int size) { - remove_from_free_list (heap, start_address); - // Reset has_next, has_prev of neighbours. - Header *header = (Header *)start_address; - if (header->has_prev) { - // Get prev header, set has_next to false. - int prev_size = ((Footer *)((ut8*)start_address - FOOTER_SIZE))->size; - Header *prev_header = (Header *)((ut8*)start_address - prev_size); - prev_header->has_next = false; - } - if (header->has_next) { - // Get next header, set has_prev to false. - int this_size = header->size; - Header *next_header = (Header *)((ut8*)start_address + this_size); - next_header->has_prev = false; - } - - // If this is the last block we've allocated using mmap, need to change last_address. - if (heap->last_address == start_address) { - heap->last_address = (int *)((ut8*)start_address - size); - } - return munmap (start_address, (size_t)size); -} - -static void sdb_heap_free(SdbHeap *heap, void *ptr) { - if (!ptr) { - return; - } - void *start_address = remove_offset (ptr); - - // Check if it has already been freed. - // Does not handle case when start_address passed was never allocated. - if (((Header *)start_address)->free) { - return; - } - - Header *header = (Header *)start_address; - int size = header->size; - uintptr_t addr = (uintptr_t)header; - if (size % SDB_PAGE_SIZE == 0 && (addr % SDB_PAGE_SIZE) == 0) { - // if: full page is free (or multiple consecutive pages), page-aligned -> can munmap it. - unmap (heap, start_address, size); - } else { - append_to_free_list (heap, start_address); - coalesce (heap, start_address); - // if we are left with a free block of size bigger than PAGE_SIZE that is - // page-aligned, munmap that part. - if (size >= SDB_PAGE_SIZE && (addr % SDB_PAGE_SIZE) == 0) { - split (heap, start_address, size, (size / SDB_PAGE_SIZE) * SDB_PAGE_SIZE); - unmap (heap, start_address, (size / SDB_PAGE_SIZE) * SDB_PAGE_SIZE); - } - } -} - -SDB_API void sdb_heap_init(SdbHeap *heap) { - heap->last_address = NULL; - heap->free_list_start = NULL; - heap->last_mapped_size = 1; -} - -SDB_API void sdb_heap_fini(SdbHeap *heap) { -#if 1 - free_list *current = heap->free_list_start; - while (current) { - free_list *next = current->next; - sdb_heap_free (heap, current); - current = next; - } -#endif -} - -SDB_API void *sdb_heap_realloc(SdbHeap *heap, void *ptr, int size) { - // If ptr is NULL, realloc() is identical to a call to malloc() for size bytes. - if (!ptr) { - return sdb_heap_malloc (heap, size); - } - // If size is zero and ptr is not NULL, a new, minimum sized object (MIN_SIZE) is - // allocated and the original object is freed. - if (size == 0 && ptr) { - sdb_heap_free (heap, ptr); - return sdb_heap_malloc (heap, 1); - } - - int required_size = META_SIZE + size; - // If there is enough space, expand the block. - int current_size = getSize (ptr); - - // if user requests to shorten the block. - if (size < current_size) { - return ptr; - } - Header *current_header = (Header *)ptr; - Footer *current_footer = (Footer *)getFooter(ptr); - // Next block exists and is free. - if (current_header->has_next && ((Header *)ptr + current_size)->free) { - int available_size = current_size + getSize ((ut8*)ptr + current_size); - // Size is enough. - if (available_size >= required_size) { - Header *next_header = (Header *)((ut8*)ptr + current_size); - remove_from_free_list (heap, next_header); - // Add size of next block to the size of current block. - current_header->size += size; - current_footer->size = current_header->size; - - // split if possible. - split (heap, current_header, available_size, required_size); - return ptr; - } - } - - // Not enough room to enlarge -> allocate new region. - void *new_ptr = sdb_heap_malloc (heap, size); - memcpy (new_ptr, ptr, current_size); - - // Free old location. - sdb_heap_free (heap, ptr); - return new_ptr; -} - -#endif -#endif diff --git a/shlr/sdb/src/ht.c b/shlr/sdb/src/ht.c deleted file mode 100644 index 45fffc6f5cc61..0000000000000 --- a/shlr/sdb/src/ht.c +++ /dev/null @@ -1,68 +0,0 @@ -/* sdb - MIT - Copyright 2011-2022 - pancake */ - -#include "sdb/ht.h" - -void sdbkv_fini(SdbKv *kv) { - sdb_gh_free (kv->base.key); - sdb_gh_free (kv->base.value); -} - -SDB_API HtPP* sdb_ht_new(void) { - HtPP *ht = ht_pp_new ((HtPPDupValue)sdb_strdup, (HtPPKvFreeFunc)sdbkv_fini, (HtPPCalcSizeV)strlen); - if (ht) { - ht->opt.elem_size = sizeof (SdbKv); - } - return ht; -} - -static bool sdb_ht_internal_insert(HtPP* ht, const char* key, const char* value, bool update) { - if (!ht || !key || !*key || !value) { - return false; - } - SdbKv kvp = {{ 0 }}; - kvp.base.key = sdb_strdup (key); - if (!kvp.base.key) { - goto err; - } - kvp.base.value = sdb_strdup (value); - if (!kvp.base.value) { - goto err; - } - kvp.base.key_len = strlen ((const char *)kvp.base.key); - kvp.base.value_len = strlen ((const char *)kvp.base.value); - kvp.expire = 0; - return ht_pp_insert_kv (ht, (HtPPKv*)&kvp, update); - - err: - sdb_gh_free (kvp.base.key); - sdb_gh_free (kvp.base.value); - return false; -} - -SDB_API bool sdb_ht_insert(HtPP* ht, const char* key, const char* value) { - return sdb_ht_internal_insert (ht, key, value, false); -} - -SDB_API bool sdb_ht_insert_kvp(HtPP* ht, SdbKv *kvp, bool update) { - return ht_pp_insert_kv (ht, (HtPPKv*)kvp, update); -} - -SDB_API bool sdb_ht_update(HtPP *ht, const char *key, const char* value) { - return sdb_ht_internal_insert (ht, key, value, true); -} - -SDB_API SdbKv* sdb_ht_find_kvp(HtPP* ht, const char* key, bool* found) { - return (SdbKv *)ht_pp_find_kv (ht, key, found); -} - -SDB_API char* sdb_ht_find(HtPP* ht, const char* key, bool* found) { - return (char *)ht_pp_find (ht, key, found); -} - -SDB_API void sdb_ht_free(HtPP *ht) { - ht_pp_free (ht); -} - -SDB_API bool sdb_ht_delete(HtPP* ht, const char *key) { - return ht_pp_delete (ht, key); -} diff --git a/shlr/sdb/src/ht.inc.c b/shlr/sdb/src/ht.inc.c deleted file mode 100644 index f9c3f1f433bbd..0000000000000 --- a/shlr/sdb/src/ht.inc.c +++ /dev/null @@ -1,366 +0,0 @@ -/* radare2 - BSD 3 Clause License - crowell, pancake, ret2libc 2016-2022 */ - -#define LOAD_FACTOR 1 -#define S_ARRAY_SIZE(x) (sizeof (x) / sizeof (x[0])) - -// Sizes of the ht. -static const ut32 ht_primes_sizes[] = { - 3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, - 163, 197, 239, 293, 353, 431, 521, 631, 761, 919, - 1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, - 5839, 7013, 8419, 10103, 12143, 14591, 17519, 21023, - 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, - 108631, 130363, 156437, 187751, 225307, 270371, 324449, - 389357, 467237, 560689, 672827, 807403, 968897, 1162687, - 1395263, 1674319, 2009191, 2411033, 2893249, 3471899, - 4166287, 4999559, 5999471, 7199369 -}; - -static inline ut32 hashfn(HtName_(Ht) *ht, const KEY_TYPE k) { - return ht->opt.hashfn ? ht->opt.hashfn (k) : KEY_TO_HASH (k); -} - -static inline ut32 bucketfn(HtName_(Ht) *ht, const KEY_TYPE k) { - return hashfn (ht, k) % ht->size; -} - -static inline KEY_TYPE dupkey(HtName_(Ht) *ht, const KEY_TYPE k) { - return ht->opt.dupkey ? ht->opt.dupkey (k) : (KEY_TYPE)k; -} - -static inline VALUE_TYPE dupval(HtName_(Ht) *ht, const VALUE_TYPE v) { - return ht->opt.dupvalue ? ht->opt.dupvalue (v) : (VALUE_TYPE)v; -} - -static inline ut32 calcsize_key(HtName_(Ht) *ht, const KEY_TYPE k) { - return ht->opt.calcsizeK ? ht->opt.calcsizeK (k) : 0; -} - -static inline ut32 calcsize_val(HtName_(Ht) *ht, const VALUE_TYPE v) { - return ht->opt.calcsizeV ? ht->opt.calcsizeV (v) : 0; -} - -static inline void freefn(HtName_(Ht) *ht, HT_(Kv) *kv) { - if (ht->opt.freefn) { - ht->opt.freefn (kv); - } -} - -static inline ut32 next_idx(ut32 idx) { - if (idx != UT32_MAX && idx < S_ARRAY_SIZE (ht_primes_sizes) - 1) { - return idx + 1; - } - return UT32_MAX; -} - -static inline ut32 compute_size(ut32 idx, ut32 sz) { - // when possible, use the precomputed prime numbers which help with - // collisions, otherwise, at least make the number odd with |1 - return idx != UT32_MAX && idx < S_ARRAY_SIZE(ht_primes_sizes) ? ht_primes_sizes[idx] : (sz | 1); -} - -static inline bool is_kv_equal(HtName_(Ht) *ht, const KEY_TYPE key, const ut32 key_len, const HT_(Kv) *kv) { - if (key_len != kv->key_len) { - return false; - } - - bool res = key == kv->key; - if (!res && ht->opt.cmp) { - res = !ht->opt.cmp (key, kv->key); - } - return res; -} - -static inline HT_(Kv) *kv_at(HtName_(Ht) *ht, HT_(Bucket) *bt, ut32 i) { - return (HT_(Kv) *)((char *)bt->arr + i * ht->opt.elem_size); -} - -static inline HT_(Kv) *next_kv(HtName_(Ht) *ht, HT_(Kv) *kv) { - return (HT_(Kv) *)((char *)kv + ht->opt.elem_size); -} - -#define BUCKET_FOREACH(ht, bt, j, kv) \ - if ((bt)->arr) \ - for ((j) = 0, (kv) = (bt)->arr; (j) < (bt)->count; (j)++, (kv) = next_kv (ht, kv)) - -#define BUCKET_FOREACH_SAFE(ht, bt, j, count, kv) \ - if ((bt)->arr) \ - for ((j) = 0, (kv) = (bt)->arr, (count) = (ht)->count; \ - (j) < (bt)->count; \ - (j) = (count) == (ht)->count? j + 1: j, (kv) = (count) == (ht)->count? next_kv (ht, kv): kv, (count) = (ht)->count) - -// Create a new hashtable and return a pointer to it. -// size - number of buckets in the hashtable -// hashfunction - the function that does the hashing, must not be null. -// comparator - the function to check if values are equal, if NULL, just checks -// == (for storing ints). -// keydup - function to duplicate to key (eg sdb_strdup), if NULL just does strup. -// valdup - same as keydup, but for values but if NULL just assign -// pair_free - function for freeing a keyvaluepair - if NULL just does free. -// calcsize - function to calculate the size of a value. if NULL, just stores 0. -static HtName_(Ht)* internal_ht_new(ut32 size, ut32 prime_idx, HT_(Options) *opt) { - HtName_(Ht)* ht = (HtName_(Ht)*)sdb_gh_calloc (1, sizeof (*ht)); - if (SDB_LIKELY (ht)) { - ht->size = size; - ht->count = 0; - ht->prime_idx = prime_idx; - ht->table = (HT_(Bucket)*)sdb_gh_calloc (ht->size, sizeof (*ht->table)); - if (!ht->table) { - sdb_gh_free (ht); - return NULL; - } - ht->opt = *opt; - // if not provided, assume we are dealing with a regular HtName_(Ht), with - // HT_(Kv) as elements - if (ht->opt.elem_size == 0) { - ht->opt.elem_size = sizeof (HT_(Kv)); - } - return ht; - } - return NULL; -} - -SDB_API HtName_(Ht) *Ht_(new_opt)(HT_(Options) *opt) { - return internal_ht_new (ht_primes_sizes[0], 0, opt); -} - -SDB_API void Ht_(free)(HtName_(Ht)* ht) { - if (SDB_LIKELY (ht)) { - ut32 i, htsize = ht->size; - for (i = 0; i < htsize; i++) { - HT_(Bucket) *bt = &ht->table[i]; - HT_(Kv) *kv; - ut32 j; - if (ht->opt.freefn) { - BUCKET_FOREACH (ht, bt, j, kv) { - ht->opt.freefn (kv); - } - } - sdb_gh_free (bt->arr); - } - sdb_gh_free (ht->table); - sdb_gh_free (ht); - } -} - -// Increases the size of the hashtable by 2. -static void internal_ht_grow(HtName_(Ht)* ht) { - HtName_(Ht)* ht2; - HtName_(Ht) swap; - ut32 idx = next_idx (ht->prime_idx); - ut32 sz = compute_size (idx, ht->size * 2); - ut32 i; - - ht2 = internal_ht_new (sz, idx, &ht->opt); - if (!ht2) { - // we can't grow the ht anymore. Never mind, we'll be slower, - // but everything can continue to work - return; - } - - for (i = 0; i < ht->size; i++) { - HT_(Bucket) *bt = &ht->table[i]; - HT_(Kv) *kv; - ut32 j; - - BUCKET_FOREACH (ht, bt, j, kv) { - Ht_(insert_kv) (ht2, kv, false); - } - } - // And now swap the internals. - swap = *ht; - *ht = *ht2; - *ht2 = swap; - - ht2->opt.freefn = NULL; - Ht_(free) (ht2); -} - -static void check_growing(HtName_(Ht) *ht) { - if (ht->count >= LOAD_FACTOR * ht->size) { - internal_ht_grow (ht); - } -} - -static HT_(Kv) *reserve_kv(HtName_(Ht) *ht, const KEY_TYPE key, const int key_len, bool update) { - HT_(Bucket) *bt = &ht->table[bucketfn (ht, key)]; - HT_(Kv) *kvtmp; - ut32 j; - - BUCKET_FOREACH (ht, bt, j, kvtmp) { - if (is_kv_equal (ht, key, key_len, kvtmp)) { - if (update) { - freefn (ht, kvtmp); - return kvtmp; - } - return NULL; - } - } - - if (bt->count + 1 >= bt->size) { - bt->size = (bt->count + 5) * 2; - HT_(Kv) *newkvarr = (HT_(Kv)*)sdb_gh_realloc (bt->arr, (bt->size) * ht->opt.elem_size); - if (SDB_LIKELY (newkvarr)) { - bt->arr = newkvarr; - } else { - return NULL; - } - } - bt->count++; - ht->count++; - return kv_at (ht, bt, bt->count - 1); -} - -SDB_API bool Ht_(insert_kv)(HtName_(Ht) *ht, HT_(Kv) *kv, bool update) { - HT_(Kv) *kv_dst = reserve_kv (ht, kv->key, kv->key_len, update); - if (SDB_LIKELY (kv_dst)) { - memcpy (kv_dst, kv, ht->opt.elem_size); - check_growing (ht); - return true; - } - return false; -} - -static bool insert_update(HtName_(Ht) *ht, const KEY_TYPE key, VALUE_TYPE value, bool update) { - ut32 key_len = calcsize_key (ht, key); - HT_(Kv)* kv_dst = reserve_kv (ht, key, key_len, update); - if (SDB_LIKELY (kv_dst)) { - kv_dst->key = dupkey (ht, key); - kv_dst->key_len = key_len; - kv_dst->value = dupval (ht, value); - kv_dst->value_len = calcsize_val (ht, value); - check_growing (ht); - return true; - } - return false; -} - -// Inserts the key value pair key, value into the hashtable. -// Doesn't allow for "update" of the value. -SDB_API bool Ht_(insert)(HtName_(Ht)* ht, const KEY_TYPE key, VALUE_TYPE value) { - return insert_update (ht, key, value, false); -} - -// Inserts the key value pair key, value into the hashtable. -// Does allow for "update" of the value. -SDB_API bool Ht_(update)(HtName_(Ht)* ht, const KEY_TYPE key, VALUE_TYPE value) { - return insert_update (ht, key, value, true); -} - -// Update the key of an element that has old_key as key and replace it with new_key -SDB_API bool Ht_(update_key)(HtName_(Ht)* ht, const KEY_TYPE old_key, const KEY_TYPE new_key) { - // First look for the value associated with old_key - bool found; - VALUE_TYPE value = Ht_(find) (ht, old_key, &found); - if (!found) { - return false; - } - - // Associate the existing value with new_key - bool inserted = insert_update (ht, new_key, value, false); - if (!inserted) { - return false; - } - - // Remove the old_key kv, paying attention to not double free the value - HT_(Bucket) *bt = &ht->table[bucketfn (ht, old_key)]; - const int old_key_len = calcsize_key (ht, old_key); - HT_(Kv) *kv; - ut32 j; - - BUCKET_FOREACH (ht, bt, j, kv) { - if (is_kv_equal (ht, old_key, old_key_len, kv)) { - if (!ht->opt.dupvalue) { - // do not free the value part if dupvalue is not - // set, because the old value has been - // associated with the new key and it should not - // be freed - kv->value = HT_NULL_VALUE; - kv->value_len = 0; - } - freefn (ht, kv); - - void *src = next_kv (ht, kv); - memmove (kv, src, (bt->count - j - 1) * ht->opt.elem_size); - bt->count--; - ht->count--; - return true; - } - } - - return false; -} - -// Returns the corresponding SdbKv entry from the key. -// If `found` is not NULL, it will be set to true if the entry was found, false -// otherwise. -SDB_API HT_(Kv)* Ht_(find_kv)(HtName_(Ht)* ht, const KEY_TYPE key, bool* found) { - if (found) { - *found = false; - } - if (!ht) { - if (found) { - *found = false; - } - return NULL; - } - - HT_(Bucket) *bt = &ht->table[bucketfn (ht, key)]; - ut32 key_len = calcsize_key (ht, key); - HT_(Kv) *kv; - ut32 j; - - BUCKET_FOREACH (ht, bt, j, kv) { - if (is_kv_equal (ht, key, key_len, kv)) { - if (found) { - *found = true; - } - return kv; - } - } - return NULL; -} - -// Looks up the corresponding value from the key. -// If `found` is not NULL, it will be set to true if the entry was found, false -// otherwise. -SDB_API VALUE_TYPE Ht_(find)(HtName_(Ht)* ht, const KEY_TYPE key, bool* found) { - HT_(Kv) *res = Ht_(find_kv) (ht, key, found); - return res ? res->value : HT_NULL_VALUE; -} - -// Deletes a entry from the hash table from the key, if the pair exists. -SDB_API bool Ht_(delete)(HtName_(Ht)* ht, const KEY_TYPE key) { - HT_(Bucket) *bt = &ht->table[bucketfn (ht, key)]; - ut32 key_len = calcsize_key (ht, key); - HT_(Kv) *kv; - ut32 j; - - BUCKET_FOREACH (ht, bt, j, kv) { - if (is_kv_equal (ht, key, key_len, kv)) { - freefn (ht, kv); - void *src = next_kv (ht, kv); - memmove (kv, src, (bt->count - j - 1) * ht->opt.elem_size); - bt->count--; - ht->count--; - return true; - } - } - return false; -} - -SDB_API void Ht_(foreach)(HtName_(Ht) *ht, HT_(ForeachCallback) cb, void *user) { - ut32 i, htsize = ht->size; - - for (i = 0; i < htsize; i++) { - HT_(Bucket) *bt = &ht->table[i]; - HT_(Kv) *kv; - ut32 j, count; - - BUCKET_FOREACH_SAFE (ht, bt, j, count, kv) { - if (!cb (user, kv->key, kv->value)) { - return; - } - } - } -} diff --git a/shlr/sdb/src/ht_pp.c b/shlr/sdb/src/ht_pp.c deleted file mode 100644 index 06bec972fa030..0000000000000 --- a/shlr/sdb/src/ht_pp.c +++ /dev/null @@ -1,48 +0,0 @@ -/* sdb - MIT - Copyright 2018-2022 - ret2libc, pancake */ - -#include "sdb/sdb.h" -#include "sdb/ht_pp.h" -#include "ht.inc.c" - -static HtName_(Ht)* internal_ht_default_new(ut32 size, ut32 prime_idx, HT_(DupValue) valdup, HT_(KvFreeFunc) pair_free, HT_(CalcSizeV) calcsizeV) { - HT_(Options) opt = { - .cmp = (HT_(ListComparator))strcmp, - .hashfn = (HT_(HashFunction))sdb_hash, - .dupkey = (HT_(DupKey))sdb_strdup, - .dupvalue = valdup, - .calcsizeK = (HT_(CalcSizeK))strlen, - .calcsizeV = calcsizeV, - .freefn = pair_free, - .elem_size = sizeof (HT_(Kv)), - }; - return internal_ht_new (size, prime_idx, &opt); -} - -// creates a default HtPP that has strings as keys -SDB_API HtName_(Ht)* Ht_(new)(HT_(DupValue) valdup, HT_(KvFreeFunc) pair_free, HT_(CalcSizeV) calcsizeV) { - return internal_ht_default_new (ht_primes_sizes[0], 0, valdup, pair_free, calcsizeV); -} - -static void free_kv_key(HT_(Kv) *kv) { - sdb_gh_free (kv->key); -} - -// creates a default HtPP that has strings as keys but does not dup, nor free the values -SDB_API HtName_(Ht)* Ht_(new0)(void) { - return Ht_(new) (NULL, free_kv_key, NULL); -} - -SDB_API HtName_(Ht)* Ht_(new_size)(ut32 initial_size, HT_(DupValue) valdup, HT_(KvFreeFunc) pair_free, HT_(CalcSizeV) calcsizeV) { - ut32 i = 0; - - while (i < S_ARRAY_SIZE (ht_primes_sizes) && - ht_primes_sizes[i] * LOAD_FACTOR < initial_size) { - i++; - } - if (i == S_ARRAY_SIZE (ht_primes_sizes)) { - i = UT32_MAX; - } - - ut32 sz = compute_size (i, (ut32)(initial_size * (2 - LOAD_FACTOR))); - return internal_ht_default_new (sz, i, valdup, pair_free, calcsizeV); -} diff --git a/shlr/sdb/src/ht_pu.c b/shlr/sdb/src/ht_pu.c deleted file mode 100644 index 6ffffab25d632..0000000000000 --- a/shlr/sdb/src/ht_pu.c +++ /dev/null @@ -1,108 +0,0 @@ -/* sdb - MIT - Copyright 2018-2023 - ret2libc, pancake, luc-tielen */ - -#include -#include "sdb/ht_pu.h" -#include "sdb/heap.h" -#include "sdb/cwisstable.h" - -CWISS_DECLARE_FLAT_HASHMAP_DEFAULT(HtPU_, void*, ut64); - -struct HtPU_t { - HtPU_ inner; -}; - -SDB_API HtPU* ht_pu_new0(void) { - HtPU *hm = (HtPU*) sdb_gh_calloc (1, sizeof (HtPU)); - if (hm) { - hm->inner = HtPU__new (0); - } - return hm; -} - -SDB_API void ht_pu_free(HtPU *hm) { - if (hm) { - HtPU__destroy (&hm->inner); - sdb_gh_free (hm); - } -} - -SDB_API bool ht_pu_insert(HtPU *hm, void *key, ut64 value) { - assert (hm); - - HtPU__Entry entry = { .key = key, .val = value }; - HtPU__Insert result = HtPU__insert (&hm->inner, &entry); - return result.inserted; -} - -SDB_API bool ht_pu_update(HtPU *hm, void *key, ut64 value) { - assert (hm); - - HtPU__Entry entry = { .key = key, .val = value }; - HtPU__Insert insert_result = HtPU__insert (&hm->inner, &entry); - const bool should_update = !insert_result.inserted; - if (should_update) { - HtPU__Entry *existing_entry = HtPU__Iter_get (&insert_result.iter); - existing_entry->val = value; - } - - return true; -} - -// Update the key of an element in the hashtable -SDB_API bool ht_pu_update_key(HtPU *hm, void *old_key, void *new_key) { - assert (hm); - - HtPU__Iter iter = HtPU__find (&hm->inner, &old_key); - HtPU__Entry *entry = HtPU__Iter_get (&iter); - if (!entry) { - return false; - } - - // First try inserting the new key - HtPU__Entry new_entry = { .key = new_key, .val = entry->val }; - HtPU__Insert result = HtPU__insert (&hm->inner, &new_entry); - if (!result.inserted) { - return false; - } - - // Then remove entry for the old key - HtPU__erase_at (iter); - return true; -} - -SDB_API bool ht_pu_delete(HtPU *hm, void *key) { - assert (hm); - return HtPU__erase (&hm->inner, &key); -} - -SDB_API ut64 ht_pu_find(HtPU *hm, void *key, bool* found) { - assert (hm); - if (found) { - *found = false; - } - - HtPU__Iter iter = HtPU__find (&hm->inner, &key); - HtPU__Entry *entry = HtPU__Iter_get (&iter); - if (!entry) { - return 0; - } - - if (found) { - *found = true; - } - return entry->val; -} - -// Iterates over all elements in the hashtable, calling the cb function on each Kv. -// If the cb returns false, the iteration is stopped. -// cb should not modify the hashtable. -SDB_API void ht_pu_foreach(HtPU *hm, HtPUForEachCallback cb, void *user) { - assert (hm); - HtPU__CIter iter; - const HtPU__Entry *entry; - for (iter = HtPU__citer (&hm->inner); (entry = HtPU__CIter_get (&iter)) != NULL; HtPU__CIter_next (&iter)) { - if (!cb (user, entry->key, entry->val)) { - return; - } - } -} diff --git a/shlr/sdb/src/ht_su.c b/shlr/sdb/src/ht_su.c deleted file mode 100644 index 0bdbec0a08ed0..0000000000000 --- a/shlr/sdb/src/ht_su.c +++ /dev/null @@ -1,171 +0,0 @@ -/* sdb - MIT - Copyright 2018-2023 - ret2libc, pancake, luc-tielen */ - -#include -#include "sdb/ht_su.h" -#include "sdb/heap.h" -#include "sdb/sdb.h" -#include "sdb/cwisstable.h" - -static inline void string_copy(void *dst, const void *src); -static inline void string_dtor(void *val); -static inline size_t string_hash(const void *val); -static inline bool string_eq(const void *a, const void *b); - -CWISS_DECLARE_FLAT_HASHMAP(HtSU_, char*, ut64, string_copy, string_dtor, string_hash, string_eq); - -struct HtSU_t { - HtSU_ inner; -}; - -static inline void string_copy(void *dst_, const void *src_) { - const HtSU__Entry *src = (const HtSU__Entry *) src_; - HtSU__Entry *dst = (HtSU__Entry *) dst_; - - const size_t len = strlen (src->key); - dst->key = (char*) sdb_gh_malloc (len + 1); - dst->val = src->val; - memcpy (dst->key, src->key, len + 1); -} - -static inline void string_dtor(void *val) { - char *str = *(char**)val; - sdb_gh_free (str); -} - -static inline size_t string_hash(const void *val) { - const char *str = *(const char *const *)val; - const size_t len = strlen (str); - CWISS_FxHash_State state = 0; - CWISS_FxHash_Write (&state, str, len); - return state; -} - -static inline bool string_eq(const void *a, const void *b) { - const char *ap = *(const char* const *)a; - const char *bp = *(const char* const *)b; - return strcmp (ap, bp) == 0; -} - -SDB_API HtSU* ht_su_new0(void) { - HtSU *hm = (HtSU*) sdb_gh_calloc (1, sizeof (HtSU)); - if (hm) { - hm->inner = HtSU__new (0); - } - return hm; -} - -SDB_API void ht_su_free(HtSU *hm) { - if (hm) { - HtSU__destroy (&hm->inner); - sdb_gh_free (hm); - } -} - -SDB_API bool ht_su_insert(HtSU *hm, const char *key, ut64 value) { - assert (hm && key); - - char *key_copy = sdb_strdup (key); - if (!key_copy) { - return false; - } - - HtSU__Entry entry = { .key = key_copy, .val = value }; - HtSU__Insert result = HtSU__insert (&hm->inner, &entry); - if (!result.inserted) { - sdb_gh_free (key_copy); - return false; - } - return true; -} - -SDB_API bool ht_su_update(HtSU *hm, const char *key, ut64 value) { - assert (hm && key); - - char *key_copy = sdb_strdup (key); - if (!key_copy) { - return false; - } - - HtSU__Entry entry = { .key = key_copy, .val = value }; - HtSU__Insert insert_result = HtSU__insert (&hm->inner, &entry); - if (!insert_result.inserted) { - sdb_gh_free (key_copy); - - HtSU__Entry *existing_entry = HtSU__Iter_get (&insert_result.iter); - existing_entry->val = value; - } - - return true; -} - -// Update the key of an element in the hashtable -SDB_API bool ht_su_update_key(HtSU *hm, const char *old_key, const char *new_key) { - assert (hm && old_key && new_key); - - HtSU__Iter iter = HtSU__find (&hm->inner, (const HtSU__Key*) &old_key); - HtSU__Entry *entry = HtSU__Iter_get (&iter); - if (!entry) { - return false; - } - - // Do nothing if keys are the same - if (SDB_UNLIKELY (strcmp (old_key, new_key) == 0)) { - return true; - } - - char *key_copy = sdb_strdup (new_key); - if (!key_copy) { - return false; - } - - // First try inserting the new key - HtSU__Entry new_entry = { .key = key_copy, .val = entry->val }; - HtSU__Insert result = HtSU__insert (&hm->inner, &new_entry); - if (!result.inserted) { - sdb_gh_free (key_copy); - return false; - } - - // Then remove entry for the old key - HtSU__erase_at (iter); - return true; -} - -SDB_API bool ht_su_delete(HtSU *hm, const char *key) { - assert (hm && key); - return HtSU__erase (&hm->inner, (const HtSU__Key*) &key); -} - -SDB_API ut64 ht_su_find(HtSU *hm, const char *key, bool* found) { - assert (hm && key); - - if (found) { - *found = false; - } - - HtSU__Iter iter = HtSU__find (&hm->inner, (const HtSU__Key*) &key); - HtSU__Entry *entry = HtSU__Iter_get (&iter); - if (!entry) { - return 0; - } - - if (found) { - *found = true; - } - return entry->val; -} - -// Iterates over all elements in the hashtable, calling the cb function on each Kv. -// If the cb returns false, the iteration is stopped. -// cb should not modify the hashtable. -SDB_API void ht_su_foreach(HtSU *hm, HtSUForEachCallback cb, void *user) { - assert (hm); - HtSU__CIter iter; - const HtSU__Entry *entry; - - for (iter = HtSU__citer (&hm->inner); (entry = HtSU__CIter_get (&iter)) != NULL; HtSU__CIter_next (&iter)) { - if (!cb (user, entry->key, entry->val)) { - return; - } - } -} diff --git a/shlr/sdb/src/ht_up.c b/shlr/sdb/src/ht_up.c deleted file mode 100644 index 32da6b9a89b2f..0000000000000 --- a/shlr/sdb/src/ht_up.c +++ /dev/null @@ -1,43 +0,0 @@ -/* sdb - MIT - Copyright 2018-2022 - ret2libc, pancake */ - -#include "sdb/sdb.h" -#include "sdb/ht_up.h" -#include "ht.inc.c" - -static HtName_(Ht)* internal_ht_default_new(ut32 size, ut32 prime_idx, HT_(DupValue) valdup, HT_(KvFreeFunc) pair_free, HT_(CalcSizeV) calcsizeV) { - HT_(Options) opt = { - .cmp = NULL, - .hashfn = NULL, // TODO: use a better hash function for numbers - .dupkey = NULL, - .dupvalue = valdup, - .calcsizeK = NULL, - .calcsizeV = calcsizeV, - .freefn = pair_free, - .elem_size = sizeof (HT_(Kv)), - }; - return internal_ht_new (size, prime_idx, &opt); -} - -SDB_API HtName_(Ht)* Ht_(new)(HT_(DupValue) valdup, HT_(KvFreeFunc) pair_free, HT_(CalcSizeV) calcsizeV) { - return internal_ht_default_new (ht_primes_sizes[0], 0, valdup, pair_free, calcsizeV); -} - -// creates a default HtUP that does not dup, nor free the values -SDB_API HtName_(Ht)* Ht_(new0)(void) { - return Ht_(new) (NULL, NULL, NULL); -} - -SDB_API HtName_(Ht)* Ht_(new_size)(ut32 initial_size, HT_(DupValue) valdup, HT_(KvFreeFunc) pair_free, HT_(CalcSizeV) calcsizeV) { - ut32 i = 0; - - while (i < S_ARRAY_SIZE (ht_primes_sizes) && - ht_primes_sizes[i] * LOAD_FACTOR < initial_size) { - i++; - } - if (i == S_ARRAY_SIZE (ht_primes_sizes)) { - i = UT32_MAX; - } - - ut32 sz = compute_size (i, (ut32)(initial_size * (2 - LOAD_FACTOR))); - return internal_ht_default_new (sz, i, valdup, pair_free, calcsizeV); -} diff --git a/shlr/sdb/src/ht_uu.c b/shlr/sdb/src/ht_uu.c deleted file mode 100644 index 230814d91e391..0000000000000 --- a/shlr/sdb/src/ht_uu.c +++ /dev/null @@ -1,110 +0,0 @@ -/* sdb - MIT - Copyright 2018-2023 - ret2libc, pancake, luc-tielen */ - -#include -#include "sdb/ht_uu.h" -#include "sdb/heap.h" -#include "sdb/cwisstable.h" - -typedef uint64_t ut64; - -CWISS_DECLARE_FLAT_HASHMAP_DEFAULT(HtUU_, ut64, ut64); - -struct HtUU_t { - HtUU_ inner; -}; - -SDB_API HtUU* ht_uu_new0(void) { - HtUU *hm = (HtUU*) sdb_gh_calloc (1, sizeof (HtUU)); - if (hm) { - hm->inner = HtUU__new (0); - } - return hm; -} - -SDB_API void ht_uu_free(HtUU *hm) { - if (hm) { - HtUU__destroy (&hm->inner); - sdb_gh_free (hm); - } -} - -SDB_API bool ht_uu_insert(HtUU *hm, const ut64 key, ut64 value) { - assert (hm); - - HtUU__Entry entry = { .key = key, .val = value }; - HtUU__Insert result = HtUU__insert (&hm->inner, &entry); - return result.inserted; -} - -SDB_API bool ht_uu_update(HtUU *hm, const ut64 key, ut64 value) { - assert (hm); - - HtUU__Entry entry = { .key = key, .val = value }; - HtUU__Insert insert_result = HtUU__insert (&hm->inner, &entry); - const bool should_update = !insert_result.inserted; - if (should_update) { - HtUU__Entry *existing_entry = HtUU__Iter_get (&insert_result.iter); - existing_entry->val = value; - } - - return true; -} - -// Update the key of an element in the hashtable -SDB_API bool ht_uu_update_key(HtUU *hm, const ut64 old_key, const ut64 new_key) { - assert (hm); - - HtUU__Iter iter = HtUU__find (&hm->inner, &old_key); - HtUU__Entry *entry = HtUU__Iter_get (&iter); - if (!entry) { - return false; - } - - // First try inserting the new key - HtUU__Entry new_entry = { .key = new_key, .val = entry->val }; - HtUU__Insert result = HtUU__insert (&hm->inner, &new_entry); - if (!result.inserted) { - return false; - } - - // Then remove entry for the old key - HtUU__erase_at (iter); - return true; -} - -SDB_API bool ht_uu_delete(HtUU *hm, const ut64 key) { - assert (hm); - return HtUU__erase (&hm->inner, &key); -} - -SDB_API ut64 ht_uu_find(HtUU *hm, const ut64 key, bool* found) { - assert (hm); - if (found) { - *found = false; - } - - HtUU__Iter iter = HtUU__find (&hm->inner, &key); - HtUU__Entry *entry = HtUU__Iter_get (&iter); - if (!entry) { - return 0; - } - - if (found) { - *found = true; - } - return entry->val; -} - -// Iterates over all elements in the hashtable, calling the cb function on each Kv. -// If the cb returns false, the iteration is stopped. -// cb should not modify the hashtable. -SDB_API void ht_uu_foreach(HtUU *hm, HtUUForEachCallback cb, void *user) { - assert (hm); - HtUU__CIter iter; - const HtUU__Entry *entry; - for (iter = HtUU__citer (&hm->inner); (entry = HtUU__CIter_get (&iter)) != NULL; HtUU__CIter_next (&iter)) { - if (!cb (user, entry->key, entry->val)) { - return; - } - } -} diff --git a/shlr/sdb/src/journal.c b/shlr/sdb/src/journal.c deleted file mode 100644 index b42544a9cd146..0000000000000 --- a/shlr/sdb/src/journal.c +++ /dev/null @@ -1,127 +0,0 @@ -/* sdb - MIT - Copyright 2011-2023 - pancake */ - -#include "sdb/sdb.h" -#include -#if R2__UNIX__ || __UNIX__ || __MINGW32__ -#include -#endif - -static bool sdb_journal_filename(Sdb *s, char *path, size_t path_size) { - if (!s || !s->name) { - return false; - } - - int res = snprintf (path, path_size, "%s.journal", s->name); - if (res < 0 || (size_t)res >= path_size) { - return false; - } - - return true; -} - -SDB_API bool sdb_journal_close(Sdb *s) { - char filename[SDB_MAX_PATH]; - if (s->journal == -1) { - return false; - } - close (s->journal); - s->journal = -1; - if (!sdb_journal_filename (s, filename, sizeof (filename))) { - return false; - } - unlink (filename); - return true; -} - -SDB_API bool sdb_journal_open(Sdb *s) { - char filename[SDB_MAX_PATH]; - if (!s || !s->name) { - return false; - } - if (!sdb_journal_filename (s, filename, sizeof (filename))) { - return false; - } - close (s->journal); - s->journal = open (filename, O_CREAT | O_RDWR | O_APPEND, 0600); - return s->journal != -1; -} - -// TODO boolify and save changes somewhere else? or just dont count that? -SDB_API int sdb_journal_load(Sdb *s) { - int rr, sz, fd, changes = 0; - char *eq, *str, *cur, *ptr = NULL; - if (!s) { - return 0; - } - fd = s->journal; - if (fd == -1) { - return 0; - } - sz = lseek (fd, 0, SEEK_END); - if (sz < 1) { - return 0; - } - if (lseek (fd, 0, SEEK_SET) == (off_t) -1) { - return 0; - } - str = (char *)sdb_gh_malloc (sz + 1); - if (!str) { - return 0; - } - rr = read (fd, str, sz); - if (rr < 0) { - sdb_gh_free (str); - return 0; - } - str[sz] = 0; - for (cur = str; ; ) { - ptr = strchr (cur, '\n'); - if (!ptr) { - break; - } - *ptr = 0; - eq = strchr (cur, '='); - if (eq) { - *eq++ = 0; - sdb_set (s, cur, eq, 0); - changes ++; - } - cur = ptr + 1; - } - sdb_gh_free (str); - return changes; -} - -SDB_API bool sdb_journal_log(Sdb *s, const char *key, const char *val) { - char str[SDB_MAX_PATH]; - if (s->journal == -1) { - return false; - } - if (snprintf (str, sizeof (str), "%s=%s\n", key, val) < 0) { - return false; - } - int len = strlen (str); - if (write (s->journal, str, len) != len) { - return false; - } -#if USE_MMAN - (void)fsync (s->journal); -#endif - return true; -} - -SDB_API bool sdb_journal_clear(Sdb *s) { - if (s->journal != -1) { - return !ftruncate (s->journal, 0); - } - return false; -} - -SDB_API bool sdb_journal_unlink(Sdb *s) { - char filename[SDB_MAX_PATH]; - if (!sdb_journal_filename (s, filename, sizeof (filename))) { - return false; - } - sdb_journal_close (s); - return !unlink (filename); -} diff --git a/shlr/sdb/src/json.c b/shlr/sdb/src/json.c deleted file mode 100644 index edb5741ac0cbd..0000000000000 --- a/shlr/sdb/src/json.c +++ /dev/null @@ -1,357 +0,0 @@ -/* sdb - MIT - Copyright 2012-2022 - pancake */ - -#include -#include "sdb/sdb.h" - -#include "json/rangstr.c" -#include "json/js0n.c" -#include "json/path.c" -#include "json/api.c" -#include "json/indent.c" - -SDB_API char *sdb_json_get_str (const char *json, const char *path) { - Rangstr rs = json_get (json, path); - return rangstr_dup (&rs); -} - -SDB_API bool sdb_json_get_bool(const char *json, const char *path) { - Rangstr rs = json_get (json, path); - const char *p = rs.p + rs.f; - return (rangstr_length (&rs) == 4 && !strncmp (p, "true", 4)); -} - -SDB_API char *sdb_json_get(Sdb *s, const char *k, const char *p, ut32 *cas) { - Rangstr rs; - char *u, *v = sdb_get (s, k, cas); - if (!v) { - return NULL; - } - rs = json_get (v, p); - u = rangstr_dup (&rs); - sdb_gh_free (v); - return u; -} - -SDB_API int sdb_json_num_inc(Sdb *s, const char *k, const char *p, int n, ut32 cas) { - ut32 c; - int cur = sdb_json_num_get (s, k, p, &c); - if (cas && c != cas) { - return 0; - } - sdb_json_num_set (s, k, p, cur + n, cas); - return cur + n; -} - -SDB_API int sdb_json_num_dec(Sdb *s, const char *k, const char *p, int n, ut32 cas) { - ut32 c; - int cur = sdb_json_num_get (s, k, p, &c); - if (cas && c != cas) { - return 0; - } - sdb_json_num_set (s, k, p, cur - n, cas); - return cur - n; -} - -SDB_API int sdb_json_num_get(Sdb *s, const char *k, const char *p, ut32 *cas) { - char *v = sdb_get (s, k, cas); - if (v) { - Rangstr rs = json_get (v, p); - int ret = rangstr_int (&rs); - sdb_gh_free (v); - return ret; - } - return 0; -} - -static int findkey(Rangstr *rs) { - int i; - for (i = rs->f; i > 0; i--) { - // Find the quote after the key - if (rs->p[i] == '"') { - for (--i; i > 0; i--) { - // Find the quote before the key - if (rs->p[i] == '"') { - return i; - } - } - } - } - return -1; -} - -static bool isstring(const char *s) { - if (!strcmp (s, "true")) { - return false; - } - if (!strcmp (s, "false")) { - return false; - } - for (; *s; s++) { - if (*s < '0' || *s > '9') { - return true; - } - } - return false; -} - -// JSON only supports base16 numbers -SDB_API int sdb_json_num_set(Sdb *s, const char *k, const char *p, int v, ut32 cas) { - char *_str, str[SDB_NUM_BUFSZ]; - _str = sdb_itoa (v, 10, str, sizeof (str)); - return sdb_json_set (s, k, p, _str, cas); -} - -SDB_API int sdb_json_unset(Sdb *s, const char *k, const char *p, ut32 cas) { - return sdb_json_set (s, k, p, NULL, cas); -} - -SDB_API bool sdb_json_set(Sdb *s, const char *k, const char *p, const char *v, ut32 cas) { - int l, idx, len[3], jslen = 0; - char *b, *str = NULL; - const char *beg[3]; - const char *end[3]; - const char *js; - Rangstr rs; - ut32 c; - - if (!s || !k || !v) { - return false; - } - js = sdb_const_get_len (s, k, &jslen, &c); - if (!js) { - const int v_len = strlen (v); - const int p_len = strlen (p); - const size_t blen = p_len + v_len + 8; - b = (char *)sdb_gh_malloc (blen); - if (b) { - int is_str = isstring (v); - const char *q = is_str? "\"": ""; - snprintf (b, blen, "{\"%s\":%s%s%s}", p, q, v, q); -#if 0 - /* disabled because it memleaks */ - sdb_set_owned (s, k, b, cas); -#else - sdb_set (s, k, b, cas); - sdb_gh_free (b); -#endif - return true; - } - return false; - } - jslen++; - if (cas && c != cas) { - return false; - } - rs = json_get (js, p); - if (!rs.p) { - // jslen already comprehends the NULL-terminator and is - // ensured to be positive by sdb_const_get_len - // 7 corresponds to the length of '{"":"",' - size_t buf_len = jslen + strlen (p) + strlen (v) + 7; - char *buf = (char *)sdb_gh_malloc (buf_len); - if (buf) { - int curlen, is_str = isstring (v); - const char *quote = is_str ? "\"" : ""; - const char *comma = ""; // XX: or comma - if (js[0] && js[1] != '}') { - comma = ","; - } - curlen = snprintf (buf, buf_len, "{\"%s\":%s%s%s%s", - p, quote, v, quote, comma); - strcpy (buf + curlen, js + 1); - // transfer ownership - sdb_set_owned (s, k, buf, cas); - return true; - } - // invalid json? - return false; - } - - // rs.p and js point to the same memory location - beg[0] = js; - end[0] = rs.p + rs.f; - len[0] = WLEN (0); - - if (*v) { - beg[1] = v; - end[1] = v + strlen (v); - len[1] = WLEN (1); - } - - beg[2] = rs.p + rs.t; - end[2] = js + jslen; - len[2] = WLEN (2); - - // TODO: accelerate with small buffer in stack for small jsons - if (*v) { - int is_str = isstring (v); - // 2 is the maximum amount of quotes that can be inserted - int msz = len[0] + len[1] + len[2] + strlen (v) + 2; - if (msz < 1) { - return false; - } - str = (char *)sdb_gh_malloc (msz); - if (!str) { - return false; - } - idx = len[0]; - memcpy (str, beg[0], idx); - if (is_str) { - if (beg[2][0] != '"') { - str[idx] = '"'; - idx++; - } - } else { - if (beg[2][0] == '"') { - beg[2]++; - len[2]--; - } - } - l = len[1]; - memcpy (str + idx, beg[1], l); - idx += len[1]; - if (is_str) { - // TODO: add quotes - if (beg[2][0] != '"') { - str[idx] = '"'; - idx++; - } - } else { - if (beg[2][0] == '"') { - beg[2]++; - len[2]--; - } - } - l = len[2]; - memcpy (str + idx, beg[2], l); - str[idx + l] = 0; - } else { - int kidx; - // DELETE KEY - rs.f -= 2; - kidx = findkey (&rs); - len[0] = R_MAX (1, kidx - 1); - - // Delete quote if deleted value was a string - if (beg[2][0] == '"') { - beg[2]++; - len[2]--; - } - - // If not the last key, delete comma - if (len[2] != 2) { - beg[2]++; - len[2]--; - } - - str = (char *)sdb_gh_malloc (len[0] + len[2] + 1); - if (!str) { - return false; - } - - memcpy (str, beg[0], len[0]); - memcpy (str + len[0], beg[2], len[2]); - str[len[0] + len[2]] = 0; - } - sdb_set_owned (s, k, str, cas); - return true; -} - -SDB_API const char *sdb_json_format(SdbJsonString *s, const char *fmt, ...) { - char *arg_s, *x, tmp[128]; - ut64 arg_l; - int i, arg_i; - double arg_f; - va_list ap; -#define JSONSTR_ALLOCATE(y)\ - if (s->len + y > s->blen) {\ - s->blen *= 2;\ - x = (char *)sdb_gh_realloc (s->buf, s->blen);\ - if (!x) {\ - va_end (ap);\ - return NULL;\ - }\ - s->buf = x;\ - } - if (!s) { - return NULL; - } - if (!s->buf) { - s->blen = 1024; - s->buf = (char *)sdb_gh_malloc (s->blen); - if (!s->buf) { - return NULL; - } - *s->buf = 0; - } - if (!fmt || !*fmt) { - return s->buf; - } - va_start (ap, fmt); - for (; *fmt; fmt++) { - if (*fmt == '%') { - fmt++; - switch (*fmt) { - case 'b': - JSONSTR_ALLOCATE (32); - arg_i = va_arg (ap, int); - arg_i = arg_i? 4: 5; - memcpy (s->buf + s->len, (arg_i == 4)? "true": "false", 5); - s->len += arg_i; - break; - case 'f': - JSONSTR_ALLOCATE (32); - arg_f = va_arg (ap, double); - snprintf (tmp, sizeof (tmp), "%f", arg_f); - memcpy (s->buf + s->len, tmp, strlen (tmp)); - s->len += strlen (tmp); - break; - case 'l': - JSONSTR_ALLOCATE (32); - arg_l = va_arg (ap, ut64); - snprintf (tmp, sizeof (tmp), "0x%" PRIx64, arg_l); - memcpy (s->buf + s->len, tmp, strlen (tmp)); - s->len += strlen (tmp); - break; - case 'd': - case 'i': - JSONSTR_ALLOCATE (32); - arg_i = va_arg (ap, int); - snprintf (tmp, sizeof (tmp), "%d", arg_i); - memcpy (s->buf + s->len, tmp, strlen (tmp)); - s->len += strlen (tmp); - break; - case 's': - arg_s = va_arg (ap, char *); - JSONSTR_ALLOCATE (strlen (arg_s) + 3); - s->buf[s->len++] = '"'; - for (i = 0; arg_s[i]; i++) { - if (arg_s[i] == '"') { - s->buf[s->len++] = '\\'; - } - s->buf[s->len++] = arg_s[i]; - } - s->buf[s->len++] = '"'; - break; - } - } else { - JSONSTR_ALLOCATE (10); - s->buf[s->len++] = *fmt; - } - s->buf[s->len] = 0; - } - va_end (ap); - return s->buf; -} - -#if 0 -int main () { - SdbJsonString s = { - 0 - }; - sdb_json_format (&s, "[{%s:%d},%b]", "Hello \"world\"", 1024, 3); - printf ("%s\n", sdb_json_format (&s, 0)); - sdb_json_format_free (&s); - return 0; -} -#endif diff --git a/shlr/sdb/src/json/Makefile b/shlr/sdb/src/json/Makefile deleted file mode 100644 index 1ddc32ddc723a..0000000000000 --- a/shlr/sdb/src/json/Makefile +++ /dev/null @@ -1,37 +0,0 @@ -include ../../config.mk - -HASOVR=$(shell clang -Wno-initializer-overrides -E -&1| grep unknown) -ifeq ($(HASOVR),) -CFLAGS+=-Wno-initializer-overrides -endif -# CFLAGS+=-Wall -g -BIN=a.out -OBJ=rangstr.o path.o js0n.o api.o main.o -OBJ+=../libsdb.a -CFLAGS+=-I../../include - -all: ${BIN} - -${BIN}: ${OBJ} - ${CC} main.c -DMAIN=1 -o ${BIN} ../libsdb.a - -clean: - rm -f ${OBJ} ${BIN} - -../libsdb.a: - cd .. ; ${MAKE} libsdb.a - -mrproper: clean - rm -rf js0n - -test: - ./${BIN} glossary.GlossDiv.GlossList.GlossEntry.GlossDef.GlossSeeAlso[0] < test.json | tail -n 1 - -update: - rm -rf js0n js0n.c - ${MAKE} js0n.c - -js0n.c: - git clone git://github.com/quartzjer/js0n.git - cp js0n/js0n.c js0n.c - rm -rf js0n diff --git a/shlr/sdb/src/json/README b/shlr/sdb/src/json/README deleted file mode 100644 index 467f49db83e87..0000000000000 --- a/shlr/sdb/src/json/README +++ /dev/null @@ -1,20 +0,0 @@ -JSON support for sdb -==================== - -Use js0n: https://github.com/quartzjer/js0n - -git clone git://github.com/quartzjer/js0n.git - ----------- - -user.pancake={"name":"Pancake","pass":"4e2e631e3671727c3f7d8d11fc4dcb0d"} -user.blah={"name":"Bin Daboo","pass":"bd20ae2b25e8d4ff64e0720a5b4162d2"} -user.boun={"name":"Bob Union","pass":"2f03be08fcddd9a889e8c9d8de933cea"} - -user.pancake?name -user.pancake?pass - -user.pancake?name=My name - -user?name=Bob Union => user.boun -user?name~B => user.boun diff --git a/shlr/sdb/src/json/api.c b/shlr/sdb/src/json/api.c deleted file mode 100644 index 2cb52447b9416..0000000000000 --- a/shlr/sdb/src/json/api.c +++ /dev/null @@ -1,55 +0,0 @@ -/* Copyleft 2012 - sdb (aka SimpleDB) - pancake */ -// XXX: this is deprecated coz its dupper for ../json.c - -#include -#include -#include -#include "sdb/rangstr.h" - -/* public sdb api */ -char *api_json_get (const char *s, const char *p) { - Rangstr rs = json_get (s, p); - return rangstr_dup (&rs); -} - -char *api_json_set (const char *s, const char *k, const char *v) { - const char *beg[3]; - const char *end[3]; - int idx, len[3]; - char *str = NULL; - Rangstr rs = json_get (s, k); - if (!rs.p) { - return NULL; - } -#define WLEN(x) (int)(size_t)(end[x]-beg[x]) - - beg[0] = s; - end[0] = rs.p + rs.f; - len[0] = WLEN (0); - - beg[1] = v; - end[1] = v + strlen (v); - len[1] = WLEN (1); - - beg[2] = rs.p + rs.t; - end[2] = s + strlen (s); - len[2] = WLEN (2); - - str = (char *)sdb_gh_malloc (len[0]+len[1]+len[2]+1); - if (!str) { - return NULL; - } - idx = len[0]; - memcpy (str, beg[0], idx); - memcpy (str+idx, beg[1], len[1]); - idx += len[1]; - memcpy (str+idx, beg[2], len[2]); - str[idx+len[2]] = 0; - return str; -} - -char *api_json_seti (const char *s, const char *k, int a) { - char str[64]; - snprintf (str, sizeof (str), "%d", a); - return api_json_set (s, k, str); -} diff --git a/shlr/sdb/src/json/indent.c b/shlr/sdb/src/json/indent.c deleted file mode 100644 index a798206ec69d4..0000000000000 --- a/shlr/sdb/src/json/indent.c +++ /dev/null @@ -1,139 +0,0 @@ -/* sdb - MIT - Copyright 2012-2018 - pancake */ - -#include - -static void doIndent(int idt, char **o, const char *tab) { - int i; - char *x; - for (i = 0; i < idt; i++) { - for (x = (char *) tab; *x; x++) { - *(*o)++ = *x; - } - } -} - -SDB_API char *sdb_json_indent(const char *s, const char *tab) { - int idx, indent = 0; - int instr = 0; - size_t o_size = 0; - char *o, *O; - if (!s) { - return NULL; - } - - size_t tab_len = strlen (tab); - for (idx = 0; s[idx]; idx++) { - if (o_size > INT_MAX - (indent * tab_len + 2)) { - return NULL; - } - - if (s[idx] == '{' || s[idx] == '[') { - indent++; - // 2 corresponds to the \n and the parenthesis - o_size += indent * tab_len + 2; - } else if (s[idx] == '}' || s[idx] == ']') { - if (indent > 0) { - indent--; - } - // 2 corresponds to the \n and the parenthesis - o_size += indent * tab_len + 2; - } else if (s[idx] == ',') { - // 2 corresponds to the \n and the , - o_size += indent * tab_len + 2; - } else if (s[idx] == ':') { - o_size += 2; - } else { - o_size++; - } - } - // 2 corresponds to the last \n and \0 - o_size += 2; - indent = 0; - - O = (char *)sdb_gh_malloc (o_size + 1); - if (!O) { - return NULL; - } - - for (o = O; *s; s++) { - if (instr) { - if (s[0] == '"') { - instr = 0; - } else if (s[0] == '\\' && s[1] == '"') { - *o++ = *s; - } - *o++ = *s; - continue; - } else { - if (s[0] == '"') { - instr = 1; - } - } - if (*s == '\n' || *s == '\r' || *s == '\t' || *s == ' ') { - continue; - } - switch (*s) { - case ':': - *o++ = *s; - *o++ = ' '; - break; - case ',': - *o++ = *s; - *o++ = '\n'; - doIndent (indent, &o, tab); - break; - case '{': - case '[': - *o++ = *s; - *o++ = (indent != -1)? '\n': ' '; - indent++; - doIndent (indent, &o, tab); - break; - case '}': - case ']': - *o++ = '\n'; - indent--; - doIndent (indent, &o, tab); - *o++ = *s; - break; - default: - *o++ = *s; - } - } - *o++ = '\n'; - *o = 0; - - return O; -} - -// TODO: move to utils? -SDB_API char *sdb_json_unindent(const char *s) { - int instr = 0; - int len = strlen (s); - char *o, *O = (char *)sdb_gh_malloc (len + 1); - if (!O) { - return NULL; - } - memset (O, 0, len); - for (o = O; *s; s++) { - if (instr) { - if (s[0] != '"') { - if (s[0] == '\\' && s[1] == '"') { - *o++ = *s; - } - } else { - instr = 0; - } - *o++ = *s; - continue; - } else if (s[0] == '"') { - instr = 1; - } - if (*s == '\n' || *s == '\r' || *s == '\t' || *s == ' ') { - continue; - } - *o++ = *s; - } - *o = 0; - return O; -} diff --git a/shlr/sdb/src/json/js0n.c b/shlr/sdb/src/json/js0n.c deleted file mode 100644 index cf767adf0acc5..0000000000000 --- a/shlr/sdb/src/json/js0n.c +++ /dev/null @@ -1,296 +0,0 @@ -// by jeremie miller - 2010-2024 -// public domain, contributions/improvements welcome via github - -// opportunity to further optimize would be having different jump tables for higher depths - -#include "sdb/rangstr.h" - -#define PUSH(i) if(depth == 1) prev = *out++ = ((cur+i) - js) -#define CAP(i) if(depth == 1) prev = *out++ = ((cur+i) - (js + prev) + 1) - -#ifdef _MSC_VER -#define HAVE_COMPUTED_GOTOS 0 -#elif __EMSCRIPTEN__ -#define HAVE_COMPUTED_GOTOS 0 -#elif __cplusplus -#define HAVE_COMPUTED_GOTOS 0 -#else -#define HAVE_COMPUTED_GOTOS 1 -#endif - -#if HAVE_COMPUTED_GOTOS - -#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunknown-pragmas" -#pragma GCC diagnostic ignored "-Wpragmas" -#endif -#pragma GCC diagnostic ignored "-Winitializer-overrides" - -#define HAVE_RAWSTR 0 - -int sdb_js0n(const ut8 *js, RangstrType len, RangstrType *out) { - ut32 prev = 0; - const ut8 *cur, *end; - int depth = 0, utf8_remain = 0; - const static void *const gostruct[] = { - [0 ... 255] = &&l_bad, - ['\t'] = &&l_loop, [' '] = &&l_loop, ['\r'] = &&l_loop, ['\n'] = &&l_loop, - ['"'] = &&l_qup, - [':'] = &&l_loop, [','] = &&l_loop, - ['['] = &&l_up, [']'] = &&l_down, // tracking [] and {} individually would allow fuller validation but is really messy - ['{'] = &&l_up, ['}'] = &&l_down, -//TODO: add support for rawstrings -#if HAVE_RAWSTR - ['a'...'z'] = &&l_rawstr, -#else - ['-'] = &&l_bare, [48 ... 57] = &&l_bare, // 0-9 - ['t'] = &&l_bare, ['f'] = &&l_bare, ['n'] = &&l_bare // true, false, null -#endif - }; - const static void *const gobare[] = { - [0 ... 31] = &&l_bad, - [32 ... 126] = &&l_loop, // could be more pedantic/validation-checking - ['\t'] = &&l_unbare, [' '] = &&l_unbare, ['\r'] = &&l_unbare, ['\n'] = &&l_unbare, - [','] = &&l_unbare, [']'] = &&l_unbare, ['}'] = &&l_unbare, - [127 ... 255] = &&l_bad - }; -#if HAVE_RAWSTR - const static void *const gorawstr[] = { - [0 ... 31] = &&l_bad, [127] = &&l_bad, - [32 ... 126] = &&l_loop, - ['\\'] = &&l_esc, [':'] = &&l_qdown, - [128 ... 191] = &&l_bad, - [192 ... 223] = &&l_utf8_2, - [224 ... 239] = &&l_utf8_3, - [240 ... 247] = &&l_utf8_4, - [248 ... 255] = &&l_bad - }; -#endif - const static void *const gostring[] = { - [0 ... 31] = &&l_bad, [127] = &&l_bad, - [32 ... 126] = &&l_loop, - ['\\'] = &&l_esc, ['"'] = &&l_qdown, - [128 ... 191] = &&l_bad, - [192 ... 223] = &&l_utf8_2, - [224 ... 239] = &&l_utf8_3, - [240 ... 247] = &&l_utf8_4, - [248 ... 255] = &&l_bad - }; - const static void *const goutf8_continue[] = { - [0 ... 127] = &&l_bad, - [128 ... 191] = &&l_utf_continue, - [192 ... 255] = &&l_bad - }; - const static void *const goesc[] = { - [0 ... 255] = &&l_bad, - ['"'] = &&l_unesc, ['\\'] = &&l_unesc, ['/'] = &&l_unesc, ['b'] = &&l_unesc, - ['f'] = &&l_unesc, ['n'] = &&l_unesc, ['r'] = &&l_unesc, ['t'] = &&l_unesc, ['u'] = &&l_unesc - }; - const void *const *go = gostruct; -#if 0 -printf (" gostrct= %p\n", gostruct); -printf (" gobare = %p\n", gobare); -printf (" gostr = %p\n", gostring); -printf (" goesc = %p\n", goesc); -printf (" goutf8= %p\n", goutf8_continue); -#endif - for (cur=js, end = js+len; cur %s %p\n", cur, go[*cur]); - goto *go[*cur]; -l_loop:; - } - return depth; // 0 if successful full parse, >0 for incomplete data -l_bad: - return 1; -l_up: - PUSH(0); - ++depth; - goto l_loop; -l_down: - --depth; - CAP (0); - goto l_loop; -l_qup: - PUSH (1); - go = gostring; - goto l_loop; -l_qdown: - CAP (-1); - go = gostruct; - goto l_loop; -l_esc: - go = goesc; - goto l_loop; -l_unesc: - go = gostring; - goto l_loop; -#if HAVE_RAWSTR -l_rawstr: - PUSH (0); - go = gorawstr; - goto l_loop; -#endif -l_bare: - PUSH (0); - go = gobare; - goto l_loop; -l_unbare: - CAP (-1); - go = gostruct; - goto *go[*cur]; -l_utf8_2: - go = goutf8_continue; - utf8_remain = 1; - goto l_loop; -l_utf8_3: - go = goutf8_continue; - utf8_remain = 2; - goto l_loop; -l_utf8_4: - go = goutf8_continue; - utf8_remain = 3; - goto l_loop; -l_utf_continue: - if (!--utf8_remain) - go = gostring; - goto l_loop; -} - -#else // HAVE_COMPUTED_GOTOS - -#define GO_DOWN (1) -#define GO_UP (1 << 1) -#define GO_Q_DOWN (1 << 2) -#define GO_Q_UP (1 << 3) -#define GO_BARE (1 << 4) -#define GO_UNBARE (1 << 5) -#define GO_ESCAPE (1 << 6) -#define GO_UNESCAPE (1 << 7) -#define GO_UTF8 (1 << 8) -#define GO_UTF8_CONTINUE (1 << 9) -int sdb_js0n(const ut8 *js, RangstrType len, RangstrType *out) { - ut32 prev = 0; - const ut8 *cur, *end; - int depth = 0, utf8_remain = 0, what_did = 1; - for (cur = js, end = js + len; cur < end; cur++) { - if (what_did & GO_BARE) { - switch (*cur) { - case ' ': - case '\t': - case '\r': - case '\n': - case ',': - case ']': - case '}': - what_did = GO_UNBARE; - CAP (-1); - break; - default: - if (*cur >= 32 && *cur <= 126) { - continue; - } - return 1; - } - // Same *cur - } - if (what_did & GO_UTF8) { - if (*cur < 128 || (*cur >=192 && *cur <= 255)) { - return 1; - } - if (!--utf8_remain) { - what_did = GO_UTF8_CONTINUE; - } - continue; - } - if (what_did & GO_ESCAPE) { - switch (*cur) { - case '"': - case '\\': - case '/': - case 'b': - case 'f': - case 'n': - case 'r': - case 't': - case 'u': - what_did = GO_UNESCAPE; - break; - default: - return 1; - } - continue; - } - if (what_did & GO_Q_UP || what_did & GO_UTF8_CONTINUE || what_did & GO_UNESCAPE) { - switch (*cur) { - case '\\': - what_did = GO_ESCAPE; - break; - case '"': - what_did = GO_Q_DOWN; - CAP (-1); - break; - default: - if (*cur <= 31 || (*cur >= 127 && *cur <= 191) || (*cur >= 248 && *cur <= 255)) { - return 1; - } - if (*cur < 127) { - continue; - } - what_did = GO_UTF8; - if (*cur < 224) { - utf8_remain = 1; - continue; - } - if (*cur < 239) { - utf8_remain = 2; - continue; - } - utf8_remain = 3; - break; - } - continue; - } - switch (*cur) { - case '\t': - case ' ': - case '\r': - case '\n': - case ',': - case ':': - break; - case '"': - PUSH (1); - what_did = GO_Q_UP; - break; - case '[': - case '{': - PUSH (0); - ++depth; - what_did = GO_UP; - break; - case ']': - case '}': - --depth; - CAP (0); - what_did = GO_DOWN; - break; - case '-': - case 't': - case 'f': - case 'n': - what_did = GO_BARE; - PUSH (0); - break; - default: - if (*cur >= 48 && *cur <= 57) { // 0-9 - what_did = GO_BARE; - PUSH (0); - break; - } - return 1; - } - } - return depth; -} -#endif // HAVE_COMPUTED_GOTOS diff --git a/shlr/sdb/src/json/main.c b/shlr/sdb/src/json/main.c deleted file mode 100644 index b24e87eb8db63..0000000000000 --- a/shlr/sdb/src/json/main.c +++ /dev/null @@ -1,92 +0,0 @@ -/* Copyleft 2012 - api (aka SimpleDB) - pancake */ - -#include -#include -#include "sdb/rangstr.h" -#include "sdb/json.h" -#include "sdb/sdb.h" - -Rangstr json_find (const char *s, Rangstr *rs); -int test_main () { - Rangstr rs ; - - rs = json_get ("{\"hello\":\"world\"}", "hello"); -printf ("OUT: "); -rangstr_print (&rs); -printf ("\n"); - -printf ("--\n"); - rs = json_get ("{\"hello\":{\"world\":123}}", "hello.world"); -printf ("OUT: "); -rangstr_print (&rs); -printf ("\n"); - return 0; -} - -int test_glossary(char *buf) { - char *path; -{ - path = "glossary.title"; - char *s= api_json_set (buf, path, "patata"); - if (s) { - printf ("%s\n", s); - sdb_gh_free (s); - } else printf ("set failed\n"); -} -{ - path = "glossary.title"; - char *s= api_json_get (buf, path); - if (s) { - printf ("%s\n", s); - sdb_gh_free (s); - } else printf ("set failed\n"); -} -{ - path = "glossary.title"; - char *s= api_json_get (buf, path); - if (s) { - printf ("%s\n", s); - sdb_gh_free (s); - } else printf ("set failed\n"); -} -return 0; -} - -int main(int argc, char **argv) { - Rangstr rs; - char buf[4096]; - int n = fread (buf, 1, sizeof (buf), stdin); - buf[n] = 0; -//return test_glossary (buf); -//return test_main (); - char *path = argv[1]; - -#if 1 - printf (">>>> %s <<<<\n", sdb_json_unindent (buf)); - printf (">>>> %s <<<<\n", sdb_json_indent (buf, " ")); -// set value // - path = "glossary.title"; - char *s = api_json_set (buf, path, "patata"); - if (s) { - printf ("%s\n", s); - sdb_gh_free (s); - } else printf ("set failed\n"); -#endif -//printf ("%s\n", str); return 0; - -// s = "[1,3,4]"; -#if 0 - char *a = "{}"; - a = json_seti (a, "id", 123); - a = json_seti (a, "user.name", "blah"); - printf ("id = %d\n", json_geti ("{'id':123}", "id")); -#endif - //json_walk (buf); - - path = argv[1]; - rs = json_get (buf, path); - printf ("-- output --\n"); - rangstr_print(&rs); - printf ("\n"); - return 0; -} diff --git a/shlr/sdb/src/json/path.c b/shlr/sdb/src/json/path.c deleted file mode 100644 index 1d7288381ed6a..0000000000000 --- a/shlr/sdb/src/json/path.c +++ /dev/null @@ -1,219 +0,0 @@ -/* sdb - MIT - Copyright 2012-2022 - pancake */ - -#include -#include -#include -#include "sdb/rangstr.h" -#include "sdb/sdb.h" -#include "sdb/types.h" - -SDB_IPI void json_path_first(Rangstr *s) { - char *p; - if (!s->p) { - return; - } - p = (char *)strchr (s->p, '.'); - s->f = 0; - s->t = p? (size_t)(p - s->p): strlen (s->p); -} - -SDB_IPI int json_path_next(Rangstr *s) { - int stop = '.'; - if (!s||!s->p||!s->p[s->t]) { - return 0; - } - if (!s->next) { - return 0; - } - if (s->p[s->t] == '"') { - s->t++; - } -rep: - if (s->p[s->t] == '[') { - s->type = '['; - stop = ']'; - } else { - s->type = 0; - } - s->f = ++s->t; - if (s->p[s->t] == stop) { - s->f = ++s->t; - } - if (!s->p[s->t]) { - return 0; - } - while (s->p[s->t] != stop) { - if (!s->p[s->t]) { - s->next = 0; - return 1; - } - if (s->p[s->t] == '[') { - break; - } - s->t++; - } - if (s->f == s->t) { - goto rep; - } - if (s->p[s->f] == '"') { - s->f++; - s->t--; - } - return 1; -} - -#if 0 -typedef int (*JSONCallback)(); - -int json_foreach(const char *s, JSONCallback cb UNUSED) { - int i, len, ret; - unsigned short *res = NULL; - len = strlen (s); - res = sdb_gh_malloc (len); - ret = sdb_js0n ((const unsigned char *)s, len, res); - if (!ret) return 0; - if (*s=='[') { - for (i=0; res[i]; i+=2) { - printf ("%d %.*s\n", i, res[i+1], s+res[i]); - } - } else { - for (i=0; res[i]; i+=4) { - printf ("%.*s = ", res[i+1], s+res[i]); - printf ("%.*s\n", res[i+3], s+res[i+2]); - } - } - return 1; -} -#endif - -#if 0 // UNUSED -SDB_IPI int json_walk (const char *s) { - RangstrType *res; - int i, ret, len = strlen (s); - res = sdb_gh_malloc (len+1); - ret = sdb_js0n ((const unsigned char *)s, len, res); - if (!ret) { - sdb_gh_free (res); - return 0; - } - if (*s=='[' || *s=='{') { - for (i=0; res[i]; i+=2) { - printf ("%d %.*s\n", i, res[i+1], s+res[i]); - } - } else { - for (i=0; res[i]; i+=4) { - printf ("%.*s = ", res[i+1], s+res[i]); - printf ("%.*s\n", res[i+3], s+res[i+2]); - } - } - sdb_gh_free (res); - return 1; -} -#endif - -SDB_IPI Rangstr json_find (const char *s, Rangstr *rs) { -#define RESFIXSZ 1024 - RangstrType resfix[RESFIXSZ] = {0}; - RangstrType *res = resfix; - int i, j, n, len, ret; - Rangstr rsn; - - if (!s) { - return rangstr_null (); - } - - len = strlen (s); - if (len > RESFIXSZ) { - res = (RangstrType *)sdb_gh_calloc (len + 1, sizeof (RangstrType)); - if (!res) { - // eprintf ("Cannot allocate %d byte%s\n", len + 1, (len > 1)? "s": ""); - return rangstr_null (); - } - } - - ret = sdb_js0n ((const unsigned char *)s, len, res); -#define PFREE(x) if (x && x != resfix) sdb_gh_free (x) - if (ret > 0) { - PFREE (res); - return rangstr_null (); - } - - if (*s == '[') { - n = rangstr_int (rs); - if (n < 0) { - goto beach; - } - - for (i = j = 0; res[i] && j < n; i += 2, j++); - if (!res[i]) { - goto beach; - } - - rsn = rangstr_news (s, res, i); - - PFREE (res); - return rsn; - } else { - for (i = 0; res[i]; i += 4) { - rsn = rangstr_news (s, res, i); - if (!rangstr_cmp (rs, &rsn)) { - rsn = rangstr_news (s, res, i+2); - PFREE (res); - return rsn; - } - } - } -beach: - PFREE (res); - return rangstr_null (); -} - -SDB_IPI Rangstr json_get (const char *js, const char *p) { - int x, n = 0; - size_t rst; - Rangstr rj2, rj = rangstr_new (js); - Rangstr rs = rangstr_new (p); - json_path_first (&rs); - do { - rst = rs.t; - rs.f++; - x = rangstr_find (&rs, '['); - rs.f--; - if (x != -1) - rs.t = x; -#if 0 -printf ("x = %d f = %d t = %d\n", x, rs.f, rs.t); -fprintf (stderr, "source (%s)\n", rangstr_dup (&rs)); -fprintf (stderr, "onjson (%s)\n", rangstr_dup (&rj)); -#endif - if (rst == rs.t && n && rj.p) // last key - break; - if (!rj.p) break; - do { - rj2 = json_find (rangstr_str (&rj), &rs); -//fprintf (stderr, "++ (%s)(%d vs %d)\n", rangstr_dup (&rs), x, rs.t); -//if (rj.p[rj.f]=='[') { break; } -//fprintf (stderr, "ee %c\n", rj.p[rj.f]); - if (!rj2.p) { - if (!rj.p[rj.t]) return rj2; - break; - } - rj = rj2; -#if 0 -fprintf (stderr, "-- (%s)\n", rangstr_dup (&rj)); -#endif - } while (json_path_next (&rs)); -//if (!rj.p) return rj; -#if 0 -printf ("x = %d\n", x); printf ("rsf = %d\n", rs.f); -fprintf (stderr, "xxx (%s)\n", rangstr_dup (&rj)); -return rj; -#endif - if ((rst == rs.t && n && rj.p)) // last key - break; - rs.t = rst; - rs.f = x; - n++; - } while (x != -1); - return rj; -} diff --git a/shlr/sdb/src/json/rangstr.c b/shlr/sdb/src/json/rangstr.c deleted file mode 100644 index 6536ad4da66dc..0000000000000 --- a/shlr/sdb/src/json/rangstr.c +++ /dev/null @@ -1,110 +0,0 @@ -/* Copyleft 2012-2022 - sdb - pancake */ - -#ifndef RANGSTR_C -#define RANGSTR_C - -#include -#include -#include -#include "sdb/rangstr.h" - -SDB_IPI Rangstr rangstr_null(void) { - Rangstr rs = {0, 0, 0, 0, 0}; - return rs; -} - -SDB_IPI Rangstr rangstr_new(const char *s) { - Rangstr rs; - if (!s) { - return rangstr_null (); - } - rs.f = 0; - rs.next = 1; - rs.t = strlen (s); - rs.p = s; - rs.type = 0; - return rs; -} - -SDB_IPI int rangstr_length(Rangstr* rs) { - if (rs->t > rs->f) { - return rs->t - rs->f; - } - return 0; -} - -SDB_IPI int rangstr_int(Rangstr *s) { - if (!s || !s->p) { - return 0; - } - - const int base = 10; - int mul = 1; - int ch, n = 0; - size_t i = 0; - if (s->p[s->f]=='[') { - i++; - } - if (s->p[s->f]=='-') { - mul = -1; - i += s->f + 1; - } else { - i += s->f; - } - for (; i < s->t; i++) { - ch = s->p[i]; - if (ch < '0' || ch > '9') { - break; - } - n = n * base + (ch - '0'); - } - return n * mul; -} - -SDB_IPI char *rangstr_dup(Rangstr *rs) { - if (!rs->p) { - return NULL; - } - int len = rangstr_length (rs); - char *p = (char *)sdb_gh_malloc (len + 1); - if (p) { - memcpy (p, rs->p + rs->f, len); - p[len] = 0; - } - return p; -} - -SDB_IPI Rangstr rangstr_news(const char *s, RangstrType *res, int i) { - Rangstr rs; - rs.next = 1; - rs.f = res[i]; - rs.t = res[i]+res[i+1]; - rs.p = s; - rs.type = 0; - return rs; -} - -SDB_IPI int rangstr_cmp(Rangstr *a, Rangstr *b) { - int la = a->t - a->f; - int lb = b->t - b->f; - int lbz = strlen (b->p + b->f); - if (lbz < lb) { - lb = lbz; - } - if (la != lb) { - return 1; - } - return memcmp (a->p + a->f, b->p + b->f, la); -} - -SDB_IPI int rangstr_find(Rangstr* a, char ch) { - size_t i = a->f; - while (i < a->t && a->p[i] && a->p[i] != ch) i++; - return (i < a->t && a->p[i]) ? (int) i: -1; -} - -SDB_IPI const char *rangstr_str(Rangstr* rs) { - return rs->p + rs->f; -} - -#endif diff --git a/shlr/sdb/src/json/test.c b/shlr/sdb/src/json/test.c deleted file mode 100644 index 3fc3b9be491d4..0000000000000 --- a/shlr/sdb/src/json/test.c +++ /dev/null @@ -1,13 +0,0 @@ -/* Copyleft 2012 - sdb (aka SimpleDB) - pancake */ - -int test_parse_json_path() { - Rangstr rs = rangstr_new ("ping.board[\"pop\"][1][2][\"caca\"].panda"); - json_path_first (&rs); - do { - printf (" - "); - rangstr_print (&rs); - printf (" Int (%d)", rangstr_int (&rs)); - printf ("\n"); - } while (json_path_next (&rs)); - printf ("--\n"); -} diff --git a/shlr/sdb/src/json/test.json b/shlr/sdb/src/json/test.json deleted file mode 100644 index 73c12da0fb181..0000000000000 --- a/shlr/sdb/src/json/test.json +++ /dev/null @@ -1,4 +0,0 @@ -{ "glossary": { "title": "example glossary", "page": 1, "GlossDiv": { "title": "First gloss title", -"GlossList": { "GlossEntry": { "ID": "SGML", "SortAs": "SGML", "GlossTerm": "Standard Generalized Markup Language", -"Acronym": "SGML", "Abbrev": "ISO 8879:1986", "GlossDef": { "para": "A meta-markup language, used to create markup languages such as DocBook.", -"GlossSeeAlso": [ "OK", "GML", "XML" ] }, "GlossSee": "markup" } } } } } diff --git a/shlr/sdb/src/lock.c b/shlr/sdb/src/lock.c deleted file mode 100644 index 7158f2291a92c..0000000000000 --- a/shlr/sdb/src/lock.c +++ /dev/null @@ -1,76 +0,0 @@ -/* sdb - MIT - Copyright 2012-2022 - pancake */ - -#include -#include "sdb/sdb.h" - -SDB_API bool sdb_lock_file(const char *f, char *buf, size_t buf_size) { - size_t len; - if (!f || !*f || !buf || !buf_size) { - return false; - } - len = strlen (f); - if (len + 10 > buf_size) { - return false; - } - memcpy (buf, f, len); - strcpy (buf + len, ".lock"); - return true; -} - -SDB_API bool sdb_lock(const char *s) { - char pidstr[64]; - if (!s) { - return false; - } - int fd = open (s, O_CREAT | O_TRUNC | O_WRONLY | O_EXCL, SDB_MODE); - if (fd == -1) { - return false; - } -#if __wasi__ || EMSCRIPTEN || __MINGW32__ - char *pid = sdb_itoa (rand (), 10, pidstr, sizeof (pidstr)); -#else - char *pid = sdb_itoa (getpid (), 10, pidstr, sizeof (pidstr)); -#endif - if (pid) { - if ((write (fd, pid, strlen (pid)) < 0) - || (write (fd, "\n", 1) < 0)) { - close (fd); - return false; - } - } - close (fd); - return true; -} - -SDB_API int sdb_lock_wait(const char *s) { - // TODO use flock() here - // wait forever here? - while (!sdb_lock (s)) { - // TODO: if waiting too much return 0 -#if __SDB_WINDOWS__ - Sleep (500); // hack -#else - // TODO use lockf() here .. flock is not much useful (fd, LOCK_EX); - sleep (1); // hack -#endif - } - return 1; -} - -SDB_API void sdb_unlock(const char *s) { - //flock (fd, LOCK_UN); - unlink (s); -} - -#if TEST -main () { - int r; - r = sdb_lock (".lock"); - printf ("%d\n", r); - r = sdb_lock (".lock"); - printf ("%d\n", r); - sdb_unlock (".lock"); - r = sdb_lock (".lock"); - printf ("%d\n", r); -} -#endif diff --git a/shlr/sdb/src/ls.c b/shlr/sdb/src/ls.c deleted file mode 100644 index a558f6df6d387..0000000000000 --- a/shlr/sdb/src/ls.c +++ /dev/null @@ -1,397 +0,0 @@ -/* sdb - MIT - Copyright 2007-2022 - pancake, alvaro */ - -#include -#include "sdb/ls.h" -#include "sdb/heap.h" - -#if 0 - 1 128= 7s / 32 - 2 64 = 7s / 30s - 3 32 = 6s / 30s - 4 24 = 6s / 30s - 5 4 = 7s / 30s -#endif - -#define MERGELIMIT 24 - -SDB_API SdbList *ls_newf(SdbListFree freefn) { - SdbList *list = ls_new (); - if (list) { - list->free = freefn; - } - return list; -} - -SDB_API SdbList *ls_new(void) { - SdbList *list = R_NEW0 (SdbList); - if (!list) { - return NULL; - } - return list; -} - -static void ls_insertion_sort_iter(SdbListIter *iter, SdbListComparator cmp) { - SdbListIter *it, *it2; - for (it = iter; it && it->data; it = it->n) { - for (it2 = it->n; it2 && it2->data; it2 = it2->n) { - if (cmp (it->data, it2->data) > 0) { - void *t = it->data; - it->data = it2->data; - it2->data = t; - } - } - } -} - -static void ls_insertion_sort(SdbList *list, SdbListComparator cmp) { - ls_insertion_sort_iter (list->head, cmp); -} - -static SdbListIter *_merge(SdbListIter *first, SdbListIter *second, SdbListComparator cmp) { - SdbListIter *next = NULL, *result = NULL, *head = NULL; - while (first || second) { - if (!second) { - next = first; - first = first->n; - } else if (!first) { - next = second; - second = second->n; - } else if (cmp (first->data, second->data) <= 0) { - next = first; - first = first->n; - } else { - next = second; - second = second->n; - } - if (!head) { - result = next; - head = result; - head->p = NULL; - } else { - result->n = next; - next->p = result; - result = result->n; - } - } - head->p = NULL; - next->n = NULL; - return head; -} - -static SdbListIter * _sdb_list_split(SdbListIter *head) { - SdbListIter *fast; - SdbListIter *slow; - if (!head || !head->n) { - return head; - } - slow = head; - fast = head; - int count = 0; - while (fast && fast->n && fast->n->n) { - fast = fast->n->n; - slow = slow->n; - count++; - } - if (count < MERGELIMIT) { - return NULL; - } - SdbListIter *tmp = slow->n; - slow->n = NULL; - return tmp; -} - -static SdbListIter * _merge_sort(SdbListIter *head, SdbListComparator cmp) { - if (!head || !head->n) { - return head; - } - SdbListIter *second = _sdb_list_split (head); - if (second) { - head = _merge_sort (head, cmp); - second = _merge_sort (second, cmp); - return _merge (head, second, cmp); - } - ls_insertion_sort_iter (head, cmp); - return head; -} - -SDB_API bool ls_merge_sort(SdbList *list, SdbListComparator cmp) { - if (!cmp) { - return false; - } - if (list && list->head && cmp) { - SdbListIter *iter; - list->head = _merge_sort (list->head, cmp); - //update tail reference - iter = list->head; - while (iter && iter->n) { - iter = iter->n; - } - list->tail = iter; - list->sorted = true; - } - return true; -} - -SDB_API bool ls_sort(SdbList *list, SdbListComparator cmp) { - if (!cmp || !list || list->cmp == cmp) { - return false; - } - if (list->length > MERGELIMIT) { - ls_merge_sort (list, cmp); - } else { - ls_insertion_sort (list, cmp); - } - list->cmp = cmp; - list->sorted = true; - return true; -} - -SDB_API void ls_delete(SdbList *list, SdbListIter *iter) { - if (!list || !iter) { - return; - } - ls_split_iter (list, iter); - if (list->free && iter->data) { - list->free (iter->data); - iter->data = NULL; - } - sdb_gh_free (iter); -} - -SDB_API bool ls_delete_data(SdbList *list, void *ptr) { - void *kvp; - SdbListIter *iter; - ls_foreach (list, iter, kvp) { - if (ptr == kvp) { - ls_delete (list, iter); - return true; - } - } - return false; -} - -SDB_API void ls_split_iter(SdbList *list, SdbListIter *iter) { - if (!list || !iter) { - return; - } - if (list->head == iter) { - list->head = iter->n; - } - if (list->tail == iter) { - list->tail = iter->p; - } - if (iter->p) { - iter->p->n = iter->n; - } - if (iter->n) { - iter->n->p = iter->p; - } - list->length--; -} - -SDB_API void ls_destroy(SdbList *list) { - SdbListIter *it; - if (!list) { - return; - } - it = list->head; - while (it) { - SdbListIter *next = it->n; - ls_delete (list, it); - it = next; - } - list->head = list->tail = NULL; - list->length = 0; -} - -SDB_API void ls_free(SdbList *list) { - if (!list) { - return; - } - ls_destroy (list); - list->free = NULL; - sdb_gh_free (list); -} - -SDB_API SdbListIter *ls_append(SdbList *list, void *data) { - SdbListIter *it; - if (!list) { - return NULL; - } - it = R_NEW (SdbListIter); - if (!it) { - return NULL; - } - if (list->tail) { - list->tail->n = it; - } - it->data = data; - it->p = list->tail; - it->n = NULL; - list->tail = it; - if (!list->head) { - list->head = it; - } - list->length++; - list->sorted = false; - return it; -} - -SDB_API SdbListIter *ls_prepend(SdbList *list, void *data) { - SdbListIter *it = R_NEW (SdbListIter); - if (!it) { - return NULL; - } - if (list->head) { - list->head->p = it; - } - it->data = data; - it->n = list->head; - it->p = NULL; - list->head = it; - if (!list->tail) { - list->tail = it; - } - list->length++; - list->sorted = false; - return it; -} - -SDB_API void *ls_pop(SdbList *list) { - void *data = NULL; - SdbListIter *iter; - if (list) { - if (list->tail) { - iter = list->tail; - if (list->head == list->tail) { - list->head = list->tail = NULL; - } else { - list->tail = iter->p; - list->tail->n = NULL; - } - data = iter->data; - sdb_gh_free (iter); - list->length--; - } - return data; - } - return NULL; -} - -SDB_API SdbList *ls_clone(SdbList *list) { - if (!list) { - return NULL; - } - SdbList *r = ls_new (); // ownership of elements stays in original list - if (!r) { - return NULL; - } - void *v; - SdbListIter *iter; - ls_foreach (list, iter, v) { - ls_append (r, v); - } - return r; -} - -SDB_API int ls_join(SdbList *list1, SdbList *list2) { - if (!list1 || !list2) { - return 0; - } - if (!(list2->length)) { - return 0; - } - if (!(list1->length)) { - list1->head = list2->head; - list1->tail = list2->tail; - } else { - list1->tail->n = list2->head; - list2->head->p = list1->tail; - list1->tail = list2->tail; - list1->tail->n = NULL; - } - list1->length += list2->length; - list2->head = list2->tail = NULL; - list1->sorted = false; - return 1; -} - - -SDB_API SdbListIter *ls_insert(SdbList *list, int n, void *data) { - SdbListIter *it, *item; - int i; - if (list) { - if (!list->head || !n) { - return ls_prepend (list, data); - } - for (it = list->head, i = 0; it && it->data; it = it->n, i++) { - if (i == n) { - item = R_NEW0 (SdbListIter); - if (!item) { - return NULL; - } - item->data = data; - item->n = it; - item->p = it->p; - if (it->p) { - it->p->n = item; - } - it->p = item; - list->length++; - list->sorted = false; - return item; - } - } - } - return ls_append (list, data); -} - - -SDB_API void *ls_pop_head(SdbList *list) { - void *data = NULL; - SdbListIter *iter; - if (list) { - if (list->head) { - iter = list->head; - if (list->head == list->tail) { - list->head = list->tail = NULL; - } else { - list->head = iter->n; - list->head->p = NULL; - } - data = iter->data; - sdb_gh_free (iter); - } - list->length--; - return data; - } - return NULL; -} - - -SDB_API int ls_del_n(SdbList *list, int n) { - SdbListIter *it; - int i; - if (!list) { - return false; - } - for (it = list->head, i = 0; it && it->data; it = it->n, i++) - if (i == n) { - if (!it->p && !it->n) { - list->head = list->tail = NULL; - } else if (!it->p) { - it->n->p = NULL; - list->head = it->n; - } else if (!it->n) { - it->p->n = NULL; - list->tail = it->p; - } else { - it->p->n = it->n; - it->n->p = it->p; - } - sdb_gh_free (it); - list->length--; - return true; - } - return false; -} diff --git a/shlr/sdb/src/main.c b/shlr/sdb/src/main.c deleted file mode 100644 index e7d8248d21420..0000000000000 --- a/shlr/sdb/src/main.c +++ /dev/null @@ -1,1088 +0,0 @@ -/* sdb - MIT - Copyright 2011-2022 - pancake */ - -#include -#include -#ifndef HAVE_SYSTEM -#define HAVE_SYSTEM 1 -#endif -#include -#if USE_DLSYSTEM -#include -#endif - -#if __SDB_WINDOWS__ -#define ftruncate _chsize -#endif - -// TODO: enums must be uppercase -typedef enum { - text, - zero, - json, - cgen, - diff, - perf -} MainFormat; - -// TODO: enums must be uppercase -typedef enum { - nope = 0, - dash, - eqeq, - dobl -} MainCreate; - -typedef struct { - int argc; - const char **argv; - int argi; - int db0; - bool failed; - const char *db; - const char *outfile; - const char *db2; - const char *grep; - ut32 options; - bool textmode; - MainCreate create; - MainFormat format; -} MainOptions; - -static bool save = false; -static Sdb *s = NULL; -static ut32 options = SDB_OPTION_FS | SDB_OPTION_NOSTAMP; - -static void terminate(int sig UNUSED) { - if (!s) { - return; - } - if (save && !sdb_sync (s)) { - sdb_free (s); - s = NULL; - exit (1); - } - sdb_gh_fini (); - //sdb_free (s); - exit (sig < 2? sig: 0); -} - -static int write_null(void) { - // success = write returns 1 == 1 -> 0 - // failure = write returns 0 != 1 -> 1 - return write (1, "", 1) != 1; -} - -#define BS 128 -#define USE_SLURPIN 1 - -static char *slurp(FILE *f, size_t *sz) { - int blocksize = BS; - static int bufsize = BS; - static char *next = NULL; - static size_t nextlen = 0; - size_t len, rr, rr2; - char *tmp, *buf = NULL; - if (sz) { - *sz = 0; - } -#if USE_SLURPIN - if (!sz) { - /* this is faster but have limits */ - /* run test/add10k.sh script to benchmark */ - const int buf_size = 96096; - - buf = (char *)sdb_gh_calloc (1, buf_size); - if (!buf) { - return NULL; - } - - if (!fgets (buf, buf_size, f)) { - sdb_gh_free (buf); - return NULL; - } - if (feof (f)) { - sdb_gh_free (buf); - return NULL; - } - - size_t buf_len = strlen (buf); - if (buf_len > 0) { - buf[buf_len - 1] = '\0'; - } - - char *newbuf = (char *)sdb_gh_realloc (buf, buf_len + 1); - return newbuf? newbuf: buf; - } -#endif - buf = (char *)sdb_gh_calloc (BS + 1, 1); - if (!buf) { - return NULL; - } - - len = 0; - for (;;) { - if (next) { - sdb_gh_free (buf); - buf = next; - bufsize = nextlen + blocksize; - //len = nextlen; - rr = nextlen; - rr2 = fread (buf + nextlen, 1, blocksize, f); - if (rr2 > 0) { - rr += rr2; - bufsize += rr2; - } - next = NULL; - nextlen = 0; - } else { - rr = fread (buf + len, 1, blocksize, f); - } - if (rr < 1) { // EOF - buf[len] = 0; - next = NULL; - break; - } - len += rr; - //buf[len] = 0; -#if !USE_SLURPIN - if (!sz) { - char *nl = strchr (buf, '\n'); - if (nl) { - *nl++ = 0; - int nlen = nl - buf; - nextlen = len - nlen; - if (nextlen > 0) { - next = (char *)sdb_gh_malloc (nextlen + blocksize + 1); - if (!next) { - eprintf ("Cannot malloc %d\n", nextlen); - break; - } - memcpy (next, nl, nextlen); - if (!*next) { - next = NULL; - } else { - // continue; - } - } else { - next = NULL; - nextlen = 0; //strlen (next);; - } - break; - } - } -#endif - bufsize += blocksize; - tmp = (char *)sdb_gh_realloc (buf, bufsize + 1); - if (!tmp) { - bufsize -= blocksize; - break; - } - memset (tmp + bufsize - blocksize, 0, blocksize); - buf = tmp; - } - if (sz) { - *sz = len; - } - if (len < 1) { - sdb_gh_free (buf); - return buf = NULL; - } - buf[len] = 0; - return buf; -} - -#if USE_MMAN -static void synchronize(int sig UNUSED) { - // TODO: must be in sdb_sync() or wat? - sdb_sync (s); - Sdb *n = sdb_new (s->path, s->name, s->lock); - if (n) { - sdb_config (n, options); - sdb_free (s); - s = n; - } -} -#endif - -static char* get_name(const char*name) { - if (!name || !*name) { - return NULL; - } - const char *l = name + strlen (name) - 1; - while (*l && l > name) { - if (*l == '/') { - name = l + 1; - break; - } - l--; - } - char *n = sdb_strdup (name); - char *v, *d = n; - for (v = (char*)n; *v; v++) { - if (*v == '.') { - break; - } - *d++ = *v; - } - *d++ = 0; - return n; -} - -static char* get_cname(const char*name) { - if (!name || !*name) { - return NULL; - } - const char *l = name + strlen (name) - 1; - while (*l && l > name) { - if (*l == '/') { - name = l + 1; - break; - } - l--; - } - char *n = sdb_strdup (name); - char *v, *d = n; - for (v = (char*)n; *v; v++) { - if (*v == '/' || *v == '-') { - *d++ = '_'; - continue; - } - if (*v == '.') { - break; - } - *d++ = *v; - } - *d++ = 0; - return n; -} - -static char *escape(const char *b, int ch) { - char *a = (char *)sdb_gh_calloc ((1 + strlen (b)), 4); - char *c = a; - while (*b) { - if (*b == ch) { - *c = '_'; - } else - switch (*b) { - case '"': - *c++ = '\\'; - *c++ = '"'; - break; - case '\\': - *c++ = '\\'; - *c++ = '\\'; - break; - case '\r': - *c++ = '\\'; - *c++ = 'r'; - break; - case '\n': - *c++ = '\\'; - *c++ = 'n'; - break; - case '\t': - *c++ = '\\'; - *c++ = 't'; - break; -#if 0 - case ' ': - *c++ = '\\'; - *c++ = 's'; - break; -#endif - default: - *c = *b; - break; - } - b++; - c++; - } - return a; -} - -static void sdb_dump_cb(MainOptions *mo, const char *k, const char *v, const char *comma) { - switch (mo->format) { - case json: - if (!strcmp (v, "true") || !strcmp (v, "false")) { - printf ("%s\"%s\":%s", comma, k, v); - } else if (sdb_isnum (v)) { - printf ("%s\"%s\":%" PRIu64, comma, k, sdb_atoi (v)); - } else if (*v == '{' || *v == '[') { - printf ("%s\"%s\":%s", comma, k, v); - } else { - printf ("%s\"%s\":\"%s\"", comma, k, v); - } - break; - case perf: - case cgen: - { - char *a = escape (k, ','); - char *b = escape (v, 0); - if (mo->textmode) { - printf (" {\"%s\",\"%s\"}, \n", a, b); - } else { - printf ("%s,\"%s\"\n", a, b); - } - sdb_gh_free (a); - sdb_gh_free (b); - } - break; - case zero: - printf ("%s=%s", k, v); - break; - default: - printf ("%s=%s\n", k, v); - break; - } -} - -static void cgen_header(MainOptions *mo, const char *cname) { - if (mo->textmode) { - printf ("// SDB-CGEN V" SDB_VERSION "\n"); - printf ("// gcc -DMAIN=1 %s.c ; ./a.out > %s.h\n", cname, cname); - printf ("#include \n"); - printf ("#include \n"); - printf ("#include \n"); - printf ("\n"); - printf ("struct kv { const char *name; const char *value; };\n"); - printf ("static const struct kv kvs[] = {\n"); - } else { - printf ("%%{\n"); - printf ("// gperf -aclEDCIG --null-strings -H sdb_hash_c_%s -N sdb_get_c_%s -t %s.gperf > %s.c\n", cname, cname, cname, cname); - printf ("// gcc -DMAIN=1 %s.c ; ./a.out > %s.h\n", cname, cname); - printf ("#include \n"); - printf ("#include \n"); - printf ("#include \n"); - printf ("%%}\n"); - printf ("\n"); - printf ("struct kv { const char *name; const char *value; };\n"); - printf ("%%%%\n"); - } -} - -// TODO rename gperf with cgen -static void cgen_footer(MainOptions *mo, const char *name, const char *cname) { - if (mo->textmode) { - printf (" {NULL, NULL}\n"); - printf ("};\n"); - printf ("// %p\n", cname); - printf ("// TODO\n"); - printf ("typedef int (*GperfForeachCallback)(void *user, const char *k, const char *v);\n"); - printf ("int gperf_%s_foreach(GperfForeachCallback cb, void *user) {\n", cname); - printf (" int i = 0; while (kvs[i].name) {\n"); - printf (" cb (user, kvs[i].name, kvs[i].value);\n"); - printf (" i++;}\n"); - printf (" return 0;\n"); - printf ("}\n"); - printf ("const char *gperf_%s_get(const char *s) {\n", cname); - printf (" int i = 0; while (kvs[i].name) {\n"); - printf (" if (!strcmp (s, kvs[i].name)) return kvs[i].value;\n"); - printf (" i++;}\n"); - printf (" return NULL;\n"); - printf ("}\n"); - printf ("#define sdb_hash_c_%s(x,y) gperf_%s_hash(x)\n", cname, cname); - printf ("const unsigned int gperf_%s_hash(const char *s) {\n", cname); - printf (" int sum = strlen (s);\n"); - printf (" while (*s) { sum += *s; s++; }\n"); - printf (" return sum;\n"); - printf ("}\n"); - printf ( - "struct {const char *name;void *get;void *hash;void *foreach;} gperf_%s = {\n" - " .name = \"%s\",\n" - " .get = &gperf_%s_get,\n" - " .hash = &gperf_%s_hash,\n" - " .foreach = &gperf_%s_foreach\n" - "};\n", cname, name, cname, cname, cname); - printf ( - "\n" - "#if MAIN\n" - "int main () {\n" - " const char *s = ((char*(*)(char*))gperf_%s.get)(\"foo\");\n" - " printf (\"%%s\\n\", s);\n" - "}\n" - "#endif\n", cname); - return; - } - printf ("%%%%\n"); - printf ("// SDB-CGEN V" SDB_VERSION "\n"); - printf ("// %p\n", cname); - printf ("typedef int (*GperfForeachCallback)(void *user, const char *k, const char *v);\n"); - printf ("int gperf_%s_foreach(GperfForeachCallback cb, void *user) {\n", cname); - printf ("\tint i;for (i=0;iname, w->value)) return 0;\n"); - printf ("}\n"); - printf ("return 1;}\n"); - printf ("const char* gperf_%s_get(const char *s) {\n", cname); - printf ("\tconst struct kv *o = sdb_get_c_%s (s, strlen(s));\n", cname); - printf ("\treturn o? o->value: NULL;\n"); - printf ("}\n"); - printf ("const unsigned int gperf_%s_hash(const char *s) {\n", cname); - printf ("\treturn sdb_hash_c_%s(s, strlen (s));\n", cname); - printf ("}\n"); - printf ( - "struct {const char*name;void*get;void*hash;void *foreach;} gperf_%s = {\n" - "\t.name = \"%s\",\n" - "\t.get = &gperf_%s_get,\n" - "\t.hash = &gperf_%s_hash,\n" - "\t.foreach = &gperf_%s_foreach\n" - "};\n" - "\n" - "#if MAIN\n" - "int main () {\n" - " char line[1024];\n" - " FILE *fd = fopen (\"%s.gperf\", \"r\");\n" - " if (!fd) {\n" - " fprintf (stderr, \"Cannot open %s.gperf\\n\");\n" - " return 1;\n" - " }\n" - " int mode = 0;\n" - " printf (\"#ifndef INCLUDE_%s_H\\n\");\n" - " printf (\"#define INCLUDE_%s_H 1\\n\");\n" - " while (!feof (fd)) {\n" - " *line = 0;\n" - " fgets (line, sizeof (line), fd);\n" - " if (mode == 1) {\n" - " char *comma = strchr (line, ',');\n" - " if (comma) {\n" - " *comma = 0;\n" - " char *up = sdb_strdup (line);\n" - " char *p = up; while (*p) { *p = toupper (*p); p++; }\n" - " printf (\"#define GPERF_%s_%%s %%d\\n\",\n" - " line, sdb_hash_c_%s (line, comma - line));\n" - " }\n" - " }\n" - " if (*line == '%%' && line[1] == '%%')\n" - " mode++;\n" - " }\n" - " printf (\"#endif\\n\");\n" - "}\n" - "#endif\n", - cname, cname, cname, cname, cname, - name, name, - cname, cname, cname, cname - ); - printf ("\n"); -} - -static int sdb_dump(MainOptions *mo) { - const char *dbname = mo->db; - const char *expgrep = mo->grep; - const bool grep = mo->grep; - - char *v = NULL; - char k[SDB_MAX_KEY] = { 0 }; - const char *comma = ""; - Sdb *db = sdb_new (NULL, dbname, 0); - if (!db) { - return 1; - } - char *cname = get_cname (dbname); - char *name = get_name (dbname); - sdb_config (db, options); - sdb_dump_begin (db); - switch (mo->format) { - case cgen: - case perf: - cgen_header (mo, cname); - break; - case json: - printf ("{"); - break; - default: - break; - } - - int ret = 0; - if (db->fd == -1) { - SdbList *l = sdb_foreach_list (db, true); - if (!mo->textmode && mo->format == cgen && ls_length (l) > SDB_MAX_GPERF_KEYS) { - ls_free (l); - eprintf ("Error: gperf doesn't work with datasets with more than 15.000 keys.\n"); - ret = -1; - goto fail; - } - SdbKv *kv; - SdbListIter *it; - ls_foreach_cast (l, it, SdbKv*, kv) { - const char *sk = sdbkv_key (kv); - const char *sv = sdbkv_value (kv); - if (sv && *sv && grep && !strstr (sk, expgrep) && !strstr (sv, expgrep)) { - continue; - } - sdb_dump_cb (mo, sk, sv, comma); - comma = ","; - } - ls_free (l); - } else { - int count = 0; - while (sdb_dump_dupnext (db, k, &v, NULL)) { - if (v && *v && grep && !strstr (k, expgrep) && !strstr (v, expgrep)) { - sdb_gh_free (v); - continue; - } - sdb_dump_cb (mo, k, v, comma); - comma = ","; - sdb_gh_free (v); - if (!mo->textmode && mo->format == cgen && count++ > SDB_MAX_GPERF_KEYS) { - eprintf ("Error: gperf doesn't work with datasets with more than 15.000 keys.\n"); - ret = -1; - } - } - } - if (ret == 0) { - switch (mo->format) { - case zero: - fflush (stdout); - ret = write_null (); - break; - case perf: - case cgen: - cgen_footer (mo, name, cname); - break; - case json: - printf ("}\n"); - break; - default: - break; - } - } -fail: - sdb_gh_free (cname); - sdb_gh_free (name); - sdb_free (db); - return ret; -} - -static int insertkeys(Sdb *db, const char **args, int nargs, int mode) { - int must_save = 0; - if (args && nargs > 0) { - int i; - for (i = 0; i < nargs; i++) { - switch (mode) { - case '-': - if (sdb_query (db, args[i])) { - must_save = true; - } - break; - case '=': - if (strchr (args[i], '=')) { - char *v, *kv = (char *) sdb_strdup (args[i]); - v = strchr (kv, '='); - if (v) { - *v++ = 0; - sdb_disk_insert (db, kv, v); - } - sdb_gh_free (kv); - } - break; - } - } - } - return must_save; -} - -static int createdb(const char *f, const char **args, int nargs) { - s = sdb_new (NULL, f, 0); - if (!s) { - eprintf ("Cannot create database\n"); - return 1; - } - sdb_config (s, options); - int ret = 0; - if (args) { - int i; - for (i = 0; i < nargs; i++) { - if (!sdb_text_load (s, args[i])) { - eprintf ("Failed to load text sdb from %s\n", args[i]); - } - } - } else { - size_t len; - char *in = slurp (stdin, &len); - if (!in) { - return 0; - } - if (!sdb_text_load_buf (s, in, len)) { - eprintf ("Failed to read text sdb from stdin\n"); - } - sdb_gh_free (in); - } - sdb_sync (s); - return ret; -} - -static int showusage(int o) { - printf ("usage: sdb [-0cCdDehjJtv|-D A B] [-|db] " - "[.file]|[-=]|==||[-+][(idx)key[:json|=value] ..]\n"); - if (o == 2) { - printf (" -0 terminate results with \\x00\n" - " -c count the number of keys database\n" - " -C create foo.{c,h} for embedding (uses gperf)\n" - " -d decode base64 from stdin\n" - " -D diff two databases\n" - " -e encode stdin as base64\n" - " -g [..] grep expression\n" - " -G print database in gperf format\n" - " -h show this help\n" - " -j output in json\n" - " -o [f] output file name for -C -t\n" - " -J enable journaling\n" - " -t use textmode (for -C)\n" - " -v show version information\n"); - return 0; - } - return o; -} - -static int showversion(void) { - printf ("sdb " SDB_VERSION "\n"); - fflush (stdout); - return 0; -} - -static int jsonIndent(void) { - size_t len; - char *out; - char *in = slurp (stdin, &len); - if (!in) { - return 0; - } - out = sdb_json_indent (in, " "); - if (!out) { - sdb_gh_free (in); - return 1; - } - puts (out); - sdb_gh_free (out); - sdb_gh_free (in); - return 0; -} - -static int base64encode(void) { - char *out; - size_t len = 0; - ut8 *in = (ut8 *) slurp (stdin, &len); - if (!in) { - return 0; - } - out = sdb_encode (in, (int)len); - if (!out) { - sdb_gh_free (in); - return 1; - } - puts (out); - sdb_gh_free (out); - sdb_gh_free (in); - return 0; -} - -static int base64decode(void) { - ut8 *out; - size_t len, ret = 1; - char *in = slurp (stdin, &len); - if (in) { - int declen; - out = sdb_decode (in, &declen); - if (out && declen >= 0) { - ret = (write (1, out, declen) == declen)? 0: 1; - } - sdb_gh_free (out); - sdb_gh_free (in); - } - return ret; -} - -static void dbdiff_cb(const SdbDiff *diff, void *user) { - char sbuf[512]; - int r = sdb_diff_format (sbuf, sizeof(sbuf), diff); - if (r < 0) { - return; - } - char *buf = sbuf; - char *hbuf = NULL; - if ((size_t)r >= sizeof (sbuf)) { - hbuf = (char *)sdb_gh_malloc (r + 1); - if (!hbuf) { - return; - } - r = sdb_diff_format (hbuf, r + 1, diff); - if (r < 0) { - goto beach; - } - } - printf ("\x1b[%sm%s\x1b[0m\n", diff->add ? "32" : "31", buf); -beach: - sdb_gh_free (hbuf); -} - -static bool dbdiff(const char *a, const char *b) { - Sdb *A = sdb_new (NULL, a, 0); - Sdb *B = sdb_new (NULL, b, 0); - bool equal = sdb_diff (A, B, dbdiff_cb, NULL); - sdb_free (A); - sdb_free (B); - return equal; -} - -static int showcount(const char *db) { - ut32 d; - s = sdb_new (NULL, db, 0); - if (sdb_stats (s, &d, NULL)) { - printf ("%d\n", d); - } - // TODO: show version, timestamp information - sdb_free (s); - return 0; -} - -static int sdb_system(const char *cmd) { - static int (*sys)(const char *cmd) = NULL; - if (!sys) { -#if HAVE_SYSTEM -#if USE_DLSYSTEM - sys = dlsym (NULL, "system"); - if (!sys) { - sys = puts; - return -1; - } -#else - sys = system; -#endif -#endif - } - return sys (cmd); -} - -static int gen_gperf(MainOptions *mo, const char *file, const char *name) { - const size_t buf_size = 4096; - char *buf = (char *)sdb_gh_malloc (buf_size); - if (!buf) { - return -1; - } - size_t out_size = strlen (file) + 32; - char *out = (char *)sdb_gh_malloc (out_size); - if (!out) { - sdb_gh_free (buf); - return -1; - } - if (mo->outfile) { - snprintf (out, out_size, "%s", mo->outfile); - } else { - snprintf (out, out_size, "%s.%s", name, (mo->textmode)? "c": "gperf"); - } - int wd = open (out, O_RDWR, 0644); - if (wd == -1) { - wd = open (out, O_RDWR | O_CREAT, 0644); - } else { - if (ftruncate (wd, 0) == -1) { - sdb_gh_free (out); - sdb_gh_free (buf); - close (wd); - return -1; - } - } - int rc = -1; - if (wd != -1) { -#if __wasi__ || EMSCRIPTEN - rc = sdb_dump (mo); // file, MODE_CGEN, false, NULL); - fflush (stdout); -#else - dup2 (1, 999); - dup2 (wd, 1); - rc = sdb_dump (mo); // file, MODE_CGEN, false, NULL); - fflush (stdout); - close (wd); - dup2 (999, 1); -#endif - } else { - eprintf ("Cannot create .%s\n", out); - } - if (mo->textmode) { - // dont do much - } else { - if (rc == 0) { - char *cname = get_cname (name); - if (!cname) { - return -1; - } - snprintf (buf, buf_size, "gperf -aclEDCIG --null-strings -H sdb_hash_c_%s" - " -N sdb_get_c_%s -t %s.gperf > %s.c\n", cname, cname, name, name); - sdb_gh_free (cname); - rc = sdb_system (buf); - if (rc == 0) { - snprintf (buf, buf_size, "gcc -DMAIN=1 %s.c ; ./a.out > %s.h\n", name, name); - rc = sdb_system (buf); - if (rc == 0) { - eprintf ("Generated %s.c and %s.h\n", name, name); - } - } else { - eprintf ("Cannot run gperf: %s\n", buf); - } - } else { - eprintf ("Outdated sdb binary in PATH?\n"); - } - } - sdb_gh_free (out); - sdb_gh_free (buf); - return rc; -} - -static const char *main_argparse_getarg(MainOptions *mo) { - int cur = mo->argi; - if (mo->argi + 1 >= mo->argc) { - return NULL; - } - mo->argi++; - mo->db0++; - return mo->argv[cur]; -} - -static bool main_argparse_flag(MainOptions *mo, char flag) { - mo->argi++; - switch (flag) { - case '0': - mo->format = zero; - break; - case 'h': - return showusage (2); - case 'o': - mo->outfile = main_argparse_getarg (mo); - break; - case 'v': - return showversion (); - case 'e': - return base64encode (); - case 'd': - return base64decode (); - case 'j': - mo->format = json; - if (mo->argi >= mo->argc) { - return jsonIndent (); - } - break; - case 'c': - if (mo->argc <= 3) { - return showusage (1); - } else { - const char *db = main_argparse_getarg (mo); - if (!db) { - return showusage (1); - } - return showcount (db); - } - break; - case 'g': - mo->grep = main_argparse_getarg (mo); - if (!mo->grep) { - eprintf ("Missing argument for -g\n"); - return false; - } - break; - case 'D': - if (mo->argi + 1 >= mo->argc) { - return showusage (0); - } - mo->format = diff; - break; - case 'G': - mo->format = perf; - break; - case 'C': - mo->format = cgen; - break; - case 't': - mo->textmode = true; - break; - case 'J': - mo->options |= SDB_OPTION_JOURNAL; - // expect argument - break; - default: - return false; - } - return true; -} - -static MainOptions *main_argparse(MainOptions *mo, int argc, const char **argv) { - if (!mo) { - return NULL; - } - mo->argc = argc; - mo->argv = argv; - mo->options = SDB_OPTION_FS | SDB_OPTION_NOSTAMP; - mo->failed = true; - int i; - mo->argi = 1; - for (i = 1; i < argc; i++) { - mo->db0++; - i = mo->argi; - if (argv[i][0] == '-' && argv[i][1]) { - int j = 1; - while (argv[i][j]) { - if (!main_argparse_flag (mo, argv[i][j])) { - mo->db = argv[mo->argi]; - mo->db0 = i + 1; - // invalid flag - break; // return NULL; - } - if (i != mo->argi) { - break; - } - j++; - } - } else { - mo->db = argv[mo->db0]; - if (i + 1 < argc) { - switch (argv[i + 1][0]) { - case '-': - if (!argv[i + 1][1]) { - mo->create = dash; - } - break; - case '=': - if (argv[i + 1][1]) { - mo->create = dobl; - } else { - mo->create = eqeq; - } - break; - default: - mo->db2 = argv[i]; - break; - } - } - break; - } - } - // mo->db = mo->argv[mo->db0 + 1]; - mo->db = argv[mo->db0]; - return mo; -} - -SDB_API int sdb_main(int argc, const char **argv) { - char *line; - int i; - - /* terminate flags */ - if (argc < 2) { - return showusage (1); - } - MainOptions _mo = {0}; - MainOptions *mo = &_mo; - main_argparse (mo, argc, argv); - // -j json return sdb_dump (argv[db0 + 1], MODE_JSON); - // -G sdb_dump (argv[db0 + 1], MODE_CGEN); // gperf - // -C print C/H files - // -t text - switch (mo->format) { - case diff: - if (mo->db && mo->db2) { - return dbdiff (mo->db, mo->db2)? 0: 1; - } - return showusage (1); - case perf: - return sdb_dump (mo); - case cgen: - { - if (mo->db0 >= argc) { - return showusage (1); - } - const char *file = mo->argv[mo->db0]; - char *name = sdb_strdup (file); - char *p = strchr (name, '.'); - if (p) { - *p = 0; - } - int rc = gen_gperf (mo, file, name); - sdb_gh_free (name); - return rc; - } - default: - break; - } - - if (!mo->db && !mo->create) { - return showusage (1); - } - if (!mo->create && mo->db) { - if (!strcmp (mo->db, "-")) { - mo->create = dash; - mo->db = NULL; - mo->argi--; - mo->db0 = mo->argi; - } - } -#if USE_MMAN - signal (SIGINT, terminate); - signal (SIGHUP, synchronize); -#endif - int ret = 0; - switch (mo->create) { - case dash: // "-" - if ((s = sdb_new (NULL, mo->db, 0))) { - sdb_config (s, options); - int kvs = mo->db0 + 2; - if (mo->argi + 2 < mo->argc) { - for (i = mo->argi + 2; i < argc; i++) { - if (sdb_query (s, mo->argv[i])) { - save = true; - } - if (mo->format) { - fflush (stdout); - ret = write_null (); - } - } - } else { - if (kvs < argc && insertkeys (s, argv + mo->argi + 2, argc - kvs, '-')) { - save = true; - } - for (; (line = slurp (stdin, NULL));) { - if (sdb_query (s, line)) { - save = true; - } - if (mo->format) { - fflush (stdout); - ret = write_null (); - } - sdb_gh_free (line); - } - } - } else { - eprintf ("Cannot create database\n"); - } - break; - case eqeq: // "=" - ret = createdb (mo->db, NULL, 0); - break; - case dobl: // "==" - { - int delta = mo->db0 + 2; - ret = createdb (mo->db, mo->argv + delta, mo->argc - delta); - } - break; - default: - // "sdb test.db" - s = sdb_new (NULL, mo->db, 0); - if (!s) { - return 1; - } - sdb_config (s, options); - if (mo->argi + 1 < mo->argc) { - for (i = mo->db0 + 1; i < argc; i++) { - if (sdb_query (s, mo->argv[i])) { - save = true; - } - if (mo->format) { - fflush (stdout); - ret = write_null (); - } - } - } else { - return sdb_dump (mo); - } - break; - } - terminate (ret); - return ret; -} diff --git a/shlr/sdb/src/match.c b/shlr/sdb/src/match.c deleted file mode 100644 index 490cbf9d697be..0000000000000 --- a/shlr/sdb/src/match.c +++ /dev/null @@ -1,111 +0,0 @@ -/* sdb - MIT - Copyright 2015-2016 - pancake */ - -#include "sdb/sdb.h" -#include - -static inline int haveSuffix(const char *glob, int glob_len, const char *sfx) { - const int sfx_len = strlen (sfx); - return (glob_len>sfx_len && !strcmp (glob+glob_len-sfx_len, sfx)); -} - -static inline int havePrefix(const char *glob, int glob_len, const char *pfx) { - const int pfx_len = strlen (pfx); - return (pfx_lenns_lock = lock; - if (depth) { // handles -1 as infinite - ls_foreach_cast (s->ns, it, SdbNs*, ns) { - sdb_ns_lock (ns->sdb, lock, depth - 1); - } - } -} - -static int in_list(SdbList *list, void *item) { - SdbNs *ns; - SdbListIter *it; - if (list && item) { - ls_foreach_cast (list, it, SdbNs*, ns) { - if (item == ns) { - return 1; - } - } - } - return 0; -} - -static void ns_free(Sdb *s, SdbList *list) { - SdbListIter next; - SdbListIter *it; - int deleted; - SdbNs *ns; - if (!list || !s) { - return; - } - // TODO: Implement and use ls_foreach_safe - if (in_list (list, s)) { - return; - } - ls_append (list, s); - ls_foreach_cast (s->ns, it, SdbNs*, ns) { - deleted = 0; - next.n = it->n; - if (!in_list (list, ns)) { - ls_delete (s->ns, it); // free (it) - free (ns->name); - ns->name = NULL; - deleted = 1; - if (ns->sdb) { - if (sdb_free (ns->sdb)) { - ns->sdb = NULL; - free (ns->name); - ns->name = NULL; - } - } - ls_append (list, ns); - ls_append (list, ns->sdb); - ns_free (ns->sdb, list); - sdb_free (ns->sdb); - } - if (!deleted) { - sdb_free (ns->sdb); - s->ns->free = NULL; - ls_delete (s->ns, it); // free (it) - } - free (ns); - it = &next; - } - ls_free (s->ns); - s->ns = NULL; -} - -SDB_API void sdb_ns_free(Sdb *s) { - SdbList *list; - if (!s) { - return; - } - list = ls_new (); - list->free = NULL; - ns_free (s, list); - ls_free (list); - ls_free (s->ns); - s->ns = NULL; -} - -static SdbNs *sdb_ns_new (Sdb *s, const char *name, ut32 hash) { - char dir[SDB_MAX_PATH]; - SdbNs *ns; - if (s->dir && *s->dir && name && *name) { - int dir_len = strlen (s->dir); - int name_len = strlen (name); - if ((dir_len+name_len+3)>SDB_MAX_PATH) { - return NULL; - } - memcpy (dir, s->dir, dir_len); - memcpy (dir + dir_len, ".", 1); - memcpy (dir + dir_len + 1, name, name_len + 1); - } else { - dir[0] = 0; - } - ns = (SdbNs *)sdb_gh_malloc (sizeof (SdbNs)); - if (!ns) { - return NULL; - } - ns->hash = hash; - ns->name = name? sdb_strdup (name): NULL; - //ns->sdb = sdb_new (dir, ns->name, 0); - ns->sdb = sdb_new0 (); - // TODO: generate path - - if (ns->sdb) { - sdb_gh_free (ns->sdb->path); - ns->sdb->path = NULL; - if (*dir) { - ns->sdb->path = sdb_strdup (dir); - } - sdb_gh_free (ns->sdb->name); - if (name && *name) { - ns->sdb->name = sdb_strdup (name); - } - } else { - sdb_gh_free (ns->name); - sdb_gh_free (ns); - ns = NULL; - } - return ns; -} - -SDB_API bool sdb_ns_unset(Sdb *s, const char *name, Sdb *r) { - SdbNs *ns; - SdbListIter *it; - if (s && (name || r)) { - ls_foreach_cast (s->ns, it, SdbNs*, ns) { - if (name && (!strcmp (name, ns->name))) { - ls_delete (s->ns, it); - return true; - } - if (r && ns->sdb == r) { - ls_delete (s->ns, it); - return true; - } - } - } - return false; -} - -SDB_API int sdb_ns_set(Sdb *s, const char *name, Sdb *r) { - SdbNs *ns; - SdbListIter *it; - ut32 hash = sdb_hash (name); - if (!s || !r || !name) { - return 0; - } - ls_foreach_cast (s->ns, it, SdbNs*, ns) { - if (ns->hash == hash) { - if (ns->sdb == r) { - return 0; - } - sdb_free (ns->sdb); - r->refs++; // sdb_ref / sdb_unref // - ns->sdb = r; - return 1; - } - } - if (s->ns_lock) { - return 0; - } - ns = R_NEW (SdbNs); - if (!ns) { - return 0; - } - ns->name = sdb_strdup (name); - if (!ns->name) { - sdb_gh_free (ns); - return 0; - } - ns->hash = hash; - ns->sdb = r; - r->refs++; - ls_append (s->ns, ns); - return 1; -} - -SDB_API Sdb *sdb_ns(Sdb *s, const char *name, int create) { - SdbListIter *it; - SdbNs *ns; - ut32 hash; - if (!s || !name || !*name) { - return NULL; - } - hash = sdb_hash (name); - ls_foreach_cast (s->ns, it, SdbNs*, ns) { - if (ns->hash == hash) { - return ns->sdb; - } - } - if (!create) { - return NULL; - } - if (s->ns_lock) { - return NULL; - } - ns = sdb_ns_new (s, name, hash); - if (!ns) { - return NULL; - } - ls_append (s->ns, ns); - return ns->sdb; -} - -SDB_API Sdb *sdb_ns_path(Sdb *s, const char *path, int create) { - char *ptr, *str; - char *slash; - - if (!s || !path || !*path) { - return s; - } - ptr = str = sdb_strdup (path); - do { - slash = strchr (ptr, '/'); - if (slash) - *slash = 0; - s = sdb_ns (s, ptr, create); - if (!s) break; - if (slash) - ptr = slash+1; - } while (slash); - sdb_gh_free (str); - return s; -} - -static void ns_sync(Sdb *s, SdbList *list) { - SdbNs *ns; - SdbListIter *it; - ls_foreach_cast (s->ns, it, SdbNs*, ns) { - if (in_list (list, ns)) { - continue; - } - ls_append (list, ns); - ns_sync (ns->sdb, list); - sdb_sync (ns->sdb); - } - sdb_sync (s); -} - -SDB_API void sdb_ns_sync(Sdb *s) { - SdbList *list = ls_new (); - ns_sync (s, list); - list->free = NULL; - ls_free (list); -} diff --git a/shlr/sdb/src/num.c b/shlr/sdb/src/num.c deleted file mode 100644 index 00f14c7b4a682..0000000000000 --- a/shlr/sdb/src/num.c +++ /dev/null @@ -1,85 +0,0 @@ -/* sdb - MIT - Copyright 2011-2022 - pancake */ - -#include "sdb/sdb.h" - -// check if key exists and if it's a number.. rename? -SDB_API bool sdb_num_exists (Sdb *s, const char *key) { - const char *o = sdb_const_get (s, key, NULL); - return o ? (*o >= '0' && *o <= '9'): false; -} - -SDB_API ut64 sdb_num_get(Sdb *s, const char *key, ut32 *cas) { - const char *v = sdb_const_get (s, key, cas); - return (!v || *v == '-') ? 0LL : sdb_atoi (v); -} - -SDB_API int sdb_num_add(Sdb *s, const char *key, ut64 v, ut32 cas) { - char *val, b[SDB_NUM_BUFSZ]; - int numbase = sdb_num_base (sdb_const_get (s, key, NULL)); - val = sdb_itoa (v, numbase, b, sizeof (b)); - return sdb_add (s, key, val, cas); -} - -SDB_API int sdb_num_set(Sdb *s, const char *key, ut64 v, ut32 cas) { - char *val, b[SDB_NUM_BUFSZ]; - int numbase = sdb_num_base (sdb_const_get (s, key, NULL)); - val = sdb_itoa (v, numbase, b, sizeof (b)); - return sdb_set (s, key, val, cas); -} - -SDB_API ut64 sdb_num_inc(Sdb *s, const char *key, ut64 n2, ut32 cas) { - ut32 c; - ut64 n = sdb_num_get (s, key, &c); - ut64 res = n + n2; - if ((cas && c != cas) || res < n) { - return 0LL; - } - sdb_num_set (s, key, res, cas); - return res; -} - -SDB_API ut64 sdb_num_dec(Sdb *s, const char *key, ut64 n2, ut32 cas) { - ut32 c; - ut64 n = sdb_num_get (s, key, &c); - if (cas && c != cas) { - return 0LL; - } - if (n2 > n) { - sdb_set (s, key, "0", cas); - return 0LL; // XXX must be -1LL? - } - n -= n2; - sdb_num_set (s, key, n, cas); - return n; -} - -SDB_API int sdb_num_min(Sdb *db, const char*k, ut64 n, ut32 cas) { - const char* a = sdb_const_get (db, k, NULL); - return (!a || n < sdb_atoi (a)) - ? sdb_num_set (db, k, n, cas): 0; -} - -SDB_API int sdb_num_max(Sdb *db, const char*k, ut64 n, ut32 cas) { - const char* a = sdb_const_get (db, k, NULL); - return (!a || n > sdb_atoi (a)) - ? sdb_num_set (db, k, n, cas): 0; -} - -SDB_API int sdb_bool_set(Sdb *db, const char *str, bool v, ut32 cas) { - return sdb_set (db, str, v? "true": "false", cas); -} - -SDB_API bool sdb_bool_get(Sdb *db, const char *str, ut32 *cas) { - const char *b = sdb_const_get (db, str, cas); - return b && (!strcmp (b, "1") || !strcmp (b, "true")); -} - -/* pointers */ - -SDB_API int sdb_ptr_set(Sdb *db, const char *key, void *p, ut32 cas) { - return sdb_num_set (db, key, (ut64)(size_t)p, cas); -} - -SDB_API void* sdb_ptr_get(Sdb *db, const char *key, ut32 *cas) { - return (void*)(size_t)sdb_num_get (db, key, cas); -} diff --git a/shlr/sdb/src/query.c b/shlr/sdb/src/query.c deleted file mode 100644 index 51f4625ac9f68..0000000000000 --- a/shlr/sdb/src/query.c +++ /dev/null @@ -1,922 +0,0 @@ -/* sdb - MIT - Copyright 2011-2022 - pancake */ - -#include -#include -#include -#include "sdb/sdb.h" - -typedef struct { - char *buf; - int len; - int size; -} StrBuf; - -static StrBuf* strbuf_new(void) { - return (StrBuf*) sdb_gh_calloc (sizeof (StrBuf), 1); -} - -#define NEWLINE_AFTER_QUERY 1 - -static StrBuf* strbuf_append(StrBuf *sb, const char *str, const int nl) { - if (!sb || !str || nl < 0) { - return sb; - } - int len = strlen (str); - if ((sb->len + len + 2) >= sb->size) { - size_t newsize = sb->size + len + 256; - char *b = (char *)sdb_gh_realloc (sb->buf, newsize); - /// TODO perform free and force all callers to update the ref? - if (!b) { - return NULL; - } - sb->buf = b; - sb->size = newsize; - } - if (sb->buf && str) { - memcpy (sb->buf + sb->len, str, len); - sb->len += len; - } -#if NEWLINE_AFTER_QUERY - if (sb->buf && nl) { - sb->buf[sb->len++] = '\n'; - len++; - } -#endif - if (sb->buf) { - sb->buf[sb->len] = 0; - } - return sb; -} - -static StrBuf *strbuf_free(StrBuf *sb) { - sdb_gh_free (sb->buf); - sdb_gh_free (sb); - return NULL; -} - -SDB_API int sdb_queryf(Sdb *s, const char *fmt, ...) { - char string[4096]; - int ret; - va_list ap; - va_start (ap, fmt); - vsnprintf (string, sizeof (string), fmt, ap); - ret = sdb_query (s, string); - va_end (ap); - return ret; -} - -SDB_API char *sdb_querysf(Sdb *s, char *buf, size_t buflen, const char *fmt, ...) { - char string[4096]; - va_list ap; - va_start (ap, fmt); - vsnprintf (string, sizeof (string), fmt, ap); - char *ret = sdb_querys (s, buf, buflen, string); - va_end (ap); - return ret; -} - -// TODO: Reimplement as a function with optimized concat -#define out_concat(x) if ((x) && *(x)) { \ - strbuf_append (out, x, 1); \ -} - -typedef struct { - StrBuf *out; - int encode; - char *root; -} ForeachListUser; - -static bool foreach_list_cb(void *user, const char *k, const char *v) { - ForeachListUser *rlu = (ForeachListUser*)user; - char *line = NULL; - char *root = NULL; - int rlen, klen, vlen; - ut8 *v2 = NULL; - if (!rlu) { - return false; - } - root = rlu->root; - klen = strlen (k); - if (rlu->encode) { - v2 = sdb_decode (v, NULL); - if (v2) { - v = (const char *)v2; - } - } - vlen = strlen (v); - if (root) { - rlen = strlen (root); - line = (char *)sdb_gh_malloc (klen + vlen + rlen + 3); - if (!line) { - sdb_gh_free (v2); - return false; - } - memcpy (line, root, rlen); - line[rlen] = '/'; /*append the '/' at the end of the namespace */ - memcpy (line + rlen + 1, k, klen); - line[rlen + klen + 1] = '='; - memcpy (line + rlen + klen + 2, v, vlen + 1); - } else { - line = (char *)sdb_gh_malloc (klen + vlen + 2); - if (!line) { - sdb_gh_free (v2); - return false; - } - memcpy (line, k, klen); - line[klen] = '='; - memcpy (line + klen + 1, v, vlen + 1); - } - strbuf_append (rlu->out, line, 1); - sdb_gh_free (v2); - sdb_gh_free (line); - return true; -} - -static void walk_namespace(StrBuf *sb, char *root, int left, char *p, SdbNs *ns, int encode) { - int len; - SdbListIter *it; - SdbNs *n; - ForeachListUser user = { sb, encode, root }; - char *roote = root + strlen (root); - if (!ns->sdb) { - return; - } - /*Pick all key=value in the local ns*/ - sdb_foreach (ns->sdb, foreach_list_cb, &user); - - /*Pick "sub"-ns*/ - ls_foreach_cast (ns->sdb->ns, it, SdbNs*, n) { - len = strlen (n->name); - p[0] = '/'; - if (len + 2 < left) { - memcpy (p + 1, n->name, len + 1); - left -= len + 2; - } - walk_namespace (sb, root, left, - roote + len + 1, n, encode); - } -} - -SDB_API char *sdb_querys(Sdb *r, char *buf, size_t len, const char *_cmd) { - bool bufset = false; - bool is_ref = false; - int ok = 0; - int i, d, w, alength, encode = 0; - const char *p, *q, *val = NULL; - char *eq, *tmp, *json, *next, *quot, *slash, *cmd = NULL; - char *newcmd = NULL, *original_cmd = NULL; - char *res = NULL; - Sdb *s = r; - ut64 n; - if (!s || (!_cmd && !buf)) { - return NULL; - } - StrBuf *out = strbuf_new (); - if ((int)len < 1 || !buf || !out) { - bufset = true; - len = 64; - buf = (char *)sdb_gh_calloc (1, len); - if (!buf) { - strbuf_free (out); - return NULL; - } - } - if (_cmd) { - cmd = original_cmd = sdb_strdup (_cmd); - if (!cmd) { - strbuf_free (out); - if (bufset) { - sdb_gh_free (buf); - } - return NULL; - } - } else { - cmd = buf; - } - // if cmd is null, we take buf as cmd - next = NULL; -repeat: - /* skip spaces */ - while (*cmd && (*cmd == ' ' || *cmd == '\t')) { - cmd++; - } - s = r; - p = cmd; - eq = NULL; - encode = 0; - is_ref = false; - quot = NULL; - json = NULL; - if (*p == '#') { - char buffer[16]; - p++; - next = (char *)strchr (p, ';'); - if (next) { - *next = 0; - } - (void)snprintf (buffer, sizeof (buffer), "0x%08x\n", sdb_hash (p)); - strbuf_append (out, buffer, 1); - if (next) { - *next = ';'; - } - goto runNext; - } else - if (*p == '%') { - encode = 1; - cmd++; - p++; - } - if (next) *next = ';'; - eq = (char *)strchr (p, '='); - if (eq) { - d = 1; - *eq++ = 0; - if (*eq == '$') { - next = (char *)strchr (eq + 1, ';'); - if (next) *next = 0; - val = sdb_const_get (s, eq + 1, 0); - if (!val) { - // eprintf ("No value for '%s'\n", eq + 1); - goto fail; - } - if (next) { - *next = ';'; - } - is_ref = true; // protect readonly buffer from being processed - } else { - val = eq; - } - } else { - val = NULL; - d = 0; - } - if (!is_ref) { - next = (char *)strchr (val? val: cmd, ';'); - } - if (!is_ref && val && *val == '"') { - val++; - // TODO: escape \" too - quot = (char*)val; -next_quote: - quot = (char *)strchr (quot, '"'); - if (quot) { - if (*(quot - 1) == '\\') { - memmove (quot - 1, quot, strlen (quot) + 1); - goto next_quote; - } - *quot++ = 0; // crash on read only mem!! - } else { - // eprintf ("Missing quote\n"); - *eq++ = 0; - out = strbuf_free (out); - goto fail; - } - next = strchr (quot, ';'); - } else { - quot = NULL; - } - if (next) { - *next = 0; - } - slash = strchr (cmd, '/'); - while (slash) { - *slash = 0; - s = sdb_ns (s, cmd, eq? 1: 0); - if (!s) { - // eprintf ("Cant find namespace %s\n", cmd); - out = strbuf_free (out); - goto fail; - } - cmd = slash + 1; - slash = strchr (cmd, '/'); - } - if (*cmd == '?') { - const char *v = sdb_const_get (s, cmd + 1, 0); - const char *t = sdb_type (v); - out_concat (t); - } else if (*cmd == '*') { - if (!strcmp (cmd, "***")) { - char root[1024]; // limit namespace length? - SdbListIter *it; - SdbNs *ns; - ls_foreach_cast (s->ns, it, SdbNs*, ns) { - int name_len = strlen (ns->name); - if (name_len < (long)sizeof (root)) { - memcpy (root, ns->name, name_len + 1); - walk_namespace (out, root, - sizeof (root) - name_len, - root + name_len, ns, encode); - } else { - // eprintf ("TODO: Namespace too long\n"); - } - } - goto fail; - } else - if (!strcmp (cmd, "**")) { - SdbListIter *it; - SdbNs *ns; - ls_foreach_cast (s->ns, it, SdbNs*, ns) { - out_concat (ns->name); - } - goto fail; - } else - if (!strcmp (cmd, "*")) { - ForeachListUser user = { out, encode, NULL }; - SdbList *list = sdb_foreach_list (s, true); - SdbListIter *iter; - SdbKv *kv; - ls_foreach_cast (list, iter, SdbKv*, kv) { - foreach_list_cb (&user, sdbkv_key (kv), sdbkv_value (kv)); - } - ls_free (list); - goto fail; - } - } - json = strchr (cmd, ':'); - if (*cmd == '[') { - char *tp = strchr (cmd, ']'); - if (!tp) { - // eprintf ("Missing ']'.\n"); - goto fail; - } - *tp++ = 0; - p = (const char *)tp; - } else { - p = cmd; - } - if (*cmd == '$') { - sdb_gh_free (newcmd); - char *nc = sdb_get (s, cmd + 1, 0); - cmd = newcmd = (nc) ? nc : sdb_strdup (""); - } - // cmd = val - // cmd is key and val is value - if (*cmd == '.') { - if (s->options & SDB_OPTION_FS) { - if (!sdb_query_file (s, cmd + 1)) { - // eprintf ("sdb: cannot open '%s'\n", cmd+1); - goto fail; - } - } - // else eprintf ("sdb: filesystem access disabled in config\n"); - } else if (*cmd == '~') { // delete - if (cmd[1] == '~') { // grep - SdbKv *kv; - SdbListIter *li; - SdbList *l = sdb_foreach_match (s, cmd + 2, false); - ls_foreach_cast (l, li, SdbKv*, kv) { - strbuf_append (out, sdbkv_key (kv), 0); - strbuf_append (out, "=", 0); - strbuf_append (out, sdbkv_value (kv), 1); - } - fflush (stdout); - ls_free (l); - } else { - d = 1; - sdb_unset_like (s, cmd + 1); - } - } else if (*cmd == '+' || *cmd == '-') { - d = 1; - if (!buf) { - buf = (char *)sdb_gh_calloc (1, len); - if (!buf) { - goto fail; - } - bufset = true; - } - *buf = 0; - if (cmd[1]=='[') { - const char *eb = strchr (cmd, ']'); - if (!eb) { - // eprintf ("Missing ']'.\n"); - goto fail; - } - int idx = sdb_atoi (cmd + 2); - /* +[idx]key=n */ - /* -[idx]key=n */ - ut64 curnum = sdb_array_get_num (s, - eb + 1, idx, 0); - if (eq) { - /* +[idx]key=n --> key[idx] += n */ - /* -[idx]key=n --> key[idx] -= n */ - st64 neq = sdb_atoi (eq); - if (*cmd == '+') { - curnum += neq; - } else if (*cmd == '-') { - curnum -= neq; - } else { - // should never happens - } - sdb_array_set_num (s, eb + 1, idx, curnum, 0); - } else { - /* +[idx]key --> key[idx] + 1 */ - /* -[idx]key --> key[idx] - 1 */ - char *nstr, numstr[128]; - if (*cmd=='+') { - curnum ++; - } else if (*cmd=='-') { - curnum --; - } else { - // never happens - } - nstr = sdb_itoa (curnum, 10, numstr, sizeof (numstr)); - strbuf_append (out, nstr, 1); - } - } else if (val) { - if (sdb_isnum (val)) { - int op = *cmd; - if (*val == '-') { - op = (*cmd == '-')? '+': '-'; - d = sdb_atoi (val + 1); - } else { - d = sdb_atoi (val); - } - if (op == '+') { - sdb_num_inc (s, cmd + 1, d, 0); - } else { - sdb_num_dec (s, cmd + 1, d, 0); - } - } else { - if (*cmd == '+') { - sdb_concat (s, cmd + 1, val, 0); - } else { - sdb_uncat (s, cmd + 1, val, 0); - } - } - } else { - int base = sdb_num_base (sdb_const_get (s, cmd+1, 0)); - if (json) { - base = 10; // NOTE: json is base10 only - *json = 0; - if (*cmd=='+') { - n = sdb_json_num_inc (s, cmd + 1, json + 1, d, 0); - } else { - n = sdb_json_num_dec (s, cmd + 1, json + 1, d, 0); - } - *json = ':'; - } else { - if (*cmd=='+') { - n = sdb_num_inc (s, cmd + 1, d, 0); - } else { - n = sdb_num_dec (s, cmd + 1, d, 0); - } - } - // keep base - if (base == 16) { - w = snprintf (buf, len - 1, "0x%" PRIx64, n); - if (w < 0 || (size_t)w > len) { - if (bufset && len < 0xff) { - sdb_gh_free (buf); - buf = (char *)sdb_gh_malloc (len = 0xff); - if (!buf) { - goto fail; - } - } - bufset = true; - snprintf (buf, 0xff, "0x%" PRIx64, n); - } - } else { - w = snprintf (buf, len-1, "%" PRId64, n); - if (w < 0 || (size_t)w > len) { - if (bufset && len < 0xff) { - sdb_gh_free (buf); - buf = (char *)sdb_gh_malloc (len = 0xff); - if (!buf) { - goto fail; - } - } - bufset = true; - snprintf (buf, 0xff, "%" PRId64, n); - } - } - } - out_concat (buf); - } else if (*cmd == '[') { - // [?] - count elements of array - if (cmd[1] == '?') { - // if (!eq) ... - alength = sdb_array_length (s, p); - if (!buf) { - buf = (char *)sdb_gh_malloc (++len); - if (!buf) { - goto fail; - } - bufset = 1; - } - w = snprintf (buf, len, "%d", alength); - if (w < 0 || (size_t)w > len) { - if (bufset) { - sdb_gh_free (buf); - } - buf = (char *)sdb_gh_malloc (len = 32); - bufset = 1; - snprintf (buf, 31, "%d", alength); - } - out_concat (buf); - } else if (cmd[1]=='!') { - if (cmd[2]=='+') { - // [!+]key=aa # add_sorted - sdb_array_add_sorted (s, p, val, 0); - } else { - // [!]key # sort - sdb_array_sort (s, p, 0); - } - } else if (cmd[1]=='#') { - // [#+]key=num # add_sorted_num - if (cmd[2]=='+') { - // [#]key # sort_num - sdb_array_add_sorted_num (s, p, sdb_atoi (val), 0); - } else { - sdb_array_sort_num (s, p, 0); - } - } else if (cmd[1] == '+' || cmd[1] == '-') { - if (cmd[1] == cmd[2]) { - // stack -#if 0 - [++]foo=33 # push - [++]foo # - [--]foo # pop - [--]foo=b # -#endif - if (cmd[1] == '-' && eq) { - /* invalid syntax */ - } else if (cmd[1] == '+' && !eq) { - /* invalid syntax */ - } else { - if (eq) { - sdb_array_push (s, p, val, 0); - } else { - char *ret = sdb_array_pop (s, p, 0); - out_concat (ret); - sdb_gh_free (ret); - } - } - } else - // [+]foo remove first element */ - // [+]foo=bar ADD */ - // [-]foo POP */ - // [-]foo=xx REMOVE (=xx ignored) */ - if (!cmd[2] || cmd[2] == ']') { - // insert - if (eq) { - if (cmd[1] == '+') { - // [+]K=1 - sdb_array_add (s, p, val, 0); - } else { - // [-]K= = remove first element - sdb_array_remove (s, p, val, 0); - } - //return NULL; - } else { - char *ret; - if (cmd[1] == '+') { - // [+]K = remove first element - // XXX: this is a little strange syntax to remove an item - ret = sdb_array_get (s, p, 0, 0); - if (ret && *ret) { - out_concat (ret); - } - // (+)foo :: remove first element - sdb_array_delete (s, p, 0, 0); - } else { - // [-]K = remove last element - ret = sdb_array_get (s, p, -1, 0); - if (ret && *ret) { - out_concat (ret); - } - // (-)foo :: remove last element - sdb_array_delete (s, p, -1, 0); - } - sdb_gh_free (ret); - } - } else { - // get/set specific element in array - i = atoi (cmd + 1); - if (eq) { - /* [+3]foo=bla */ - if (i < 0) { - char *arr = sdb_array_get (s, p, -i, NULL); - if (arr) { - if (encode) { - char *newtmp = (char*)sdb_decode (arr, NULL); - if (!newtmp) { - goto fail; - } - sdb_gh_free (arr); - arr = newtmp; - } - ok = 0; - out_concat (arr); - sdb_array_delete (s, p, -i, 0); - sdb_gh_free (arr); - } else goto fail; - } else { - if (encode) { - val = sdb_encode ((const ut8*)val, -1); - } - ok = cmd[1]? ((cmd[1]=='+')? - sdb_array_insert (s, p, i, val, 0): - sdb_array_set (s, p, i, val, 0) - ): sdb_array_delete (s, p, i, 0); - if (encode) { - sdb_gh_free ((void*)val); - val = NULL; - } - } - if (ok && buf) { - *buf = 0; - } else { - buf = NULL; - } - } else { - if (i == 0) { - /* [-b]foo */ - if (cmd[1]=='-') { - sdb_array_remove (s, p, cmd+2, 0); - } else { - // eprintf ("TODO: [b]foo -> get index of b key inside foo array\n"); - // sdb_array_dels (s, p, cmd+1, 0); - } - } else if (i<0) { - /* [-3]foo */ - char *arr = sdb_array_get (s, p, -i, NULL); - if (arr && *arr) { - out_concat (arr); - sdb_array_delete (s, p, -i, 0); - } - sdb_gh_free (arr); - } else { - /* [+3]foo */ - char *arr = sdb_array_get (s, p, i, NULL); - if (arr && *arr) { - out_concat (arr); - } - sdb_gh_free (arr); - } - } - } - } else { - if (eq) { - /* [3]foo=bla */ - char *sval = (char*)val; - if (encode) { - sval = sdb_encode ((const ut8*)val, -1); - } - if (cmd[1]) { - int idx = atoi (cmd+1); - ok = sdb_array_set (s, p, idx, sval, 0); -// TODO: handle when idx > sdb_alen - if (encode) - sdb_gh_free (sval); - } else { - if (encode) { - ok = sdb_set_owned (s, p, sval, 0); - } else { - ok = sdb_set (s, p, sval, 0); - } - } - if (ok && buf) { - *buf = 0; - } - } else { - /* [3]foo */ - const char *sval = sdb_const_get (s, p, 0); - size_t wl; - if (cmd[1]) { - i = atoi (cmd + 1); - buf = sdb_array_get (s, p, i, NULL); - if (buf) { - bufset = true; - len = strlen (buf) + 1; - } - if (encode) { - char *newbuf = (char*)sdb_decode (buf, NULL); - if (newbuf) { - sdb_gh_free (buf); - buf = newbuf; - len = strlen(buf) + 1; - } - } - out_concat (buf); - } else { - if (!sval) { - goto fail; - } - wl = strlen (sval); - if (!buf || wl >= len) { - buf = (char *)sdb_gh_malloc (wl + 2); - if (!buf) { - sdb_gh_free (out->buf); - out->buf = NULL; - goto fail; - } - bufset = true; - len = wl + 2; - } - for (i = 0; sval[i]; i++) { - if (sval[i + 1]) { - buf[i] = (sval[i] == SDB_RS) - ? '\n': sval[i]; - } else { - buf[i] = sval[i]; - } - } - buf[i] = 0; - if (encode) { - char *newbuf = (char*)sdb_decode (buf, NULL); - if (newbuf) { - if (bufset) { - sdb_gh_free (buf); - } - buf = newbuf; - len = strlen (buf) + 1; - } - } - out_concat (buf); - } - } - } - } else { - if (eq) { - // 1 0 kvpath=value - // 1 1 kvpath:jspath=value - if (encode) { - val = sdb_encode ((const ut8*)val, -1); - } - if (json > eq) { - json = NULL; - } - - if (json) { - *json++ = 0; - ok = sdb_json_set (s, cmd, json, val, 0); - } else { - while (*val && isspace (*val)) { - val++; - } - if (*cmd) { - int clen = strlen (cmd) - 1; - while (clen >= 0 && isspace (cmd[clen])) { - cmd[clen] = '\0'; - clen--; - } - ok = sdb_set (s, cmd, val, 0); - } - } - if (encode) { - sdb_gh_free ((void*)val); - val = NULL; - } - if (ok && buf) { - *buf = 0; - } - } else { - // 0 1 kvpath:jspath - // 0 0 kvpath - if (json) { - *json++ = 0; - if (*json) { - // TODO: not optimized to reuse 'buf' - if ((tmp = sdb_json_get (s, cmd, json, 0))) { - if (encode) { - char *newtmp = (char*)sdb_decode (tmp, NULL); - if (!newtmp) - goto fail; - sdb_gh_free (tmp); - tmp = newtmp; - } - out_concat (tmp); - sdb_gh_free (tmp); - } - } else { - // kvpath: -> show indented json - char *o = sdb_json_indent (sdb_const_get (s, cmd, 0), " "); - out_concat (o); - sdb_gh_free (o); - } - } else { - // sdbget - if ((q = sdb_const_get (s, cmd, 0))) { - if (encode) { - q = (char*)sdb_decode (q, NULL); - } - out_concat (q); - if (encode) { - sdb_gh_free ((void*)q); - } - } - } - } - } -runNext: - if (next) { - if (bufset) { - sdb_gh_free (buf); - buf = NULL; - bufset = false; - } - cmd = next + 1; - encode = 0; - goto repeat; - } - if (eq) { - *--eq = '='; - } -fail: - if (bufset) { - sdb_gh_free (buf); - } - if (out) { - res = out->buf; - sdb_gh_free (out); - } else { - sdb_gh_free (res); - res = NULL; - } - sdb_gh_free (original_cmd); - sdb_gh_free (newcmd); - return res; -} - -// TODO: should return a string instead, the must_save can be moved outside -SDB_API bool sdb_query(Sdb *s, const char *cmd) { - char buf[128]; - bool must_save = ((*cmd == '~') || strchr (cmd, '=')); - char *out = sdb_querys (s, buf, sizeof (buf) - 1, cmd); - if (out) { - if (*out) { - fputs (out, stdout); - } - if (out != buf) { - sdb_gh_free (out); - } - } - return must_save; -} - -SDB_API int sdb_query_lines(Sdb *s, const char *cmd) { - char *o, *p, *op; - if (!s || !cmd) { - return 0; - } - op = sdb_strdup (cmd); - if (!op) { - return 0; - } - p = op; - do { - o = strchr (p, '\n'); - if (o) { - *o = 0; - } - (void)sdb_query (s, p); - if (o) { - p = o + 1; - } - } while (o); - sdb_gh_free (op); - return 1; -} - -static char *slurp(const char *file) { - if (!file || !*file) { - return NULL; - } - int fd = open (file, O_RDONLY); - if (fd == -1) { - return NULL; - } - long sz = lseek (fd, 0, SEEK_END); - if (sz < 0) { - close (fd); - return NULL; - } - if (lseek (fd, 0, SEEK_SET) == (off_t)-1) { - close (fd); - return NULL; - } - char *text = (char *)sdb_gh_malloc (sz + 1); - if (!text) { - close (fd); - return NULL; - } - int ret = read (fd, text, sz); - if (ret != sz) { - sdb_gh_free (text); - text = NULL; - } else { - text[sz] = 0; - } - close (fd); - return text; -} - -SDB_API int sdb_query_file(Sdb *s, const char* file) { - int ret = 0; - char *txt = slurp (file); - if (txt) { - ret = sdb_query_lines (s, txt); - sdb_gh_free (txt); - } - return ret; -} diff --git a/shlr/sdb/src/sdb.1 b/shlr/sdb/src/sdb.1 deleted file mode 100644 index dcdea020428ec..0000000000000 --- a/shlr/sdb/src/sdb.1 +++ /dev/null @@ -1,72 +0,0 @@ -.Dd Feb 7, 2021 -.Dt SDB 1 -.Os -.Sh NAME -.Nm sdb -.Nd simple key-value database baked by base64, json and arrays -.Sh SYNOPSIS -.Nm sdb -.Op Fl 0dehjJv -.Ar -|db -.Ar [-|=|==] -.Ar [.file|expr ..] -.Sh DESCRIPTION -SDB is a simple disk and memory string-based key-value database. It is based on CDB and uses -.Bl -tag -width Fl -.It Fl d -Decode stdin as base64 and prints to result to stdout -.It Fl D -Find differences between two databases -.It Fl C -Create the C and H files for a perfect hash implementation of the contents of the given Sdb -.It Fl G -Create the gperf file used by -C -.It Fl e -Encode stdin in base64 and prints to stdout -.It Fl h -Show help message -.It Fl j -Indent JSON from stdin if no more arguments, otherwise dump database as JSON. -.It Fl J -Enable journaling -.It Fl h -Show help message -.It Fl v -Show version -.El -.Sh EXAMPLES -Some useful ways to run it: -.Pp -$ sdb - ; in memory database -.Pp -$ sdb test.db = < test.txt ; create database from text file -.Pp -$ sdb test.db == a.txt b.txt ; create database from text files in a single command -.Pp -$ sdb test.db ; dump contents of database -.Pp -$ sdb test.db a=b a ; inline queries -.Pp -Append those quoted commands to 'sdb -' to test these sdb_query expressions: -.Pp -a=hello b=world a b # hello world -.Pp -a=1 +a -a # 2 1 ; key inc/dec -.Pp -a={"a":122} a:a=O a # {"a":0} ; json set -.Pp -a={"foo":122} +a:foo # 123 ; json increment -.Pp -[]a=1,2,3,4,5 [?]a # 5 ; count array -.Pp -[]a=1,2,3,4,5 [0]a # 1 ; get element -.Pp -[]a=1,2 [0]a=X a # X2 ; replace -.Pp -[]a=1,2 [+0]a=0 a # 012 ; prepend -.Pp -[]a=1,2 [-1]a=3 a # 123 ; append -.Pp -.Sh AUTHORS -.Pp -pancake diff --git a/shlr/sdb/src/sdb.c b/shlr/sdb/src/sdb.c deleted file mode 100644 index fa02d8dd8f694..0000000000000 --- a/shlr/sdb/src/sdb.c +++ /dev/null @@ -1,1276 +0,0 @@ -/* sdb - MIT - Copyright 2011-2023 - pancake */ - -#include -#include -#include -#include "sdb/sdb.h" - -static inline SdbKv *next_kv(HtPP *ht, SdbKv *kv) { - return (SdbKv *)((char *)kv + ht->opt.elem_size); -} - -#define BUCKET_FOREACH(ht, bt, j, kv) \ - for ((j) = 0, (kv) = (SdbKv *)(bt)->arr; j < (bt)->count; (j)++, (kv) = next_kv (ht, kv)) - -#define BUCKET_FOREACH_SAFE(ht, bt, j, count, kv) \ - if ((bt)->arr) \ - for ((j) = 0, (kv) = (SdbKv *)(bt)->arr, (count) = (ht)->count; \ - (j) < (bt)->count; \ - (j) = (count) == (ht)->count? j + 1: j, (kv) = (count) == (ht)->count? next_kv (ht, kv): kv, (count) = (ht)->count) - -static inline int nextcas(SdbKv const *kv) { - if (!kv->cas) { - return 1; - } - return kv->cas + 1; -} - -SDB_API Sdb* sdb_new0(void) { - return sdb_new (NULL, NULL, 0); -} - -SDB_API Sdb* sdb_new(const char *path, const char *name, int lock) { - Sdb* s = (Sdb*)sdb_gh_calloc (1, sizeof (Sdb)); - if (!s) { - return NULL; - } - s->db.fd = -1; - s->fd = -1; - s->journal = -1; - s->refs = 1; - s->ht = sdb_ht_new (); - if (path && !*path) { - path = NULL; - } - if (name && *name && strcmp (name, "-")) { - char buf[SDB_MAX_PATH]; - - if (path && *path) { - size_t plen = strlen (path); - size_t nlen = strlen (name); - s->dir = (char *)sdb_gh_malloc (plen + nlen + 2); - if (!s->dir) { - sdb_gh_free (s); - return NULL; - } - memcpy (s->dir, path, plen); - s->dir[plen] = '/'; - memcpy (s->dir + plen + 1, name, nlen + 1); - s->path = sdb_strdup (path); - } else { - s->dir = sdb_strdup (name); - } - switch (lock) { - case 1: - if (!sdb_lock_file (s->dir, buf, sizeof (buf))) { - goto fail; - } - if (!sdb_lock (buf)) { - goto fail; - } - break; - case 2: - if (!sdb_lock_file (s->dir, buf, sizeof (buf))) { - goto fail; - } - if (!sdb_lock_wait (buf)) { - goto fail; - } - break; - } - if (sdb_open (s, s->dir) == -1) { - s->last = s->timestamped? sdb_now (): 0LL; - // TODO: must fail if we cant open for write in sync - } - s->name = sdb_strdup (name); - } else { - s->last = s->timestamped? sdb_now (): 0LL; - s->fd = -1; - } - s->journal = -1; - s->fdump = -1; - s->depth = 0; - s->ndump = NULL; - s->ns = ls_new (); // TODO: should be NULL - if (!s->ns) { - goto fail; - } - s->ns->free = NULL; - if (!s->ns) { - goto fail; - } - s->lock = lock; - cdb_init (&s->db, s->fd); - return s; -fail: - if (s->fd != -1) { - close (s->fd); - s->fd = -1; - } - sdb_gh_free (s->dir); - sdb_gh_free (s->name); - sdb_gh_free (s->path); - sdb_gh_free (s); - return NULL; -} - -// XXX: this is wrong. stuff not stored in memory is lost -SDB_API void sdb_file(Sdb* s, const char *dir) { - char buf[SDB_MAX_PATH]; - if (s->lock) { - sdb_lock_file (s->dir, buf, sizeof (buf)); - sdb_unlock (buf); - } - sdb_gh_free (s->dir); - s->dir = (dir && *dir)? sdb_strdup (dir): NULL; - if (s->lock) { - sdb_lock_file (s->dir, buf, sizeof (buf)); - sdb_lock (buf); - } -} - -static bool sdb_merge_cb(void *user, const char *k, const char *v) { - sdb_set ((Sdb*)user, k, v, 0); - return true; -} - -SDB_API bool sdb_merge(Sdb* d, Sdb *s) { - return sdb_foreach (s, sdb_merge_cb, d); -} - -SDB_API bool sdb_isempty(Sdb *s) { - if (s) { - if (s->db.fd != -1) { - sdb_dump_begin (s); - while (sdb_dump_hasnext (s)) { - return false; - } - } - if (s->ht && s->ht->count > 0) { - return false; - } - } - return true; -} - -SDB_API int sdb_count(Sdb *s) { - int count = 0; - if (s) { - if (s->db.fd != -1) { - sdb_dump_begin (s); - while (sdb_dump_hasnext (s)) { - count++; - } - } - if (s->ht) { - count += s->ht->count; - } - } - return count; -} - -static void sdb_fini(Sdb* s, bool donull) { - char buf[SDB_MAX_PATH]; - if (!s) { - return; - } - sdb_hook_free (s); - cdb_free (&s->db); - if (s->lock) { - sdb_lock_file (s->dir, buf, sizeof (buf)); - sdb_unlock (buf); - } - sdb_ns_free (s); - s->refs = 0; - sdb_gh_free (s->name); - sdb_gh_free (s->path); - ls_free (s->ns); - sdb_ht_free (s->ht); - sdb_journal_close (s); - if (s->fd != -1) { - close (s->fd); - s->fd = -1; - } - sdb_gh_free (s->ndump); - sdb_gh_free (s->dir); - sdb_gh_free (sdbkv_value (&s->tmpkv)); - s->tmpkv.base.value_len = 0; - if (donull) { - memset (s, 0, sizeof (Sdb)); - } -} - -SDB_API bool sdb_free(Sdb* s) { - if (s && s->ht && s->refs) { - s->refs--; - if (s->refs < 1) { - s->refs = 0; - sdb_fini (s, false); - s->ht = NULL; - sdb_gh_free (s); - return true; - } - } - return false; -} - -SDB_API const char *sdb_const_get_len(Sdb* s, const char *key, int *vlen, ut32 *cas) { - ut32 pos, len; - ut64 now = 0LL; - bool found; - - if (cas) { - *cas = 0; - } - if (vlen) { - *vlen = 0; - } - if (!s || !key) { - return NULL; - } - // TODO: optimize, iterate once - size_t keylen = strlen (key); - - /* search in memory */ - if (s->ht) { - SdbKv *kv = (SdbKv*) sdb_ht_find_kvp (s->ht, key, &found); - if (found) { - char *kvv = sdbkv_value (kv); - if (!kvv || !*kvv) { - return NULL; - } - if (s->timestamped && kv->expire) { - if (!now) { - now = sdb_now (); - } - if (now > kv->expire) { - sdb_unset (s, key, 0); - return NULL; - } - } - if (cas) { - *cas = kv->cas; - } - if (vlen) { - *vlen = sdbkv_value_len (kv); - } - return sdbkv_value (kv); - } - } - /* search in gperf */ - if (s->gp && s->gp->get) { - return s->gp->get (key); - } - /* search in disk */ - if (s->fd == -1) { - return NULL; - } - (void) cdb_findstart (&s->db); - if (!s->ht || cdb_findnext (&s->db, s->ht->opt.hashfn (key), key, keylen) < 1) { - return NULL; - } - len = cdb_datalen (&s->db); - if (len < SDB_MIN_VALUE || len >= SDB_MAX_VALUE) { - return NULL; - } - if (vlen) { - *vlen = len; - } - pos = cdb_datapos (&s->db); - return s->db.map + pos; -} - -SDB_API const char *sdb_const_get(Sdb* s, const char *key, ut32 *cas) { - return sdb_const_get_len (s, key, NULL, cas); -} - -// TODO: add sdb_getf? - -SDB_API char *sdb_get_len(Sdb* s, const char *key, int *vlen, ut32 *cas) { - const char *value = sdb_const_get_len (s, key, vlen, cas); - return value ? sdb_strdup (value) : NULL; -} - -SDB_API char *sdb_get(Sdb* s, const char *key, ut32 *cas) { - return sdb_get_len (s, key, NULL, cas); -} - -SDB_API char *sdb_nget(Sdb* s, ut64 nkey, ut32 *cas) { - char buf[SDB_NUM_BUFSZ]; - const char *key = sdb_itoa (nkey, 16, buf, sizeof (buf)); - return sdb_get_len (s, key, NULL, cas); -} - -SDB_API int sdb_unset(Sdb* s, const char *key, ut32 cas) { - return key? sdb_set (s, key, "", cas): 0; -} - -SDB_API int sdb_nunset(Sdb* s, ut64 nkey, ut32 cas) { - return sdb_nset (s, nkey, "", cas); -} - -/* remove from memory */ -SDB_API bool sdb_remove(Sdb *s, const char *key, ut32 cas) { - return sdb_ht_delete (s->ht, key); -} - -// alias for '-key=str'.. '+key=str' concats -SDB_API int sdb_uncat(Sdb *s, const char *key, const char *value, ut32 cas) { - // remove 'value' from current key value. - // TODO: cas is ignored here - int vlen = 0, valen; - char *p, *v = sdb_get_len (s, key, &vlen, NULL); - int mod = 0; - if (!v || !key || !value) { - sdb_gh_free (v); - return 0; - } - valen = strlen (value); - if (valen > 0) { - while ((p = strstr (v, value))) { - memmove (p, p + valen, strlen (p + valen) + 1); - mod = 1; - } - } - if (mod) { - sdb_set_owned (s, key, v, 0); - } else { - sdb_gh_free (v); - } - return 0; -} - -SDB_API int sdb_concat(Sdb *s, const char *key, const char *value, ut32 cas) { - int kl, vl; - const char *p; - char *o; - if (!s || !key || !*key || !value || !*value) { - return 0; - } - p = sdb_const_get_len (s, key, &kl, 0); - if (!p) { - return sdb_set (s, key, value, cas); - } - vl = strlen (value); - o = (char *)sdb_gh_malloc (kl + vl + 1); - if (o) { - memcpy (o, p, kl); - memcpy (o + kl, value, vl + 1); - return sdb_set_owned (s, key, o, cas); - } - return 0; -} - -// set if not defined -SDB_API int sdb_add(Sdb* s, const char *key, const char *val, ut32 cas) { - if (sdb_exists (s, key)) { - return 0; - } - return sdb_set (s, key, val, cas); -} - -SDB_API int sdb_nadd(Sdb* s, ut64 nkey, const char *val, ut32 cas) { - char buf[SDB_NUM_BUFSZ]; - const char *key = sdb_itoa (nkey, 16, buf, sizeof (buf)); - return sdb_add (s, key, val, cas); -} - -SDB_API bool sdb_exists(Sdb* s, const char *key) { - ut32 pos; - char ch; - bool found; - size_t klen = strlen (key) + 1; - if (!s) { - return false; - } - SdbKv *kv = (SdbKv*)sdb_ht_find_kvp (s->ht, key, &found); - if (found && kv) { - char *v = sdbkv_value (kv); - return v && *v; - } - if (s->fd == -1) { - return false; - } - (void)cdb_findstart (&s->db); - if (cdb_findnext (&s->db, sdb_hash (key), key, klen)) { - pos = cdb_datapos (&s->db); - cdb_read (&s->db, &ch, 1, pos); - return ch != 0; - } - return false; -} - -SDB_API int sdb_open_gperf(Sdb *s, SdbGperf *gp) { - if (!s || !gp) { - return -1; - } - s->gp = gp; - return 0; -} - -static int sdb_open_text(Sdb *s, const char *file) { - if (!sdb_text_load (s, file)) { - return -1; - } - return s->fd; -} - -SDB_API int sdb_open(Sdb *s, const char *file) { - struct stat st; - if (!s) { - return -1; - } - if (file) { - if (sdb_text_check (s, file)) { - return sdb_open_text (s, file); - } - if (s->fd != -1) { - close (s->fd); - s->fd = -1; - } - s->fd = open (file, O_RDONLY | O_BINARY); - if (file != s->dir) { - sdb_gh_free (s->dir); - s->dir = sdb_strdup (file); - s->path = NULL; // TODO: path is important - } - } - s->last = 0LL; - if (s->fd != -1 && fstat (s->fd, &st) != -1) { - if ((S_IFREG & st.st_mode) != S_IFREG) { - close (s->fd); - s->fd = -1; - return -1; - } - s->last = st.st_mtime; - } - if (s->fd != -1) { - cdb_init (&s->db, s->fd); - } - return s->fd; -} - -SDB_API void sdb_close(Sdb *s) { - if (s) { - if (s->fd != -1) { - if (s->db.fd != -1 && s->db.fd == s->fd) { - /* close db fd as well */ - s->db.fd = -1; - } - close (s->fd); - s->fd = -1; - } - if (s->dir) { - sdb_gh_free (s->dir); - s->dir = NULL; - } - s->gp = NULL; - } -} - -SDB_API void sdb_reset(Sdb* s) { - if (!s) { - return; - } - /* ignore disk cache, file is not removed, but we will ignore - * its values when syncing again */ - sdb_close (s); - /* empty memory hashtable */ - sdb_ht_free (s->ht); - s->ht = sdb_ht_new (); -} - -static char lastChar(const char *str) { - int len = strlen (str); - return str[(len > 0)? len - 1: 0]; -} - -static bool match(const char *str, const char *expr) { - bool startsWith = *expr == '^'; - bool endsWith = lastChar (expr) == '$'; - if (startsWith && endsWith) { - return strlen (str) == strlen (expr) - 2 && \ - !strncmp (str, expr + 1, strlen (expr) - 2); - } - if (startsWith) { - return !strncmp (str, expr + 1, strlen (expr) - 1); - } - if (endsWith) { - int alen = strlen (str); - int blen = strlen (expr) - 1; - if (alen <= blen) { - return false; - } - const char *a = str + strlen (str) - blen; - return (!strncmp (a, expr, blen)); - } - return strstr (str, expr); -} - -SDB_API bool sdbkv_match(SdbKv *kv, const char *expr) { - // TODO: add syntax to negate condition - // TODO: add syntax to OR k/v instead of AND - // [^]str[$]=[^]str[$] - const char *eq = strchr (expr, '='); - if (eq) { - char *e = sdb_strdup (expr); - char *ep = e + (eq - expr); - *ep++ = 0; - bool res = !*e || match (sdbkv_key (kv), e); - bool res2 = !*ep || match (sdbkv_value (kv), ep); - sdb_gh_free (e); - return res && res2; - } - return match (sdbkv_key (kv), expr); -} - -SDB_API SdbKv* sdbkv_new(const char *k, const char *v) { - return sdbkv_new2 (k, strlen (k), v, strlen (v)); -} - -SDB_API SdbKv* sdbkv_new2(const char *k, int kl, const char *v, int vl) { - SdbKv *kv; - if (v) { - if (vl >= SDB_VSZ) { - return NULL; - } - } else { - vl = 0; - } - if (kl >= SDB_KSZ) { - return NULL; - } - kv = R_NEW0 (SdbKv); - if (!kv) { - return NULL; - } - kv->base.key_len = kl; - kv->base.key = sdb_gh_malloc (kv->base.key_len + 1); - if (!kv->base.key) { - sdb_gh_free (kv); - return NULL; - } - memcpy (kv->base.key, k, kv->base.key_len + 1); - kv->base.value_len = vl; - if (vl) { - kv->base.value = sdb_gh_malloc (vl + 1); - if (!kv->base.value) { - sdb_gh_free (kv->base.key); - sdb_gh_free (kv); - return NULL; - } - memcpy (kv->base.value, v, vl + 1); - } else { - kv->base.value = NULL; - kv->base.value_len = 0; - } - kv->cas = nextcas (kv); - kv->expire = 0LL; - return kv; -} - -SDB_API void sdbkv_free(SdbKv *kv) { - if (kv) { - sdb_gh_free (sdbkv_key (kv)); - sdb_gh_free (sdbkv_value (kv)); - R_FREE (kv); - } -} - -static ut32 sdb_set_internal(Sdb* s, const char *key, char *val, bool owned, ut32 cas) { - ut32 vlen, klen; - bool found; - if (!s || !key) { - return 0; - } - if (!val) { - if (owned) { - val = sdb_strdup (""); - } else { - val = (char *)""; - } - } - // XXX strlen computed twice.. because of check_*() - klen = strlen (key); - vlen = strlen (val); - if (klen >= SDB_KSZ || vlen >= SDB_VSZ) { - if (owned) { - sdb_gh_free (val); - } - return 0; - } - if (s->journal != -1) { - sdb_journal_log (s, key, val); - } - cdb_findstart (&s->db); - SdbKv *kv = sdb_ht_find_kvp (s->ht, key, &found); - if (found && sdbkv_value (kv)) { - if (cdb_findnext (&s->db, sdb_hash (key), key, klen)) { - if (cas && kv->cas != cas) { - if (owned) { - sdb_gh_free (val); - } - return 0; - } - if (vlen == sdbkv_value_len (kv) && !strcmp (sdbkv_value (kv), val)) { - sdb_hook_call (s, key, val); - return kv->cas; - } - kv->cas = cas = nextcas (kv); - if (owned) { - kv->base.value_len = vlen; - sdb_gh_free (kv->base.value); - kv->base.value = val; // owned - } else { - if ((ut32)vlen > kv->base.value_len) { - sdb_gh_free (kv->base.value); - kv->base.value = sdb_gh_malloc (vlen + 1); - } - memcpy (kv->base.value, val, vlen + 1); - kv->base.value_len = vlen; - } - } else { - sdb_ht_delete (s->ht, key); - } - sdb_hook_call (s, key, val); - return cas; - } - // empty values are also stored - // TODO store only the ones that are in the CDB - if (owned) { - kv = sdbkv_new2 (key, klen, NULL, 0); - if (kv) { - kv->base.value = val; - kv->base.value_len = vlen; - } - } else { - kv = sdbkv_new2 (key, klen, val, vlen); - } - if (kv) { - cas = kv->cas = nextcas (kv); - sdb_ht_insert_kvp (s->ht, kv, true /*update*/); - sdb_hook_call (s, key, val); - sdb_gh_free (kv); - return cas; - } - // kv set failed, no need to callback sdb_hook_call (s, key, val); - return 0; -} - -SDB_API int sdb_set_owned(Sdb* s, const char *key, char *val, ut32 cas) { - return sdb_set_internal (s, key, val, true, cas); -} - -SDB_API int sdb_set(Sdb* s, const char *key, const char *val, ut32 cas) { - return sdb_set_internal (s, key, (char *)val, false, cas); -} - -SDB_API int sdb_nset(Sdb* s, ut64 nkey, const char *val, ut32 cas) { - char buf[SDB_NUM_BUFSZ]; - const char *key = sdb_itoa (nkey, 16, buf, sizeof (buf)); - return sdb_set_internal (s, key, (char *)val, false, cas); -} - -SDB_API int sdb_num_nset(Sdb* s, ut64 nkey, ut64 nval, ut32 cas) { - char buf[SDB_NUM_BUFSZ]; - const char *key = sdb_itoa (nkey, 16, buf, sizeof (buf)); - return sdb_num_set (s, key, nval, cas); -} - -SDB_API ut64 sdb_num_nget(Sdb *s, ut64 nkey, ut32 *cas) { - char buf[SDB_NUM_BUFSZ]; - const char *key = sdb_itoa (nkey, 16, buf, sizeof (buf)); - return sdb_num_get (s, key, cas); -} - -static bool sdb_foreach_list_cb(void *user, const char *k, const char *v) { - SdbList *list = (SdbList *)user; - SdbKv *kv = R_NEW0 (SdbKv); - if (kv) { - /* seems like some k/v are constructed in the stack and cant be used after returning */ - kv->base.key = sdb_strdup (k); - kv->base.value = sdb_strdup (v); - ls_append (list, kv); - return true; - } - return false; -} - -static int __cmp_asc(const void *a, const void *b) { - const SdbKv *ka = (SdbKv *)a; - const SdbKv *kb = (SdbKv *)b; - return strcmp (sdbkv_key (ka), sdbkv_key (kb)); -} - -SDB_API SdbList *sdb_foreach_list(Sdb* s, bool sorted) { - SdbList *list = ls_newf ((SdbListFree)sdbkv_free); - sdb_foreach (s, sdb_foreach_list_cb, list); - if (sorted) { - ls_sort (list, __cmp_asc); - } - return list; -} - -struct foreach_list_filter_t { - SdbForeachCallback filter; - SdbList *list; -}; - -static bool sdb_foreach_list_filter_cb(void *user, const char *k, const char *v) { - struct foreach_list_filter_t *u = (struct foreach_list_filter_t *)user; - SdbList *list = u->list; - SdbKv *kv = NULL; - - if (!u->filter || u->filter (NULL, k, v)) { - kv = R_NEW0 (SdbKv); - if (!kv) { - goto err; - } - kv->base.key = sdb_strdup (k); - kv->base.value = sdb_strdup (v); - if (!kv->base.key || !kv->base.value) { - goto err; - } - ls_append (list, kv); - } - return true; - err: - sdbkv_free (kv); - return false; -} - -SDB_API SdbList *sdb_foreach_list_filter(Sdb* s, SdbForeachCallback filter, bool sorted) { - struct foreach_list_filter_t u; - SdbList *list = ls_newf ((SdbListFree)sdbkv_free); - - if (!list) { - return NULL; - } - u.filter = filter; - u.list = list; - sdb_foreach (s, sdb_foreach_list_filter_cb, &u); - if (sorted) { - ls_sort (list, __cmp_asc); - } - return list; -} - -typedef struct { - const char *expr; - SdbList *list; - bool single; -} _match_sdb_user; - -static bool sdb_foreach_match_cb(void *user, const char *k, const char *v) { - _match_sdb_user *o = (_match_sdb_user*)user; - SdbKv tkv = {{0}}; - tkv.base.key = (char *)k; - tkv.base.value = (char *)v; - if (sdbkv_match (&tkv, o->expr)) { - SdbKv *kv = R_NEW0 (SdbKv); - if (!kv) { - return false; - } - kv->base.key = sdb_strdup (k); - kv->base.value = sdb_strdup (v); - ls_append (o->list, kv); - if (o->single) { - return false; - } - } - return true; -} - -SDB_API SdbList *sdb_foreach_match(Sdb* s, const char *expr, bool single) { - SdbList *list = ls_newf ((SdbListFree)sdbkv_free); - _match_sdb_user o = { expr, list, single }; - sdb_foreach (s, sdb_foreach_match_cb, &o); - return list; -} - -static int getbytes(Sdb *s, char *b, int len) { - if (!cdb_read (&s->db, b, len, s->pos)) { - return -1; - } - s->pos += len; - return len; -} - -static bool sdb_foreach_end(Sdb *s, bool result) { - s->depth--; - return result; -} - -static bool sdb_foreach_cdb(Sdb *s, SdbForeachCallback cb, SdbForeachCallback cb2, void *user) { - char *v = NULL; - char k[SDB_MAX_KEY] = {0}; - bool found; - sdb_dump_begin (s); - while (sdb_dump_dupnext (s, k, &v, NULL)) { - SdbKv *kv = sdb_ht_find_kvp (s->ht, k, &found); - if (found) { - sdb_gh_free (v); - if (kv && sdbkv_key (kv) && sdbkv_value (kv)) { - if (!cb (user, sdbkv_key (kv), sdbkv_value (kv))) { - return false; - } - if (cb2 && !cb2 (user, k, sdbkv_value (kv))) { - return false; - } - } - } else { - if (!cb (user, k, v)) { - sdb_gh_free (v); - return false; - } - sdb_gh_free (v); - } - } - return true; -} - -SDB_API bool sdb_foreach(Sdb* s, SdbForeachCallback cb, void *user) { - if (!s) { - return false; - } - if (s->gp) { - return s->gp->foreach ((GperfForeachCallback)cb, user); - } - s->depth++; - bool result = sdb_foreach_cdb (s, cb, NULL, user); - if (!result) { - return sdb_foreach_end (s, false); - } - - ut32 i; - for (i = 0; i < s->ht->size; i++) { - HtPPBucket *bt = &s->ht->table[i]; - SdbKv *kv; - ut32 j, count; - - BUCKET_FOREACH_SAFE (s->ht, bt, j, count, kv) { - if (kv) { - const char *kvv = sdbkv_value (kv); - if (kvv && *kvv && !cb (user, sdbkv_key (kv), kvv)) { - return sdb_foreach_end (s, false); - } - } - } - } - return sdb_foreach_end (s, true); -} - -static bool _insert_into_disk(void *user, const char *key, const char *value) { - Sdb *s = (Sdb *)user; - if (s) { - sdb_disk_insert (s, key, value); - return true; - } - return false; -} - -static bool _remove_afer_insert(void *user, const char *k, const char *v) { - Sdb *s = (Sdb *)user; - if (s) { - sdb_ht_delete (s->ht, k); - return true; - } - return false; -} - -SDB_API bool sdb_sync(Sdb* s) { - bool result; - ut32 i; - - if (!s || !sdb_disk_create (s)) { - return false; - } - result = sdb_foreach_cdb (s, _insert_into_disk, _remove_afer_insert, s); - if (!result) { - return false; - } - - /* append new keyvalues */ - for (i = 0; i < s->ht->size; i++) { - HtPPBucket *bt = &s->ht->table[i]; - SdbKv *kv; - ut32 j, count; - - BUCKET_FOREACH_SAFE (s->ht, bt, j, count, kv) { - if (sdbkv_key (kv)) { - const char *kvv = sdbkv_value (kv); - if (kvv && *kvv && !kv->expire) { - if (sdb_disk_insert (s, sdbkv_key (kv), sdbkv_value (kv))) { - sdb_remove (s, sdbkv_key (kv), 0); - } - } - } - } - } - sdb_disk_finish (s); - sdb_journal_clear (s); - // TODO: sdb_reset memory state? - return true; -} - -SDB_API void sdb_dump_begin(Sdb* s) { - if (s->fd != -1) { - s->pos = sizeof (((struct cdb_make *)0)->final); - seek_set (s->fd, s->pos); - } else { - s->pos = 0; - } -} - -SDB_API SdbKv *sdb_dump_next(Sdb* s) { - char *v = NULL; - char k[SDB_MAX_KEY] = {0}; - int vl = 0; - // we dont need to malloc, because all values are null terminated in memory. - if (!sdb_dump_dupnext (s, k, &v, &vl)) { - return NULL; - } - vl--; - snprintf (sdbkv_key (&s->tmpkv), SDB_KSZ, "%s", k); - sdb_gh_free (sdbkv_value (&s->tmpkv)); - s->tmpkv.base.value = v; - s->tmpkv.base.value_len = vl; - return &s->tmpkv; -} - -SDB_API bool sdb_dump_hasnext(Sdb* s) { - ut32 k, v; - if (!cdb_getkvlen (&s->db, &k, &v, s->pos)) { - return false; - } - if (k < 1 || v < 1) { - return false; - } - s->pos += k + v + 4; - return true; -} - -SDB_API bool sdb_stats(Sdb *s, ut32 *disk, ut32 *mem) { - if (!s) { - return false; - } - if (disk) { - ut32 count = 0; - if (s->fd != -1) { - sdb_dump_begin (s); - while (sdb_dump_hasnext (s)) { - count ++; - } - } - *disk = count; - } - if (mem) { - *mem = s->ht->count; - } - return disk || mem; -} - -// TODO: make it static? internal api? -SDB_API bool sdb_dump_dupnext(Sdb* s, char *key, char **value, int *_vlen) { - ut32 vlen = 0, klen = 0; - if (value) { - *value = NULL; - } - if (_vlen) { - *_vlen = 0; - } - if (!cdb_getkvlen (&s->db, &klen, &vlen, s->pos)) { - return false; - } - s->pos += 4; - if (klen < 1 || vlen < 1) { - return false; - } - if (_vlen) { - *_vlen = vlen; - } - if (key) { - key[0] = 0; - if (klen > SDB_MIN_KEY && klen < SDB_MAX_KEY) { - if (getbytes (s, key, klen) == -1) { - return 0; - } - key[klen] = 0; - } - } - if (value) { - *value = 0; - if (vlen < SDB_MAX_VALUE) { - *value = (char *)sdb_gh_malloc (vlen + 10); - if (!*value) { - return false; - } - if (getbytes (s, *value, vlen) == -1) { - sdb_gh_free (*value); - *value = NULL; - return false; - } - (*value)[vlen] = 0; - } - } - return true; -} - -static inline ut64 parse_expire(ut64 e) { - const ut64 month = 30 * 24 * 60 * 60; - if (e > 0 && e < month) { - e += sdb_now (); - } - return e; -} - -SDB_API bool sdb_expire_set(Sdb* s, const char *key, ut64 expire, ut32 cas) { - char *buf; - ut32 pos, len; - SdbKv *kv; - bool found; - s->timestamped = true; - if (!key) { - s->expire = parse_expire (expire); - return true; - } - kv = (SdbKv*)sdb_ht_find_kvp (s->ht, key, &found); - if (found && kv) { - if (*sdbkv_value (kv)) { - if (!cas || cas == kv->cas) { - kv->expire = parse_expire (expire); - return true; - } - } - return false; - } - if (s->fd == -1) { - return false; - } - (void) cdb_findstart (&s->db); - if (!cdb_findnext (&s->db, sdb_hash (key), key, strlen (key) + 1)) { - return false; - } - pos = cdb_datapos (&s->db); - len = cdb_datalen (&s->db); - if (len < 1 || len >= INT32_MAX) { - return false; - } - if (!(buf = (char *)sdb_gh_calloc (1, len + 1))) { - return false; - } - cdb_read (&s->db, buf, len, pos); - buf[len] = 0; - sdb_set_owned (s, key, buf, cas); - return sdb_expire_set (s, key, expire, cas); // recursive -} - -SDB_API ut64 sdb_expire_get(Sdb* s, const char *key, ut32 *cas) { - bool found = false; - SdbKv *kv = (SdbKv*)sdb_ht_find_kvp (s->ht, key, &found); - if (found && kv && *sdbkv_value (kv)) { - if (cas) { - *cas = kv->cas; - } - return kv->expire; - } - return 0LL; -} - -SDB_API bool sdb_hook(Sdb* s, SdbHook cb, void* user) { - int i = 0; - SdbHook hook; - SdbListIter *iter; - if (s->hooks) { - ls_foreach_cast (s->hooks, iter, SdbHook, hook) { - if (!(i % 2) && (hook == cb)) { - return false; - } - i++; - } - } else { - s->hooks = ls_new (); - s->hooks->free = NULL; - } - ls_append (s->hooks, (void*)cb); - ls_append (s->hooks, user); - return true; -} - -SDB_API bool sdb_unhook(Sdb* s, SdbHook h) { - int i = 0; - SdbHook hook; - SdbListIter *iter, *iter2; - ls_foreach_cast (s->hooks, iter, SdbHook, hook) { - if (!(i % 2) && (hook == h)) { - iter2 = iter->n; - ls_delete (s->hooks, iter); - ls_delete (s->hooks, iter2); - return true; - } - i++; - } - return false; -} - -SDB_API int sdb_hook_call(Sdb *s, const char *k, const char *v) { - SdbListIter *iter; - SdbHook hook; - int i = 0; - if (s->timestamped && s->last) { - s->last = sdb_now (); - } - ls_foreach_cast (s->hooks, iter, SdbHook, hook) { - if (!(i % 2) && k && iter->n) { - void *u = iter->n->data; - hook (s, u, k, v); - } - i++; - } - return i >> 1; -} - -SDB_API void sdb_hook_free(Sdb *s) { - ls_free (s->hooks); - s->hooks = NULL; -} - -SDB_API void sdb_config(Sdb *s, int options) { - s->options = options; - if (options & SDB_OPTION_SYNC) { - // sync on every query - } - if (options & SDB_OPTION_JOURNAL) { - // sync on every query - sdb_journal_open (s); - // load journaling if exists - sdb_journal_load (s); - sdb_journal_clear (s); - } else { - sdb_journal_close (s); - } - if (options & SDB_OPTION_NOSTAMP) { - // sync on every query - s->last = 0LL; - } - if (options & SDB_OPTION_FS) { - // have access to fs (handle '.' or not in query) - } -} - -SDB_API bool sdb_unlink(Sdb* s) { - sdb_fini (s, true); - return sdb_disk_unlink (s); -} - -SDB_API void sdb_drain(Sdb *s, Sdb *f) { - if (s && f) { - f->refs = s->refs; - sdb_fini (s, true); - *s = *f; - sdb_gh_free (f); - } -} - -static bool copy_foreach_cb(void *user, const char *k, const char *v) { - Sdb *dst = (Sdb *)user; - sdb_set (dst, k, v, 0); - return true; -} - -SDB_API void sdb_copy(Sdb *src, Sdb *dst) { - sdb_foreach (src, copy_foreach_cb, dst); - SdbListIter *it; - SdbNs *ns; - ls_foreach_cast (src->ns, it, SdbNs*, ns) { - sdb_copy (ns->sdb, sdb_ns (dst, ns->name, true)); - } -} - -typedef struct { - Sdb *sdb; - const char *key; -} UnsetCallbackData; - -static bool unset_cb(void *user, const char *k, const char *v) { - UnsetCallbackData *ucd = (UnsetCallbackData *)user; - if (sdb_match (k, ucd->key)) { - sdb_unset (ucd->sdb, k, 0); - } - return true; -} - -SDB_API int sdb_unset_like(Sdb *s, const char *k) { - UnsetCallbackData ucd = { s, k }; - return sdb_foreach (s, unset_cb, &ucd); -} - -typedef struct { - Sdb *sdb; - const char *key; - const char *val; - SdbForeachCallback cb; - const char **array; - int array_index; - int array_size; -} LikeCallbackData; - -static bool like_cb(void *user, const char *k, const char *v) { - LikeCallbackData *lcd = (LikeCallbackData *)user; - if (!user) { - return false; - } - if (k && lcd->key && !sdb_match (k, lcd->key)) { - return true; - } - if (v && lcd->val && !sdb_match (v, lcd->val)) { - return true; - } - if (lcd->array) { - int idx = lcd->array_index; - int newsize = lcd->array_size + sizeof (char*) * 2; - const char **newarray = (const char **)sdb_gh_realloc ((void*)lcd->array, newsize); - if (!newarray) { - return false; - } - lcd->array = newarray; - lcd->array_size = newsize; - // concatenate in array - lcd->array[idx] = k; - lcd->array[idx + 1] = v; - lcd->array[idx + 2] = NULL; - lcd->array[idx + 3] = NULL; - lcd->array_index = idx+2; - } else { - if (lcd->cb) { - lcd->cb (lcd->sdb, k, v); - } - } - return true; -} - -SDB_API char** sdb_like(Sdb *s, const char *k, const char *v, SdbForeachCallback cb) { - LikeCallbackData lcd = { s, k, v, cb, NULL, 0, 0 }; - if (cb) { - sdb_foreach (s, like_cb, &lcd); - return NULL; - } - if (k && !*k) { - lcd.key = NULL; - } - if (v && !*v) { - lcd.val = NULL; - } - lcd.array_size = sizeof (char*) * 2; - lcd.array = (const char **)sdb_gh_calloc (lcd.array_size, 1); // XXX shouldnt be const - if (!lcd.array) { - return NULL; - } - lcd.array_index = 0; - sdb_foreach (s, like_cb, &lcd); - if (lcd.array_index == 0) { - sdb_gh_free ((void*)lcd.array); - return NULL; - } - return (char**)lcd.array; -} diff --git a/shlr/sdb/src/set.c b/shlr/sdb/src/set.c deleted file mode 100644 index cdb4f08f4d472..0000000000000 --- a/shlr/sdb/src/set.c +++ /dev/null @@ -1,78 +0,0 @@ -/* sdb - MIT - Copyright 2019-2020 - pancake */ - -#include "sdb/set.h" - -//// set foreach spaguetti -typedef struct { - void *cbptr; - void *userdata; -} SetData; - -static bool u_foreach_cb(void *user, const ut64 k, const void *nada) { - SetData *sd = (SetData*)user; - set_u_foreach_cb cb = (set_u_foreach_cb)sd->cbptr; - return cb (sd->userdata, k); -} - -SDB_API void set_u_foreach(SetU *s, set_u_foreach_cb cb, void *userdata) { - SetData sd; - sd.cbptr = (void *)cb; - sd.userdata = (void *)userdata; - ht_up_foreach (s, u_foreach_cb, &sd); -} - -static bool p_foreach_cb(void *user, const void *k, const void *nada) { - SetData *sd = (SetData*)user; - set_p_foreach_cb cb = (set_p_foreach_cb)sd->cbptr; - return cb (sd->userdata, k); -} - -SDB_API void set_p_foreach(SetP *s, set_p_foreach_cb cb, void *userdata) { - SetData sd; - sd.cbptr = (void *)cb; - sd.userdata = (void *)userdata; - ht_pp_foreach (s, p_foreach_cb, &sd); -} -//// - -SDB_API SetP *set_p_new(void) { - return ht_pp_new0 (); -} - -SDB_API void set_p_add(SetP *s, void *u) { - ht_pp_insert (s, u, (void*)1); -} - -SDB_API bool set_p_contains(SetP *s, void *u) { - return ht_pp_find (s, u, NULL) != NULL; -} - -SDB_API void set_p_delete(SetP *s, void *u) { - ht_pp_delete (s, u); -} - -SDB_API void set_p_free(SetP *p) { - ht_pp_free ((HtPP*)p); -} - -// u - -SDB_API SetU *set_u_new(void) { - return (SetU*)ht_up_new0 (); -} - -SDB_API void set_u_add(SetU *s, ut64 u) { - ht_up_insert (s, u, (void*)1); -} - -SDB_API bool set_u_contains(SetU *s, ut64 u) { - return ht_up_find (s, u, NULL) != NULL; -} - -SDB_API void set_u_delete(SetU *s, ut64 u) { - ht_up_delete (s, u); -} - -SDB_API void set_u_free(SetU *s) { - ht_up_free (s); -} diff --git a/shlr/sdb/src/text.c b/shlr/sdb/src/text.c deleted file mode 100644 index 604dc89424208..0000000000000 --- a/shlr/sdb/src/text.c +++ /dev/null @@ -1,492 +0,0 @@ -/* sdb - MIT - Copyright 2020-2022 - pancake, thestr4ng3r */ - -#include "sdb/sdb.h" - -#include -#include -#include -#if USE_MMAN -#include -#endif - -/** - * ******************** - * Plaintext SDB Format - * ******************** - * - * Files are UTF-8 and use '\n' line endings. Always. - * - * Lines starting with '/' denote the path of the namespace for the following data: - * - * /some/namespace - * - * The default path is root, just a slash also means root. - * These paths are always absolute from the root. Characters that must be escaped in a path are: '/', '\\', '\n', '\r': - * - * /s\/ome/name\nspa\\ce - * - * SDB entries are written each as a single k=v line: - * - * somekey=somevalue - * - * To distinguish these from path lines, if there is a leading '/' in the key, it must be escaped - * (slashes later in the line don't have to be escaped): - * - * \/slashedkey=somevalue - * - * Other than that, at any postion, '\\', '\n' and '\r' must be escaped: - * - * some\\key=some\nvalue - * - * In the key, '=' must also be escaped (not necessary in the value): - * - * some\=key=some=value - * - * -------- - * Example: - * - * / - * key=intheroot - * \/slashedkey=somevalue - * some\\key=some\nvalue - * some\=key=some=value - * - * /subns - * some=stuff in the sub-namespace - * - * /subns/deeper - * this=is in /subns/deeper - * -*/ - -static int cmp_ns(const void *a, const void *b) { - const SdbNs *nsa = (const SdbNs *)a; - const SdbNs *cia = (const SdbNs *)b; - return strcmp (nsa->name, cia->name); -} - - -// n = position we are currently looking at -// p = position until we have already written everything -// flush a block of text that doesn't have to be escaped - -static bool escape_flush(int fd, const char *p, const char *n) { - if (p != n && write (fd, p, n - p) != n - p) { - return false; - } - return true; -} - -static bool escape_loop(int fd, const char *str, char ch) { - const char *p = str; - const char *n = p; - bool ok = true; - while (*n && ok) { - ok = true; - switch (*n) { - case '\\': - ok = escape_flush (fd, p, n) && write (fd, "\\\\", 2) == 2; - p = n + 1; - break; - case '\r': - ok = escape_flush (fd, p, n) && write (fd, "\\r", 2) == 2; - p = n + 1; - break; - case '\n': - ok = escape_flush (fd, p, n) && write (fd, "\\n", 2) == 2; - p = n + 1; - break; - default: - if (ch && *n == ch) { - char pair[2] = { '\\', ch }; - ok = escape_flush (fd, p, n) && write (fd, &pair, 2) == 2; - p = n + 1; - } - break; - } - n++; - } - return ok && escape_flush (fd, p, n); -} - -static bool write_path(int fd, SdbList *path) { - if (write (fd, "/", 1) != 1) { // always print a /, even if path is empty - return false; - } - SdbListIter *it; - const char *path_token; - bool first = true; - ls_foreach_cast (path, it, const char *, path_token) { - if (first) { - first = false; - } else { - if (write (fd, "/", 1) != 1) { - return false; - } - } - if (!escape_loop (fd, path_token, '/')) { - return false; - } - } - return true; -} - -static bool write_key(int fd, const char *k) { - // escape leading '/' - if (*k == '/') { - if (write (fd, "\\", 1) != 1) { - return false; - } - } - return escape_loop (fd, k, '='); -} - -static bool write_value(int fd, const char *v) { - return escape_loop (fd, v, 0); -} - -static bool save_kv_cb(void *user, const char *k, const char *v) { - int fd = *((int *)user); - if (!write_key (fd, k) || write (fd, "=", 1) != 1) { - return false; - } - if (!write_value (fd, v) || write (fd, "\n", 1) != 1) { - return false; - } - return true; -} - -static bool text_save(Sdb *s, int fd, bool sort, SdbList *path) { - // path - if (!write_path (fd, path) || write (fd, "\n", 1) != 1) { - return false; - } - - // k=v entries - if (sort) { - SdbList *l = sdb_foreach_list (s, true); - SdbKv *kv; - SdbListIter *it; - ls_foreach_cast (l, it, SdbKv*, kv) { - save_kv_cb (&fd, sdbkv_key (kv), sdbkv_value (kv)); - } - ls_free (l); - } else { - // This is faster when sorting is not needed. - sdb_foreach (s, save_kv_cb, &fd); - } - - // sub-namespaces - SdbList *l = s->ns; - if (sort) { - l = ls_clone (l); - ls_sort (l, cmp_ns); - } - SdbNs *ns; - SdbListIter *it; - ls_foreach_cast (l, it, SdbNs*, ns) { - if (write (fd, "\n", 1) != 1) { - ls_free (l); - return false; - } - ls_push (path, ns->name); - text_save (ns->sdb, fd, sort, path); - ls_pop (path); - } - if (l != s->ns) { - ls_free (l); - } - - return true; -} - -SDB_API bool sdb_text_save_fd(Sdb *s, int fd, bool sort) { - SdbList *path = ls_new (); - if (!path) { - return false; - } - bool r = text_save (s, fd, sort, path); - ls_free (path); - return r; -} - -SDB_API bool sdb_text_save(Sdb *s, const char *file, bool sort) { - int fd = open (file, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644); - if (fd < 0) { - return false; - } - bool r = sdb_text_save_fd (s, fd, sort); - close (fd); - return r; -} - -typedef enum { - STATE_NEWLINE, - STATE_PATH, - STATE_KEY, - STATE_VALUE -} LoadState; - -typedef struct { - bool eof; - char *buf; - size_t bufsz; - Sdb *root_db; - Sdb *cur_db; // current namespace, changes when encountering a path line - size_t pos; // current processing position in the buffer - size_t line_begin; - size_t token_begin; // beginning of the currently processed token in the buffer - size_t shift; // amount to shift chars to the left (from unescaping) - SdbList/**/ *path; - LoadState state; - bool unescape; // whether the prev char was a backslash, i.e. the current one is escaped -} LoadCtx; - -// to be called at the end of a line. -// save all the data processed from the line into the database. -// assumes that the ctx->buf is allocated until ctx->buf[ctx->pos] inclusive! -static void load_process_line(LoadCtx *ctx) { - ctx->unescape = false; - // finish up the line - ctx->buf[ctx->pos - ctx->shift] = '\0'; - switch (ctx->state) { - case STATE_PATH: { - ls_push (ctx->path, (void *)ctx->token_begin); - SdbListIter *it; - void *token_off_tmp; - ctx->cur_db = ctx->root_db; - ls_foreach_cast (ctx->path, it, void*, token_off_tmp) { - size_t token_off = (size_t)token_off_tmp; - if (!ctx->buf[token_off]) { - continue; - } - ctx->cur_db = sdb_ns (ctx->cur_db, ctx->buf + token_off, 1); - if (!ctx->cur_db) { - ctx->cur_db = ctx->root_db; - break; - } - } - ls_destroy (ctx->path); - break; - } - case STATE_VALUE: { - const char *k = ctx->buf + ctx->line_begin; - const char *v = ctx->buf + ctx->token_begin; - if (!*k || !*v) { - break; - } - sdb_set (ctx->cur_db, k, v, 0); - break; - } - default: - break; - } - // prepare for next line - ctx->shift = 0; - ctx->state = STATE_NEWLINE; -} - -static inline char unescape_raw_char(char c) { - switch (c) { - case 's': - return ' '; - case 'n': - return '\n'; - case 'r': - return '\r'; - case 't': - return '\t'; - default: - return c; - } -} - -static void load_process_single_char(LoadCtx *ctx) { - char c = ctx->buf[ctx->pos]; - if (c == '\n' || c == '\r') { - load_process_line (ctx); - ctx->pos++; - return; - } - - if (ctx->state == STATE_NEWLINE) { - ctx->line_begin = ctx->pos; - // at the start of a line, decide whether it's a path or a k=v - // by whether there is a leading slash. - if (c == '/') { - ctx->state = STATE_PATH; - ctx->token_begin = ctx->pos + 1; - ctx->pos++; - c = ctx->buf[ctx->pos]; - return; - } - ctx->state = STATE_KEY; - } - - if (ctx->unescape) { - ctx->buf[ctx->pos - ctx->shift] = unescape_raw_char (c); - ctx->unescape = false; - } else if (c == '\\') { - // got a backslash, the next char, unescape in the next iteration or die! - ctx->shift++; - ctx->unescape = true; - } else if (ctx->state == STATE_PATH && c == '/') { - // new path token - ctx->buf[ctx->pos - ctx->shift] = '\0'; - ls_push (ctx->path, (void *)ctx->token_begin); - ctx->token_begin = ctx->pos + 1; - ctx->shift = 0; - } else if (ctx->state == STATE_KEY && c == '=') { - // switch from key to value mode - ctx->buf[ctx->pos - ctx->shift] = '\0'; - ctx->token_begin = ctx->pos + 1; - ctx->shift = 0; - ctx->state = STATE_VALUE; - } else if (ctx->shift) { - // just some char, shift it back if necessary - ctx->buf[ctx->pos - ctx->shift] = c; - } - ctx->pos++; -} - -static bool load_process_final_line(LoadCtx *ctx) { - // load_process_line needs ctx.buf[ctx.pos] to be allocated! - // so we need room for one additional byte after the buffer. - size_t linesz = ctx->bufsz - ctx->line_begin; - char *linebuf = (char *)sdb_gh_malloc (linesz + 1); - if (!linebuf) { - return false; - } - memcpy (linebuf, ctx->buf + ctx->line_begin, linesz); - ctx->buf = linebuf; - // shift everything by the size we skipped - ctx->bufsz -= ctx->line_begin; - ctx->pos = linesz; - ctx->token_begin -= ctx->line_begin; - SdbListIter *it; - void *token_off_tmp; - ls_foreach_cast (ctx->path, it, void*, token_off_tmp) { - it->data = (void *)((size_t)token_off_tmp - ctx->line_begin); - } - ctx->line_begin = 0; - load_process_line (ctx); - free (linebuf); - ctx->buf = NULL; - return true; -} - -static void load_ctx_fini(LoadCtx *ctx) { - ls_free (ctx->path); -} - -static bool load_ctx_init(LoadCtx *ctx, Sdb *s, char *buf, size_t sz) { - ctx->eof = false; - ctx->buf = buf; - ctx->bufsz = sz; - ctx->root_db = s; - ctx->cur_db = s; - ctx->pos = 0; - ctx->line_begin = 0; - ctx->token_begin = 0; - ctx->shift = 0; - ctx->path = ls_new (); - ctx->state = STATE_NEWLINE; - ctx->unescape = false; - if (!ctx->buf || !ctx->path) { - load_ctx_fini (ctx); - return false; - } - return true; -} - -SDB_API bool sdb_text_load_buf(Sdb *s, char *buf, size_t sz) { - if (!sz) { - return true; - } - LoadCtx ctx; - if (!load_ctx_init (&ctx, s, buf, sz)) { - return false; - } - bool ret = true; - while (ctx.pos < ctx.bufsz) { - load_process_single_char (&ctx); - } - if (ctx.line_begin < ctx.bufsz && ctx.state != STATE_NEWLINE) { - load_process_final_line (&ctx); - } - load_ctx_fini (&ctx); - return ret; -} - -SDB_API bool sdb_text_load(Sdb *s, const char *file) { - int fd = open (file, O_RDONLY | O_BINARY); - if (fd < 0) { - return false; - } - bool r = false; - char *x = NULL; - struct stat st; - if (fstat (fd, &st) || !st.st_size) { - goto beach; - } -#if USE_MMAN - x = (char *)mmap (0, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); - if (x == MAP_FAILED) { - goto beach; - } -#else - x = (char *)sdb_gh_calloc (1, st.st_size); - if (!x) { - goto beach; - } - if (read (fd, x, st.st_size) != st.st_size) { - sdb_gh_free (x); - goto beach; - } -#endif - r = sdb_text_load_buf (s, x, st.st_size); -#if USE_MMAN - munmap (x, st.st_size); -#else - sdb_gh_free (x); -#endif -beach: - close (fd); - return r; -} - -SDB_API bool sdb_text_check(Sdb *s, const char *file) { - char buf[64] = {0}; - int fd = open (file, O_RDONLY | O_BINARY); - if (fd < 0) { - return false; - } - struct stat st; - if (fstat (fd, &st) || !st.st_size) { - close (fd); - return false; - } - int count = read (fd, buf, R_MIN (st.st_size, (off_t)sizeof (buf))); - close (fd); - if (count < 1) { - return false; - } - bool is_ascii = true; - bool has_eq = false; - bool has_nl = false; - buf[sizeof (buf) - 1] = 0; - char *p = buf; - while (*p) { - if (*p == '=') { - has_eq = true; - } else if (*p == '\n') { - has_nl = true; - } else if (!has_eq) { - if (*p < 10 || *p > '~') { - is_ascii = false; - } - } - p++; - } - return count > 4 && is_ascii && has_nl && has_eq; -} diff --git a/shlr/sdb/src/util.c b/shlr/sdb/src/util.c deleted file mode 100644 index 79015da097f3f..0000000000000 --- a/shlr/sdb/src/util.c +++ /dev/null @@ -1,394 +0,0 @@ -/* sdb - MIT - Copyright 2011-2022 - pancake */ - -#include "sdb/sdb.h" - -#define FORCE_COLLISION 0 - -#if USE_MONOTONIC_CLOCK -#include -#else - -#ifdef _MSC_VER -#pragma message ("gettimeofday: Windows support is ugly here") -#include -#include - -struct timezone { - int tz_minuteswest; /* minutes W of Greenwich */ - int tz_dsttime; /* type of dst correction */ -}; - -SDB_API int gettimeofday(struct timeval* p, struct timezone * tz) { - //ULARGE_INTEGER ul; // As specified on MSDN. - ut64 ul = 0; - static bool tzflag = false; - FILETIME ft; - if (p) { - // Returns a 64-bit value representing the number of - // 100-nanosecond intervals since January 1, 1601 (UTC). - GetSystemTimeAsFileTime (&ft); - // Fill ULARGE_INTEGER low and high parts. - //ul.LowPart = ft.dwLowDateTime; - //ul.HighPart = ft.dwHighDateTime; - ul |= ft.dwHighDateTime; - ul <<= 32; - ul |= ft.dwLowDateTime; - // Convert to microseconds. - //ul.QuadPart /= 10ULL; - ul /= 10; - // Remove Windows to UNIX Epoch delta. - //ul.QuadPart -= 11644473600000000ULL; - ul -= 11644473600000000ULL; - // Modulo to retrieve the microseconds. - //p->tv_usec = (long)(ul.QuadPart % 1000000LL); - // Divide to retrieve the seconds. - //p->tv_sec = (long)(ul.QuadPart / 1000000LL); - p->tv_sec = (long)(ul / 1000000LL); - p->tv_usec = (long)(ul % 1000000LL); - } - if (tz) { - if (!tzflag) { - _tzset (); - tzflag = true; - } - tz->tz_minuteswest = _timezone / 60; - tz->tz_dsttime = _daylight; - } - return 0; -} - -#else -#include -#endif -#endif - -#if !SDB_INLINE_HASH -SDB_API ut32 sdb_hash_len(const char *s, ut32 *len) { - ut32 h = CDB_HASHSTART; -#if FORCE_COLLISION - h = 0; - while (*s) { - h += *s; - s++; - } -#else - ut32 count = 0; - if (s) { - while (*s) { - SDB_HASH_ONELINER; - // h = (h + (h << 5)) ^ *s++; // 2.22s - // h = (h ^ (h << 1)) + *s++; // 2.15s - count++; - } - } - if (len) { - *len = count; - } -#endif - return h; -} - -SDB_API ut32 sdb_hash(const char *s) { - return sdb_hash_len (s, NULL); -} -#endif - -SDB_API ut8 sdb_hash_byte(const char *s) { - const ut32 hash = sdb_hash_len (s, NULL); - const ut8 *h = (const ut8*)&hash; - return h[0] ^ h[1] ^ h[2] ^ h[3]; -} - -SDB_API char *sdb_itoa(ut64 n, int base, char *os, int oslen) { - if (base == 0) { - base = SDB_NUM_BASE; - } - static const char *const lookup = "0123456789abcdef"; - char tmpbuf[64], *s = NULL; - int sl, copy_string = 1; - if (os) { - *os = 0; - s = os; - sl = oslen; - } else { - s = tmpbuf; - sl = sizeof (tmpbuf); - } - const int imax = sl - 2; - int i = imax; - if (base < 0) { - copy_string = 0; - base = -base; - } - if (base > 16) { - return NULL; - } - if (!n) { - if (!os) { - return sdb_strdup ("0"); - } - if (sl > 1) { - memcpy (os, "0", 2); - } else { - *os = 0; - } - return os; - } - s[imax + 1] = '\0'; - if (base <= 10) { - for (; n && i > 0; n /= base) { - s[i--] = (n % base) + '0'; - } - } else { - for (; n && i > 0; n /= base) { - s[i--] = lookup[(n % base)]; - } - if (i != imax) { - s[i--] = 'x'; - } - s[i--] = '0'; - } - if (!os) { - return sdb_strdup (s + i + 1); - } - if (copy_string) { - // unnecessary memmove in case we use the return value - // return s + i + 1; - int a = strlen (s + i + 1) + 1; - int len = R_MIN (a, sl); - memmove (os, s + i + 1, len); - return os; - } - return os + i + 1; -} - -SDB_API char *sdb_itoas(ut64 n, int base) { - return sdb_itoa (n, base, NULL, 0); -} - -SDB_API ut64 sdb_atoi(const char *s) { - char *p; - ut64 ret; - if (!s || *s == '-') { - return 0LL; - } - ret = strtoull (s, &p, 0); - return p ? ret: 0LL; -} - -// NOTE: Reuses memory. probably not bindings friendly.. -SDB_API char *sdb_array_compact(char *p) { - char *e; - // remove empty elements - while (*p) { - if (!strncmp (p, ",,", 2)) { - p++; - for (e = p + 1; *e == ','; e++) {}; - memmove (p, e, strlen (e) + 1); - } else { - p++; - } - } - return p; -} - -// NOTE: Reuses memory. probably not bindings friendly.. -SDB_API char *sdb_aslice(char *out, int from, int to) { - int len, idx = 0; - char *str = NULL; - char *end = NULL; - char *p = out; - if (from >= to) { - return NULL; - } - while (*p) { - if (!str && idx == from) { - str = p; - } - if (idx == to) { - end = p; - break; - } - if (*p == ',') { - idx++; - } - p++; - } - if (str) { - if (!end) { - end = str + strlen (str); - } - len = (size_t)(end - str); - memmove (out, str, len); - out[len] = 0; - return out; - } - return NULL; -} - -// TODO: find better name for it -// TODO: optimize, because this is the main bottleneck for sdb_array_set() -SDB_API int sdb_alen(const char *str) { - int len = 1; - const char *n, *p = str; - if (!p|| !*p) { - return 0; - } - for (len = 0; ; len++) { - n = strchr (p, SDB_RS); - if (!n) { - break; - } - p = n + 1; - } - return ++len; -} - -SDB_API int sdb_alen_ignore_empty(const char *str) { - int len = 1; - const char *n, *p = str; - if (!p || !*p) { - return 0; - } - while (*p == SDB_RS) { - p++; - } - for (len = 0; ; ) { - n = strchr (p, SDB_RS); - if (!n) { - break; - } - p = n + 1; - if (*(p) == SDB_RS) { - continue; - } - len++; - } - if (*p) { - len++; - } - return len; -} - -SDB_API char *sdb_anext(char *str, char **next) { - char *nxt, *p = strchr (str, SDB_RS); - if (p) { - *p = 0; - nxt = p + 1; - } else { - nxt = NULL; - } - if (next) { - *next = nxt; - } - return str; -} - -SDB_API const char *sdb_const_anext(const char *str) { - const char *p = strchr (str, SDB_RS); - return p ? p + 1 : NULL; -} - -SDB_API ut64 sdb_now (void) { -#if USE_MONOTONIC_CLOCK - struct timespec ts; - if (!clock_gettime (CLOCK_MONOTONIC, &ts)) { - return ts.tv_sec; - } -#else - struct timeval now; - if (!gettimeofday (&now, NULL)) { - return now.tv_sec; - } -#endif - return 0LL; -} - -SDB_API ut64 sdb_unow (void) { - ut64 x = 0LL; -#if USE_MONOTONIC_CLOCK - struct timespec ts; - if (!clock_gettime (CLOCK_MONOTONIC, &ts)) { - x = ts.tv_sec; - x <<= 32; - x += ts.tv_nsec / 1000; - } -#else - struct timeval now; - if (!gettimeofday (&now, NULL)) { - x = now.tv_sec; - x <<= 32; - x += now.tv_usec; - } -#endif - return x; -} - -SDB_API int sdb_isnum(const char *s) { - const char vs = *s; - return ((vs == '-' || vs == '+') || (vs >= '0' && vs <= '9')); -} - -SDB_API int sdb_num_base(const char *s) { - if (!s) { - return SDB_NUM_BASE; - } - if (!strncmp (s, "0x", 2)) { - return 16; - } - return (*s=='0' && s[1]) ? 8: 10; -} - -SDB_API const char *sdb_type(const char *k) { - if (!k || !*k) { - return "undefined"; - } - if (sdb_isnum (k)) { - return "number"; - } - if (sdb_isjson (k)) { - return "json"; - } - if (strchr (k, ',')) { - return "array"; - } - if (!strcmp (k, "true") || !strcmp (k, "false")) { - return "boolean"; - } - return "string"; -} - -// TODO: check all the values -SDB_API bool sdb_isjson (const char *k) { - int level = 0; - bool quotes = false; - if (!k || (*k != '{' && *k != '[')) { - return false; - } - for (; *k; k++) { - if (quotes) { - if (*k == '"') { - quotes = false; - } - continue; - } - switch (*k) { - case '"': - quotes = true; - break; - case '[': - case '{': - level++; - break; - case ']': - case '}': - level--; - if (level < 0) { - /* invalid json */ - return false; - } - break; - } - } - return (!quotes && !level); -} diff --git a/shlr/sdb/test/Makefile b/shlr/sdb/test/Makefile deleted file mode 100644 index 6b0684547e06e..0000000000000 --- a/shlr/sdb/test/Makefile +++ /dev/null @@ -1 +0,0 @@ -all clean mrproper: diff --git a/shlr/sdb/wasi.mk b/shlr/sdb/wasi.mk deleted file mode 100644 index 07343c88a13d4..0000000000000 --- a/shlr/sdb/wasi.mk +++ /dev/null @@ -1,7 +0,0 @@ - -WASI_SDK=$(HOME)/Downloads/wasi/wasi-sdk-16.0 -WASI_SYSROOT=$(HOME)/Downloads/wasi/wasi-sysroot-16.0 -WASI_CC="$(WASI_SDK)/bin/clang --sysroot=$(WASI_SYSROOT) -D_WASI_EMULATED_MMAN -D_WASI_EMULATED_SIGNAL -DUSE_MMAN=0 -DHAVE_SYSTEM=0" - -$(WASK_SDK): - $(SHELL) wasi.sh diff --git a/shlr/sdb/wasi.sh b/shlr/sdb/wasi.sh deleted file mode 100755 index f5e346a7a59ec..0000000000000 --- a/shlr/sdb/wasi.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/sh - -export WASI_SDK=${HOME}/Downloads/wasi/wasi-sdk-16.0 -export WASI_SYSROOT=${HOME}/Downloads/wasi/wasi-sysroot-16.0 - -if [ ! -d "$WASI_SDK" ]; then - #OS=linux,macos,mingw - OS=`uname` - case "$OS" in - linux|Linux) OS=linux ; ;; - darwin|Darwin) OS=macos ; ;; - windows|Windows) OS=mingw ; ;; - esac - mkdir -p ~/Downloads/wasi - wget -c -O ~/Downloads/wasi/wasi-sdk.tar.gz https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-16/wasi-sdk-16.0-$OS.tar.gz || exit 1 - wget -c -O ~/Downloads/wasi/wasi-root.tar.gz https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-16/wasi-sysroot-16.0.tar.gz || exit 1 - ( - cd ~/Downloads/wasi - tar xzvf wasi-sdk.tar.gz - tar xzvf wasi-root.tar.gz - mv wasi-sysroot wasi-sysroot-16.0 - ) -fi diff --git a/subprojects/sdb.mk b/subprojects/sdb.mk index 87c9b6058b986..015e24df74674 100644 --- a/subprojects/sdb.mk +++ b/subprojects/sdb.mk @@ -1,8 +1,7 @@ # This file is autogenerated by acr-wrap WRAP_wrap_git_url:=https://github.com/radareorg/sdb.git -WRAP_wrap_git_revision:=2e24eb0616dfce5e28130660313b56db9252dd5c -# revision = 2.0.1 +WRAP_wrap_git_revision:=2.0.2 WRAP_wrap_git_directory:=sdb WRAP_wrap_git_depth:=1 @@ -11,7 +10,7 @@ sdb_all: sdb sdb: git clone --no-checkout --depth=1 https://github.com/radareorg/sdb.git sdb - cd sdb && git fetch --depth=1 origin 2e24eb0616dfce5e28130660313b56db9252dd5c + cd sdb && git fetch --depth=1 origin 2.0.2 cd sdb && git checkout sdb_clean: diff --git a/subprojects/sdb.wrap b/subprojects/sdb.wrap index 4159d395f8556..1bc1117783736 100644 --- a/subprojects/sdb.wrap +++ b/subprojects/sdb.wrap @@ -1,6 +1,5 @@ [wrap-git] url = https://github.com/radareorg/sdb.git -revision = 2e24eb0616dfce5e28130660313b56db9252dd5c -# revision = 2.0.1 +revision = 2.0.2 directory = sdb depth = 1 diff --git a/sys/sdk.sh b/sys/sdk.sh index f586410119d77..c6fe7a272e6e4 100755 --- a/sys/sdk.sh +++ b/sys/sdk.sh @@ -26,7 +26,7 @@ mkdir -p "${SDKDIR}"/lib rm -f libr/libr.a cp -rf libr/include "${SDKDIR}" mkdir -p "${SDKDIR}/include/sdb" -cp -rf shlr/sdb/include/sdb/* "${SDKDIR}/include/sdb" +cp -rf subprojects/sdb/include/sdb/* "${SDKDIR}/include/sdb" FILES=`find libr shlr -iname '*.a'` cp -f ${FILES} "${SDKDIR}"/lib OS=`uname` diff --git a/test/unit/Makefile b/test/unit/Makefile index cccc9a3c62c0b..68a76a7160c11 100644 --- a/test/unit/Makefile +++ b/test/unit/Makefile @@ -6,7 +6,7 @@ LDFLAGS+=-L$(LIBDIR) LDFLAGS+=-lr_core -lm -lr_config -lr_debug -lr_bin -lr_lang -lr_anal -lr_bp -lr_egg -lr_asm -lr_flag -lr_search -lr_syscall -lr_fs -lr_io -lr_socket -lr_cons -lr_magic -lr_crypto -lr_arch -lr_esil -lr_reg -lr_util -ldl CFLAGS+=-I$(INCLUDEDIR) CFLAGS+=-I../../libr/include -CFLAGS+=-I../../shlr/sdb/include +CFLAGS+=-I../../subprojects/sdb/include CFLAGS+=-g ifeq ($(ASAN),1) ASAN_LD_PRELOAD=LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libasan.so.5