judy-1.0.5/0000755000175000017500000000000010624600220012704 5ustar troyhebetroyhebejudy-1.0.5/test/0000755000175000017500000000000010624600217013671 5ustar troyhebetroyhebejudy-1.0.5/test/Makefile.in0000644000175000017500000002571110624600217015744 0ustar troyhebetroyhebe# Makefile.in generated by automake 1.9.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ top_builddir = .. am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd INSTALL = @INSTALL@ install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = test DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = SOURCES = DIST_SOURCES = DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMDEP_FALSE = @AMDEP_FALSE@ AMDEP_TRUE = @AMDEP_TRUE@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO = @ECHO@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ F77 = @F77@ FFLAGS = @FFLAGS@ FLAVOR = @FLAVOR@ GREP = @GREP@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ MAKEINFO = @MAKEINFO@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ VERSION_INFO = @VERSION_INFO@ WARN_CFLAGS = @WARN_CFLAGS@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_F77 = @ac_ct_F77@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ EXTRA_DIST = $(TESTS) TEST_ENVIRONMENT = top_builddir=$(top_builddir) TESTS = Checkit DISTCLEANFILES = .deps Makefile CLEANFILES = Judy1LHCheck Judy1LHTime Makefile SL_Hash SL_Judy SL_Redblack SL_Splay all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu test/Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --gnu test/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs distclean-libtool: -rm -f libtool uninstall-info-am: tags: TAGS TAGS: ctags: CTAGS CTAGS: check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list='$(TESTS)'; \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *" $$tst "*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ echo "XPASS: $$tst"; \ ;; \ *) \ echo "PASS: $$tst"; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *" $$tst "*) \ xfail=`expr $$xfail + 1`; \ echo "XFAIL: $$tst"; \ ;; \ *) \ failed=`expr $$failed + 1`; \ echo "FAIL: $$tst"; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ echo "SKIP: $$tst"; \ fi; \ done; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="All $$all tests passed"; \ else \ banner="All $$all tests behaved as expected ($$xfail expected failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all tests failed"; \ else \ banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ skipped="($$skip tests were not run)"; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ echo "$$dashes"; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ list='$(DISTFILES)'; for file in $$list; do \ case $$file in \ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ esac; \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ if test "$$dir" != "$$file" && test "$$dir" != "."; then \ dir="/$$dir"; \ $(mkdir_p) "$(distdir)$$dir"; \ else \ dir=''; \ fi; \ if test -d $$d/$$file; then \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic distclean-libtool dvi: dvi-am dvi-am: html: html-am info: info-am info-am: install-data-am: install-exec-am: install-info: install-info-am install-man: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-info-am .PHONY: all all-am check check-TESTS check-am clean clean-generic \ clean-libtool distclean distclean-generic distclean-libtool \ distdir dvi dvi-am html html-am info info-am install \ install-am install-data install-data-am install-exec \ install-exec-am install-info install-info-am install-man \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ uninstall uninstall-am uninstall-info-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: judy-1.0.5/test/Judy1LHTime.c0000644000175000017500000017004510622113030016071 0ustar troyhebetroyhebe// @(#) $Revision: 4.20 $ $Source: /judy/test/manual/Judy1LHTime.c $ //======================================================================= // This program measures the performance of a Judy1 and JudyL Array. // -by- // Author Douglas L. Baskins, Aug 2003. // Permission to use this code is freely granted, provided that this // statement is retained. // email - dougbaskins@yahoo.com //======================================================================= #include // sbrk() #include // exit() #include // printf(), setbuf() #include // pow() #include // gettimeofday() #include // uname() #include // for Judy macros J*() //#include // compiling with old Judy.h without JudyHS #ifdef NOINLINE /* this is the 21st century? */ #define _INLINE_ static #else #define _INLINE_ inline #endif //======================================================================= // This program measures the performance of a Judy1, JudyL and // limited to one size of string (sizeof Word_t) JudyHS Arrays. // // Compile: // // cc -O Judy1LHTime.c -lm -lJudy -o Judy1LHTime // -or- // cc -O -DCPUMHZ=2400 Judy1LHTime.c -lm -lJudy -o Judy1LHTime /* Notes: 1) Use '-DCPUMHZ=2400' in cc line if better clock resolution is desired and it compiles successfully. The 2400 is the cpu MHz : 2400 -or- cat /proc/cpuinfo | grep "cpu MHz" in a Linux system. 2) */ //======================================================================= // T I M I N G M A C R O S //======================================================================= double DeltaUSec; // Global for remembering delta times #ifdef CPUMHZ // For a 1.34 nS clock cycle processor (750Mhz) #define CPUSPEED (1.0 / (CPUMHZ)) //#define rdtscll(val) __asm__ __volatile__("rdtsc" : "=A" (val)) #define rdtscl(low) __asm__ __volatile__("rdtsc" : "=a" (low) : : "edx") static inline uint32_t get_cycles(void) { uint32_t ret = 0; rdtscl(ret); return (ret); } #define STARTTm \ { \ gettimeofday(&TVBeg__, NULL); \ GCBeg__ = get_cycles(); \ } #define ENDTm(D) \ { \ uint32_t GCEnd__; \ GCEnd__ = get_cycles(); \ gettimeofday(&TVEnd__, NULL); \ (D) = (double)(TVEnd__.tv_sec - TVBeg__.tv_sec) * 1E6 + \ ((double)(TVEnd__.tv_usec - TVBeg__.tv_usec)); \ if (D < 10000.0) D = (double)(GCEnd__ - GCBeg__) * CPUSPEED; \ } #else // ! CPUMHZ #define STARTTm gettimeofday(&TVBeg__, NULL) #define ENDTm(D) \ { \ gettimeofday(&TVEnd__, NULL); \ (D) = (double)(TVEnd__.tv_sec - TVBeg__.tv_sec) * 1E6 + \ ((double)(TVEnd__.tv_usec - TVBeg__.tv_usec)); \ } #endif // ! CPUMHZ // **************************************************************************** // J U D Y M A L L O C // // Allocate RAM. This is the single location in Judy code that calls // malloc(3C). Note: JPM accounting occurs at a higher level. enum { JudyMal1, JudyMalL, JudyMalHS } MalFlag; static Word_t MalFreeCnt = 0; Word_t TotJudy1MemUsed = 0; Word_t TotJudyLMemUsed = 0; Word_t TotJudyHSMemUsed = 0; Word_t JudyMalloc(Word_t Words) { Word_t Addr; Word_t IncWords; Addr = (Word_t)malloc(Words * sizeof(Word_t)); if (Addr) { IncWords = Words; MalFreeCnt++; // Adjust for overhead of (dl)malloc if (Words % 1) IncWords += 1; else IncWords += 2; switch (MalFlag) { case JudyMal1: TotJudy1MemUsed += IncWords; break; case JudyMalL: TotJudyLMemUsed += IncWords; break; case JudyMalHS: TotJudyHSMemUsed += IncWords; break; } } return (Addr); } // JudyMalloc() // **************************************************************************** // J U D Y F R E E void JudyFree(void *PWord, Word_t Words) { Word_t DecWords; if (Words == 0) printf("OOps JudyFree called with 0 words\n"); free(PWord); DecWords = Words; MalFreeCnt++; // Adjust for overhead of (dl)malloc if (Words % 1) DecWords += 1; else DecWords += 2; switch (MalFlag) { case JudyMal1: TotJudy1MemUsed -= DecWords; break; case JudyMalL: TotJudyLMemUsed -= DecWords; break; case JudyMalHS: TotJudyHSMemUsed -= DecWords; break; } } // JudyFree() // **************************************************************************** // J U D Y M A L L O C // // Higher-level "wrapper" for allocating objects that need not be in RAM, // although at this time they are in fact only in RAM. Later we hope that some // entire subtrees (at a JPM or branch) can be "virtual", so their allocations // and frees should go through this level. Word_t JudyMallocVirtual(Word_t Words) { return (JudyMalloc(Words)); } // JudyMallocVirtual() // **************************************************************************** // J U D Y F R E E void JudyFreeVirtual(void *PWord, Word_t Words) { JudyFree(PWord, Words); } // JudyFreeVirtual() //======================================================================= // Common macro to handle a failure #define FAILURE(STR, UL) \ { \ printf( "\nError: %s %lu, file='%s', 'function='%s', line %d\n", \ STR, (Word_t)(UL), __FILE__, __FUNCTI0N__, __LINE__); \ fprintf(stderr,"\nError: %s %lu, file='%s', 'function='%s', line %d\n", \ STR, (Word_t)(UL), __FILE__, __FUNCTI0N__, __LINE__); \ exit(1); \ } // Interations without improvement // Minimum of 2 loops, maximum of 1000000 #define MINLOOPS 2 #define MAXLOOPS 1000000 // Maximum or 10 loops with no improvement #define ICNT 10 // Structure to keep track of times typedef struct MEASUREMENTS_STRUCT { Word_t ms_delta; } ms_t , *Pms_t; // Specify prototypes for each test routine int NextNumb(Word_t *PNumber, double *PDNumb, double DMult, Word_t MaxN); Word_t TestJudyIns(void **J1, void **JL, void **JH, Word_t Seed, Word_t Elems); Word_t TestJudyDup(void **J1, void **JL, void **JH, Word_t Seed, Word_t Elems); int TestJudyDel(void **J1, void **JL, void **JH, Word_t Seed, Word_t Elems); Word_t TestJudyGet(void *J1, void *JL, void *JH, Word_t Seed, Word_t Elems); int TestJudy1Copy(void *J1, Word_t Elem); int TestJudyCount(void *J1, void *JL, Word_t LowIndex, Word_t Elems); Word_t TestJudyNext(void *J1, void *JL, Word_t LowIndex, Word_t Elems); int TestJudyPrev(void *J1, void *JL, Word_t HighIndex, Word_t Elems); Word_t TestJudyNextEmpty(void *J1, void *JL, Word_t LowIndex, Word_t Elems); Word_t TestJudyPrevEmpty(void *J1, void *JL, Word_t HighIndex, Word_t Elems); //======================================================================= // These are LFSF feedback taps for bitwidths of 10..64 sized numbers. // Tested with Seed=0xc1fc to 35 billion numbers //======================================================================= Word_t StartSeed = 0xc1fc; // default beginning number Word_t FirstSeed; Word_t MagicList[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0..9 0x27f, // 10 0x27f, // 11 0x27f, // 12 0x27f, // 13 0x27f, // 14 0x27f, // 15 0x1e71, // 16 0xdc0b, // 17 0xdc0b, // 18 0xdc0b, // 19 0xdc0b, // 20 0xc4fb, // 21 0xc4fb, // 22 0xc4fb, // 23 0x13aab, // 24 0x11ca3, // 25 0x11ca3, // 26 0x11ca3, // 27 0x13aab, // 28 0x11ca3, // 29 0xc4fb, // 30 0xc4fb, // 31 0x13aab, // 32 0x14e73, // 33 0x145d7, // 34 0x145f9, // 35 following tested with Seed=0xc1fc to 35 billion numbers 0x151ed, // 36 .. 41 0x151ed, // 37 0x151ed, // 38 0x151ed, // 39 0x151ed, // 40 0x146c3, // 41 .. 64 0x146c3, // 42 0x146c3, // 43 0x146c3, // 44 0x146c3, // 45 0x146c3, // 46 0x146c3, // 47 0x146c3, // 48 0x146c3, // 49 0x146c3, // 50 0x146c3, // 51 0x146c3, // 52 0x146c3, // 53 0x146c3, // 54 0x146c3, // 55 0x146c3, // 56 0x146c3, // 57 0x146c3, // 58 0x146c3, // 59 0x146c3, // 60 0x146c3, // 61 0x146c3, // 62 0x146c3, // 63 0x146c3 // 64 }; // Routine to "mirror" the input data word static Word_t Swizzle(Word_t word) { // BIT REVERSAL, Ron Gutman in Dr. Dobb's Journal, #316, Sept 2000, pp133-136 // #ifdef __LP64__ word = ((word & 0x00000000ffffffff) << 32) | ((word & 0xffffffff00000000) >> 32); word = ((word & 0x0000ffff0000ffff) << 16) | ((word & 0xffff0000ffff0000) >> 16); word = ((word & 0x00ff00ff00ff00ff) << 8) | ((word & 0xff00ff00ff00ff00) >> 8); word = ((word & 0x0f0f0f0f0f0f0f0f) << 4) | ((word & 0xf0f0f0f0f0f0f0f0) >> 4); word = ((word & 0x3333333333333333) << 2) | ((word & 0xcccccccccccccccc) >> 2); word = ((word & 0x5555555555555555) << 1) | ((word & 0xaaaaaaaaaaaaaaaa) >> 1); #else // not __LP64__ word = ((word & 0x0000ffff) << 16) | ((word & 0xffff0000) >> 16); word = ((word & 0x00ff00ff) << 8) | ((word & 0xff00ff00) >> 8); word = ((word & 0x0f0f0f0f) << 4) | ((word & 0xf0f0f0f0) >> 4); word = ((word & 0x33333333) << 2) | ((word & 0xcccccccc) >> 2); word = ((word & 0x55555555) << 1) | ((word & 0xaaaaaaaa) >> 1); #endif // not __LP64__ return (word); } double DeltaUSec1 = 0.0; // Global for measuring delta times double DeltaUSecL = 0.0; // Global for measuring delta times double DeltaUSecHS = 0.0; // Global for measuring delta times double DeltaMalFre1 = 0.0; // Delta mallocs/frees per inserted index double DeltaMalFreL = 0.0; // Delta mallocs/frees per inserted index double DeltaMalFreHS = 0.0; // Delta mallocs/frees per inserted index double DeltaMalFre = 0.0; // Delta mallocs/frees per inserted index Word_t J1Flag = 0; // time Judy1 Word_t JLFlag = 0; // time JudyL Word_t JHFlag = 0; // time JudyHS Word_t dFlag = 0; // time Judy1Unset JudyLDel Word_t vFlag = 0; // time Searching Word_t CFlag = 0; // time Counting Word_t cFlag = 0; // time Copy of Judy1 array Word_t IFlag = 0; // time duplicate inserts/sets Word_t DFlag = 0; // bit reverse the data stream Word_t lFlag = 0; // do not do multi-insert tests Word_t SkipN = 0; // default == Random skip Word_t TValues = 1000000; // Maximum retrieve tests for timing Word_t nElms = 1000000; // Max population of arrays Word_t ErrorFlag = 0; Word_t PtsPdec = 40; // measurement points per decade // Stuff for LFSR (pseudo random number generator) Word_t RandomBit = ~0UL / 2 + 1; Word_t BValue = sizeof(Word_t) * 8; Word_t Magic; // for error routines -- notice misspelling, name conflicts with some compilers #undef __FUNCTI0N__ #define __FUNCTI0N__ "Random" _INLINE_ Word_t // so INLINING compilers get to look at it. Random(Word_t newseed) { if (newseed & RandomBit) { newseed += newseed; newseed ^= Magic; } else { newseed += newseed; } newseed &= RandomBit * 2 - 1; if (newseed == FirstSeed) FAILURE("LFSR failed", newseed); return (newseed); } _INLINE_ Word_t // so INLINING compilers get to look at it. GetNextIndex(Word_t Index) { if (SkipN) Index += SkipN; else Index = Random(Index); return (Index); } #undef __FUNCTI0N__ #define __FUNCTI0N__ "main" struct timeval TVBeg__, TVEnd__; #ifdef CPUMHZ uint32_t GCBeg__; #endif // CPUMHZ int main(int argc, char *argv[]) { // Names of Judy Arrays void *J1 = NULL; // Judy1 void *JL = NULL; // JudyL void *JH = NULL; // JudyHS Word_t Count1, CountL; // , CountHS; Word_t Bytes; double Mult; Pms_t Pms; Word_t Seed; Word_t PtsPdec = 40; // points per decade Word_t Groups; // Number of measurement groups Word_t grp; Word_t Pop1; Word_t Meas; int Col; int c; extern char *optarg; setbuf(stdout, NULL); // unbuffer output //============================================================ // PARSE INPUT PARAMETERS //============================================================ while ((c = getopt(argc, argv, "n:S:T:P:b:B:dDcC1LHvIl")) != -1) { switch (c) { case 'n': // Max population of arrays nElms = strtoul(optarg, NULL, 0); // Size of Linear Array if (nElms == 0) FAILURE("No tests: -n", nElms); break; case 'S': // Step Size, 0 == Random SkipN = strtoul(optarg, NULL, 0); break; case 'T': // Maximum retrieve tests for timing TValues = strtoul(optarg, NULL, 0); break; case 'P': // measurement points per decade PtsPdec = strtoul(optarg, NULL, 0); break; case 'b': // May not work past 35 bits if changed StartSeed = strtoul(optarg, NULL, 0); break; case 'B': // expanse of data points (random only) BValue = strtoul(optarg, NULL, 0); if ((BValue > 64) || (MagicList[BValue] == 0) || (BValue > (sizeof(Word_t) * 8))) { ErrorFlag++; printf("\nIllegal number of random bits of %lu !!!\n", BValue); } break; case 'v': vFlag = 1; // time Searching break; case '1': // time Judy1 J1Flag = 1; break; case 'L': // time JudyL JLFlag = 1; break; case 'H': // time JudyHS JHFlag = 1; break; case 'd': // time Judy1Unset JudyLDel dFlag = 1; break; case 'D': // bit reverse the data stream DFlag = 1; break; case 'c': // time Copy Judy1 array cFlag = 1; break; case 'C': // time Counting CFlag = 1; break; case 'I': // time duplicate insert/set IFlag = 1; break; case 'l': // do not loop in tests lFlag = 1; break; default: ErrorFlag++; break; } } if (ErrorFlag) { printf("\n%s -n# -P# -S# -B# -T# -dDcCpdI\n\n", argv[0]); printf("Where:\n"); printf("-n <#> number of indexes (1000000) used in tests\n"); printf("-P <#> number measurement points (40) per decade\n"); printf("-S <#> index skip amount, 0 = random\n"); printf("-B <#> # bits (10..%d) in random number generator\n", (int)sizeof(Word_t) * 8); printf("-L time JudyL\n"); printf("-1 time Judy1\n"); printf("-H time JudyHS\n"); printf("-I time DUPLICATE Ins/Set times\n"); printf("-c time copy Judy1 Array\n"); printf("-C time JudyCount tests\n"); printf("-v time Judy First/Last/Next/Prev tests\n"); printf("-d time JudyDel/Unset\n"); printf("-l do not loop on same Indexes\n"); printf("-T <#> max number indexes in read times - 0 == MAX\n"); printf("\n"); exit(1); } // If none, then all if (!JLFlag && !J1Flag && !JHFlag) JHFlag = JLFlag = J1Flag = 1; // Set number of Random bits in LFSR RandomBit = 1UL << (BValue - 1); Magic = MagicList[BValue]; if (nElms > ((RandomBit - 2) * 2)) { printf ("# Number = -n%lu of Indexes reduced to max expanse of Random numbers\n", nElms); nElms = ((RandomBit - 2) * 2); } printf("# TITLE %s -n%lu -S%lu -T%lu -B%lu -P%lu", argv[0], nElms, SkipN, TValues, BValue, PtsPdec); // case 'b': // May not work past 35 bits if changed if (J1Flag) printf(" -1"); if (JLFlag) printf(" -L"); if (JHFlag) printf(" -H"); if (DFlag) printf(" -D"); if (dFlag) printf(" -d"); if (cFlag) printf(" -c"); if (CFlag) printf(" -C"); if (IFlag) printf(" -I"); if (lFlag) printf(" -l"); if (vFlag) printf(" -v"); printf("\n"); // uname(2) strings describing the machine { struct utsname ubuf; // for system name if (uname(&ubuf) == -1) printf("# Uname(2) failed\n"); else printf("# %s %s %s %s %s\n", ubuf.sysname, ubuf.nodename, ubuf.release, ubuf.version, ubuf.machine); } if (sizeof(Word_t) == 8) printf("# %s 64 Bit version\n", argv[0]); else if (sizeof(Word_t) == 4) printf("# %s 32 Bit version\n", argv[0]); printf("# XLABEL Population\n"); printf("# YLABEL Microseconds / Index\n"); //============================================================ // CALCULATE NUMBER OF MEASUREMENT GROUPS //============================================================ // Calculate Multiplier for number of points per decade Mult = pow(10.0, 1.0 / (double)PtsPdec); { double sum; Word_t numb, prevnumb; // Count number of measurements needed (10K max) sum = numb = 1; for (Groups = 2; Groups < 10000; Groups++) { if (NextNumb(&numb, &sum, Mult, nElms)) break; } // Get memory for measurements Pms = (Pms_t) calloc(Groups, sizeof(ms_t)); // Now calculate number of Indexes for each measurement point numb = sum = 1; prevnumb = 0; for (grp = 0; grp < Groups; grp++) { Pms[grp].ms_delta = numb - prevnumb; prevnumb = numb; NextNumb(&numb, &sum, Mult, nElms); } } // Groups = number of sizes //============================================================ // PRINT HEADER TO PERFORMANCE TIMERS //============================================================ Col = 1; printf("# COLHEAD %d Population\n", Col++); printf("# COLHEAD %d Measurments\n", Col++); printf("# COLHEAD %d J1S - Judy1Set\n", Col++); printf("# COLHEAD %d JLI - JudyLIns\n", Col++); printf("# COLHEAD %d JHSI - JudyHSIns\n", Col++); printf("# COLHEAD %d J1T - Judy1Test\n", Col++); printf("# COLHEAD %d JLG - JudyLGet\n", Col++); printf("# COLHEAD %d JHSG - JudyHSGet\n", Col++); if (IFlag) { printf("# COLHEAD %d J1S-dup\n", Col++); printf("# COLHEAD %d JLI-dup\n", Col++); printf("# COLHEAD %d JHSI-dup\n", Col++); } if (cFlag) { printf("# COLHEAD %d Copy J1T->J1S\n", Col++); } if (CFlag) { printf("# COLHEAD %d J1C\n", Col++); printf("# COLHEAD %d JLC\n", Col++); } if (vFlag) { printf("# COLHEAD %d J1N\n", Col++); printf("# COLHEAD %d JLN\n", Col++); printf("# COLHEAD %d J1P\n", Col++); printf("# COLHEAD %d JLP\n", Col++); printf("# COLHEAD %d J1NE\n", Col++); printf("# COLHEAD %d JLNE\n", Col++); printf("# COLHEAD %d J1PE\n", Col++); printf("# COLHEAD %d JLPE\n", Col++); } if (dFlag) { printf("# COLHEAD %d J1U\n", Col++); printf("# COLHEAD %d JLD\n", Col++); printf("# COLHEAD %d JHSD\n", Col++); } printf("# COLHEAD %d 1heap/I - Judy1 heap memery per Index\n", Col++); printf("# COLHEAD %d Lheap/I - JudyL heap memery per Index\n", Col++); printf("# COLHEAD %d HSheap/I - JudyHS heap memery per Index\n", Col++); printf("# COLHEAD %d MF1/I - Judy1 malloc+free's per delta Indexes\n", Col++); printf("# COLHEAD %d MFL/I - JudyL malloc+free's per delta Indexes\n", Col++); printf("# COLHEAD %d MFHS/I - JudyHS malloc+free's per delta Indexes\n", Col++); #ifdef CPUMHZ printf("#\n# Compiled for processor speed of %d Mhz\n#\n", CPUMHZ); #endif // CPUMHZ printf("# %s - Leaf sizes in Words\n", Judy1MallocSizes); printf("# %s - Leaf sizes in Words\n#\n", JudyLMallocSizes); printf("# Pop1 Measmts J1S JLI JHSI J1T JLG JHSG"); if (IFlag) printf(" dupJ1S dupJLI dupJHI"); if (cFlag) printf(" CopyJ1"); if (CFlag) printf(" J1C JLC"); if (vFlag) printf(" J1N JLN J1P JLP J1NE JLNE J1PE JLPE"); if (dFlag) printf(" J1U JLD JHSD"); printf(" 1heap/I Lheap/I HSheap/I"); printf(" MF1/I"); printf(" MFL/I"); printf(" MFHS/I"); printf("\n"); //============================================================ // BEGIN TESTS AT EACH GROUP SIZE //============================================================ // Get the kicker to test the LFSR FirstSeed = Seed = StartSeed & (RandomBit * 2 - 1); for (Pop1 = grp = 0; grp < Groups; grp++) { Word_t LowIndex; Word_t Delta; Word_t NewSeed; Delta = Pms[grp].ms_delta; // Test J1S, JLI NewSeed = TestJudyIns(&J1, &JL, &JH, Seed, Delta); // Accumulate the Total population of arrays Pop1 += Delta; Meas = Pop1; // Only test the maximum of TValues if not zero if (TValues) Meas = (Pop1 < TValues) ? Pop1 : TValues; printf("%10lu %9lu", Pop1, Meas); printf(" %6.3f", DeltaUSec1); printf(" %6.3f", DeltaUSecL); printf(" %6.3f", DeltaUSecHS); fflush(NULL); // Test J1T, JLG, JHSG LowIndex = TestJudyGet(J1, JL, JH, FirstSeed, Meas); printf(" %6.3f", DeltaUSec1); printf(" %6.3f", DeltaUSecL); printf(" %6.3f", DeltaUSecHS); fflush(NULL); // Test J1T, JLI, JHSI - duplicates if (IFlag) { LowIndex = TestJudyDup(&J1, &JL, &JH, FirstSeed, Meas); printf(" %6.3f", DeltaUSec1); printf(" %6.3f", DeltaUSecL); printf(" %6.3f", DeltaUSecHS); fflush(NULL); } if (cFlag) { TestJudy1Copy(J1, Meas); printf(" %6.3f", DeltaUSec1); fflush(NULL); } if (CFlag) { TestJudyCount(J1, JL, LowIndex, Meas); printf(" %6.3f", DeltaUSec1); printf(" %6.3f", DeltaUSecL); fflush(NULL); } if (vFlag) { // Test J1N, JLN // HighIndex = TestJudyNext(J1, JL, LowIndex, Meas); TestJudyNext(J1, JL, 0, Meas); printf(" %6.3f", DeltaUSec1); printf(" %6.3f", DeltaUSecL); fflush(NULL); // Test J1P, JLP TestJudyPrev(J1, JL, ~0UL, Meas); // TestJudyPrev(J1, JL, HighIndex, Meas); printf(" %6.3f", DeltaUSec1); printf(" %6.3f", DeltaUSecL); fflush(NULL); // Test J1NE, JLNE TestJudyNextEmpty(J1, JL, 0UL, Meas); printf(" %6.3f", DeltaUSec1); printf(" %6.3f", DeltaUSecL); fflush(NULL); // Test J1PE, JLPE TestJudyPrevEmpty(J1, JL, ~0UL, Meas); printf(" %6.3f", DeltaUSec1); printf(" %6.3f", DeltaUSecL); fflush(NULL); } // Test J1U, JLD, JHSD if (dFlag) { TestJudyDel(&J1, &JL, &JH, FirstSeed, Meas); printf(" %6.3f", DeltaUSec1); printf(" %6.3f", DeltaUSecL); printf(" %6.3f", DeltaUSecHS); fflush(NULL); // Now put them back TestJudyIns(&J1, &JL, &JH, FirstSeed, Meas); } // Advance Index number set Seed = NewSeed; // Print the number of bytes used per Index printf(" %7.3f", (double)TotJudy1MemUsed * sizeof(Word_t) / (double)Pop1); printf(" %7.3f", (double)TotJudyLMemUsed * sizeof(Word_t) / (double)Pop1); printf(" %8.3f", (double)TotJudyHSMemUsed * sizeof(Word_t) / (double)Pop1); printf(" %5.3f", DeltaMalFre1); printf(" %5.3f", DeltaMalFreL); printf(" %5.3f", DeltaMalFreHS); printf("\n"); fflush(NULL); // assure data gets to file in case malloc fail } #ifdef SKIPMACRO Count1 = Judy1Count(J1, 0, -1, PJE0); CountL = JudyLCount(JL, 0, -1, PJE0); #else JLC(CountL, JL, 0, -1); // get the counts J1C(Count1, J1, 0, -1); #endif // SKIPMACRO if (JLFlag && J1Flag) { if (CountL != Count1) FAILURE("Judy1/LCount not equal", Count1); } // if (Count1) { Word_t Cnt1 = Count1; if (Cnt1 == 0) Cnt1 = 1UL; STARTTm; #ifdef SKIPMACRO Bytes = Judy1FreeArray(&J1, PJE0); #else J1FA(Bytes, J1); // Free the Judy1 Array #endif // SKIPMACRO ENDTm(DeltaUSec1); DeltaUSec1 /= (double)Cnt1; printf("# Judy1FreeArray: %lu, %0.3f bytes/Index, %0.3f USec/Index\n", Count1, (double)Bytes / (double)Cnt1, DeltaUSec1); } // if (CountL) { Word_t CntL = CountL; if (CntL == 0) CntL = 1UL; STARTTm; #ifdef SKIPMACRO Bytes = JudyLFreeArray(&JL, PJE0); #else JLFA(Bytes, JL); // Free the JudyL Array #endif // SKIPMACRO ENDTm(DeltaUSecL); DeltaUSecL /= (double)CntL; printf("# JudyLFreeArray: %lu, %0.3f bytes/Index, %0.3f USec/Index\n", CountL, (double)Bytes / (double)CntL, DeltaUSecL); } // if (CountHS) { // Word_t CntHS = CountHS; // if (CntHS == 0) CntHS = 1UL; STARTTm; #ifdef SKIPMACRO Bytes = JudyHSFreeArray(&JH, PJE0); // Free the JudyHS Array #else JHSFA(Bytes, JH); // Free the JudyHS Array #endif // SKIPMACRO ENDTm(DeltaUSecHS); DeltaUSecHS /= (double)nElms; // no Counts yet printf("# JudyHSFreeArray: %lu, %0.3f bytes/Index, %0.3f USec/Index\n", nElms, (double)Bytes / (double)nElms, DeltaUSecHS); } exit(0); } #undef __FUNCTI0N__ #define __FUNCTI0N__ "TestJudyIns" Word_t TestJudyIns(void **J1, void **JL, void **JH, Word_t Seed, Word_t Elements) { Word_t TstIndex; Word_t elm; Word_t *PValue; Word_t Seed1 = 0; int Rc; double DDel; Word_t icnt; Word_t lp; Word_t Loops; Word_t StartMallocs; if (Elements < 100) Loops = (MAXLOOPS / Elements) + MINLOOPS; else Loops = 1; if (lFlag) Loops = 1; // Judy1Set timings if (J1Flag) { MalFlag = JudyMal1; for (DDel = 1e40, icnt = ICNT, lp = 0; lp < Loops; lp++) { if (lp != 0) { for (Seed1 = Seed, elm = 0; elm < Elements; elm++) { Seed1 = GetNextIndex(Seed1); if (DFlag) TstIndex = Swizzle(Seed1); else TstIndex = Seed1; #ifdef SKIPMACRO Rc = Judy1Unset(J1, TstIndex, PJE0); #else J1U(Rc, *J1, TstIndex); #endif // SKIPMACRO } } StartMallocs = MalFreeCnt; STARTTm; for (Seed1 = Seed, elm = 0; elm < Elements; elm++) { Seed1 = GetNextIndex(Seed1); if (DFlag) TstIndex = Swizzle(Seed1); else TstIndex = Seed1; J1S(Rc, *J1, TstIndex); if (Rc == 0) FAILURE("Judy1Set failed - DUP Index at", elm); #ifdef DIAG Rc = Judy1Test(*J1, TstIndex, PJE0); if (Rc != 1) FAILURE("Judy1Test failed at", elm); #endif // DIAG } ENDTm(DeltaUSec1); DeltaMalFre1 = (double)(MalFreeCnt - StartMallocs) / Elements; if (DDel > DeltaUSec1) { icnt = ICNT; DDel = DeltaUSec1; } else { if (--icnt == 0) break; } } DeltaUSec1 = DDel / (double)Elements; } // JudyLIns timings if (JLFlag) { MalFlag = JudyMalL; for (DDel = 1e40, icnt = ICNT, lp = 0; lp < Loops; lp++) { if (lp != 0) { for (Seed1 = Seed, elm = 0; elm < Elements; elm++) { Seed1 = GetNextIndex(Seed1); if (DFlag) TstIndex = Swizzle(Seed1); else TstIndex = Seed1; #ifdef SKIPMACRO Rc = JudyLDel(JL, TstIndex, PJE0); #else JLD(Rc, *JL, TstIndex); #endif // SKIPMACRO } } StartMallocs = MalFreeCnt; STARTTm; for (Seed1 = Seed, elm = 0; elm < Elements; elm++) { Seed1 = GetNextIndex(Seed1); if (DFlag) TstIndex = Swizzle(Seed1); else TstIndex = Seed1; JLI(PValue, *JL, TstIndex); if (*PValue == TstIndex) { printf("Index = 0x%0lx, ", TstIndex); FAILURE("JudyLIns failed - DUP Index", TstIndex); } *PValue = TstIndex; // save Index in Value #ifdef DIAG PValue = (PWord_t)JudyLGet(*JL, TstIndex, PJE0); if (PValue == NULL) { printf("Index = 0x%0lx, ", TstIndex); FAILURE("JudyLGet failed", TstIndex); } #endif // DIAG } ENDTm(DeltaUSecL); DeltaUSecL /= Elements; DeltaMalFreL = (double)(MalFreeCnt - StartMallocs) / Elements; if (DDel > DeltaUSecL) { icnt = ICNT; DDel = DeltaUSecL; } else { if (--icnt == 0) break; } } } // JudyHSIns timings if (JHFlag) { MalFlag = JudyMalHS; for (DDel = 1e40, icnt = ICNT, lp = 0; lp < Loops; lp++) { if (lp != 0) { for (Seed1 = Seed, elm = 0; elm < Elements; elm++) { Seed1 = GetNextIndex(Seed1); if (DFlag) TstIndex = Swizzle(Seed1); else TstIndex = Seed1; JHSD(Rc, *JH, &TstIndex, sizeof(Word_t)); } } StartMallocs = MalFreeCnt; STARTTm; for (Seed1 = Seed, elm = 0; elm < Elements; elm++) { Seed1 = GetNextIndex(Seed1); if (DFlag) TstIndex = Swizzle(Seed1); else TstIndex = Seed1; JHSI(PValue, *JH, &TstIndex, sizeof(Word_t)); if (*PValue == TstIndex) FAILURE("JudyHSIns failed - DUP Index", TstIndex); *PValue = TstIndex; // save Index in Value } ENDTm(DeltaUSecHS); DeltaUSecHS /= Elements; DeltaMalFreHS = (double)(MalFreeCnt - StartMallocs) / Elements; if (DDel > DeltaUSecHS) { icnt = ICNT; DDel = DeltaUSecHS; } else { if (--icnt == 0) break; } } } return (Seed1); // New seed } #undef __FUNCTI0N__ #define __FUNCTI0N__ "TestJudyDup" Word_t TestJudyDup(void **J1, void **JL, void **JH, Word_t Seed, Word_t Elements) { Word_t LowIndex = ~0UL; Word_t TstIndex; Word_t elm; Word_t *PValue; Word_t Seed1; int Rc; double DDel; Word_t icnt; Word_t lp; Word_t Loops; Loops = (MAXLOOPS / Elements) + MINLOOPS; if (lFlag) Loops = 1; if (J1Flag) { MalFlag = JudyMal1; LowIndex = ~0UL; for (DDel = 1e40, icnt = ICNT, lp = 0; lp < Loops; lp++) { STARTTm; for (Seed1 = Seed, elm = 0; elm < Elements; elm++) { Seed1 = GetNextIndex(Seed1); if (DFlag) TstIndex = Swizzle(Seed1); else TstIndex = Seed1; if (TstIndex < LowIndex) LowIndex = TstIndex; J1S(Rc, *J1, TstIndex); if (Rc != 0) FAILURE("Judy1Test Rc != 0", Rc); } ENDTm(DeltaUSec1); if (DDel > DeltaUSec1) { icnt = ICNT; DDel = DeltaUSec1; } else { if (--icnt == 0) break; } } DeltaUSec1 = DDel / (double)Elements; } icnt = ICNT; if (JLFlag) { MalFlag = JudyMalL; LowIndex = ~0UL; for (DDel = 1e40, lp = 0; lp < Loops; lp++) { STARTTm; for (Seed1 = Seed, elm = 0; elm < Elements; elm++) { Seed1 = GetNextIndex(Seed1); if (DFlag) TstIndex = Swizzle(Seed1); else TstIndex = Seed1; if (TstIndex < LowIndex) LowIndex = TstIndex; JLI(PValue, *JL, TstIndex); if (PValue == (Word_t *)NULL) FAILURE("JudyLGet ret PValue = NULL", 0L); if (*PValue != TstIndex) FAILURE("JudyLGet ret wrong Value at", elm); } ENDTm(DeltaUSecL); if (DDel > DeltaUSecL) { icnt = ICNT; DDel = DeltaUSecL; } else { if (--icnt == 0) break; } } DeltaUSecL = DDel / (double)Elements; } icnt = ICNT; if (JHFlag) { MalFlag = JudyMalHS; LowIndex = ~0UL; for (DDel = 1e40, lp = 0; lp < Loops; lp++) { STARTTm; for (Seed1 = Seed, elm = 0; elm < Elements; elm++) { Seed1 = GetNextIndex(Seed1); if (DFlag) TstIndex = Swizzle(Seed1); else TstIndex = Seed1; if (TstIndex < LowIndex) LowIndex = TstIndex; JHSI(PValue, *JH, &TstIndex, sizeof(Word_t)); if (PValue == (Word_t *)NULL) FAILURE("JudyHSGet ret PValue = NULL", 0L); if (*PValue != TstIndex) FAILURE("JudyHSGet ret wrong Value at", elm); } ENDTm(DeltaUSecHS); if (DDel > DeltaUSecHS) { icnt = ICNT; DDel = DeltaUSecHS; } else { if (--icnt == 0) break; } } DeltaUSecHS = DDel / (double)Elements; } return (LowIndex); } #undef __FUNCTI0N__ #define __FUNCTI0N__ "TestJudyGet" Word_t TestJudyGet(void *J1, void *JL, void *JH, Word_t Seed, Word_t Elements) { Word_t LowIndex = ~0UL; Word_t TstIndex; Word_t elm; Word_t *PValue; Word_t Seed1; int Rc; double DDel; Word_t icnt; Word_t lp; Word_t Loops; Loops = (MAXLOOPS / Elements) + MINLOOPS; if (lFlag) Loops = 1; if (J1Flag) { MalFlag = JudyMal1; LowIndex = ~0UL; for (DDel = 1e40, icnt = ICNT, lp = 0; lp < Loops; lp++) { STARTTm; for (Seed1 = Seed, elm = 0; elm < Elements; elm++) { Seed1 = GetNextIndex(Seed1); if (DFlag) TstIndex = Swizzle(Seed1); else TstIndex = Seed1; if (TstIndex < LowIndex) LowIndex = TstIndex; #ifdef SKIPMACRO Rc = Judy1Test(J1, TstIndex, PJE0); #else J1T(Rc, J1, TstIndex); #endif // SKIPMACRO if (Rc != 1) { printf ("\nJudy1Test wrong Rc = %d, Index = 0x%lx, elm = %lu", Rc, TstIndex, elm); FAILURE("Judy1Test Rc != 1", Rc); } } ENDTm(DeltaUSec1); if (DDel > DeltaUSec1) { icnt = ICNT; DDel = DeltaUSec1; } else { if (--icnt == 0) break; } } DeltaUSec1 = DDel / (double)Elements; } icnt = ICNT; if (JLFlag) { MalFlag = JudyMalL; LowIndex = ~0UL; for (DDel = 1e40, lp = 0; lp < Loops; lp++) { STARTTm; for (Seed1 = Seed, elm = 0; elm < Elements; elm++) { Seed1 = GetNextIndex(Seed1); if (DFlag) TstIndex = Swizzle(Seed1); else TstIndex = Seed1; if (TstIndex < LowIndex) LowIndex = TstIndex; #ifdef SKIPMACRO PValue = (PWord_t)JudyLGet(JL, TstIndex, PJE0); #else JLG(PValue, JL, TstIndex); #endif // SKIPMACRO if (PValue == (Word_t *)NULL) { printf("\nJudyGet Index = 0x%lx", TstIndex); FAILURE("JudyLGet ret PValue = NULL", 0L); } if (*PValue != TstIndex) { printf("JudyLGet returned Value=0x%lx, should be=0x%lx\n", *PValue, TstIndex); FAILURE("JudyLGet ret wrong Value at", elm); } } ENDTm(DeltaUSecL); if (DDel > DeltaUSecL) { icnt = ICNT; DDel = DeltaUSecL; } { if (--icnt == 0) break; } } DeltaUSecL = DDel / (double)Elements; } icnt = ICNT; if (JHFlag) { MalFlag = JudyMalHS; LowIndex = ~0UL; for (DDel = 1e40, lp = 0; lp < Loops; lp++) { STARTTm; for (Seed1 = Seed, elm = 0; elm < Elements; elm++) { Seed1 = GetNextIndex(Seed1); if (DFlag) TstIndex = Swizzle(Seed1); else TstIndex = Seed1; if (TstIndex < LowIndex) LowIndex = TstIndex; JHSG(PValue, JH, &TstIndex, sizeof(Word_t)); if (PValue == (Word_t *)NULL) FAILURE("JudyHSGet ret PValue = NULL", 0L); if (*PValue != TstIndex) FAILURE("JudyHSGet ret wrong Value at", elm); } ENDTm(DeltaUSecHS); if (DDel > DeltaUSecHS) { icnt = ICNT; DDel = DeltaUSecHS; } else { if (--icnt == 0) break; } } DeltaUSecHS = DDel / (double)Elements; } return (LowIndex); } #undef __FUNCTI0N__ #define __FUNCTI0N__ "TestJudy1Copy" int TestJudy1Copy(void *J1, Word_t Elements) { Pvoid_t J1a; // Judy1 new array Word_t elm = 0; Word_t Bytes; double DDel; Word_t icnt; Word_t lp; Word_t Loops; Loops = (MAXLOOPS / Elements) + MINLOOPS; if (lFlag) Loops = 1; MalFlag = JudyMal1; for (DDel = 1e40, icnt = ICNT, lp = 0; lp < Loops; lp++) { Word_t NextIndex; int Rc; STARTTm; J1a = NULL; // Initialize To array NextIndex = 0; // Start at the beginning elm = 0; #ifdef SKIPMACRO Rc = Judy1First(J1, &NextIndex, PJE0); while (Rc == 1) { if (elm++ == Elements) break; Rc = Judy1Set(&J1a, NextIndex, PJE0); if (Rc != 1) FAILURE("Judy1Set at", elm); Rc = Judy1Next(J1, &NextIndex, PJE0); } #else J1F(Rc, J1, NextIndex); // return first Index while (Rc == 1) { if (elm++ == Elements) break; J1S(Rc, J1a, NextIndex); if (Rc != 1) FAILURE("J1S at", elm); J1N(Rc, J1, NextIndex); } #endif // SKIPMACRO ENDTm(DeltaUSec1); #ifdef SKIPMACRO Bytes = Judy1FreeArray(&J1a, PJE0); #else J1FA(Bytes, J1a); // no need to keep it around #endif // SKIPMACRO if (DDel > DeltaUSec1) { icnt = ICNT; DDel = DeltaUSec1; } else { if (--icnt == 0) break; } } DeltaUSec1 = DDel / (double)elm; return (0); } #undef __FUNCTI0N__ #define __FUNCTI0N__ "TestJudyCount" int TestJudyCount(void *J1, void *JL, Word_t LowIndex, Word_t Elements) { Word_t elm; Word_t Count1, CountL; Word_t TstIndex = LowIndex; int Rc; double DDel; Word_t icnt; Word_t lp; Word_t Loops; Loops = (MAXLOOPS / Elements) + MINLOOPS; if (lFlag) Loops = 1; if (J1Flag) { MalFlag = JudyMal1; for (DDel = 1e40, icnt = ICNT, lp = 0; lp < Loops; lp++) { TstIndex = LowIndex; STARTTm; for (elm = 0; elm < Elements; elm++) { #ifdef SKIPMACRO Count1 = Judy1Count(J1, LowIndex, TstIndex, PJE0); #else J1C(Count1, J1, LowIndex, TstIndex); #endif // SKIPMACRO if (Count1 != (elm + 1)) { printf("Count1 = %lu, elm +1 = %lu\n", Count1, elm + 1); FAILURE("J1C at", elm); } #ifdef SKIPMACRO Rc = Judy1Next(J1, &TstIndex, PJE0); #else J1N(Rc, J1, TstIndex); #endif // SKIPMACRO } ENDTm(DeltaUSec1); if (DDel > DeltaUSec1) { icnt = ICNT; DDel = DeltaUSec1; } else { if (--icnt == 0) break; } } DeltaUSec1 = DDel / (double)Elements; } if (JLFlag) { MalFlag = JudyMalL; for (DDel = 1e40, icnt = ICNT, lp = 0; lp < Loops; lp++) { TstIndex = LowIndex; STARTTm; for (elm = 0; elm < Elements; elm++) { PWord_t PValue; #ifdef SKIPMACRO CountL = JudyLCount(JL, LowIndex, TstIndex, PJE0); #else JLC(CountL, JL, LowIndex, TstIndex); #endif // SKIPMACRO if (CountL != (elm + 1)) { printf("CountL = %lu, elm +1 = %lu\n", CountL, elm + 1); FAILURE("JLC at", elm); } #ifdef SKIPMACRO PValue = (PWord_t)JudyLNext(JL, &TstIndex, PJE0); #else JLN(PValue, JL, TstIndex); #endif // SKIPMACRO } ENDTm(DeltaUSecL); if (DDel > DeltaUSecL) { icnt = ICNT; DDel = DeltaUSecL; } else { if (--icnt == 0) break; } } DeltaUSecL = DDel / (double)Elements; } return (0); } #undef __FUNCTI0N__ #define __FUNCTI0N__ "TestJudyNext" Word_t TestJudyNext(void *J1, void *JL, Word_t LowIndex, Word_t Elements) { Word_t elm; double DDel; Word_t icnt; Word_t lp; Word_t Loops; Word_t JLindex; Word_t J1index; Loops = (MAXLOOPS / Elements) + MINLOOPS; if (lFlag) Loops = 1; if (J1Flag) { MalFlag = JudyMal1; for (DDel = 1e40, icnt = ICNT, lp = 0; lp < Loops; lp++) { int Rc; J1index = LowIndex; STARTTm; #ifdef SKIPMACRO Rc = Judy1First(J1, &J1index, PJE0); #else J1F(Rc, J1, J1index); #endif // SKIPMACRO for (elm = 0; elm < Elements; elm++) { if (Rc != 1) { printf("\nElements = %lu, elm = %lu\n", Elements, elm); FAILURE("Judy1Next Rc != 1 =", Rc); } #ifdef SKIPMACRO Rc = Judy1Next(J1, &J1index, PJE0); #else J1N(Rc, J1, J1index); // Get next one #endif // SKIPMACRO } ENDTm(DeltaUSec1); if ((TValues == 0) && (Rc != 0)) { FAILURE("Judy1Next Rc != 0", Rc); } if (DDel > DeltaUSec1) { icnt = ICNT; DDel = DeltaUSec1; } else { if (--icnt == 0) break; } } DeltaUSec1 = DDel / (double)Elements; } if (JLFlag) { MalFlag = JudyMalL; for (DDel = 1e40, icnt = ICNT, lp = 0; lp < Loops; lp++) { Word_t *PValue; // Get an Index low enough for Elements JLindex = LowIndex; STARTTm; JLF(PValue, JL, JLindex); for (elm = 0; elm < Elements; elm++) { Word_t Prev; if (PValue == NULL) { printf("\nElements = %lu, elm = %lu\n", Elements, elm); FAILURE("JudyLNext ret NULL PValue at", elm); } if (*PValue != JLindex) { printf("\n*PValue=0x%lx, JLindex=0x%lx\n", *PValue, JLindex); FAILURE("JudyLNext ret bad *PValue at", elm); } Prev = JLindex; #ifdef SKIPMACRO PValue = (PWord_t)JudyLNext(JL, &JLindex, PJE0); #else JLN(PValue, JL, JLindex); // Get next one #endif // SKIPMACRO if (JLindex == Prev) { printf("OOPs, JLN did not advance 0x%lx\n", Prev); FAILURE("JudyLNext ret did not advance", Prev); } } ENDTm(DeltaUSecL); if ((TValues == 0) && (PValue != NULL)) { FAILURE("JudyLNext PValue != NULL", PValue); } if (DDel > DeltaUSecL) { icnt = ICNT; DDel = DeltaUSecL; } else { if (--icnt == 0) break; } } DeltaUSecL = DDel / (double)Elements; } // perhaps a check should be done here -- if I knew what to expect. if (JLFlag) return (JLindex); if (J1Flag) return (J1index); return (-1); } #undef __FUNCTI0N__ #define __FUNCTI0N__ "TestJudyPrev" int TestJudyPrev(void *J1, void *JL, Word_t HighIndex, Word_t Elements) { Word_t elm; double DDel; Word_t icnt; Word_t lp; Word_t Loops; Word_t J1index; Word_t JLindex; Loops = (MAXLOOPS / Elements) + MINLOOPS; if (lFlag) Loops = 1; if (J1Flag) { MalFlag = JudyMal1; for (DDel = 1e40, icnt = ICNT, lp = 0; lp < Loops; lp++) { J1index = HighIndex; int Rc; STARTTm; #ifdef SKIPMACRO Rc = Judy1Last(J1, &J1index, PJE0); #else J1L(Rc, J1, J1index); #endif // SKIPMACRO for (elm = 0; elm < Elements; elm++) { if (Rc != 1) FAILURE("Judy1Prev Rc != 1, is: ", Rc); #ifdef SKIPMACRO Rc = Judy1Prev(J1, &J1index, PJE0); #else J1P(Rc, J1, J1index); // Get previous one #endif // SKIPMACRO } ENDTm(DeltaUSec1); if ((TValues == 0) && (Rc != 0)) { FAILURE("Judy1Prev Rc != 0", Rc); } if (DDel > DeltaUSec1) { icnt = ICNT; DDel = DeltaUSec1; } else { if (--icnt == 0) break; } } DeltaUSec1 = DDel / (double)Elements; } if (JLFlag) { MalFlag = JudyMalL; for (DDel = 1e40, icnt = ICNT, lp = 0; lp < Loops; lp++) { Word_t *PValue; JLindex = HighIndex; STARTTm; JLL(PValue, JL, JLindex); for (elm = 0; elm < Elements; elm++) { if (PValue == NULL) { printf("\nElements = %lu, elm = %lu\n", Elements, elm); FAILURE("JudyLPrev ret NULL PValue at", elm); } if (*PValue != JLindex) FAILURE("JudyLPrev ret bad *PValue at", elm); JLP(PValue, JL, JLindex); // Get previous one } ENDTm(DeltaUSecL); if ((TValues == 0) && (PValue != NULL)) FAILURE("JudyLPrev PValue != NULL", PValue); if (DDel > DeltaUSecL) { icnt = ICNT; DDel = DeltaUSecL; } else { if (--icnt == 0) break; } } DeltaUSecL = DDel / (double)Elements; } // perhaps a check should be done here -- if I knew what to expect. return (0); } #undef __FUNCTI0N__ #define __FUNCTI0N__ "TestJudyNextEmpty" // Returns number of consecutive Indexes Word_t TestJudyNextEmpty(void *J1, void *JL, Word_t LowIndex, Word_t Elements) { Word_t elm; double DDel; Word_t icnt; Word_t lp; Word_t Loops; int Rc; // Return code Loops = (MAXLOOPS / Elements) + MINLOOPS; if (lFlag) Loops = 1; if (J1Flag) { MalFlag = JudyMal1; for (DDel = 1e40, icnt = ICNT, lp = 0; lp < Loops; lp++) { Word_t Seed1 = LowIndex; STARTTm; for (elm = 0; elm < Elements; elm++) { Word_t J1index; J1index = Seed1; #ifdef SKIPMACRO Rc = Judy1NextEmpty(J1, &J1index, PJE0); #else J1NE(Rc, J1, J1index); #endif // SKIPMACRO if (Rc != 1) FAILURE("Judy1NextEmpty Rcode != 1 =", Rc); Seed1 = GetNextIndex(Seed1); } ENDTm(DeltaUSec1); if (DDel > DeltaUSec1) { icnt = ICNT; DDel = DeltaUSec1; } else { if (--icnt == 0) break; } } DeltaUSec1 = DDel / (double)Elements; } if (JLFlag) { MalFlag = JudyMalL; for (DDel = 1e40, icnt = ICNT, lp = 0; lp < Loops; lp++) { Word_t Seed1 = LowIndex; STARTTm; for (elm = 0; elm < Elements; elm++) { Word_t JLindex; JLindex = Seed1; #ifdef SKIPMACRO Rc = JudyLNextEmpty(JL, &JLindex, PJE0); #else JLNE(Rc, JL, JLindex); #endif // SKIPMACRO if (Rc != 1) FAILURE("JudyLNextEmpty Rcode != 1 =", Rc); Seed1 = GetNextIndex(Seed1); } ENDTm(DeltaUSecL); if (DDel > DeltaUSecL) { icnt = ICNT; DDel = DeltaUSecL; } else { if (--icnt == 0) break; } } DeltaUSecL = DDel / (double)Elements; } return (0); } // Routine to time and test JudyPrevEmpty routines #undef __FUNCTI0N__ #define __FUNCTI0N__ "TestJudyPrevEmpty" Word_t TestJudyPrevEmpty(void *J1, void *JL, Word_t HighIndex, Word_t Elements) { Word_t elm; double DDel; Word_t icnt; Word_t lp; Word_t Loops; int Rc; Loops = (MAXLOOPS / Elements) + MINLOOPS; if (lFlag) Loops = 1; if (J1Flag) { MalFlag = JudyMal1; for (DDel = 1e40, icnt = ICNT, lp = 0; lp < Loops; lp++) { Word_t Seed1 = HighIndex; STARTTm; for (elm = 0; elm < Elements; elm++) { Word_t J1index; J1index = Seed1; #ifdef SKIPMACRO Rc = Judy1PrevEmpty(J1, &J1index, PJE0); #else J1PE(Rc, J1, J1index); #endif // SKIPMACRO if (Rc != 1) FAILURE("Judy1PrevEmpty Rc != 1 =", Rc); Seed1 = GetNextIndex(Seed1); } ENDTm(DeltaUSec1); if (DDel > DeltaUSec1) { icnt = ICNT; DDel = DeltaUSec1; } else { if (--icnt == 0) break; } } DeltaUSec1 = DDel / (double)Elements; } if (JLFlag) { MalFlag = JudyMalL; for (DDel = 1e40, icnt = ICNT, lp = 0; lp < Loops; lp++) { Word_t Seed1 = HighIndex; STARTTm; for (elm = 0; elm < Elements; elm++) { Word_t JLindex; JLindex = Seed1; JLPE(Rc, JL, JLindex); // Rc = JudyLPrevEmpty(JL, &JLindex,PJE0) if (Rc != 1) FAILURE("JudyLPrevEmpty Rcode != 1 =", Rc); Seed1 = GetNextIndex(Seed1); } ENDTm(DeltaUSecL); if (DDel > DeltaUSecL) { icnt = ICNT; DDel = DeltaUSecL; } else { if (--icnt == 0) break; } } DeltaUSecL = DDel / (double)Elements; } return (0); } #undef __FUNCTI0N__ #define __FUNCTI0N__ "TestJudyDel" int TestJudyDel(void **J1, void **JL, void **JH, Word_t Seed, Word_t Elements) { Word_t TstIndex; Word_t elm; Word_t Seed1; int Rc; if (J1Flag) { MalFlag = JudyMal1; STARTTm; for (Seed1 = Seed, elm = 0; elm < Elements; elm++) { Seed1 = GetNextIndex(Seed1); if (DFlag) TstIndex = Swizzle(Seed1); else TstIndex = Seed1; #ifdef SKIPMACRO Rc = Judy1Unset(J1, TstIndex, PJE0); #else J1U(Rc, *J1, TstIndex); #endif // SKIPMACRO if (Rc != 1) FAILURE("Judy1Unset ret Rcode != 1", Rc); } ENDTm(DeltaUSec1); DeltaUSec1 /= Elements; } if (JLFlag) { MalFlag = JudyMalL; STARTTm; for (Seed1 = Seed, elm = 0; elm < Elements; elm++) { Seed1 = GetNextIndex(Seed1); if (DFlag) TstIndex = Swizzle(Seed1); else TstIndex = Seed1; #ifdef SKIPMACRO Rc = JudyLDel(JL, TstIndex, PJE0); #else JLD(Rc, *JL, TstIndex); #endif // SKIPMACRO if (Rc != 1) FAILURE("JudyLDel ret Rcode != 1", Rc); } ENDTm(DeltaUSecL); DeltaUSecL /= Elements; } if (JHFlag) { MalFlag = JudyMalHS; STARTTm; for (Seed1 = Seed, elm = 0; elm < Elements; elm++) { Seed1 = GetNextIndex(Seed1); if (DFlag) TstIndex = Swizzle(Seed1); else TstIndex = Seed1; JHSD(Rc, *JH, &TstIndex, sizeof(Word_t)); if (Rc != 1) FAILURE("JudyHSDel ret Rcode != 1", Rc); } ENDTm(DeltaUSecHS); DeltaUSecHS /= Elements; } return (0); } // Routine to get next size of Indexes int // return 1 if last number NextNumb(Word_t *PNumber, // pointer to returned next number double *PDNumb, // Temp double of above double DMult, // Multiplier Word_t MaxNumb) // Max number to return { // Save prev number double PrevPDNumb = *PDNumb; double DDiff; // Calc next number >= 1.0 beyond previous do { *PDNumb *= DMult; DDiff = *PDNumb - PrevPDNumb; } while (DDiff < 0.5); // Return it in integer format if (DDiff < 100.0) *PNumber += (Word_t)(DDiff + 0.5); else *PNumber = *PDNumb + 0.5; // Verify it did not exceed max number if (*PNumber >= MaxNumb) { // it did, so return max *PNumber = MaxNumb; return (1); // flag it } return (0); // more available } judy-1.0.5/test/timeit.h0000644000175000017500000001556210204462077015352 0ustar troyhebetroyhebe#ifndef _TIMEIT_H #define _TIMEIT_H // @(#) $Revision: 4.14 $ $Source: /judy/src/apps/benchmark/timeit.h $ // // Timing and timers header file with example program. // // You should compile with one of these defined: // // JU_HPUX_PA # control register available (via asm()). // JU_HPUX_IPF # TBD, see below. // JU_LINUX_IA32 # control register available (via get_cycles()). // JU_LINUX_IPF # control register available (via get_cycles()). // JU_WIN_IA32 # uses clock(). // // Otherwise default (low-res) timing code using gettimeofday() results. This // mode is only accurate to usecs, and fuzzy due to syscall overhead. // // Public macros; the *_HRTm() forms are much faster than the others: // // TIMER_vars(T) - declare variables to use for timers // STARTTm(T) - start the timer with variable T // ENDTm(D,T) - compute usec from last STARTTm(T), save result in double D // START_HRTm(T) - high-res for short intervals (< 2^32[64] clock ticks) only // END_HRTm(D,T) - high-res for short intervals (< 2^32[64] clock ticks) only // // Private macros: // // __START_HRTm(T) - read high-res control register, save in T // __END_HRTm(T) - read high-res control register, save in T // __HRONLY(D,T) - use high-res clock only // // Note: The __*_HRTm and __HRONLY macros are only available on platforms with // control registers for high-res clocks. On hpux_pa this is a 32-bit register // and gettimeofday() must be used to handle rollover; on linux_* this is a // 64-bit register. #ifndef JU_WIN_IA32 #include // Win32 uses a whole different paradigm. #include // for getopt(), which Win32 lacks. #endif #include // Public variables: extern double USecPerClock; // defined in timeit.c. // __HRONLY is used for multiple platforms, but only in cases where there is a // high-res clock and find_CPU_speed() is available from timeit.c: #define __HRONLY(D,T) \ { \ if (USecPerClock == 0.0) USecPerClock = find_CPU_speed(); \ (D) = ((double) (__stop_##T - __start_##T)) * USecPerClock; \ } // TIMING ROUTINES: // ********************* HPUX PA **************************** // // Define __START_HRTm and __END_HRTm only, and let later common code add // STARTTm and ENDTm. // // TBD: On hpux_pa or hpux_ipf 64-bit, is CR_IT a 64-bit register? If so, it's // unnecessary and wasteful to use gettimeofday() later to watch for rollover. // // TBD: JU_HPUX_IPF does not recognize CR_IT ("Undeclared variable 'CR_IT'"), // so for now treat that platform as having no high-res clock and do not // included it in this section. #if (JU_HPUX_PA) #include #include double find_CPU_speed(void); // Note: On hpux_*, at least older compilers, it is neither necessary nor even // allowed to mark the __start_* and __stop_* variables as volatile; the // compiler does not optimize out the code even without it: #define TIMER_vars(T) \ register unsigned long __start_##T, __stop_##T; \ struct timeval __TVBeg_##T, __TVEnd_##T #define __START_HRTm(T) _asm("MFCTL", CR_IT, __start_##T) #define __END_HRTm(T) _asm("MFCTL", CR_IT, __stop_##T ) #endif // (JU_HPUX_PA) // ********************* LINUX IA32 ************************** // #ifdef JU_LINUX_IA32 #include double find_CPU_speed(void); #define TIMER_vars(T) \ register unsigned long __start_##T, __stop_##T; \ struct timeval __TVBeg_##T, __TVEnd_##T #define __START_HRTm(T) rdtscl(__start_##T) #define __END_HRTm(T) rdtscl(__stop_##T) #endif // JU_LINUX_IA32 // ********************* LINUX_IPF ************************** // // Define __START_HRTm and __END_HRTm, and also STARTTm and ENDTm in terms of // the former (no need for gettimeofday()). #ifdef JU_LINUX_IPF #include double find_CPU_speed(void); // Using cycles_t rather than unsigned long [long] should be more portable; // and, it appears necessary to mark __start_* and __end_* as volatile so the // gcc compiler does not optimize out the register access: #define TIMER_vars(T) \ register volatile cycles_t __start_##T, __stop_##T; \ struct timeval __TVBeg_##T, __TVEnd_##T // This seems required for linux_ia32: // Older code (see 4.13) used rdtscl(), but this is not portable and does not // result in a 64-bit value, unlike get_cycles(), which apparently takes // advantage of a 64-bit control register on both IA32 and IPF => always // high-res timing with no rollover issues. Note, cycles_t is unsigned, so the // math works even in case of a rollover. #define __START_HRTm(T) __start_##T = get_cycles() #define __END_HRTm(T) __stop_##T = get_cycles() #define STARTTm(T) __START_HRTm(T) #define ENDTm(D,T) { __END_HRTm(T); __HRONLY(D,T); } #endif // JU_LINUX_IPF // ********************* WIN IA32 ***************************** // // WIN IA32 has no way to access the control register (?), so define STARTTm // and ENDTm directly using clock(): #ifdef JU_WIN_IA32 clock_t TBeg, TEnd; #define TIMER_vars(T) struct timeval __TVBeg_##T, __TVEnd_##T #define STARTTm(T) __TVBeg_##T = clock() #define ENDTm(D,T) { __TVEnd_##T = clock(); \ (D) = ((double) (__TVEnd_##T - __TVBeg_##T)); } #endif // JU_WIN_IA32 // ********************* OTHER ***************************** // // Default to using the low-res, slow-access clock only. #ifndef TIMER_vars #define TIMER_vars(T) struct timeval __TVBeg_##T, __TVEnd_##T #define STARTTm(T) gettimeofday(&__TVBeg_##T, NULL) #define ENDTm(D,T) gettimeofday(&__TVEnd_##T, NULL); \ (D) = (((double) __TVEnd_##T.tv_sec * ((double) 1E6)) \ + (double) __TVEnd_##T.tv_usec) \ - (((double) __TVBeg_##T.tv_sec * ((double) 1E6)) \ + (double) __TVBeg_##T.tv_usec) #endif // ! TIMER_vars // COMMON CODE FOR SYSTEMS WITH HIGH-RES CLOCKS (CONTROL REGISTERS): #ifdef __START_HRTm // Platforms that define __START_HRTm but not STARTTm (presently only hpux_pa) // use gettimeofday() for the low-res clock and __START_HRTm/__END_HRTm for // the high-res clock. If the low-res clock did not "roll over", use the // high-res clock; see __HRONLY. // // Note: Rollover is defined conservatively as 1E5 usec (= 1/10 sec). This // would require a 40 GHz 32-bit system to be violated. #ifndef STARTTm #define STARTTm(T) \ { \ gettimeofday(&__TVBeg_##T, NULL); __START_HRTm(T); \ } #define ENDTm(D,T) \ { \ __END_HRTm(T); gettimeofday(&__TVEnd_##T, NULL); \ \ (D) = (((double) __TVEnd_##T.tv_sec * ((double) 1E6)) \ + (double) __TVEnd_##T.tv_usec) \ - (((double) __TVBeg_##T.tv_sec * ((double) 1E6)) \ + (double) __TVBeg_##T.tv_usec); \ \ if ((D) < 1E5) __HRONLY(D,T); \ } #endif // ! STARTTm // Faster forms for heavy/frequent use in code loops where intervals are less // than 2^32[64] clock ticks: #define START_HRTm(T) __START_HRTm(T) #define END_HRTm(D,T) { __END_HRTm(T); __HRONLY(D,T); } #endif // __START_HRTm #endif // #ifndef _TIMEIT_H judy-1.0.5/test/JudyString.c0000644000175000017500000000525210204462077016147 0ustar troyhebetroyhebe#include #include #include #include #define MAXLENSTR 1000000 char Index[MAXLENSTR]; // string to store. Pvoid_t PJHArray = (PWord_t)NULL; // Judy array. // By Doug Baskins Apr 2004 - for JudyHS man page -- but too long int // Usage: JudyString file_to_store main(int argc, char *argv[]) { Pvoid_t PJHArray = (PWord_t)NULL; // Judy array. PWord_t PValue; // Judy array element. Word_t Bytes; // size of JudySL array. Word_t Len; // length of string FILE *fid = NULL; // stream id int Chr; // next char long Lines; // number of lines input file Word_t Dups; // Count duplicate lines if (argc < 2) { printf("Must supply input file in arg\n"); exit(2); } if ((fid = fopen(argv[1], "r")) == NULL) { printf("Failed to open '%s'\n", argv[1]); exit(2); } printf("Open '%s' and store strings in JudyHS array\n", argv[1]); Lines = 0; Len = 0; Dups = 0; while ((Chr = fgetc(fid)) != EOF) { if (Chr == '\n' && Len) { Index[Len] = '\0'; //printf("%3lu,%lu: %s\n", Lines, Len, Index); //printf("%s\n", Index); JHSI(PValue, PJHArray, Index, Len); // store string into array if (*PValue != 0) Dups++; *PValue += 1; Lines++; Len = 0; } else if (Len < MAXLENSTR) { Index[Len] = Chr; Len++; } } fclose(fid); fid = NULL; printf("'%s' has %lu lines, %lu duplicate lines\n", argv[1], Lines, Dups); printf("Re-open '%s' and verify each string is in JudyHS array\n", argv[1]); if ((fid = fopen(argv[1], "r")) == NULL) { printf("Failed to re-open '%s'\n", argv[1]); exit(2); } Lines = 0; Len = 0; while ((Chr = fgetc(fid)) != EOF) { if (Len < MAXLENSTR) Index[Len] = Chr; if (Chr == '\n' && Len) { Index[Len] = '\0'; JHSG(PValue, PJHArray, Index, Len); // store string into array if (PValue == NULL) { printf("'%s'\n", Index); printf("JHSG() failed at Line %lu\n", Lines); exit(1); } Len = 0; Lines++; } else Len++; } printf("Begin JHSFA (JudyHSFreeArray)\n"); JHSFA(Bytes, PJHArray); // free array fprintf(stderr, "JHSFA() free'ed %lu bytes of memory\n", Bytes); return (0); } judy-1.0.5/test/Judy1LCheck.c0000644000175000017500000005243410204462077016117 0ustar troyhebetroyhebe// @(#) $Revision: 4.15 $ $Source: /judy/test/manual/Judy1LCheck.c $ // This program tests the accuracy of a Judy1 with a JudyL Array. // -by- // Douglas L. Baskins (8/2001) doug@sourcejudy.com #ifndef JU_WIN_IA32 #include // unavailable on Win32, and no getopt(). #endif #include // calloc() #include // pow() #include // printf() #include // Common macro to handle a failure #define FAILURE(STR, UL) \ { \ printf( "Error: %s %lu, file='%s', 'function='%s', line %d\n", \ STR, UL, __FILE__, __FUNCTI0N__, __LINE__); \ fprintf(stderr, "Error: %s %lu, file='%s', 'function='%s', line %d\n", \ STR, UL, __FILE__, __FUNCTI0N__, __LINE__); \ exit(1); \ } // Structure to keep track of times typedef struct MEASUREMENTS_STRUCT { Word_t ms_delta; } ms_t, *Pms_t; // Specify prototypes for each test routine int NextNumb(Word_t * PNumber, double *PDNumb, double DMult, Word_t MaxNumb); Word_t TestJudyIns(void **J1, void **JL, Word_t Seed, Word_t Elements); Word_t TestJudyDup(void **J1, void **JL, Word_t Seed, Word_t Elements); int TestJudyDel(void **J1, void **JL, Word_t Seed, Word_t Elements); Word_t TestJudyGet(void *J1, void *JL, Word_t Seed, Word_t Elements); int TestJudyCount(void *J1, void *JL, Word_t LowIndex, Word_t Elements); Word_t TestJudyNext(void *J1, void *JL, Word_t LowIndex, Word_t Elements); int TestJudyPrev(void *J1, void *JL, Word_t HighIndex, Word_t Elements); int TestJudyNextEmpty(void *J1, void *JL, Word_t LowIndex, Word_t Elements); int TestJudyPrevEmpty(void *J1, void *JL, Word_t HighIndex, Word_t Elements); Word_t MagicList[] = { 0,0,0,0,0,0,0,0,0,0, // 0..9 0x27f, // 10 0x27f, // 11 0x27f, // 12 0x27f, // 13 0x27f, // 14 0x27f, // 15 0x1e71, // 16 0xdc0b, // 17 0xdc0b, // 18 0xdc0b, // 19 0xdc0b, // 20 0xc4fb, // 21 0xc4fb, // 22 0xc4fb, // 23 0x13aab, // 24 0x11ca3, // 25 0x11ca3, // 26 0x11ca3, // 27 0x13aab, // 28 0x11ca3, // 29 0xc4fb, // 30 0xc4fb, // 31 0x13aab, // 32 0x14e73, // 33 0x145d7, // 34 0x145f9, // 35 following tested with Seed=0xc1fc to 35Gig numbers 0x151ed, // 36 .. 41 0x151ed, // 37 0x151ed, // 38 0x151ed, // 39 0x151ed, // 40 0x146c3, // 41 .. 64 0x146c3, // 42 0x146c3, // 43 0x146c3, // 44 0x146c3, // 45 0x146c3, // 46 0x146c3, // 47 0x146c3, // 48 0x146c3, // 49 0x146c3, // 50 0x146c3, // 51 0x146c3, // 52 0x146c3, // 53 0x146c3, // 54 0x146c3, // 55 0x146c3, // 56 0x146c3, // 57 0x146c3, // 58 0x146c3, // 59 0x146c3, // 60 0x146c3, // 61 0x146c3, // 62 0x146c3, // 63 0x146c3 // 64 }; // Routine to "mirror" the input data word static Word_t Swizzle(Word_t word) { // BIT REVERSAL, Ron Gutman in Dr. Dobb's Journal, #316, Sept 2000, pp133-136 // #ifdef __LP64__ word = ((word & 0x00000000ffffffff) << 32) | ((word & 0xffffffff00000000) >> 32); word = ((word & 0x0000ffff0000ffff) << 16) | ((word & 0xffff0000ffff0000) >> 16); word = ((word & 0x00ff00ff00ff00ff) << 8) | ((word & 0xff00ff00ff00ff00) >> 8); word = ((word & 0x0f0f0f0f0f0f0f0f) << 4) | ((word & 0xf0f0f0f0f0f0f0f0) >> 4); word = ((word & 0x3333333333333333) << 2) | ((word & 0xcccccccccccccccc) >> 2); word = ((word & 0x5555555555555555) << 1) | ((word & 0xaaaaaaaaaaaaaaaa) >> 1); #else // __LP64__ word = ((word & 0x0000ffff) << 16) | ((word & 0xffff0000) >> 16); word = ((word & 0x00ff00ff) << 8) | ((word & 0xff00ff00) >> 8); word = ((word & 0x0f0f0f0f) << 4) | ((word & 0xf0f0f0f0) >> 4); word = ((word & 0x33333333) << 2) | ((word & 0xcccccccc) >> 2); word = ((word & 0x55555555) << 1) | ((word & 0xaaaaaaaa) >> 1); #endif // __LP64__ return(word); } Word_t dFlag = 1; Word_t pFlag = 0; Word_t CFlag = 0; Word_t DFlag = 0; Word_t SkipN = 0; // default == Random skip Word_t nElms = 1000000; // Default = 1M Word_t ErrorFlag = 0; Word_t TotalIns = 0; Word_t TotalPop = 0; Word_t TotalDel = 0; // Stuff for LFSR (pseudo random number generator) Word_t RandomBit = ~0UL / 2 + 1; Word_t BValue = sizeof(Word_t) * 8; Word_t Magic; Word_t StartSeed = 0xc1fc; // default beginning number Word_t FirstSeed; #undef __FUNCTI0N__ #define __FUNCTI0N__ "Random" static Word_t // Placed here so INLINING compilers get to look at it. Random(Word_t newseed) { if (newseed & RandomBit) { newseed += newseed; newseed ^= Magic; } else { newseed += newseed; } newseed &= RandomBit * 2 - 1; if (newseed == FirstSeed) { printf("End of LFSR, Total Population = %lu\n", TotalPop); exit(0); } return(newseed); } static Word_t // Placed here so INLINING compilers get to look at it. GetNextIndex(Word_t Index) { if (SkipN) Index += SkipN; else Index = Random(Index); return(Index); } #undef __FUNCTI0N__ #define __FUNCTI0N__ "main" int main(int argc, char *argv[]) { // Names of Judy Arrays void *J1 = NULL; // Judy1 void *JL = NULL; // JudyL double Mult; Pms_t Pms; Word_t Seed; Word_t PtsPdec = 10; // points per decade Word_t Groups; // Number of measurement groups Word_t grp; int c; extern char *optarg; ////////////////////////////////////////////////////////////// // PARSE INPUT PARAMETERS ////////////////////////////////////////////////////////////// while ((c = getopt(argc, argv, "n:S:P:b:L:B:pdDC")) != -1) { switch (c) { case 'n': // Number of elements nElms = strtoul(optarg, NULL, 0); // Size of Linear Array if (nElms == 0) FAILURE("No tests: -n", nElms); // Check if more than a trillion (64 bit only) if ((double)nElms > 1e12) FAILURE("Too many Indexes=", nElms); break; case 'S': // Step Size, 0 == Random SkipN = strtoul(optarg, NULL, 0); break; case 'P': // PtsPdec = strtoul(optarg, NULL, 0); break; case 'b': // May not work past 35 bits if changed StartSeed = strtoul(optarg, NULL, 0); break; case 'B': BValue = strtoul(optarg, NULL, 0); if ( (BValue > (sizeof(Word_t) * 8)) || (MagicList[BValue] == 0) ) { ErrorFlag++; printf("\nIllegal number of random bits of %lu !!!\n", BValue); } break; case 'p': // Print test indexes pFlag = 1; break; case 'd': // Delete indexes dFlag = 0; break; case 'D': // Swizzle indexes DFlag = 1; break; case 'C': // Skip counting test. CFlag = 1; break; default: ErrorFlag++; break; } } if (ErrorFlag) { printf("\n%s -n# -S# -B# -P# -b # -DRCpd\n\n", argv[0]); printf("Where:\n"); printf("-n <#> number of indexes used in tests\n"); printf("-C skip JudyCount tests\n"); printf("-p print index set - for debug\n"); printf("-d do not call JudyDel/Unset\n"); printf("-D Swizzle data (mirror)\n"); printf("-S <#> index skip amount, 0 = random\n"); printf("-B <#> # bits-1 in random number generator\n"); printf("-P <#> number measurement points per decade\n"); printf("\n"); exit(1); } // Set number of Random bits in LFSR RandomBit = 1UL << (BValue - 1); Magic = MagicList[BValue]; if (nElms > ((RandomBit-2) * 2)) { printf("# Number = -n%lu of Indexes reduced to max expanse of Random numbers\n", nElms); nElms = ((RandomBit-2) * 2); } printf("\n%s -n%lu -S%lu -B%lu", argv[0], nElms, SkipN, BValue); if (DFlag) printf(" -D"); if (!dFlag) printf(" -d"); if (pFlag) printf(" -p"); if (CFlag) printf(" -C"); printf("\n\n"); if (sizeof(Word_t) == 8) printf("%s 64 Bit version\n", argv[0]); else if (sizeof(Word_t) == 4) printf("%s 32 Bit version\n", argv[0]); ////////////////////////////////////////////////////////////// // CALCULATE NUMBER OF MEASUREMENT GROUPS ////////////////////////////////////////////////////////////// // Calculate Multiplier for number of points per decade Mult = pow(10.0, 1.0 / (double)PtsPdec); { double sum; Word_t numb, prevnumb; // Count number of measurements needed (10K max) sum = numb = 1; for (Groups = 2; Groups < 10000; Groups++) if (NextNumb(&numb, &sum, Mult, nElms)) break; // Get memory for measurements Pms = (Pms_t) calloc(Groups, sizeof(ms_t)); // Now calculate number of Indexes for each measurement point numb = sum = 1; prevnumb = 0; for (grp = 0; grp < Groups; grp++) { Pms[grp].ms_delta = numb - prevnumb; prevnumb = numb; NextNumb(&numb, &sum, Mult, nElms); } } // Groups = number of sizes ////////////////////////////////////////////////////////////// // BEGIN TESTS AT EACH GROUP SIZE ////////////////////////////////////////////////////////////// // Get the kicker to test the LFSR FirstSeed = Seed = StartSeed & (RandomBit * 2 - 1); printf("Total Pop Total Ins New Ins Total Del"); printf(" J1MU/I JLMU/I\n"); #ifdef testLFSR { Word_t Seed1 = Seed; while(1) { Seed1 = GetNextIndex(Seed1); TotalPop++; if (TotalPop > 40000000000) printf("Total = %lu\n", TotalPop), exit(1); } } #endif // testLFSR for (grp = 0; grp < Groups; grp++) { Word_t LowIndex, HighIndex; Word_t Delta; Word_t NewSeed; Delta = Pms[grp].ms_delta; // Test JLI, J1S NewSeed = TestJudyIns(&J1, &JL, Seed, Delta); // Test JLG, J1T LowIndex = TestJudyGet(J1, JL, Seed, Delta); // Test JLI, J1S -dup LowIndex = TestJudyDup(&J1, &JL, Seed, Delta); // Test JLC, J1C if (!CFlag) { TestJudyCount(J1, JL, LowIndex, Delta); } // Test JLN, J1N HighIndex = TestJudyNext(J1, JL, LowIndex, Delta); // Test JLP, J1P TestJudyPrev(J1, JL, HighIndex, Delta); // Test JLNE, J1NE TestJudyNextEmpty(J1, JL, LowIndex, Delta); // Test JLPE, J1PE TestJudyPrevEmpty(J1, JL, HighIndex, Delta); // Test JLD, J1U if (dFlag) { TestJudyDel(&J1, &JL, Seed, Delta); } printf("%9lu %9lu %7lu %9lu", TotalPop, TotalIns, Delta, TotalDel); { Word_t Count1, CountL; // Print the number of bytes used per Index J1C(Count1, J1, 0, ~0); printf(" %6.3f", (double)Judy1MemUsed(J1) / (double)Count1); JLC(CountL, JL, 0, ~0); printf(" %6.3f", (double)JudyLMemUsed(JL) / (double)CountL); } printf("\n"); // Advance Index number set Seed = NewSeed; } { Word_t Count1, CountL; Word_t Bytes; JLC(CountL, JL, 0, ~0); J1C(Count1, J1, 0, ~0); if (CountL != TotalPop) FAILURE("JudyLCount wrong", CountL); if (Count1 != TotalPop) FAILURE("Judy1Count wrong", Count1); if (TotalPop) { J1FA(Bytes, J1); // Free the Judy1 Array printf("Judy1FreeArray = %6.3f Bytes/Index\n", (double)Bytes / (double)Count1); if (pFlag) { printf("J1FA: %8lu\tbytes = %lu\n", TotalPop, Bytes); } JLFA(Bytes, JL); // Free the JudyL Array printf("JudyLFreeArray = %6.3f Bytes/Index\n", (double)Bytes / (double)CountL); if (pFlag) { printf("JLFA: %8lu\tbytes = %lu\n", TotalPop, Bytes); } TotalPop = 0; } } printf("Passed JudyL and Judy1 tests\n"); exit(0); } #undef __FUNCTI0N__ #define __FUNCTI0N__ "TestJudyIns" Word_t TestJudyIns(void **J1, void **JL, Word_t Seed, Word_t Elements) { Word_t TstIndex; Word_t elm; Word_t *PValue, *PValue1; Word_t Seed1; int Rcode; for (Seed1 = Seed, elm = 0; elm < Elements; elm++) { Seed1 = GetNextIndex(Seed1); if (Seed1 == 0) FAILURE("This command not robust if Index == 0", elm); if (DFlag) TstIndex = Swizzle(Seed1); else TstIndex = Seed1; if (pFlag) { printf("Ins: %8lu\t0x%lx\n", elm, TstIndex); } J1S(Rcode, *J1, TstIndex); if (Rcode == JERR) FAILURE("Judy1Set failed at", elm); if (Rcode == 0) FAILURE("Judy1Set failed - DUP Index, population =", TotalPop); J1T(Rcode, *J1, TstIndex); if (Rcode != 1) FAILURE("Judy1Test failed - Index missing, population =", TotalPop); J1S(Rcode, *J1, TstIndex); if (Rcode != 0) FAILURE("Judy1Set failed - Index missing, population =", TotalPop); JLI(PValue, *JL, TstIndex); if (PValue == PJERR) FAILURE("JudyLIns failed at", elm); if (*PValue == TstIndex) FAILURE("JudyLIns failed - DUP Index, population =", TotalPop); // Save Index in Value *PValue = TstIndex; JLG(PValue1, *JL, TstIndex); if (PValue != PValue1) FAILURE("JudyLGet failed - Index missing, population =", TotalPop); JLI(PValue1, *JL, TstIndex); if (PValue != PValue1) { if (*PValue1 != TstIndex) { FAILURE("JudyLIns failed - Index missing, population =", TotalPop); } else { // not ready for this yet! printf("Index moved -- TotalPop = %lu\n", TotalPop); } } TotalPop++; TotalIns++; } return (Seed1); // New seed } #undef __FUNCTI0N__ #define __FUNCTI0N__ "TestJudyGet" Word_t TestJudyGet(void *J1, void *JL, Word_t Seed, Word_t Elements) { Word_t LowIndex = ~0UL; Word_t TstIndex; Word_t elm; Word_t *PValue; Word_t Seed1; int Rcode; for (Seed1 = Seed, elm = 0; elm < Elements; elm++) { Seed1 = GetNextIndex(Seed1); if (DFlag) TstIndex = Swizzle(Seed1); else TstIndex = Seed1; if (TstIndex < LowIndex) LowIndex = TstIndex; J1T(Rcode, J1, TstIndex); if (Rcode != 1) FAILURE("Judy1Test Rcode != 1", (Word_t) Rcode); JLG(PValue, JL, TstIndex); if (PValue == (Word_t *) NULL) FAILURE("JudyLGet ret PValue = NULL", 0L); if (*PValue != TstIndex) FAILURE("JudyLGet ret wrong Value at", elm); } return(LowIndex); } #undef __FUNCTI0N__ #define __FUNCTI0N__ "TestJudyDup" Word_t TestJudyDup(void **J1, void **JL, Word_t Seed, Word_t Elements) { Word_t LowIndex = ~0UL; Word_t TstIndex; Word_t elm; Word_t *PValue; Word_t Seed1; int Rcode; for (Seed1 = Seed, elm = 0; elm < Elements; elm++) { Seed1 = GetNextIndex(Seed1); if (DFlag) TstIndex = Swizzle(Seed1); else TstIndex = Seed1; if (TstIndex < LowIndex) LowIndex = TstIndex; J1S(Rcode, *J1, TstIndex); if (Rcode != 0) FAILURE("Judy1Set Rcode != 0", (Word_t) Rcode); JLI(PValue, *JL, TstIndex); if (PValue == (Word_t *) NULL) FAILURE("JudyLIns ret PValue = NULL", 0L); if (*PValue != TstIndex) FAILURE("JudyLIns ret wrong Value at", elm); } return(LowIndex); } #undef __FUNCTI0N__ #define __FUNCTI0N__ "TestJudyCount" int TestJudyCount(void *J1, void *JL, Word_t LowIndex, Word_t Elements) { Word_t elm; Word_t Count1, CountL; Word_t TstIndex = LowIndex; int Rcode; TstIndex = LowIndex; for (elm = 0; elm < Elements; elm++) { J1C(Count1, J1, LowIndex, TstIndex); if (Count1 == JERR) FAILURE("Judy1Count ret JERR", (Word_t) Count1); if (Count1 != (elm + 1)) { J1C(CountL, J1, 0, -1); printf("J1C(%lu, J1, 0, -1)\n", CountL); JLC(CountL, JL, 0, -1); printf("JLC(%lu, JL, 0, -1)\n", CountL); printf("LowIndex = 0x%lx, TstIndex = 0x%lx, diff = %lu\n", LowIndex, TstIndex, TstIndex - LowIndex); JLC(CountL, JL, LowIndex, TstIndex); printf("CountL = %lu, Count1 = %lu, should be: elm + 1 = %lu\n", CountL, Count1, elm + 1); FAILURE("J1C at", elm); } JLC(CountL, JL, LowIndex, TstIndex); if (CountL == JERR) FAILURE("JudyLCount ret JERR", (Word_t) CountL); if (CountL != (elm + 1)) FAILURE("JLC at", elm); J1N(Rcode, J1, TstIndex); } return(0); } #undef __FUNCTI0N__ #define __FUNCTI0N__ "TestJudyNext" Word_t TestJudyNext(void *J1, void *JL, Word_t LowIndex, Word_t Elements) { Word_t JLindex, J1index; Word_t *PValue; Word_t elm; int Rcode; // Get an Index low enough for Elements J1index = JLindex = LowIndex; JLF(PValue, JL, JLindex); J1F(Rcode, J1, J1index); for (elm = 0; elm < Elements; elm++) { if (PValue == NULL) FAILURE("JudyLNext ret NULL PValue at", elm); if (Rcode != 1) FAILURE("Judy1Next Rcode != 1 =", (Word_t) Rcode); if (JLindex != J1index) FAILURE("Judy1Next & Judy1Next ret different PIndex at", elm); JLN(PValue, JL, JLindex); // Get next one J1N(Rcode, J1, J1index); // Get next one } // perhaps a check should be done here -- if I knew what to expect. return(JLindex); // return last one } #undef __FUNCTI0N__ #define __FUNCTI0N__ "TestJudyPrev" int TestJudyPrev(void *J1, void *JL, Word_t HighIndex, Word_t Elements) { Word_t JLindex, J1index; Word_t *PValue; Word_t elm; int Rcode; // Get an Index high enough for Elements J1index = JLindex = HighIndex; JLL(PValue, JL, JLindex); J1L(Rcode, J1, J1index); for (elm = 0; elm < Elements; elm++) { if (PValue == NULL) FAILURE("JudyLPrev ret NULL PValue at", elm); if (Rcode != 1) FAILURE("Judy1Prev Rcode != 1 =", (Word_t) Rcode); if (JLindex != J1index) FAILURE("Judy1Prev & Judy1Prev ret different PIndex at", elm); JLP(PValue, JL, JLindex); // Get previous one J1P(Rcode, J1, J1index); // Get previous one } // perhaps a check should be done here -- if I knew what to expect. return(0); } #undef __FUNCTI0N__ #define __FUNCTI0N__ "TestJudyNextEmpty" int TestJudyNextEmpty(void *J1, void *JL, Word_t LowIndex, Word_t Elements) { Word_t elm; Word_t JLindex, J1index; Word_t Seed1; int Rcode; // Return code // Set 1st search to .. Seed1 = LowIndex; J1index = JLindex = Seed1; for (elm = 0; elm < Elements; elm++) { Word_t *PValue; // Find next Empty Index, JLindex is modified by JLNE JLNE(Rcode, JL, JLindex); // Rcode = JudyLNextEmpty(JL, &JLindex, PJE0) if (Rcode != 1) FAILURE("JudyLNextEmpty Rcode != 1 =", (Word_t) Rcode); if (pFlag) { printf("JNE: %8lu\t0x%lx\n", elm, JLindex); } // Find next Empty Index, J1index is modified by J1NE J1NE(Rcode, J1, J1index); // Rcode = Judy1NextEmpty(J1, &J1index, PJE0) if (Rcode != 1) FAILURE("Judy1NextEmpty Rcode != 1 =", (Word_t) Rcode); if (J1index != JLindex) FAILURE("JLNE != J1NE returned index at", elm); J1T(Rcode, J1, J1index); if (Rcode != 0) FAILURE("J1NE returned non-empty Index =", J1index); JLG(PValue, JL, JLindex); if (PValue != (Word_t *) NULL) FAILURE("JLNE returned non-empty Index =", JLindex); Seed1 = GetNextIndex(Seed1); J1index = JLindex = Seed1; } return(0); } // Routine to JudyPrevEmpty routines #undef __FUNCTI0N__ #define __FUNCTI0N__ "TestJudyPrevEmpty" int TestJudyPrevEmpty(void *J1, void *JL, Word_t HighIndex, Word_t Elements) { Word_t elm; Word_t JLindex, J1index; Word_t Seed1; int Rcode; // Set 1st search to .. Seed1 = HighIndex; J1index = JLindex = Seed1; for (elm = 0; elm < Elements; elm++) { Word_t *PValue; J1PE(Rcode, J1, J1index); // Rcode = Judy1PrevEmpty(J1, &J1index, PJE0) if (Rcode != 1) FAILURE("Judy1PrevEmpty Rcode != 1 =", (Word_t) Rcode); if (pFlag) { printf("JPE: %8lu\t0x%lx\n", elm, J1index); } // Find next Empty Index, JLindex is modified by JLPE JLPE(Rcode, JL, JLindex); // Rcode = JudyLPrevEmpty(JL, &JLindex, PJE0) if (Rcode != 1) FAILURE("JudyLPrevEmpty Rcode != 1 =", (Word_t) Rcode); if (J1index != JLindex) FAILURE("JLPE != J1PE returned index at", elm); J1T(Rcode, J1, J1index); if (Rcode != 0) FAILURE("J1PE returned non-empty Index =", J1index); JLG(PValue, JL, JLindex); if (PValue != (Word_t *) NULL) FAILURE("JLPE returned non-empty Index =", JLindex); Seed1 = GetNextIndex(Seed1); J1index = JLindex = Seed1; } return(0); } #undef __FUNCTI0N__ #define __FUNCTI0N__ "TestJudyDel" int TestJudyDel(void **J1, void **JL, Word_t Seed, Word_t Elements) { Word_t TstIndex; Word_t elm; Word_t Seed1; int Rcode; // Only delete half of thoes inserted for (Seed1 = Seed, elm = 0; elm < (Elements / 2); elm++) { Seed1 = GetNextIndex(Seed1); if (DFlag) TstIndex = Swizzle(Seed1); else TstIndex = Seed1; if (pFlag) { printf("Del: %8lu\t0x%lx\n", elm, TstIndex); } TotalDel++; J1U(Rcode, *J1, TstIndex); if (Rcode != 1) FAILURE("Judy1Unset ret Rcode != 1", (Word_t) Rcode); JLD(Rcode, *JL, TstIndex); if (Rcode != 1) FAILURE("JudyLDel ret Rcode != 1", (Word_t) Rcode); TotalPop--; } return(0); } // Routine to get next size of Indexes int // return 1 if last number NextNumb(Word_t * PNumber, // pointer to returned next number double *PDNumb, // Temp double of above double DMult, // Multiplier Word_t MaxNumb) // Max number to return { Word_t num; // Save prev number Word_t PrevNumb = *PNumber; // Verify integer number increased for (num = 0; num < 1000; num++) { // Calc next number *PDNumb *= DMult; // Return it in integer format *PNumber = (Word_t) (*PDNumb + 0.5); if (*PNumber != PrevNumb) break; } // Verify it did exceed max ulong if ((*PDNumb + 0.5) > (double)(-1UL)) { // It did, so return max number *PNumber = -1UL; return (1); // flag it } // Verify it did not exceed max number if ((*PDNumb + 0.5) > (double)MaxNumb) { // it did, so return max *PNumber = MaxNumb; return(1); // flag it } return(0); // more available } judy-1.0.5/test/README0000644000175000017500000000240410204462077014555 0ustar troyhebetroyhebeStringCompare.c Program to compare JudyHS with other ADT's Centrino_1.3Mhz_Plots/ Contains output of "StringCompare" on 1.3Mhz Centrino Checkit Script to validate Judy works before installing Judy1LHCheck.c Updated to include JudyHS() Judy1LHTime.c Updated to include JudyHS() jbgraph Script interface to 'gnuplot' to plot output of *Time.c progs. testjbgraph Demo script to show how to use jbgraph (1+ Minute) malloc-pre2.8a.c Only known malloc() (my me) that does not have performance problem, See: for later version. See: for further information. JudyMalloc.c For testing Judy free()s all memory that it malloc()ed. CheckDupLines.c For the JudyHS manual example JudyString.c For the JudyHS manual, but too long -- The following are obsolete. Judy1LCheck.c Program to test functionality of Judy API. (obsolete) Judy1LTime.c Program to time common Judy functions. (obsolete) SLcompare.c Program to compare JudySL performance with others (obsolete) timeit.c High resolution timers for certain platforms (obsolete) timeit.h High resolution timers for certain platforms (obsolete) judy-1.0.5/test/StringCompare.c0000644000175000017500000023606010204462077016625 0ustar troyhebetroyhebe// @(#) $Revision: 4.1 $ $Source: /judy/test/manual/StringCompare.c $ //======================================================================= // Author Douglas L. Baskins, Jan 2003. // Permission to use this code is freely granted, provided that this // statement is retained. // email - dougbaskins .at, yahoo.com //======================================================================= //======================================================================= // // This program will time various ADTs that store and retrieve strings. // Currently there are 7 ADTs implemented: /* 1) Hash - this is the fastest one when table size matches data size 2) JudyHS - 2nd in speed and very scaleable. 3) JLHash - this uses a JudyL() array instead of hash table and is very scaleable because the hash table size is ~4 billion. 4) JudySL - ordered and requires null terminated strings. 5) Ternary - code borrowed from Mr Dobbs, perhaps 2000 6) Redblack - code borrowed from J. Zobel, April 2001. 7) Splay - code borrowed from J. Zobel, April 2001. Note: Splay, Redblack and Ternary methods are not very fast, so they have not been completed and made bug free. I.E. no Delete and Free Array routines. Ternary is fastest retrieve of these three, but uses an extraordinary amount of memory. */ //======================================================================= // // Compile: // // cc -O StringCompare.c -lm -lJudy -o StringCompare // -or- // cc -O -DCPUMHZ=1299 StringCompare.c -lm -lJudy -o StringCompare /* Notes: 1) Use '-DCPUMHZ=1299' in cc line if better clock resolution is desired and it compiles successfully. The 1299 is the cpu MHz : 1298.916 from cat /proc/cpuinfo in a Linux system. 2) -static will generally get better performance because memcmp(), memcpy() routines are usually slower with shared librarys. */ // Usage: // // StringCompare -A Hash textfile // StringCompare -A JudyHS textfile // StringCompare -A JLHash textfile // StringCompare -A JudySL textfile // StringCompare -A Ternary textfile // StringCompare -A Redblack textfile // StringCompare -A Splay textfile #include // malloc(3) #include // getopt(3) #include // printf(3) #include // open(2) #include // memcmp(3), memcpy(3) #include // errno(3) #include // mmap(2) #include // gettimeofday(2) #include // pow(3) #include // uname(2) #include // Judy arrays //======================================================================= // D e f i n e: T O T U R N O F F A S S E R T I O N S !!!!!!!! //======================================================================= //#define NDEBUG 1 #include // assert(3) //======================================================================= // G L O B A L D A T A //======================================================================= int foolflag = 0; // fool compiler from optimizing static Word_t gStored = 0; // number of strings inserted static Word_t gChainln = 0; // links traversed during RETRIVE static Word_t PtsPdec = 40; // default measurement points per decade #define INFSTRGS 1000000000 // 1 billion strings is infinity static Word_t nStrg = INFSTRGS; // infinity -- measure all strings static Word_t TValues = 100000; // max measure points for RETRIVE tests static int pFlag = 0; // pre-fault hash table pages into RAM static int rFlag = 0; // do not randomize input file static int aFlag = 0; // word align string buffers static int DFlag = 0; // do the delete measurement static int CFlag = 0; // build sequential Get buffers static Word_t aCount = 0; // Count of missaligned string buffers // define the maximum length of a string allowed #define MAXSTRLEN (100000) static int MLength = MAXSTRLEN; static Word_t HTblsz; // 1M default hash table size static int fileidx; // argv[fileidx] == file string // for saving input string data typedef struct STRING_ { int dt_strlen; uint8_t *dt_string; } dt_t , *Pdt_t; static Pdt_t PdtS_ = NULL; // memory for Cache access Gets static uint8_t *Strbuf_ = NULL; static Word_t Strsiz_ = 0; // Roundup BYTES to an even number of words /* On Linux 2.6.3-4mdkenterprise (Mandrake 10.0 Community) printing (even to a file) makes the timings inaccurate. So, use -L2 or greater to average (actually save min times) and print results after all tests are completed. */ #define Printf if (Pass == 0) printf #define ROUNDUPWORD(BYTES) (((BYTES) + sizeof(Word_t) - 1) & (-sizeof(Word_t))) #define BYTES2WORDS(BYTES) (((BYTES) + sizeof(Word_t) - 1) / (sizeof(Word_t))) //======================================================================= // T I M I N G M A C R O S //======================================================================= static double DeltaUSec; // Global for remembering delta times // Some operating systems have get_cycles() in /usr/include/asm/timex.h #ifdef CPUMHZ // For a 1.34 nS clock cycle processor (750Mhz) #define CPUSPEED (1.0 / (CPUMHZ)) #include #define TIMER_vars(T) cycles_t __TVBeg_##T #define STARTTm(T) __TVBeg_##T = get_cycles() #define ENDTm(D,T) { (D) = (double)(get_cycles() - __TVBeg_##T) * CPUSPEED; } #else // ! CPUMHZ #define TIMER_vars(T) struct timeval __TVBeg_##T, __TVEnd_##T #define STARTTm(T) gettimeofday(&__TVBeg_##T, NULL) #define ENDTm(D,T) \ { \ gettimeofday(&__TVEnd_##T, NULL); \ (D) = (double)(__TVEnd_##T.tv_sec - __TVBeg_##T.tv_sec) * 1E6 + \ ((double)(__TVEnd_##T.tv_usec - __TVBeg_##T.tv_usec)); \ } #endif // ! CPUMHZ //======================================================================= // M E M O R Y S I Z E M A C R O S //======================================================================= // use mallinfo() instead of sbrk() for memory usage measurements // this should include the RAM that was mmap()ed in malloc() static Word_t DeltaMem; // for remembering // Some mallocs have mallinfo() // #define MALLINFO 1 #ifdef MALLINFO #include // mallinfo() static struct mallinfo malStart; #define STARTmem malStart = mallinfo() #define ENDmem(DELTAMEM) \ { \ struct mallinfo malEnd = mallinfo(); \ /* strange little dance from signed to unsigned to double */ \ unsigned int _un_int = malEnd.arena - malStart.arena; \ (DELTAMEM) = (double)_un_int; /* to double */ \ } #else // NO MALLINFO // this usually works for machines with less than 1-2Gb RAM. // (it does NOT include memory ACQUIRED by mmap()) static char *malStart; #define STARTmem (malStart = (char *)sbrk(0)) #define ENDmem(DELTAMEM) \ { \ char *malEnd = (char *)sbrk(0); \ (DELTAMEM) = (double)(malEnd - malStart); \ } #endif // NO MALLINFO //======================================================================= // F I L E O P E N and M A L L O C F A I L M A C R O S //======================================================================= #define FILERROR \ { \ printf("\n !! OOps - Open file error \"%s\": %s (errno = %d)\n", \ argv[fileidx], strerror(errno), errno); \ fprintf(stderr, " OOps - Open file error \"%s\": %s (errno = %d)\n",\ argv[fileidx], strerror(errno), errno); \ exit(1); \ } #define MALLOCERROR \ { \ printf("\n !! OOps - malloc failed at Line = %d\n", __LINE__); \ fprintf(stderr, " OOps - malloc failed at Line = %d\n", __LINE__); \ exit(1); \ } //======================================================================= // This alternate form of JudyMalloc() is used to keep track how much ram is // used on some of the below ADT's //======================================================================= // JUDY INCLUDE FILES //#include "Judy.h" // **************************************************************************** // J U D Y M A L L O C // // Allocate RAM. This is the single location in Judy code that calls // malloc(3C). Note: JPM accounting occurs at a higher level. static Word_t TotalJudyMalloc = 0; Word_t JudyMalloc(Word_t Words) { Word_t Addr; Addr = (Word_t)malloc(Words * sizeof(Word_t)); if (Addr) TotalJudyMalloc += Words; return (Addr); } // JudyMalloc() // **************************************************************************** // J U D Y F R E E void JudyFree(void *PWord, Word_t Words) { free(PWord); assert((long)(TotalJudyMalloc - Words) >= 0L); TotalJudyMalloc -= Words; } // JudyFree() // **************************************************************************** // J U D Y M A L L O C // // Higher-level "wrapper" for allocating objects that need not be in RAM, // although at this time they are in fact only in RAM. Later we hope that some // entire subtrees (at a JPM or branch) can be "virtual", so their allocations // and frees should go through this level. Word_t JudyMallocVirtual(Word_t Words) { return (JudyMalloc(Words)); } // JudyMallocVirtual() // **************************************************************************** // J U D Y F R E E void JudyFreeVirtual(void *PWord, Word_t Words) { JudyFree(PWord, Words); } // JudyFreeVirtual() //======================================================================= // Routine to get next size of Indexes //======================================================================= static int NextNumb(Word_t *PNumber, // pointer to returned next number double *PDNumb, // Temp double of above double DMult, // Multiplier Word_t MaxNumb) // Max number to return { // Save prev number double PrevPDNumb = *PDNumb; double DDiff; // Calc next number >= 1.0 beyond previous do { *PDNumb *= DMult; DDiff = *PDNumb - PrevPDNumb; } while (DDiff < 0.5); // Return it in integer format if (DDiff < 100.0) *PNumber += (Word_t)(DDiff + 0.5); else *PNumber = (Word_t)(*PDNumb + 0.5); // Verify it did not exceed max number if (*PNumber >= MaxNumb) { *PNumber = MaxNumb; // it did, so return max return (1); // flag it } return (0); // more available } //======================================================================= // M E A S U R E M E N T S T R U C T U R E //======================================================================= typedef struct _MEASUREMENTS_STRUCT *Pms_t; typedef struct _MEASUREMENTS_STRUCT { Word_t ms_delta; // number of points in current group double ms_Bytes; // average allocated memory/per string double ms_mininsert; // Min Retrive number double ms_minretrive; // Min Retrive number } ms_t; static Pms_t Pms; // array of MEASUREMENTS_STRUCT // Method type typedef enum { M_invalid, M_Print, M_Hash, M_JLHash, M_JudySL, M_JudyHS, M_Splay, M_Redblack, M_Ternary } Method_t; //======================================================================= // R a n d o m i z e i n p u t s t r i n g s //======================================================================= static void Randomize(Pdt_t Pstrstr, Word_t Len) { Word_t ii; // swap the "random" index with the sequential one for (ii = 1; ii < Len; ii++) { dt_t dttemp; Word_t swapii; // get "random" index swapii = (Word_t)rand() % Len; // and swap dttemp = Pstrstr[ii]; Pstrstr[ii] = Pstrstr[swapii]; Pstrstr[swapii] = dttemp; } } //======================================================================= // B u i l d s e q u e n c i a l s t r i n g b u f f e r //======================================================================= Pdt_t BuildSeqBuf(Pdt_t Pstrstr, Word_t Len) { Word_t SumStrings = 0; Word_t ii; Word_t Strlen; uint8_t *string; assert(Len <= TValues); // calculate how much memory needed for strings for (ii = 0; ii < Len; ii++) { Strlen = Pstrstr[ii].dt_strlen; if (aFlag) SumStrings += ROUNDUPWORD(Strlen + 1); else SumStrings += Strlen + 1; } // check if old string buffer is big enough if (SumStrings > Strsiz_) { if (Strbuf_) free(Strbuf_); else SumStrings += SumStrings / 5; // bump 20% Strbuf_ = (uint8_t *) malloc(SumStrings); if (Strbuf_ == NULL) MALLOCERROR; Strsiz_ = SumStrings; } for (ii = 0, string = Strbuf_; ii < Len; ii++) { Strlen = Pstrstr[ii].dt_strlen; PdtS_[ii].dt_strlen = Strlen; PdtS_[ii].dt_string = string; memcpy(string, Pstrstr[ii].dt_string, Strlen + 1); if (aFlag) string += ROUNDUPWORD(Strlen + 1); else string += Strlen + 1; } return (PdtS_); } //======================================================================= // H A S H M E T H O D S T R U C T U R E S //======================================================================= // These structures are used in Hash() and JLHash() ADTs // for storing length of string // Hash chain structure (varible length depending on string) // static part of the length #define HSTRUCTOVD (sizeof(hrec_t) - sizeof(int)) typedef struct HASHREC_ *Phrec_t; typedef struct HASHREC_ { Phrec_t hr_Next; // collision chain link pointer Word_t hr_Value; // Data associated with string int hr_Strlen; // length of string 2 billion max uint8_t hr_String[sizeof(int)]; // string is allocated with struct } hrec_t; // hash head structure to keep hash array information typedef struct HASHINFO_ { Pvoid_t hi_Htbl; // Hash table Word_t hi_tblsize; // Hash table size (Words) Word_t hi_TotalWords; // Hash array total words Word_t hi_Pop1; // Hash array total population } hinfo_t, *Phinfo_t; // size in words of the header structure #define HASHHEADSZ (sizeof(hinfo_t) / sizeof(Word_t)) //======================================================================= // H A S H A L G O R I T H M //======================================================================= // // For CPUs with a slow mod (%) use table size a power of 2. A test is // made to see if the SIZE is a power of 2, and if so an .AND.(&) is used // instead of a .MOD.(%) to trim the hash return size. Note: a SIZE == 0, // results in no trimming of hash return size. #define HASHSTR(STRING,LENGTH,SIZE) \ ((SIZE) == ((SIZE) & -(SIZE))) ? \ (HashStr(STRING, LENGTH) & ((SIZE) -1)) : \ (HashStr(STRING, LENGTH) % (SIZE)) // String hash function. Hash string to a unsigned int (uint32_t) This // one needs a fast 32 bit mpy, which is often very slow on older(RISC) // machines. If you are sure you will not over populate the hash table, // then a poorer/faster hash algorithm should be used. Replace with your // own, milage may vary. This program measures the speed, whether used // or not. static uint32_t HashStr(void *Str, Word_t Len) { uint32_t A = 31415; uint32_t hashv = Len; uint8_t *k = (uint8_t *) Str; while (Len--) { hashv = (A * hashv) + *k++; A *= 27183; } return (hashv); } //======================================================================= // S T O R E and R E T R I V E R O U T I N E S //======================================================================= //======================================================================= // H A S H M E T H O D U S I N G J U D Y L A S H A S H T A B L E //======================================================================= PWord_t JLHashGet(Pvoid_t JLHash, uint8_t * String, Word_t Strlen) { Phinfo_t PHash = (Phinfo_t) JLHash; Phrec_t Phrec, *PPhrec; uint32_t hval; if (PHash == NULL) return (NULL); // get hash value, if mod(%) is slow (in some CPUs), make it a power of 2 hval = HASHSTR(String, Strlen, PHash->hi_tblsize); JLG(PPhrec, PHash->hi_Htbl, hval); // use JudyL to get &pointer if (PPhrec == NULL) return (NULL); // no table entry // search for matching string for (Phrec = *PPhrec; Phrec != NULL; Phrec = Phrec->hr_Next) { gChainln++; // Hash chain length if (Phrec->hr_Strlen == Strlen) // length match? { if (memcmp(Phrec->hr_String, String, Strlen) == 0) return (&(Phrec->hr_Value)); // match! pointer to Value } } return (NULL); } // Return pointer to struct hrec_t associated with string PWord_t JLHashIns(PPvoid_t PPHash, uint8_t * String, Word_t Strlen, Word_t TblSize) { Phrec_t Phrec, *PPhrec; Phinfo_t PHash; Word_t Len; uint32_t hval; PHash = (Phinfo_t) * PPHash; // core-dump if calling error if (PHash == NULL) // if hash table not allocated { // allocate the header PHash = (Phinfo_t) JudyMalloc(HASHHEADSZ); if (PHash == NULL) MALLOCERROR; // Initialize the header struct PHash->hi_tblsize = TblSize; PHash->hi_TotalWords = HASHHEADSZ; PHash->hi_Pop1 = 0; // none yet PHash->hi_Htbl = NULL; *PPHash = (Pvoid_t)PHash; // return header to caller } // get hash value, if mod(%) is slow (in some CPUs), make it a power of 2 hval = HASHSTR(String, Strlen, PHash->hi_tblsize); // get pointer to hash table entry JLI(PPhrec, PHash->hi_Htbl, hval); // JLI will exit if out of memory // search for matching string for (Phrec = *PPhrec; Phrec != NULL; Phrec = Phrec->hr_Next) { if (Phrec->hr_Strlen == Strlen) // string length match? { if (memcmp(Phrec->hr_String, String, Strlen) == 0) { return (&(Phrec->hr_Value)); // match! pointer to Value } } } // String match not found, so do an insert Len = BYTES2WORDS(Strlen + HSTRUCTOVD); Phrec = (Phrec_t) JudyMalloc(Len); // get memory for storing string if (Phrec == NULL) MALLOCERROR; PHash->hi_TotalWords += Len; // keep track of total mallocs Phrec->hr_Strlen = Strlen; // set string length memcpy(Phrec->hr_String, String, Strlen); Phrec->hr_Next = *PPhrec; // pointer to synonym *PPhrec = Phrec; // place new struct in front of list (PHash->hi_Pop1)++; // add one to population Phrec->hr_Value = (Word_t)0; // zero the associated Value return (&(Phrec->hr_Value)); // return pointer to Value } // Return 1 if successful, else 0 int JLHashDel(PPvoid_t PPHash, uint8_t * String, Word_t Strlen) { Phrec_t Phrec, *PPhrec, *PPhrec1; Phinfo_t PHash; uint32_t hval; // avoid an core dump here if (PPHash == NULL) return (0); PHash = (Phinfo_t) (*PPHash); // get header if (PHash == NULL) return (0); // not found // get hash value, if mod(%) is slow (in some CPUs), make it a power of 2 hval = HASHSTR(String, Strlen, PHash->hi_tblsize); // get pointer hash table entry JLG(PPhrec, PHash->hi_Htbl, hval); if (PPhrec == NULL) return (0); // hash entry not found PPhrec1 = PPhrec; // save head hash entry ^ // search for matching string for (Phrec = *PPhrec; Phrec != NULL; Phrec = Phrec->hr_Next) { if (Phrec->hr_Strlen == Strlen) // string length match? { if (memcmp(Phrec->hr_String, String, Strlen) == 0) // string match? { int Rc; // not used Word_t Len; *PPhrec = Phrec->hr_Next; // put next in previous Len = BYTES2WORDS(Strlen + HSTRUCTOVD); JudyFree(Phrec, Len); PHash->hi_TotalWords -= Len; // ram usage accounting (PHash->hi_Pop1)--; // Decrement population if (*PPhrec1 == NULL) // no chain left { // delete hash table entry JLD(Rc, PHash->hi_Htbl, hval); assert(Rc == 1); } // If last element, free everything if (PHash->hi_Pop1 == 0) { assert(PHash->hi_TotalWords == HASHHEADSZ); JudyFree(PHash, HASHHEADSZ); // the header table *PPHash = NULL; // from caller } return (1); // successful } } PPhrec = &(Phrec->hr_Next); // previous = current } return (0); // string not found } // Free the whole JLHash structure Word_t JLHashFreeArray(PPvoid_t PPHash) { Phrec_t Phrec, *PPhrec; Phinfo_t PHash; Word_t DeletedWords, Bytes; Word_t Index = 0; // for First, Next loop // avoid an core dump here if (PPHash == NULL) return ((Word_t)0); PHash = (Phinfo_t) (*PPHash); // get header if (PHash == NULL) return ((Word_t)0); // not found // get bytes of memory usage in (JudyL) Hash table JLMU(Bytes, PHash->hi_Htbl); DeletedWords = HASHHEADSZ; // start with header // Get 1st table entry in Hash table JLF(PPhrec, PHash->hi_Htbl, Index); // found an entry in hash table? while (PPhrec != NULL) { int Rc; // not used Phrec = *PPhrec; // walk the synonym linked list while (Phrec != NULL) { Word_t Len; Phrec_t Phrecfree = Phrec; // number of words to free -- struct hrec_t Len = BYTES2WORDS(Phrec->hr_Strlen + HSTRUCTOVD); // sum total length of mallocs in words DeletedWords += Len; (PHash->hi_Pop1)--; // Decrement population // get pointer to next synonym on list Phrec = Phrec->hr_Next; // free the struct hrec_t JudyFree(Phrecfree, Len); } // delete hash table entry JLD(Rc, PHash->hi_Htbl, Index); assert(Rc == 1); // get next hash table entry JLN(PPhrec, PHash->hi_Htbl, Index); } assert(PHash->hi_TotalWords == DeletedWords); assert(PHash->hi_Pop1 == 0); JudyFree(PHash, HASHHEADSZ); // the header table *PPHash = NULL; // set pointer null // return total bytes freed return ((DeletedWords * sizeof(Word_t)) + Bytes); } //======================================================================= // H A S H M E T H O D //======================================================================= PWord_t HashGet(Phinfo_t PHash, uint8_t * String, Word_t Strlen) { Phrec_t Phrec, *Htbl; uint32_t hval; // avoid an core dump here if (PHash == NULL) return (NULL); // get hash value, if mod(%) is slow (in some CPUs), make it a power of 2 hval = HASHSTR(String, Strlen, PHash->hi_tblsize); // type Hash table pointer Htbl = (Phrec_t *) PHash->hi_Htbl; // search for matching string for (Phrec = Htbl[hval]; Phrec != NULL; Phrec = Phrec->hr_Next) { gChainln++; // Hash chain length if (Phrec->hr_Strlen == Strlen) // length match? { if (memcmp(Phrec->hr_String, String, Strlen) == 0) return (&(Phrec->hr_Value)); // match! pointer to Value } } return (NULL); } // Return pointer to struct hrec_t associated with string Pvoid_t HashIns(Phinfo_t * PPHash, uint8_t * String, Word_t Strlen, Word_t TblSize) { Phrec_t Phrec, *Htbl; Phinfo_t PHash; Word_t Len; uint32_t hval; PHash = *PPHash; // core-dump if calling error if (PHash == NULL) // if hash table not allocated { // allocate the header PHash = (Phinfo_t) JudyMalloc(HASHHEADSZ); if (PHash == NULL) MALLOCERROR; // allocate the hash table PHash->hi_Htbl = (Pvoid_t)JudyMalloc(TblSize); if (PHash->hi_Htbl == NULL) MALLOCERROR; // you cant beat this with modern compilers/librarys memset(PHash->hi_Htbl, 0, TblSize * sizeof(Word_t)); // Initialize the header struct PHash->hi_tblsize = TblSize; PHash->hi_TotalWords = TblSize + HASHHEADSZ; PHash->hi_Pop1 = 0; // none yet *PPHash = PHash; // return header to caller } // get hash value, if mod(%) is slow (in some CPUs), make it a power of 2 hval = HASHSTR(String, Strlen, TblSize); // type Hash table pointer Htbl = (Phrec_t *) PHash->hi_Htbl; // search for matching string in hash table entry for (Phrec = Htbl[hval]; Phrec != NULL; Phrec = Phrec->hr_Next) { if (Phrec->hr_Strlen == Strlen) // string length match? { if (memcmp(Phrec->hr_String, String, Strlen) == 0) // string match? { return (&(Phrec->hr_Value)); // match! pointer to Value } } } // string not found, so do an insert Len = BYTES2WORDS(Strlen + HSTRUCTOVD); Phrec = (Phrec_t) JudyMalloc(Len); if (Phrec == NULL) MALLOCERROR; PHash->hi_TotalWords += Len; // keep track of total mallocs Phrec->hr_Strlen = Strlen; // set string length memcpy(Phrec->hr_String, String, Strlen); // copy it // place new allocation first in chain Phrec->hr_Next = Htbl[hval]; Htbl[hval] = Phrec; (PHash->hi_Pop1)++; // add one to population Phrec->hr_Value = (Word_t)0; // zero the associated Value return (&(Phrec->hr_Value)); // return pointer to Value } // Delete entry in hash array, return 1 if successful, else 0 int HashDel(Phinfo_t * PPHash, uint8_t * String, Word_t Strlen) { Phrec_t Phrec, *PPhrec, *Htbl; Phinfo_t PHash; uint32_t hval; // avoid an core dump here if (PPHash == NULL) return (0); PHash = *PPHash; // get header if (PHash == NULL) return (0); // not found // get hash value, if mod(%) is slow (in some CPUs), make it a power of 2 hval = HASHSTR(String, Strlen, PHash->hi_tblsize); // type Hash table pointer Htbl = (Phrec_t *) PHash->hi_Htbl; // get pointer hash table entry PPhrec = &Htbl[hval]; // search for matching string for (Phrec = *PPhrec; Phrec != NULL; Phrec = Phrec->hr_Next) { if (Phrec->hr_Strlen == Strlen) // length match? { if (memcmp(Phrec->hr_String, String, Strlen) == 0) { Word_t Len; // put next hrec_t in previous hrec_t *PPhrec = Phrec->hr_Next; Len = BYTES2WORDS(Strlen + HSTRUCTOVD); JudyFree(Phrec, Len); PHash->hi_TotalWords -= Len; (PHash->hi_Pop1)--; // Decrement population // If last element, free everything if (PHash->hi_Pop1 == 0) { assert(PHash->hi_TotalWords == (HASHHEADSZ + PHash->hi_tblsize)); JudyFree(Htbl, PHash->hi_tblsize); // hash table JudyFree(PHash, HASHHEADSZ); // header struct *PPHash = NULL; // from caller } return (1); // successful } } PPhrec = &(Phrec->hr_Next); // previous = current } return (0); // not found } Word_t HashFreeArray(Phinfo_t * PPHash) { int ii; Phrec_t Phrec, *Htbl; Phinfo_t PHash; Word_t DeletedWords; // avoid an core dump here if (PPHash == NULL) return ((Word_t)0); PHash = (Phinfo_t) (*PPHash); // get header if (PHash == NULL) return ((Word_t)0); // start accumulator of deleted memory DeletedWords = HASHHEADSZ + PHash->hi_tblsize; // type Hash table pointer Htbl = (Phrec_t *) PHash->hi_Htbl; // walk thru all table entrys for (ii = 0; ii < PHash->hi_tblsize; ii++) { Phrec = Htbl[ii]; // next hash table entry while (Phrec != NULL) // walk the synonym linked list { Word_t Len; Phrec_t Phrecfree; // get pointer to next synonym on list Phrecfree = Phrec; Phrec = Phrec->hr_Next; (PHash->hi_Pop1)--; // Decrement population // number of words to free -- struct hrec_t Len = BYTES2WORDS(Phrecfree->hr_Strlen + HSTRUCTOVD); DeletedWords += Len; // sum words freed // free the struct hrec_t JudyFree(Phrecfree, Len); } } // and free the hash table JudyFree(Htbl, PHash->hi_tblsize); assert(PHash->hi_TotalWords == DeletedWords); assert(PHash->hi_Pop1 == 0); JudyFree(PHash, HASHHEADSZ); // the header table *PPHash = NULL; // set pointer null // return total bytes freed return (DeletedWords * sizeof(Word_t)); } //======================================================================= // S P L A Y M E T H O D //======================================================================= /* Author J. Zobel, April 2001. Permission to use this code is freely granted, provided that this statement is retained. */ #define ROTATEFAC 11 typedef struct spwordrec { char *word; struct spwordrec *left, *right; struct spwordrec *par; } SPTREEREC; typedef struct spansrec { struct spwordrec *root; struct spwordrec *ans; } SPANSREC; SPANSREC spans = { 0 }; #define ONELEVEL(PAR,CURR,DIR,RID) \ { \ PAR->DIR = CURR->RID; \ if(PAR->DIR!=NULL) \ PAR->DIR->PAR = PAR; \ CURR->RID = PAR; \ PAR->PAR = CURR; \ CURR->PAR = NULL; \ } #define ZIGZIG(GPAR,PAR,CURR,DIR,RID) \ { \ CURR->PAR = GPAR->PAR; \ if (CURR->PAR != NULL) \ { \ if (CURR->PAR->DIR == GPAR) \ CURR->PAR->DIR = CURR; \ else \ CURR->PAR->RID = CURR; \ } \ GPAR->DIR = PAR->RID; \ if (GPAR->DIR != NULL) \ GPAR->DIR->PAR = GPAR; \ PAR->DIR = CURR->RID; \ if (CURR->RID != NULL) \ CURR->RID->PAR = PAR; \ CURR->RID = PAR; \ PAR->PAR = CURR; \ PAR->RID = GPAR; \ GPAR->PAR = PAR; \ } #define ZIGZAG(GPAR,PAR,CURR,DIR,RID) \ { \ CURR->PAR = GPAR->PAR; \ if (CURR->PAR != NULL) \ { \ if (CURR->PAR->DIR == GPAR) \ CURR->PAR->DIR = CURR; \ else \ CURR->PAR->RID = CURR; \ } \ PAR->RID = CURR->DIR; \ if (PAR->RID != NULL) \ PAR->RID->PAR = PAR; \ GPAR->DIR = CURR->RID; \ if (GPAR->DIR != NULL) \ GPAR->DIR->PAR = GPAR; \ CURR->DIR = PAR; \ PAR->PAR = CURR; \ CURR->RID = GPAR; \ GPAR->PAR = CURR; \ } int scount = ROTATEFAC; /* Create a node to hold a word */ static SPTREEREC * spwcreate(char *word, SPTREEREC * par) { SPTREEREC *tmp; tmp = (SPTREEREC *) malloc(sizeof(SPTREEREC)); tmp->word = (char *)malloc(strlen(word) + 1); strcpy(tmp->word, word); tmp->left = tmp->right = NULL; tmp->par = par; gStored++; // count stored return (tmp); } /* Search for word in a splay tree. If word is found, bring it to root, possibly intermittently. Structure ans is used to pass in the root, and to pass back both the new root (which may or may not be changed) and the looked-for record. */ static void splaysearch(SPANSREC * ans, char *word) { SPTREEREC *curr = ans->root, *par, *gpar; int val; scount--; if (ans->root == NULL) { ans->ans = NULL; return; } while (curr != NULL && (val = strcmp(word, curr->word)) != 0) { if (val > 0) curr = curr->right; else curr = curr->left; } ans->ans = curr; if (curr == ans->root) { return; } if (scount <= 0 && curr != NULL) /* Move node towards root */ { scount = ROTATEFAC; while ((par = curr->par) != NULL) { if (par->left == curr) { if ((gpar = par->par) == NULL) { ONELEVEL(par, curr, left, right); } else if (gpar->left == par) { ZIGZIG(gpar, par, curr, left, right); } else { ZIGZAG(gpar, par, curr, right, left); } } else { if ((gpar = par->par) == NULL) { ONELEVEL(par, curr, right, left); } else if (gpar->left == par) { ZIGZAG(gpar, par, curr, left, right); } else { ZIGZIG(gpar, par, curr, right, left); } } } ans->root = curr; } return; } /* Insert word into a splay tree. If word is already present, bring it to root, possibly intermittently. Structure ans is used to pass in the root, and to pass back both the new root (which may or may not be changed) and the looked-for record. */ static void splayinsert(SPANSREC * ans, char *word) { SPTREEREC *curr = ans->root, *par, *gpar, *prev = NULL, *spwcreate(); int val = 0; scount--; if (ans->root == NULL) { ans->ans = ans->root = spwcreate(word, NULL); return; } while (curr != NULL && (val = strcmp(word, curr->word)) != 0) { prev = curr; if (val > 0) curr = curr->right; else curr = curr->left; } if (curr == NULL) { if (val > 0) curr = prev->right = spwcreate(word, prev); else curr = prev->left = spwcreate(word, prev); } ans->ans = curr; if (scount <= 0) /* Move node towards root */ { scount = ROTATEFAC; while ((par = curr->par) != NULL) { if (par->left == curr) { if ((gpar = par->par) == NULL) { ONELEVEL(par, curr, left, right); } else if (gpar->left == par) { ZIGZIG(gpar, par, curr, left, right); } else { ZIGZAG(gpar, par, curr, right, left); } } else { if ((gpar = par->par) == NULL) { ONELEVEL(par, curr, right, left); } else if (gpar->left == par) { ZIGZAG(gpar, par, curr, left, right); } else { ZIGZIG(gpar, par, curr, right, left); } } } ans->root = curr; } return; } //======================================================================= // R E D B L A C K M E T H O D //======================================================================= /* Author J. Zobel, April 2001. Permission to use this code is freely granted, provided that this statement is retained. */ typedef struct rbwordrec { char *word; struct rbwordrec *left, *right; struct rbwordrec *par; char colour; } RBTREEREC; typedef struct rbansrec { struct rbwordrec *root; struct rbwordrec *ans; } BRANSREC; BRANSREC rbans = { 0 }; #define RED 0 #define BLACK 1 /* Find word in a redblack tree */ static void redblacksearch(BRANSREC * ans, char *word) { RBTREEREC *curr = ans->root; int val; if (ans->root != NULL) { while (curr != NULL && (val = strcmp(word, curr->word)) != 0) { if (val > 0) curr = curr->right; else curr = curr->left; } } ans->ans = curr; return; } /* Rotate the right child of par upwards */ /* Could be written as a macro, but not really necessary as it is only called on insertion */ void leftrotate(BRANSREC * ans, RBTREEREC * par) { RBTREEREC *curr, *gpar; if ((curr = par->right) != NULL) { par->right = curr->left; if (curr->left != NULL) curr->left->par = par; curr->par = par->par; if ((gpar = par->par) == NULL) ans->root = curr; else { if (par == gpar->left) gpar->left = curr; else gpar->right = curr; } curr->left = par; par->par = curr; } } /* Rotate the left child of par upwards */ void rightrotate(BRANSREC * ans, RBTREEREC * par) { RBTREEREC *curr, *gpar; if ((curr = par->left) != NULL) { par->left = curr->right; if (curr->right != NULL) curr->right->par = par; curr->par = par->par; if ((gpar = par->par) == NULL) ans->root = curr; else { if (par == gpar->left) gpar->left = curr; else gpar->right = curr; } curr->right = par; par->par = curr; } } /* Create a node to hold a word */ RBTREEREC * rbwcreate(char *word, RBTREEREC * par) { RBTREEREC *tmp; tmp = (RBTREEREC *) malloc(sizeof(RBTREEREC)); tmp->word = (char *)malloc(strlen(word) + 1); strcpy(tmp->word, word); tmp->left = tmp->right = NULL; tmp->par = par; gStored++; // count stored return (tmp); } /* Insert word into a redblack tree */ void redblackinsert(BRANSREC * ans, char *word) { RBTREEREC *curr = ans->root, *par, *gpar, *prev = NULL, *rbwcreate(); int val = 0; if (ans->root == NULL) { ans->ans = ans->root = rbwcreate(word, NULL); return; } while (curr != NULL && (val = strcmp(word, curr->word)) != 0) { prev = curr; if (val > 0) curr = curr->right; else curr = curr->left; } ans->ans = curr; if (curr == NULL) /* Insert a new node, rotate up if necessary */ { if (val > 0) curr = prev->right = rbwcreate(word, prev); else curr = prev->left = rbwcreate(word, prev); curr->colour = RED; while ((par = curr->par) != NULL && (gpar = par->par) != NULL && curr->par->colour == RED) { if (par == gpar->left) { if (gpar->right != NULL && gpar->right->colour == RED) { par->colour = BLACK; gpar->right->colour = BLACK; gpar->colour = RED; curr = gpar; } else { if (curr == par->right) { curr = par; leftrotate(ans, curr); par = curr->par; } par->colour = BLACK; if ((gpar = par->par) != NULL) { gpar->colour = RED; rightrotate(ans, gpar); } } } else { if (gpar->left != NULL && gpar->left->colour == RED) { par->colour = BLACK; gpar->left->colour = BLACK; gpar->colour = RED; curr = gpar; } else { if (curr == par->left) { curr = par; rightrotate(ans, curr); par = curr->par; } par->colour = BLACK; if ((gpar = par->par) != NULL) { gpar->colour = RED; leftrotate(ans, gpar); } } } } if (curr->par == NULL) ans->root = curr; ans->root->colour = BLACK; } return; } //======================================================================= // T E R N A R Y M E T H O D //======================================================================= typedef struct tnode *Tptr; typedef struct tnode { uint8_t splitchar; Tptr lokid, eqkid, hikid; } Tnode; void TernaryIns(Tptr * p, uint8_t * s, int Len) { int d; uint8_t *instr = s; Tptr pp; while ((pp = *p) != NULL) { if ((d = *s - pp->splitchar) == 0) { if (*s++ == 0) { printf("Oops duplicate Ternary string %s\n", instr); return; } p = &(pp->eqkid); } else if (d < 0) p = &(pp->lokid); else p = &(pp->hikid); } for (;;) { *p = (Tptr) malloc(sizeof(Tnode)); pp = *p; pp->splitchar = *s; pp->lokid = pp->eqkid = pp->hikid = 0; if (*s++ == 0) { pp->eqkid = (Tptr) instr; gStored++; // number of strings stored return; } p = &(pp->eqkid); } } int TernaryGet(Tptr p, uint8_t * s, int Len) { while (p) { if (*s < p->splitchar) p = p->lokid; else if (*s == p->splitchar) { if (*s++ == 0) return 1; p = p->eqkid; } else p = p->hikid; } return 0; } //======================================================================= // M E A S U R E A D T S P E E D and M E M O R Y U S A G E //======================================================================= //Word_t TotalJudyMalloc; #define GETSTRING(PCurStr, Strlen) int main(int argc, char *argv[]) { TIMER_vars(tm); // declare timer variables FILE *fid; // to read file. int Chr; // char read from fgetc Pdt_t Pdt, Pdts; // array of lengths and pointers to str uint8_t *PCurStr; // Current string pointer Word_t LineCnt; // line counter int Strlen; // = strlen(); Word_t StrTot; // Total len of strings Word_t StrNumb; // current line number Word_t ReadLin; // strings to read double Mult; // multiplier between groups Word_t Groups; // number of measurement groups Word_t grp; // current group Pvoid_t JudySL = NULL; // JudySL root pointer Pvoid_t JudyHS = NULL; // JudyHS root pointer Pvoid_t JLHash = NULL; // JLHash root pointer Phinfo_t HRoot = NULL; // hash table root pointer Tptr Ternary = { 0 }; // Ternary struct root pointer Method_t Method = M_invalid; // the method to measure Word_t lines = 0; // to shut up compiler Word_t Bytes = 0; // Bytes deallocated from FreeArray Word_t StringMemory; // Bytes allocated for input data int Pass; int Passes = 1; int Opt; extern char *optarg; int ErrorFlag = 0; // un-buffer output setbuf(stdout, NULL); //============================================================ // PARSE INPUT PARAMETERS //============================================================ while ((Opt = getopt(argc, argv, "A:H:L:n:T:P:M:praDC")) != -1) { switch (Opt) { case 'A': if (Method != M_invalid) { printf("\nOnly ONE '-A' is allowed!!!!!!\n"); ErrorFlag++; break; } if (strcmp(optarg, "Print") == 0) Method = M_Print; if (strcmp(optarg, "Hash") == 0) { Method = M_Hash; HTblsz = 1LU << 20; // default 1.0+ million } if (strcmp(optarg, "JLHash") == 0) { Method = M_JLHash; HTblsz = 0; // max 2^32 } if (strcmp(optarg, "JudySL") == 0) Method = M_JudySL; if (strcmp(optarg, "Splay") == 0) Method = M_Splay; if (strcmp(optarg, "Redblack") == 0) Method = M_Redblack; if (strcmp(optarg, "JudyHS") == 0) Method = M_JudyHS; if (strcmp(optarg, "Ternary") == 0) Method = M_Ternary; break; case 'H': // Size of Hash table HTblsz = strtoul(optarg, NULL, 0); break; case 'L': // Number of Loops Passes = atoi(optarg); if (Passes <= 0) { printf("\n !! OOps - Number of Loops must be > 0\n"); ErrorFlag++; } break; case 'n': // Max population of arrays nStrg = strtoul(optarg, NULL, 0); // Size of Linear Array if (nStrg == 0) { printf("\n !! OOps - Number of strings must be > 0\n"); ErrorFlag++; } break; case 'T': // Maximum retrieve tests for timing TValues = strtoul(optarg, NULL, 0); break; case 'P': // measurement points per decade PtsPdec = strtoul(optarg, NULL, 0); break; case 'M': // maximum length of input string MLength = atoi(optarg); break; case 'p': // pre-initialize Hash table pFlag = 1; break; case 'r': // do not randomize input if (CFlag) { printf ("\n !! OOps '-r' and '-C' flag are mutually exclusive\n"); ErrorFlag++; break; } rFlag = 1; break; case 'a': // word align string buffers aFlag = 1; break; case 'D': // do a delete at end DFlag = 1; break; case 'C': // build sequential Get string buffers if (rFlag) { printf ("\n !! OOps '-C' and '-r' flag are mutually exclusive\n"); ErrorFlag++; break; } CFlag = 1; break; default: ErrorFlag++; break; } } if (Method == -1) { printf ("\n !! OOps -- '-A ' I.E. '-AHash' or '-AJudyHS' is a required option\n"); ErrorFlag++; } fileidx = optind; if (optind >= argc) { printf("\n !! OOps -- No input file specified\n"); ErrorFlag++; } if (ErrorFlag) { printf("\n"); printf("$ %s -A -n# -H# -P# -T# -p -r -a InputStringFile\n\n", argv[0]); printf("Where: "); printf("'InputStringFile' is text file of strings to use in test\n\n"); printf ("-A is Hash|JLHash|JudySL|JudyHS|Splay|Redblack|Ternary|Print\n"); printf("\n"); printf("-n <#> max number of strings to use in tests (all)\n"); printf("-H <#> is number elements in Hash table\n"); printf("-P <#> number of measurement points per decade (40)\n"); printf ("-T <#> Change the 'Get' number_of_strings to measure per data point\n"); printf("-D Use 'Delete' routine instead of 'FreeArray' routine\n"); printf("-p pre-zero hash table to fault in all pages\n"); printf("-r Do not randomize Insert and Get order of strings\n"); printf("-C Build contigious string buffers for 'Get' tests\n"); printf("-a Word_t align the start address of input strings\n"); printf("-M <#> Change the maximum 'strlen(String)' of input Strings\n"); printf("\n\n"); exit(1); } // calculate max number mask used in hash routine //============================================================ // PRINT COMMAND NAME + RUN ARGUMENTS //============================================================ printf("# %s", argv[0]); if (nStrg != INFSTRGS) printf(" -n%lu", nStrg); switch (Method) { case M_Hash: printf(" -A Hash"); break; case M_JLHash: printf(" -A JLHash"); break; case M_JudySL: printf(" -A JudySL"); break; case M_JudyHS: printf(" -A JudyHS"); break; case M_Splay: printf(" -A Splay"); break; case M_Redblack: printf(" -A Redblack"); break; case M_Ternary: printf(" -A Ternary"); break; default: break; } if (HTblsz) printf(" -H%lu", HTblsz); printf(" -P%lu", PtsPdec); printf(" -L%d", Passes); if (pFlag) printf(" -p"); if (rFlag) printf(" -r"); if (DFlag) printf(" -D"); if (CFlag) printf(" -C"); printf(" -M%d", MLength); printf(" %s", argv[fileidx]); printf("\n"); // print some header printf("# This file is in a format to input to 'jbgraph'\n"); printf("# XLABEL Stored\n"); printf("# YLABEL Microseconds / Index\n"); printf("# COLHEAD 1 Total Insert attempts\n"); printf("# COLHEAD 2 Number Gets\n"); printf("# COLHEAD 3 Duplicate strings\n"); printf("# COLHEAD 4 Insert Time (uS)\n"); printf("# COLHEAD 5 Get Time (uS)\n"); printf("# COLHEAD 6 Hash Chain Length\n"); printf("# COLHEAD 7 Average RAM/String\n"); // uname(2) strings describing the machine { struct utsname ubuf; // for system name if (uname(&ubuf) == -1) printf("# Uname(2) failed\n"); else printf("# %s %s %s %s %s\n", ubuf.sysname, ubuf.nodename, ubuf.release, ubuf.version, ubuf.machine); } if (sizeof(Word_t) == 8) printf("# 64 Bit CPU\n"); else if (sizeof(Word_t) == 4) printf("# 32 Bit CPU\n"); #ifdef CPUMHZ printf("# Processor speed compiled at %d Mhz\n", CPUMHZ); #endif // CPUMHZ if (Method == M_Hash) printf("# Hash record struct: sizeof(hrec_t) = %d\n", sizeof(hrec_t)); if (Method == M_Ternary) printf("# Ternary record struct: sizeof(Tnode) = %d\n", sizeof(Tnode)); // OPEN INPUT FILE: if ((fid = fopen(argv[fileidx], "r")) == NULL) FILERROR; for (StrTot = Strlen = LineCnt = 0; (Chr = fgetc(fid)) != EOF;) { if (Chr == '\n') { if (Strlen) // eat zero length lines { if (Strlen > MLength) Strlen = MLength; LineCnt++; // increase string count Strlen++; // add a \0 for JudySL if (aFlag) // for word alignment StrTot += ROUNDUPWORD(Strlen); else StrTot += Strlen; // memory needed to store strings if (LineCnt == nStrg) // shorten if required by -n option break; Strlen = 0; } } else { Strlen++; } } fclose(fid); fid = NULL; nStrg = LineCnt; // adj if necessary // get struct to keep track of the strings StringMemory = sizeof(dt_t) * nStrg; Pdt = (Pdt_t) malloc(sizeof(dt_t) * nStrg); if (Pdt == NULL) MALLOCERROR; // get memory to store the strings StringMemory += StrTot; PCurStr = (uint8_t *) malloc(StrTot); if (PCurStr == NULL) MALLOCERROR; // BRING FILE INTO RAM, COUNT LINES and CHECK LENGTH //============================================================ // CALCULATE NUMBER OF MEASUREMENT GROUPS -- points per decade //============================================================ // Calculate Multiplier for number of points per decade Mult = pow(10.0, 1.0 / (double)PtsPdec); { double sum; Word_t numb, prevnumb; // Count number of measurements needed (10K max) sum = numb = 1; for (Groups = 2; Groups < 10000; Groups++) if (NextNumb(&numb, &sum, Mult, nStrg)) break; // Get memory for measurements Pms = (Pms_t) calloc(Groups, sizeof(ms_t)); if (Pms == NULL) MALLOCERROR; // Now calculate number of Indexes for each measurement point numb = sum = 1; prevnumb = 0; for (grp = 0; grp < Groups; grp++) { Pms[grp].ms_delta = numb - prevnumb; Pms[grp].ms_mininsert = 10000000.0; // infinity Pms[grp].ms_minretrive = 10000000.0; // infinity Pms[grp].ms_Bytes = 0.0; prevnumb = numb; NextNumb(&numb, &sum, Mult, nStrg); } } // Groups = number of sizes // print remaining header if (Method == M_Hash) { printf("# Allocate Hash table = %lu elements\n", HTblsz); } if (Method == M_JLHash) { if (HTblsz) printf("# JLHash table virtual size = %lu\n", HTblsz); else printf("# JLHash table virtual size = 4294967296\n"); } //======================================================================= // Read text input file into RAM //======================================================================= if ((fid = fopen(argv[fileidx], "r")) == NULL) FILERROR; for (Strlen = LineCnt = 0; LineCnt < nStrg;) { Chr = fgetc(fid); if (Chr == '\n') { if (Strlen) // eat zero length lines { if (Strlen > MLength) Strlen = MLength; Pdt[LineCnt].dt_string = PCurStr - Strlen; Pdt[LineCnt].dt_strlen = Strlen; LineCnt++; Strlen = 0; *PCurStr++ = '\0'; // for JudySL if (aFlag) // for word alignment PCurStr = (uint8_t *) ROUNDUPWORD((Word_t)PCurStr); if ((Word_t)PCurStr % sizeof(Word_t)) aCount++; } } else { if (Strlen < MLength) { Strlen++; if (Chr == '\0') Chr = ' '; // for JudySL *PCurStr++ = (uint8_t) Chr; } } } fclose(fid); fid = NULL; assert(nStrg == LineCnt); printf("# %lu (%.1f%%) non-Word_t aligned string buffers\n", aCount, (double)aCount / (double)LineCnt * 100.0); printf("# Ram used for input data = %lu bytes\n", StringMemory); printf("# Average string length = %.1f bytes\n", (double)(StrTot - LineCnt) / LineCnt); // Allocate memory for Cached assess to 'Get' (largest delta). This flag // will put the 'randomized' 'Get' order strings in a sequential buffer. // Modern processors will 'read ahead' with an access to RAM is sequential // -- thus saving the 'Get' having to bring the string into cache. if (CFlag) { PdtS_ = (Pdt_t) malloc(TValues * sizeof(dt_t)); if (PdtS_ == NULL) MALLOCERROR; // now guess how much memory will be needed for the strings Strsiz_ = ((StrTot / nStrg) * TValues); Strsiz_ += Strsiz_; // bump %20 Strbuf_ = (uint8_t *) malloc(Strsiz_); if (Strbuf_ == NULL) MALLOCERROR; printf ("# %lu bytes malloc() for 'cached' strings for Get measurement\n", Strsiz_); } //======================================================================= // TIME GETSTRING() from Cache (most of the time) //======================================================================= STARTTm(tm); // start timer for (LineCnt = 0; LineCnt < nStrg; LineCnt++) { GETSTRING(PCurStr, Strlen); Strlen = Pdt[LineCnt].dt_strlen; PCurStr = Pdt[LineCnt].dt_string; if (strlen(PCurStr) != Strlen) // bring string into Cache { // necessary to prevent cc from optimizing out printf(" !! OOps Bug, wrong string length\n"); exit(1); } } ENDTm(DeltaUSec, tm); // end timer printf ("# Access Time = %6.3f uS average per string (mostly from Cache)\n", DeltaUSec / nStrg); //======================================================================= // TIME GETSTRING() + HASHSTR() from Cache (most of the time) //======================================================================= STARTTm(tm); // start timer for (LineCnt = 0; LineCnt < nStrg; LineCnt++) { uint32_t hval; GETSTRING(PCurStr, Strlen); PCurStr = Pdt[LineCnt].dt_string; Strlen = Pdt[LineCnt].dt_strlen; hval = HASHSTR(PCurStr, Strlen, HTblsz); if (foolflag) printf("OOps foolflag is set, hval = %d\n", hval); } ENDTm(DeltaUSec, tm); // end timer printf ("# HashStr() Time = %6.3f uS average per string (mostly from Cache)\n", DeltaUSec / nStrg); // randomize the input strings (adjacent strings will not be on same page) if (rFlag == 0) { Randomize(Pdt, nStrg); // Randomize ALL to be stored //======================================================================= // TIME GETSTRING() from RAM (most of the time) //======================================================================= STARTTm(tm); // start timer for (LineCnt = 0; LineCnt < nStrg; LineCnt++) { GETSTRING(PCurStr, Strlen); Strlen = Pdt[LineCnt].dt_strlen; PCurStr = Pdt[LineCnt].dt_string; if (strlen(PCurStr) != Strlen) // bring string into Cache { // necessary to prevent cc from optimizing out printf(" !! OOps Bug, wrong string length\n"); exit(1); } } ENDTm(DeltaUSec, tm); // end timer printf ("# Access Time = %6.3f uS average per string (mostly from RAM)\n", DeltaUSec / nStrg); //======================================================================= // TIME GETSTRING() + HASHSTR() from RAM (most of the time) //======================================================================= STARTTm(tm); // start timer for (LineCnt = 0; LineCnt < nStrg; LineCnt++) { uint32_t hval; GETSTRING(PCurStr, Strlen); Strlen = Pdt[LineCnt].dt_strlen; PCurStr = Pdt[LineCnt].dt_string; hval = HASHSTR(PCurStr, Strlen, HTblsz); if (foolflag) printf("OOps foolflag is set, hval = %u\n", hval); } ENDTm(DeltaUSec, tm); // end timer printf ("# HashStr() Time = %6.3f uS average per string (mostly from RAM)\n", DeltaUSec / nStrg); } //======================================================================= // Insert, Get and Delete loops //======================================================================= for (Pass = 0; Pass < Passes; Pass++) { printf("# Pass %d\n", Pass); // heading of table Printf ("# TotInserts DeltaGets DupStrs InsTime GetTime HChainLen Ram/String\n"); gStored = 0; // number of strings inserted StrNumb = 0; // number of attempted strings inserted STARTmem; // current malloc() mem usage for (grp = 0; grp < Groups; grp++) { PWord_t PValue; Word_t Begin = gStored; // remember current STOREed Word_t Delta = Pms[grp].ms_delta; switch (Method) { case M_Print: { STARTTm(tm); // start timer for (lines = 0; lines < Delta; lines++, StrNumb++) { GETSTRING(PCurStr, Strlen); PCurStr = Pdt[StrNumb].dt_string; Printf("%s\n", (char *)PCurStr); } ENDTm(DeltaUSec, tm); // end timer break; } case M_Hash: { STARTTm(tm); // start timer for (lines = 0; lines < Delta; lines++, StrNumb++) { GETSTRING(PCurStr, Strlen); Strlen = Pdt[StrNumb].dt_strlen; PCurStr = Pdt[StrNumb].dt_string; PValue = HashIns(&HRoot, PCurStr, Strlen, HTblsz); if ((*PValue)++ == 0) gStored++; // number of strings stored } ENDTm(DeltaUSec, tm); // end timer break; } case M_JLHash: { STARTTm(tm); // start timer for (lines = 0; lines < Delta; lines++, StrNumb++) { GETSTRING(PCurStr, Strlen); Strlen = Pdt[StrNumb].dt_strlen; PCurStr = Pdt[StrNumb].dt_string; PValue = JLHashIns(&JLHash, PCurStr, Strlen, HTblsz); if ((*PValue)++ == 0) gStored++; // number of strings stored } ENDTm(DeltaUSec, tm); // end timer break; } case M_JudySL: { STARTTm(tm); // start timer for (lines = 0; lines < Delta; lines++, StrNumb++) { GETSTRING(PCurStr, Strlen); PCurStr = Pdt[StrNumb].dt_string; JSLI(PValue, JudySL, PCurStr); // insert string if ((*PValue)++ == 0) gStored++; // number of strings stored } ENDTm(DeltaUSec, tm); // end timer break; } case M_JudyHS: { STARTTm(tm); // start timer for (lines = 0; lines < Delta; lines++, StrNumb++) { GETSTRING(PCurStr, Strlen); Strlen = Pdt[StrNumb].dt_strlen; PCurStr = Pdt[StrNumb].dt_string; JHSI(PValue, JudyHS, PCurStr, Strlen); // insert string if ((*PValue)++ == 0) gStored++; // number of strings stored } ENDTm(DeltaUSec, tm); // end timer break; } // NOTE: the ADT's below here are so slow, that I did not add much effort // to clean them up. (dlb) case M_Splay: { STARTTm(tm); // start timer for (lines = 0; lines < Delta; lines++, StrNumb++) { GETSTRING(PCurStr, Strlen); PCurStr = Pdt[StrNumb].dt_string; splayinsert(&spans, (char *)PCurStr); } ENDTm(DeltaUSec, tm); // end timer break; } case M_Redblack: { STARTTm(tm); // start timer for (lines = 0; lines < Delta; lines++, StrNumb++) { GETSTRING(PCurStr, Strlen); PCurStr = Pdt[StrNumb].dt_string; redblackinsert(&rbans, (char *)PCurStr); } ENDTm(DeltaUSec, tm); // end timer break; } case M_Ternary: { STARTTm(tm); // start timer for (lines = 0; lines < Delta; lines++, StrNumb++) { GETSTRING(PCurStr, Strlen); Strlen = Pdt[StrNumb].dt_strlen; PCurStr = Pdt[StrNumb].dt_string; TernaryIns(&Ternary, PCurStr, Strlen); } ENDTm(DeltaUSec, tm); // end timer break; } default: assert(0); // cant happen break; } ENDmem(DeltaMem); // current malloc() mem usage ReadLin = StrNumb; // adjust delta if (ReadLin > TValues) ReadLin = TValues; // if (Delta > TValues) // ReadLin = Delta; // use the Delta Printf(" %11lu", StrNumb); // Total stored Printf(" %10lu", ReadLin); // Number to read back Begin = gStored - Begin; // actual STORED assert(lines == Delta); Printf(" %8lu", Delta - Begin); // Duplicate strings // Average time per line to store (including duplicate strings) Mult = DeltaUSec / (double)Delta; if (Mult < Pms[grp].ms_mininsert) Pms[grp].ms_mininsert = Mult; Printf(" %7.3f", Mult); // Bytes allocated thru malloc() if (TotalJudyMalloc == 0) Pms[grp].ms_Bytes = (double)DeltaMem; else Pms[grp].ms_Bytes = (double)(TotalJudyMalloc * sizeof(Word_t)); Pms[grp].ms_Bytes /= (double)gStored; fflush(stdout); //======================================================================= // READ BACK LOOP //======================================================================= Pdts = Pdt; // Strings to 'Get' gChainln = 0; // total chain lengths if (rFlag == 0) { Randomize(Pdt, StrNumb); // Randomize ONLY those stored if (CFlag) { // Allocate and make sequencial string buffer Pdts = BuildSeqBuf(Pdt, ReadLin); } } switch (Method) { case M_Print: break; case M_Hash: { STARTTm(tm); // start timer for (lines = 0; lines < ReadLin; lines++) { GETSTRING(PCurStr, Strlen); Strlen = Pdts[lines].dt_strlen; PCurStr = Pdts[lines].dt_string; PValue = HashGet(HRoot, PCurStr, Strlen); // get string assert(PValue != NULL); assert(*PValue > 0); } ENDTm(DeltaUSec, tm); // end timer break; } case M_JLHash: { STARTTm(tm); // start timer for (lines = 0; lines < ReadLin; lines++) { GETSTRING(PCurStr, Strlen); Strlen = Pdts[lines].dt_strlen; PCurStr = Pdts[lines].dt_string; PValue = JLHashGet(JLHash, PCurStr, Strlen); // get string assert(PValue != NULL); assert(*PValue > 0); } ENDTm(DeltaUSec, tm); // end timer break; } case M_JudySL: { STARTTm(tm); // start timer for (lines = 0; lines < ReadLin; lines++) { GETSTRING(PCurStr, Strlen); PCurStr = Pdts[lines].dt_string; JSLG(PValue, JudySL, PCurStr); // get string assert(PValue != NULL); assert(*PValue > 0); } ENDTm(DeltaUSec, tm); // end timer break; } case M_JudyHS: { STARTTm(tm); // start timer for (lines = 0; lines < ReadLin; lines++) { GETSTRING(PCurStr, Strlen); Strlen = Pdts[lines].dt_strlen; PCurStr = Pdts[lines].dt_string; JHSG(PValue, JudyHS, PCurStr, Strlen); // get string assert(PValue != NULL); assert(*PValue > 0); } ENDTm(DeltaUSec, tm); // end timer break; } // NOTE: the ADT's below here are so slow, that I did not add much effort // to clean them up. (dlb) case M_Splay: { STARTTm(tm); // start timer for (lines = 0; lines < ReadLin; lines++) { GETSTRING(PCurStr, Strlen); PCurStr = Pdts[lines].dt_string; splaysearch(&spans, (char *)PCurStr); } ENDTm(DeltaUSec, tm); // end timer break; } case M_Redblack: { STARTTm(tm); // start timer for (lines = 0; lines < ReadLin; lines++) { GETSTRING(PCurStr, Strlen); PCurStr = Pdts[lines].dt_string; redblacksearch(&rbans, (char *)PCurStr); } ENDTm(DeltaUSec, tm); // end timer break; } case M_Ternary: { STARTTm(tm); // start timer for (lines = 0; lines < ReadLin; lines++) { GETSTRING(PCurStr, Strlen); Strlen = Pdts[lines].dt_strlen; PCurStr = Pdts[lines].dt_string; if (TernaryGet(Ternary, PCurStr, Strlen) == 0) { printf("\n OOps - Ternary Bug at Line = %d\n", __LINE__); exit(1); } } ENDTm(DeltaUSec, tm); // end timer break; } default: assert(0); // cant happen break; } Mult = DeltaUSec / (double)ReadLin; // save least value if (Mult < Pms[grp].ms_minretrive) Pms[grp].ms_minretrive = Mult; Printf(" %7.3f", Mult); // RETRIVE per string Printf(" %9.6f", (double)gChainln / (double)ReadLin); // RAM USED PER STRING TO STORE DATA Printf(" %13.1f", (double)Pms[grp].ms_Bytes); Printf("\n"); fflush(stdout); } if (Method == M_Print) exit(0); Printf("# Total Duplicate strings = %lu\n", nStrg - gStored); //======================================================================= // Delete loop //======================================================================= DeltaUSec = -1.0; // set deleted flag if (rFlag == 0) { Randomize(Pdt, StrNumb); // Randomize ONLY those stored } switch (Method) { case M_JudySL: { if (DFlag) { Printf("# Begin JudySLDel() loop...\n"); STARTTm(tm); // start timer for (lines = 0; lines < nStrg; lines++) { int Rc; GETSTRING(PCurStr, Strlen); PCurStr = Pdt[lines].dt_string; JSLD(Rc, JudySL, PCurStr); // delete string assert(Rc != JERR); } ENDTm(DeltaUSec, tm); // end timer } else { Printf("# Begin JudySLFreeArray()...\n"); STARTTm(tm); // start timer JSLFA(Bytes, JudySL); ENDTm(DeltaUSec, tm); // end timer } break; } case M_JudyHS: { if (DFlag) { int Rc; Printf("# Begin JudyHSDel() loop..."); STARTTm(tm); // start timer for (lines = 0; lines < nStrg; lines++) { GETSTRING(PCurStr, Strlen); Strlen = Pdt[lines].dt_strlen; PCurStr = Pdt[lines].dt_string; JHSD(Rc, JudyHS, PCurStr, Strlen); // Delete string assert(Rc != JERR); } ENDTm(DeltaUSec, tm); // end timer } else { Printf("# Begin JudyHSFreeArray()...\n"); STARTTm(tm); // start timer JHSFA(Bytes, JudyHS); ENDTm(DeltaUSec, tm); // end timer } break; } case M_Hash: { if (DFlag) { Printf("# Begin HashDel() loop...\n"); STARTTm(tm); // start timer for (lines = 0; lines < nStrg; lines++) { GETSTRING(PCurStr, Strlen); Strlen = Pdt[lines].dt_strlen; PCurStr = Pdt[lines].dt_string; HashDel(&HRoot, PCurStr, Strlen); // Delete string } ENDTm(DeltaUSec, tm); // end timer } else { Printf("# Begin HashFreeArray()...\n"); STARTTm(tm); // start timer Bytes = HashFreeArray(&HRoot); ENDTm(DeltaUSec, tm); // end timer } break; } case M_JLHash: { if (DFlag) { Printf("# Begin JLHashDel() loop...\n"); STARTTm(tm); // start timer for (lines = 0; lines < nStrg; lines++) { GETSTRING(PCurStr, Strlen); Strlen = Pdt[lines].dt_strlen; PCurStr = Pdt[lines].dt_string; JLHashDel(&JLHash, PCurStr, Strlen); // Delete string } ENDTm(DeltaUSec, tm); // end timer } else { Printf("# Begin JLHashFreeArray()...\n"); STARTTm(tm); // start timer Bytes = JLHashFreeArray(&JLHash); ENDTm(DeltaUSec, tm); // end timer } break; } default: printf("# Delete not implemented yet, so quit\n"); Passes = 1; // No, delete, so quit break; } // average time per line to delete (including duplicate strings) if (Bytes) // Measured freed bytes? { Printf("# returned %lu bytes\n", Bytes); } if (TotalJudyMalloc) // Any bytes left after free? { printf ("# !!! BUG, %lu bytes not deleted in *Free()\n", TotalJudyMalloc * sizeof(Word_t)); } if (DeltaUSec != -1.0) // Measured how long to free? { Printf("# Free %lu strings, %0.3f uSecs Ave/string\n", gStored, DeltaUSec / (double)gStored); } Printf("\n"); } if (Passes != 1) { printf("# TotInserts 0 0 InsTime GetTime 0 Ram/String\n"); StrNumb = 0; for (grp = 0; grp < Groups; grp++) { StrNumb += Pms[grp].ms_delta; printf(" %11lu", StrNumb); // Total stored printf(" 0 0"); // place holder printf(" %7.3f", Pms[grp].ms_mininsert); printf(" %7.3f", Pms[grp].ms_minretrive); printf(" 0"); // place holder printf(" %7.3f", Pms[grp].ms_Bytes); printf("\n"); } } exit(0); // done } // main() judy-1.0.5/test/Judy1LHCheck.c0000644000175000017500000006073510622113030016214 0ustar troyhebetroyhebe// @(#) $Revision: 4.15 $ $Source: /judy/test/manual/Judy1LHCheck.c $ // This program tests the accuracy of a Judy1 with a JudyL Array. // -by- // Douglas L. Baskins (8/2001) doug@sourcejudy.com #include // calloc() #include // getopt() #include // pow() #include // printf() #include // Compile: // # cc -O Judy1LHCheck.c -lm -lJudy -o Judy1LHCheck // Common macro to handle a failure #define FAILURE(STR, UL) \ { \ printf( "Error: %s %lu, file='%s', 'function='%s', line %d\n", \ STR, (Word_t)(UL), __FILE__, __FUNCTI0N__, __LINE__); \ fprintf(stderr, "Error: %s %lu, file='%s', 'function='%s', line %d\n", \ STR, (Word_t)(UL), __FILE__, __FUNCTI0N__, __LINE__); \ exit(1); \ } // Structure to keep track of times typedef struct MEASUREMENTS_STRUCT { Word_t ms_delta; } ms_t, *Pms_t; // Specify prototypes for each test routine int NextNumb(Word_t * PNumber, double *PDNumb, double DMult, Word_t MaxNumb); Word_t TestJudyIns(void **J1, void **JL, void **JH, Word_t Seed, Word_t Elements); Word_t TestJudyDup(void **J1, void **JL, void **JH, Word_t Seed, Word_t Elements); int TestJudyDel(void **J1, void **JL, void **JH, Word_t Seed, Word_t Elements); Word_t TestJudyGet(void *J1, void *JL, void *JH, Word_t Seed, Word_t Elements); int TestJudyCount(void *J1, void *JL, Word_t LowIndex, Word_t Elements); Word_t TestJudyNext(void *J1, void *JL, Word_t LowIndex, Word_t Elements); int TestJudyPrev(void *J1, void *JL, Word_t HighIndex, Word_t Elements); int TestJudyNextEmpty(void *J1, void *JL, Word_t LowIndex, Word_t Elements); int TestJudyPrevEmpty(void *J1, void *JL, Word_t HighIndex, Word_t Elements); Word_t MagicList[] = { 0,0,0,0,0,0,0,0,0,0, // 0..9 0x27f, // 10 0x27f, // 11 0x27f, // 12 0x27f, // 13 0x27f, // 14 0x27f, // 15 0x1e71, // 16 0xdc0b, // 17 0xdc0b, // 18 0xdc0b, // 19 0xdc0b, // 20 0xc4fb, // 21 0xc4fb, // 22 0xc4fb, // 23 0x13aab, // 24 0x11ca3, // 25 0x11ca3, // 26 0x11ca3, // 27 0x13aab, // 28 0x11ca3, // 29 0xc4fb, // 30 0xc4fb, // 31 0x13aab, // 32 0x14e73, // 33 0x145d7, // 34 0x145f9, // 35 following tested with Seed=0xc1fc to 35Gig numbers 0x151ed, // 36 .. 41 0x151ed, // 37 0x151ed, // 38 0x151ed, // 39 fails at 549751488512 (549Gig) 0x151ed, // 40 0x146c3, // 41 .. 64 0x146c3, // 42 0x146c3, // 43 0x146c3, // 44 0x146c3, // 45 0x146c3, // 46 0x146c3, // 47 0x146c3, // 48 0x146c3, // 49 0x146c3, // 50 0x146c3, // 51 0x146c3, // 52 0x146c3, // 53 0x146c3, // 54 0x146c3, // 55 0x146c3, // 56 0x146c3, // 57 0x146c3, // 58 0x146c3, // 59 0x146c3, // 60 0x146c3, // 61 0x146c3, // 62 0x146c3, // 63 0x146c3 // 64 }; // Routine to "mirror" the input data word static Word_t Swizzle(Word_t word) { // BIT REVERSAL, Ron Gutman in Dr. Dobb's Journal, #316, Sept 2000, pp133-136 // #ifdef __LP64__ word = ((word & 0x00000000ffffffff) << 32) | ((word & 0xffffffff00000000) >> 32); word = ((word & 0x0000ffff0000ffff) << 16) | ((word & 0xffff0000ffff0000) >> 16); word = ((word & 0x00ff00ff00ff00ff) << 8) | ((word & 0xff00ff00ff00ff00) >> 8); word = ((word & 0x0f0f0f0f0f0f0f0f) << 4) | ((word & 0xf0f0f0f0f0f0f0f0) >> 4); word = ((word & 0x3333333333333333) << 2) | ((word & 0xcccccccccccccccc) >> 2); word = ((word & 0x5555555555555555) << 1) | ((word & 0xaaaaaaaaaaaaaaaa) >> 1); #else // __LP64__ word = ((word & 0x0000ffff) << 16) | ((word & 0xffff0000) >> 16); word = ((word & 0x00ff00ff) << 8) | ((word & 0xff00ff00) >> 8); word = ((word & 0x0f0f0f0f) << 4) | ((word & 0xf0f0f0f0) >> 4); word = ((word & 0x33333333) << 2) | ((word & 0xcccccccc) >> 2); word = ((word & 0x55555555) << 1) | ((word & 0xaaaaaaaa) >> 1); #endif // __LP64__ return(word); } Word_t dFlag = 1; Word_t pFlag = 0; Word_t CFlag = 0; Word_t DFlag = 0; Word_t SkipN = 0; // default == Random skip Word_t nElms = 1000000; // Default = 1M Word_t ErrorFlag = 0; Word_t TotalIns = 0; Word_t TotalPop = 0; Word_t TotalDel = 0; // Stuff for LFSR (pseudo random number generator) Word_t RandomBit = ~0UL / 2 + 1; Word_t BValue = sizeof(Word_t) * 8; Word_t Magic; Word_t StartSeed = 0xc1fc; // default beginning number Word_t FirstSeed; #undef __FUNCTI0N__ #define __FUNCTI0N__ "Random" static Word_t // Placed here so INLINING compilers get to look at it. Random(Word_t newseed) { if (newseed & RandomBit) { newseed += newseed; newseed ^= Magic; } else { newseed += newseed; } newseed &= RandomBit * 2 - 1; if (newseed == FirstSeed) { printf("Passed (End of LFSR) Judy1, JudyL, JudyHS tests for %lu numbers with <= %ld bits\n", TotalPop, BValue); exit(0); } return(newseed); } static Word_t // Placed here so INLINING compilers get to look at it. GetNextIndex(Word_t Index) { if (SkipN) Index += SkipN; else Index = Random(Index); return(Index); } #undef __FUNCTI0N__ #define __FUNCTI0N__ "main" int main(int argc, char *argv[]) { // Names of Judy Arrays void *J1 = NULL; // Judy1 void *JL = NULL; // JudyL void *JH = NULL; // JudyHS double Mult; Pms_t Pms; Word_t Seed; Word_t PtsPdec = 10; // points per decade Word_t Groups; // Number of measurement groups Word_t grp; int c; extern char *optarg; ////////////////////////////////////////////////////////////// // PARSE INPUT PARAMETERS ////////////////////////////////////////////////////////////// while ((c = getopt(argc, argv, "n:S:P:b:L:B:pdDC")) != -1) { switch (c) { case 'n': // Number of elements nElms = strtoul(optarg, NULL, 0); // Size of Linear Array if (nElms == 0) FAILURE("No tests: -n", nElms); // Check if more than a trillion (64 bit only) if ((double)nElms > 1e12) FAILURE("Too many Indexes=", nElms); break; case 'S': // Step Size, 0 == Random SkipN = strtoul(optarg, NULL, 0); break; case 'P': // PtsPdec = strtoul(optarg, NULL, 0); break; case 'b': // May not work past 35 bits if changed StartSeed = strtoul(optarg, NULL, 0); break; case 'B': BValue = strtoul(optarg, NULL, 0); if ( (BValue > (sizeof(Word_t) * 8)) || (MagicList[BValue] == 0) ) { ErrorFlag++; printf("\nIllegal number of random bits of %lu !!!\n", BValue); } break; case 'p': // Print test indexes pFlag = 1; break; case 'd': // Delete indexes dFlag = 0; break; case 'D': // Swizzle indexes DFlag = 1; break; case 'C': // Skip counting test. CFlag = 1; break; default: ErrorFlag++; break; } } if (ErrorFlag) { printf("\n%s -n# -S# -B# -P# -b # -DRCpd\n\n", argv[0]); printf("Where:\n"); printf("-n <#> number of indexes used in tests\n"); printf("-C skip JudyCount tests\n"); printf("-p print index set - for debug\n"); printf("-d do not call JudyDel/Unset\n"); printf("-D Swizzle data (mirror)\n"); printf("-S <#> index skip amount, 0 = random\n"); printf("-B <#> # bits-1 in random number generator\n"); printf("-P <#> number measurement points per decade\n"); printf("\n"); exit(1); } // Set number of Random bits in LFSR RandomBit = 1UL << (BValue - 1); Magic = MagicList[BValue]; if (nElms > ((RandomBit-2) * 2)) { printf("# Number = -n%lu of Indexes reduced to max expanse of Random numbers\n", nElms); nElms = ((RandomBit-2) * 2); } printf("\n%s -n%lu -S%lu -B%lu", argv[0], nElms, SkipN, BValue); if (DFlag) printf(" -D"); if (!dFlag) printf(" -d"); if (pFlag) printf(" -p"); if (CFlag) printf(" -C"); printf("\n\n"); if (sizeof(Word_t) == 8) printf("%s 64 Bit version\n", argv[0]); else if (sizeof(Word_t) == 4) printf("%s 32 Bit version\n", argv[0]); ////////////////////////////////////////////////////////////// // CALCULATE NUMBER OF MEASUREMENT GROUPS ////////////////////////////////////////////////////////////// // Calculate Multiplier for number of points per decade Mult = pow(10.0, 1.0 / (double)PtsPdec); { double sum; Word_t numb, prevnumb; // Count number of measurements needed (10K max) sum = numb = 1; for (Groups = 2; Groups < 10000; Groups++) if (NextNumb(&numb, &sum, Mult, nElms)) break; // Get memory for measurements Pms = (Pms_t) calloc(Groups, sizeof(ms_t)); // Now calculate number of Indexes for each measurement point numb = sum = 1; prevnumb = 0; for (grp = 0; grp < Groups; grp++) { Pms[grp].ms_delta = numb - prevnumb; prevnumb = numb; NextNumb(&numb, &sum, Mult, nElms); } } // Groups = number of sizes ////////////////////////////////////////////////////////////// // BEGIN TESTS AT EACH GROUP SIZE ////////////////////////////////////////////////////////////// // Get the kicker to test the LFSR FirstSeed = Seed = StartSeed & (RandomBit * 2 - 1); printf("Total Pop Total Ins New Ins Total Del"); printf(" J1MU/I JLMU/I\n"); #ifdef testLFSR { Word_t Seed1 = Seed; printf("Begin test of LSFR, BValue = %lu\n", BValue); while(1) { Seed1 = GetNextIndex(Seed1); TotalPop++; if (TotalPop == 0) printf("BUG!!!\n"); } exit(0); } #endif // testLFSR for (grp = 0; grp < Groups; grp++) { Word_t LowIndex, HighIndex; Word_t Delta; Word_t NewSeed; Delta = Pms[grp].ms_delta; // Test JLI, J1S NewSeed = TestJudyIns(&J1, &JL, &JH, Seed, Delta); // Test JLG, J1T LowIndex = TestJudyGet(J1, JL, JH, Seed, Delta); // Test JLI, J1S -dup LowIndex = TestJudyDup(&J1, &JL, &JH, Seed, Delta); // Test JLC, J1C if (!CFlag) { TestJudyCount(J1, JL, LowIndex, Delta); } // Test JLN, J1N HighIndex = TestJudyNext(J1, JL, 0UL, TotalPop); // Test JLP, J1P TestJudyPrev(J1, JL, ~0UL, TotalPop); // Test JLNE, J1NE TestJudyNextEmpty(J1, JL, LowIndex, Delta); // Test JLPE, J1PE TestJudyPrevEmpty(J1, JL, HighIndex, Delta); // Test JLD, J1U if (dFlag) { TestJudyDel(&J1, &JL, &JH, Seed, Delta); } printf("%9lu %9lu %7lu %9lu", TotalPop, TotalIns, Delta, TotalDel); { Word_t Count1, CountL; // Print the number of bytes used per Index J1C(Count1, J1, 0, ~0); printf(" %6.3f", (double)Judy1MemUsed(J1) / (double)Count1); JLC(CountL, JL, 0, ~0); printf(" %6.3f", (double)JudyLMemUsed(JL) / (double)CountL); } printf("\n"); // Advance Index number set Seed = NewSeed; } { Word_t Count1, CountL; Word_t Bytes; JLC(CountL, JL, 0, ~0); J1C(Count1, J1, 0, ~0); if (CountL != TotalPop) FAILURE("JudyLCount wrong", CountL); if (Count1 != TotalPop) FAILURE("Judy1Count wrong", Count1); if (TotalPop) { J1FA(Bytes, J1); // Free the Judy1 Array printf("Judy1FreeArray = %6.3f Bytes/Index\n", (double)Bytes / (double)Count1); if (pFlag) { printf("J1FA: %8lu\tbytes = %lu\n", TotalPop, Bytes); } JLFA(Bytes, JL); // Free the JudyL Array printf("JudyLFreeArray = %6.3f Bytes/Index\n", (double)Bytes / (double)CountL); if (pFlag) { printf("JLFA: %8lu\tbytes = %lu\n", TotalPop, Bytes); } JHSFA(Bytes, JH); // Free the JudyL Array printf("JudyHSFreeArray = %6.3f Bytes/Index\n", (double)Bytes / (double)TotalPop); // Count not available yet if (pFlag) { printf("JHSFA: %8lu\tbytes = %lu\n", TotalPop, Bytes); } TotalPop = 0; } } printf("Passed Judy1, JudyL, JudyHS tests for %lu numbers with <= %ld bits\n", nElms, BValue); exit(0); } #undef __FUNCTI0N__ #define __FUNCTI0N__ "TestJudyIns" Word_t TestJudyIns(void **J1, void **JL, void **JH, Word_t Seed, Word_t Elements) { Word_t TstIndex; Word_t elm; Word_t *PValue, *PValue1; Word_t Seed1; int Rcode; for (Seed1 = Seed, elm = 0; elm < Elements; elm++) { Seed1 = GetNextIndex(Seed1); if (Seed1 == 0) FAILURE("This command not robust if Index == 0", elm); if (DFlag) TstIndex = Swizzle(Seed1); else TstIndex = Seed1; if (pFlag) { printf("Ins: %8lu\t0x%lx\n", elm, TstIndex); } // Judy1 J1S(Rcode, *J1, TstIndex); if (Rcode == JERR) FAILURE("Judy1Set failed at", elm); if (Rcode == 0) FAILURE("Judy1Set failed - DUP Index, population =", TotalPop); #ifdef SKIPMACRO Rcode = Judy1Test(*J1, TstIndex); #else J1T(Rcode, *J1, TstIndex); #endif // SKIPMACRO if (Rcode != 1) FAILURE("Judy1Test failed - Index missing, population =", TotalPop); J1S(Rcode, *J1, TstIndex); if (Rcode != 0) FAILURE("Judy1Set failed - Index missing, population =", TotalPop); // JudyL JLI(PValue, *JL, TstIndex); if (PValue == PJERR) FAILURE("JudyLIns failed at", elm); if (*PValue == TstIndex) FAILURE("JudyLIns failed - DUP Index, population =", TotalPop); // Save Index in Value *PValue = TstIndex; #ifdef SKIPMACRO PValue1 = (PWord_t)JudyLGet(*JL, TstIndex); #else JLG(PValue1, *JL, TstIndex); #endif // SKIPMACRO if (PValue != PValue1) FAILURE("JudyLGet failed - Index missing, population =", TotalPop); JLI(PValue1, *JL, TstIndex); if (PValue != PValue1) { if (*PValue1 != TstIndex) { FAILURE("JudyLIns failed - Index missing, population =", TotalPop); } else { // not ready for this yet! printf("Index moved -- TotalPop = %lu\n", TotalPop); } } // JudyHS JHSI(PValue, *JH, (void *)(&TstIndex), sizeof(Word_t)); if (PValue == PJERR) FAILURE("JudyHSIns failed at", elm); if (*PValue == TstIndex) FAILURE("JudyHSIns failed - DUP Index, population =", TotalPop); // Save Index in Value *PValue = TstIndex; JHSG(PValue1, *JH, (void *)(&TstIndex), sizeof(Word_t)); if (PValue != PValue1) FAILURE("JudyHSGet failed - Index missing, population =", TotalPop); JHSI(PValue1, *JH, (void *)(&TstIndex), sizeof(Word_t)); if (PValue != PValue1) { if (*PValue1 != TstIndex) { FAILURE("JudyHSIns failed - Index missing, population =", TotalPop); } else { // not ready for this yet! printf("Index moved -- TotalPop = %lu\n", TotalPop); } } TotalPop++; TotalIns++; } return (Seed1); // New seed } #undef __FUNCTI0N__ #define __FUNCTI0N__ "TestJudyGet" Word_t TestJudyGet(void *J1, void *JL, void *JH, Word_t Seed, Word_t Elements) { Word_t LowIndex = ~0UL; Word_t TstIndex; Word_t elm; Word_t *PValue; Word_t Seed1; int Rcode; for (Seed1 = Seed, elm = 0; elm < Elements; elm++) { Seed1 = GetNextIndex(Seed1); if (DFlag) TstIndex = Swizzle(Seed1); else TstIndex = Seed1; if (TstIndex < LowIndex) LowIndex = TstIndex; #ifdef SKIPMACRO Rcode = Judy1Test(J1, TstIndex); #else J1T(Rcode, J1, TstIndex); #endif // SKIPMACRO if (Rcode != 1) FAILURE("Judy1Test Rcode != 1", Rcode); #ifdef SKIPMACRO PValue = (PWord_t)JudyLGet(JL, TstIndex); #else JLG(PValue, JL, TstIndex); #endif // SKIPMACRO if (PValue == (Word_t *) NULL) FAILURE("JudyLGet ret PValue = NULL", 0L); if (*PValue != TstIndex) FAILURE("JudyLGet ret wrong Value at", elm); JHSG(PValue, JH, (void *)(&TstIndex), sizeof(Word_t)); if (PValue == (Word_t *) NULL) FAILURE("JudyHSGet ret PValue = NULL", 0L); if (*PValue != TstIndex) FAILURE("JudyHSGet ret wrong Value at", elm); } return(LowIndex); } #undef __FUNCTI0N__ #define __FUNCTI0N__ "TestJudyDup" Word_t TestJudyDup(void **J1, void **JL, void **JH, Word_t Seed, Word_t Elements) { Word_t LowIndex = ~0UL; Word_t TstIndex; Word_t elm; Word_t *PValue; Word_t Seed1; int Rcode; for (Seed1 = Seed, elm = 0; elm < Elements; elm++) { Seed1 = GetNextIndex(Seed1); if (DFlag) TstIndex = Swizzle(Seed1); else TstIndex = Seed1; if (TstIndex < LowIndex) LowIndex = TstIndex; J1S(Rcode, *J1, TstIndex); if (Rcode != 0) FAILURE("Judy1Set Rcode != 0", Rcode); JLI(PValue, *JL, TstIndex); if (PValue == (Word_t *) NULL) FAILURE("JudyLIns ret PValue = NULL", 0L); if (*PValue != TstIndex) FAILURE("JudyLIns ret wrong Value at", elm); JHSI(PValue, *JH, &TstIndex, sizeof(Word_t)); if (PValue == (Word_t *) NULL) FAILURE("JudyHSIns ret PValue = NULL", 0L); if (*PValue != TstIndex) FAILURE("JudyHSIns ret wrong Value at", elm); } return(LowIndex); } #undef __FUNCTI0N__ #define __FUNCTI0N__ "TestJudyCount" int TestJudyCount(void *J1, void *JL, Word_t LowIndex, Word_t Elements) { Word_t elm; Word_t Count1, CountL; Word_t TstIndex = LowIndex; int Rcode; TstIndex = LowIndex; for (elm = 0; elm < Elements; elm++) { J1C(Count1, J1, LowIndex, TstIndex); if (Count1 == JERR) FAILURE("Judy1Count ret JERR", Count1); if (Count1 != (elm + 1)) { J1C(CountL, J1, 0, -1); printf("J1C(%lu, J1, 0, -1)\n", CountL); JLC(CountL, JL, 0, -1); printf("JLC(%lu, JL, 0, -1)\n", CountL); printf("LowIndex = 0x%lx, TstIndex = 0x%lx, diff = %lu\n", LowIndex, TstIndex, TstIndex - LowIndex); JLC(CountL, JL, LowIndex, TstIndex); printf("CountL = %lu, Count1 = %lu, should be: elm + 1 = %lu\n", CountL, Count1, elm + 1); FAILURE("J1C at", elm); } JLC(CountL, JL, LowIndex, TstIndex); if (CountL == JERR) FAILURE("JudyLCount ret JERR", CountL); if (CountL != (elm + 1)) { printf("CountL = %lu, elm +1 = %lu\n", CountL, elm + 1); FAILURE("JLC at", elm); } J1N(Rcode, J1, TstIndex); } return(0); } #undef __FUNCTI0N__ #define __FUNCTI0N__ "TestJudyNext" Word_t TestJudyNext(void *J1, void *JL, Word_t LowIndex, Word_t Elements) { Word_t JLindex, J1index, JPindex = 0; Word_t *PValue; Word_t elm; int Rcode; // Get an Index low enough for Elements J1index = JLindex = LowIndex; JLF(PValue, JL, JLindex); J1F(Rcode, J1, J1index); for (elm = 0; elm < Elements; elm++) { if (PValue == NULL) FAILURE("JudyLNext ret NULL PValue at", elm); if (Rcode != 1) FAILURE("Judy1Next Rcode != 1 =", Rcode); if (JLindex != J1index) FAILURE("JudyLNext & Judy1Next ret different PIndex at", elm); JPindex = J1index; // save the last found index JLN(PValue, JL, JLindex); // Get next one J1N(Rcode, J1, J1index); // Get next one } if (PValue != NULL) FAILURE("JudyLNext PValue != NULL", PValue); if (Rcode != 0) FAILURE("Judy1Next Rcode != 1 =", Rcode); // perhaps a check should be done here -- if I knew what to expect. return(JPindex); // return last one } #undef __FUNCTI0N__ #define __FUNCTI0N__ "TestJudyPrev" int TestJudyPrev(void *J1, void *JL, Word_t HighIndex, Word_t Elements) { Word_t JLindex, J1index; Word_t *PValue; Word_t elm; int Rcode; // Get an Index high enough for Elements J1index = JLindex = HighIndex; JLL(PValue, JL, JLindex); J1L(Rcode, J1, J1index); for (elm = 0; elm < Elements; elm++) { if (PValue == NULL) FAILURE("JudyLPrev ret NULL PValue at", elm); if (Rcode != 1) FAILURE("Judy1Prev Rcode != 1 =", Rcode); if (JLindex != J1index) FAILURE("JudyLPrev & Judy1Prev ret different PIndex at", elm); JLP(PValue, JL, JLindex); // Get previous one J1P(Rcode, J1, J1index); // Get previous one } if (PValue != NULL) FAILURE("JudyLPrev PValue != NULL", PValue); if (Rcode != 0) FAILURE("Judy1Prev Rcode != 1 =", Rcode); // perhaps a check should be done here -- if I knew what to expect. return(0); } #undef __FUNCTI0N__ #define __FUNCTI0N__ "TestJudyNextEmpty" int TestJudyNextEmpty(void *J1, void *JL, Word_t LowIndex, Word_t Elements) { Word_t elm; Word_t JLindex, J1index; Word_t Seed1; int Rcode1; // Return code int RcodeL; // Return code // Set 1st search to .. Seed1 = LowIndex; J1index = JLindex = Seed1; for (elm = 0; elm < Elements; elm++) { Word_t *PValue; if (pFlag) { printf("JNE: %8lu\t0x%lx\n", elm, JLindex); } // Find next Empty Index, JLindex is modified by JLNE JLNE(RcodeL, JL, JLindex); // Rcode = JudyLNextEmpty(JL, &JLindex, PJE0) // Find next Empty Index, J1index is modified by J1NE J1NE(Rcode1, J1, J1index); // Rcode = Judy1NextEmpty(J1, &J1index, PJE0) if ((Rcode1 != 1) || (RcodeL != 1)) { printf("RcodeL = %d, Rcode1 = %d, Index1 = 0x%lx, IndexL = 0x%lx\n", RcodeL, Rcode1, J1index, JLindex); FAILURE("Judy1NextEmpty Rcode != 1 =", Rcode1); } if (J1index != JLindex) FAILURE("JLNE != J1NE returned index at", elm); #ifdef SKIPMACRO Rcode1 = Judy1Test(J1, J1index); #else J1T(Rcode1, J1, J1index); #endif // SKIPMACRO if (Rcode1 != 0) FAILURE("J1NE returned non-empty Index =", J1index); #ifdef SKIPMACRO PValue = (PWord_t)JudyLGet(JL, JLindex); #else JLG(PValue, JL, JLindex); #endif // SKIPMACRO if (PValue != (Word_t *) NULL) FAILURE("JLNE returned non-empty Index =", JLindex); Seed1 = GetNextIndex(Seed1); J1index = JLindex = Seed1; } return(0); } // Routine to JudyPrevEmpty routines #undef __FUNCTI0N__ #define __FUNCTI0N__ "TestJudyPrevEmpty" int TestJudyPrevEmpty(void *J1, void *JL, Word_t HighIndex, Word_t Elements) { Word_t elm; Word_t JLindex, J1index; Word_t Seed1; int Rcode1; int RcodeL; // Set 1st search to .. Seed1 = HighIndex; J1index = JLindex = Seed1; for (elm = 0; elm < Elements; elm++) { Word_t *PValue; Word_t JPIndex; JPIndex = J1index; if (pFlag) { printf("JPE: %8lu\t0x%lx\n", elm, JPIndex); } J1PE(Rcode1, J1, J1index); // Rcode = Judy1PrevEmpty(J1, &J1index, PJE0) // Find next Empty Index, JLindex is modified by JLPE JLPE(RcodeL, JL, JLindex); // RcodeL = JudyLPrevEmpty(JL, &JLindex, PJE0) if ((RcodeL != 1) || (Rcode1 != 1)) { printf("RcodeL = %d, Rcode1 = %d, Index1 = 0x%lx, IndexL = 0x%lx\n", RcodeL, Rcode1, J1index, JLindex); FAILURE("Judy*PrevEmpty Rcode* != 1 =", RcodeL); } if (J1index != JLindex) FAILURE("JLPE != J1PE returned index at", elm); #ifdef SKIPMACRO Rcode1 = Judy1Test(J1, J1index); #else J1T(Rcode1, J1, J1index); #endif // SKIPMACRO if (Rcode1 != 0) FAILURE("J1PE returned non-empty Index =", J1index); #ifdef SKIPMACRO PValue = (PWord_t)JudyLGet(JL, JLindex); #else JLG(PValue, JL, JLindex); #endif // SKIPMACRO if (PValue != (Word_t *) NULL) FAILURE("JLPE returned non-empty Index =", JLindex); Seed1 = GetNextIndex(Seed1); J1index = JLindex = Seed1; } return(0); } #undef __FUNCTI0N__ #define __FUNCTI0N__ "TestJudyDel" int TestJudyDel(void **J1, void **JL, void **JH, Word_t Seed, Word_t Elements) { Word_t TstIndex; Word_t elm; Word_t Seed1; int Rcode; // Only delete half of those inserted for (Seed1 = Seed, elm = 0; elm < (Elements / 2); elm++) { Seed1 = GetNextIndex(Seed1); if (DFlag) TstIndex = Swizzle(Seed1); else TstIndex = Seed1; if (pFlag) { printf("Del: %8lu\t0x%lx\n", elm, TstIndex); } TotalDel++; J1U(Rcode, *J1, TstIndex); if (Rcode != 1) FAILURE("Judy1Unset ret Rcode != 1", Rcode); JLD(Rcode, *JL, TstIndex); if (Rcode != 1) FAILURE("JudyLDel ret Rcode != 1", Rcode); JHSD(Rcode, *JH, (void *)(&TstIndex), sizeof(Word_t)); if (Rcode != 1) FAILURE("JudyHSDel ret Rcode != 1", Rcode); TotalPop--; } return(0); } // Routine to get next size of Indexes int // return 1 if last number NextNumb(Word_t * PNumber, // pointer to returned next number double *PDNumb, // Temp double of above double DMult, // Multiplier Word_t MaxNumb) // Max number to return { Word_t num; // Save prev number Word_t PrevNumb = *PNumber; // Verify integer number increased for (num = 0; num < 1000; num++) { // Calc next number *PDNumb *= DMult; // Return it in integer format *PNumber = (Word_t) (*PDNumb + 0.5); if (*PNumber != PrevNumb) break; } // Verify it did exceed max ulong if ((*PDNumb + 0.5) > (double)(-1UL)) { // It did, so return max number *PNumber = -1UL; return (1); // flag it } // Verify it did not exceed max number if ((*PDNumb + 0.5) > (double)MaxNumb) { // it did, so return max *PNumber = MaxNumb; return(1); // flag it } return(0); // more available } judy-1.0.5/test/CheckDupLines.c0000644000175000017500000000236610204462077016531 0ustar troyhebetroyhebe#include #include #include #include //#include "JudyHS.h" // for Judy.h without JudyHS*() // By Doug Baskins Apr 2004 - for JudyHS man page #define MAXLINE 1000000 /* max length of line */ char Index[MAXLINE]; // string to check int // Usage: CheckDupLines < file main() { Pvoid_t PJArray = (PWord_t)NULL; // Judy array. PWord_t PValue; // Judy array element. Word_t Bytes; // size of JudyHS array. Word_t LineNumb = 0; // current line number Word_t Dups = 0; // number of duplicate lines while (fgets(Index, MAXLINE, stdin) != (char *)NULL) { LineNumb++; // line number // store string into array JHSI(PValue, PJArray, Index, strlen(Index)); if (*PValue) // check if duplicate { Dups++; // yes, count printf("Duplicate lines %lu:%lu:%s", *PValue, LineNumb, Index); } else { *PValue = LineNumb; // store Line number } } printf("%lu Duplicates, free JudyHS array of %lu Lines\n", Dups, LineNumb - Dups); JHSFA(Bytes, PJArray); // free array printf("The JudyHS array allocated %lu bytes of memory\n", Bytes); return (0); } judy-1.0.5/test/Centrino_1.3Mhz_Plots/0000755000175000017500000000000010624600177017700 5ustar troyhebetroyhebejudy-1.0.5/test/Centrino_1.3Mhz_Plots/JudyHS_CO.plot0000644000175000017500000010513110204462077022327 0ustar troyhebetroyhebe# StringCompare -n14962357 -A JudyHS -P40 -L10 -C -M100000 /home/data/domnames.txt # This file is in a format to input to 'jbgraph' # XLABEL Stored # YLABEL Microseconds / Index # COLHEAD 1 Total Insert attempts # COLHEAD 2 Number Gets # COLHEAD 3 Duplicate strings # COLHEAD 4 Insert Time (uS) # COLHEAD 5 Get Time (uS) # COLHEAD 6 Hash Chain Length # COLHEAD 7 Average RAM/String # Linux localhost 2.6.3-4mdkenterprise #1 SMP Tue Mar 2 07:00:53 CET 2004 i686 # 32 Bit CPU # Processor speed compiled at 1299 Mhz # 11218731 (75.0%) non-Word_t aligned string buffers # Ram used for input data = 372621771 bytes # Average string length = 15.9 bytes # 3200000 bytes malloc() for 'cached' strings for Get measurement # Access Time = 0.112 uS average per string (mostly from Cache) # HashStr() Time = 0.271 uS average per string (mostly from Cache) # Access Time = 0.295 uS average per string (mostly from RAM) # HashStr() Time = 0.476 uS average per string (mostly from RAM) # Pass 0 # TotInserts DeltaGets DupStrs InsTime GetTime HChainLen Ram/String # 1 1 0 30.232 2.608 0.000000 52.0 # 2 2 0 8.020 0.314 0.000000 44.0 # 3 3 0 1.616 0.268 0.000000 42.7 # 4 4 0 1.424 0.267 0.000000 45.0 # 5 5 0 1.166 0.252 0.000000 41.6 # 6 6 0 1.122 0.251 0.000000 39.3 # 7 7 0 1.511 0.256 0.000000 41.1 # 8 8 0 1.346 0.258 0.000000 39.5 # 9 9 0 1.476 0.245 0.000000 38.7 # 10 10 0 1.397 0.252 0.000000 41.2 # 11 11 0 1.299 0.256 0.000000 40.4 # 12 12 0 1.287 0.248 0.000000 39.7 # 13 13 0 0.999 0.256 0.000000 39.1 # 14 14 0 1.191 0.261 0.000000 38.9 # 15 15 0 1.197 0.259 0.000000 38.7 # 16 16 0 7.658 0.264 0.000000 41.0 # 17 17 0 1.427 0.258 0.000000 40.0 # 18 18 0 1.255 0.262 0.000000 39.1 # 19 19 0 1.232 0.263 0.000000 38.7 # 20 20 0 1.085 0.265 0.000000 38.4 # 21 21 0 1.185 0.254 0.000000 37.9 # 22 22 0 1.178 0.259 0.000000 38.0 # 23 23 0 1.135 0.265 0.000000 37.6 # 24 24 0 1.072 0.265 0.000000 37.0 # 25 25 0 1.267 0.264 0.000000 36.6 # 26 26 0 1.329 0.262 0.000000 36.3 # 27 27 0 1.260 0.267 0.000000 36.3 # 28 28 0 1.308 0.499 0.000000 36.1 # 29 29 0 1.189 0.262 0.000000 36.0 # 30 30 0 1.219 0.263 0.000000 35.6 # 31 31 0 1.200 0.270 0.000000 36.1 # 32 32 0 1.320 0.265 0.000000 35.9 # 34 34 0 0.967 0.264 0.000000 35.3 # 36 36 0 1.090 0.266 0.000000 35.1 # 38 38 0 1.500 0.274 0.000000 36.8 # 40 40 0 0.915 0.266 0.000000 36.2 # 42 42 0 1.145 0.268 0.000000 36.0 # 44 44 0 1.169 0.270 0.000000 36.0 # 46 46 0 0.990 0.272 0.000000 35.9 # 48 48 0 0.995 0.271 0.000000 35.5 # 50 50 0 1.040 0.268 0.000000 35.4 # 53 53 0 0.925 0.274 0.000000 35.2 # 56 56 0 1.202 0.270 0.000000 35.1 # 59 59 0 0.744 0.270 0.000000 34.3 # 62 62 0 0.926 0.270 0.000000 34.1 # 65 65 0 0.920 0.267 0.000000 34.0 # 69 69 0 0.838 0.271 0.000000 33.9 # 73 73 0 0.921 0.270 0.000000 33.9 # 77 77 0 0.833 0.270 0.000000 33.8 # 81 81 0 0.939 0.268 0.000000 33.9 # 85 85 0 0.811 0.272 0.000000 33.7 # 90 90 0 0.995 0.272 0.000000 34.2 # 95 95 0 0.739 0.270 0.000000 33.5 # 100 100 0 0.883 0.273 0.000000 33.2 # 106 106 0 0.860 0.270 0.000000 32.6 # 112 112 0 0.828 0.271 0.000000 32.4 # 118 118 0 1.276 0.273 0.000000 32.2 # 125 125 0 0.982 0.278 0.000000 32.4 # 132 132 0 1.076 0.275 0.000000 32.8 # 139 139 0 0.839 0.279 0.000000 32.3 # 147 147 0 0.931 0.277 0.000000 32.6 # 155 155 0 0.918 0.280 0.000000 32.5 # 164 164 0 0.929 0.282 0.000000 32.8 # 173 173 0 0.832 0.281 0.000000 32.6 # 183 183 0 0.912 0.284 0.000000 32.7 # 194 194 0 0.903 0.287 0.000000 32.6 # 205 205 0 0.886 0.286 0.000000 32.5 # 217 217 0 1.086 0.286 0.000000 32.3 # 230 230 0 0.886 0.286 0.000000 32.5 # 243 243 0 0.821 0.287 0.000000 32.5 # 257 257 0 0.804 0.287 0.000000 32.1 # 272 272 0 0.876 0.315 0.000000 32.0 # 288 288 0 0.867 0.289 0.000000 31.8 # 305 305 0 0.849 0.289 0.000000 31.8 # 323 323 0 2.211 0.299 0.000000 32.1 # 342 342 0 1.446 0.301 0.000000 32.8 # 362 362 0 1.032 0.320 0.000000 33.0 # 383 383 0 1.079 0.301 0.000000 33.4 # 405 405 0 0.983 0.304 0.000000 33.4 # 429 429 0 1.005 0.304 0.000000 33.3 # 454 454 0 0.850 0.321 0.000000 33.0 # 480 480 0 1.039 0.306 0.000000 33.4 # 508 508 0 0.984 0.307 0.000000 33.5 # 538 538 0 1.059 0.320 0.000000 33.6 # 569 569 0 0.857 0.307 0.000000 33.5 # 602 602 0 0.997 0.306 0.000000 33.8 # 637 637 0 0.935 0.320 0.000000 33.7 # 674 674 0 0.946 0.307 0.000000 33.7 # 714 714 0 0.940 0.309 0.000000 33.6 # 756 756 0 1.174 0.308 0.000000 33.8 # 800 800 0 0.925 0.307 0.000000 34.0 # 847 847 0 0.908 0.310 0.000000 33.9 # 897 897 0 0.931 0.308 0.000000 34.0 # 950 950 0 0.904 0.310 0.000000 34.0 # 1006 1006 0 0.891 0.318 0.000000 33.9 # 1065 1065 0 0.842 0.310 0.000000 33.7 # 1128 1128 0 0.880 0.318 0.000000 33.6 # 1194 1194 0 0.875 0.312 0.000000 33.6 # 1264 1264 0 1.027 0.314 0.000000 33.6 # 1339 1339 0 0.867 0.314 0.000000 33.5 # 1418 1418 0 0.857 0.320 0.000000 33.3 # 1502 1502 0 0.962 0.424 0.000000 33.4 # 1591 1591 0 0.899 0.324 0.000000 33.5 # 1685 1685 0 0.935 0.323 0.000000 33.5 # 1784 1784 0 0.936 0.323 0.000000 33.6 # 1884 1884 0 0.961 0.324 0.000000 33.8 # 1995 1995 0 0.894 0.325 0.000000 33.7 # 2113 2113 0 0.883 0.323 0.000000 33.7 # 2239 2239 0 0.851 0.324 0.000000 33.6 # 2371 2371 0 0.901 0.329 0.000000 33.5 # 2512 2512 0 0.937 0.328 0.000000 33.6 # 2661 2661 0 1.014 0.423 0.000000 33.7 # 2818 2818 0 1.001 0.423 0.000000 33.7 # 2985 2985 0 0.983 0.424 0.000000 33.7 # 3162 3162 0 1.056 0.431 0.000000 33.8 # 3350 3350 0 0.995 0.431 0.000000 33.7 # 3548 3548 0 1.012 0.434 0.000000 33.7 # 3758 3758 0 0.997 0.435 0.000000 33.7 # 3981 3981 0 1.122 0.600 0.000000 33.8 # 4217 4217 0 1.111 0.427 0.000000 33.8 # 4467 4467 0 1.000 0.423 0.000000 33.8 # 4732 4732 0 1.023 0.429 0.000000 33.8 # 5012 5012 0 1.016 0.435 0.000000 33.8 # 5309 5309 0 1.012 0.491 0.000000 33.8 # 5623 5623 0 1.489 0.473 0.000000 33.8 # 5957 5957 0 1.029 0.456 0.000000 33.7 # 6310 6310 0 1.056 0.456 0.000000 33.6 # 6683 6683 0 1.093 0.463 0.000000 33.5 # 7079 7079 0 1.102 0.469 0.000000 33.5 # 7499 7499 0 1.040 0.472 0.000000 33.3 # 7943 7943 0 1.069 0.425 0.000000 33.2 # 8414 8414 0 1.042 0.427 0.000000 33.1 # 8913 8913 0 1.375 0.433 0.000000 33.0 # 9441 9441 0 1.063 0.434 0.000000 32.9 # 10000 10000 0 1.042 0.437 0.000000 32.8 # 10593 10593 0 1.068 0.499 0.000000 32.7 # 11220 11220 0 1.071 0.437 0.000000 32.6 # 11885 11885 0 1.010 0.459 0.000000 32.4 # 12589 12589 0 1.064 0.444 0.000000 32.3 # 13335 13335 0 1.042 0.445 0.000000 32.2 # 14125 14125 0 1.053 0.456 0.000000 32.1 # 14962 14962 0 1.092 0.448 0.000000 32.0 # 15849 15849 0 1.049 0.449 0.000000 31.9 # 16788 16788 0 1.065 0.495 0.000000 31.8 # 17783 17783 0 1.087 0.478 0.000000 31.7 # 18836 18836 0 1.064 0.458 0.000000 31.7 # 19953 19953 0 1.059 0.467 0.000000 31.6 # 21135 21135 0 1.087 0.469 0.000000 31.5 # 22387 22387 0 1.091 0.507 0.000000 31.5 # 23714 23714 0 1.116 0.504 0.000000 31.4 # 25119 25119 0 1.108 0.483 0.000000 31.4 # 26607 26607 0 1.093 0.499 0.000000 31.3 # 28184 28184 0 1.104 0.524 0.000000 31.2 # 29854 29854 0 1.129 0.517 0.000000 31.2 # 31623 31623 0 1.115 0.516 0.000000 31.1 # 33497 33497 0 1.230 0.520 0.000000 31.1 # 35481 35481 0 1.110 0.544 0.000000 31.0 # 37584 37584 0 1.147 0.542 0.000000 30.9 # 39811 39811 0 1.141 0.574 0.000000 30.8 # 42170 42170 0 1.134 0.552 0.000000 30.8 # 44668 44668 0 1.232 0.600 0.000000 30.7 # 47315 47315 0 1.183 0.604 0.000000 30.7 # 50119 50119 0 1.230 0.601 0.000000 30.7 # 53088 53088 0 1.216 0.589 0.000000 30.6 # 56234 56234 0 1.176 0.621 0.000000 30.6 # 59566 59566 0 1.178 0.601 0.000000 30.5 # 63096 63096 0 1.183 0.616 0.000000 30.5 # 66834 66834 0 1.205 0.643 0.000000 30.5 # 70795 70795 0 1.207 0.644 0.000000 30.5 # 74989 74989 0 1.214 0.634 0.000000 30.4 # 79433 79433 0 1.270 0.643 0.000000 30.4 # 84140 84140 0 1.263 0.652 0.000000 30.4 # 89125 89125 0 1.269 0.660 0.000000 30.4 # 94406 94406 0 1.342 0.683 0.000000 30.5 # 100000 100000 0 1.403 0.699 0.000000 30.7 # 105925 100000 0 1.350 0.699 0.000000 30.8 # 112202 100000 0 1.378 0.705 0.000000 31.0 # 118850 100000 0 1.390 0.700 0.000000 31.2 # 125893 100000 0 1.405 0.710 0.000000 31.4 # 133352 100000 0 1.534 0.727 0.000000 31.5 # 141254 100000 0 1.375 0.730 0.000000 31.7 # 149624 100000 0 1.378 0.739 0.000000 31.8 # 158489 100000 0 1.603 0.740 0.000000 31.9 # 167880 100000 0 1.325 0.751 0.000000 31.9 # 177828 100000 0 1.322 0.755 0.000000 32.0 # 188365 100000 0 1.333 0.760 0.000000 32.0 # 199526 100000 0 1.312 0.760 0.000000 32.1 # 211349 100000 0 1.326 0.768 0.000000 32.1 # 223872 100000 0 1.320 0.787 0.000000 32.1 # 237137 100000 0 1.304 0.778 0.000000 32.1 # 251189 100000 0 1.368 0.769 0.000000 32.1 # 266073 100000 0 1.324 0.795 0.000000 32.1 # 281838 100000 0 1.323 0.800 0.000000 32.1 # 298538 100000 0 1.336 0.827 0.000000 32.0 # 316228 100000 0 1.349 0.812 0.000000 32.0 # 334965 100000 0 1.330 0.816 0.000000 32.0 # 354813 100000 0 1.330 0.816 0.000000 32.0 # 375837 100000 0 1.358 0.798 0.000000 32.1 # 398107 100000 0 1.483 0.827 0.000000 32.1 # 421697 100000 0 1.354 0.832 0.000000 32.2 # 446684 100000 0 1.353 0.837 0.000000 32.2 # 473151 100000 0 1.365 0.839 0.000000 32.3 # 501187 100000 0 1.542 0.846 0.000000 32.3 # 530884 100000 0 1.345 0.844 0.000000 32.4 # 562341 100000 0 1.357 0.825 0.000000 32.4 # 595662 100000 0 1.338 0.830 0.000000 32.5 # 630957 100000 0 1.349 0.818 0.000000 32.5 # 668344 100000 0 1.338 0.825 0.000000 32.5 # 707946 100000 0 1.328 0.817 0.000000 32.5 # 749894 100000 0 1.331 0.821 0.000000 32.5 # 794328 100000 0 1.327 0.818 0.000000 32.5 # 841395 100000 0 1.342 0.820 0.000000 32.4 # 891251 100000 0 1.318 0.813 0.000000 32.4 # 944061 100000 0 1.326 0.814 0.000000 32.4 # 1000000 100000 0 1.316 0.812 0.000000 32.3 # 1059254 100000 0 1.310 0.810 0.000000 32.3 # 1122018 100000 0 1.309 0.808 0.000000 32.2 # 1188502 100000 0 1.506 0.932 0.000000 32.1 # 1258925 100000 0 1.468 0.810 0.000000 32.0 # 1333521 100000 0 1.493 0.919 0.000000 32.0 # 1412538 100000 0 1.445 0.913 0.000000 31.9 # 1496236 100000 0 1.428 0.908 0.000000 31.8 # 1584893 100000 0 1.422 0.890 0.000000 31.7 # 1678804 100000 0 1.396 0.884 0.000000 31.7 # 1778279 100000 0 1.385 0.824 0.000000 31.6 # 1883649 100000 0 1.434 0.876 0.000000 31.5 # 1995262 100000 0 1.415 0.868 0.000000 31.5 # 2113489 100000 0 1.364 0.850 0.000000 31.4 # 2238721 100000 0 1.376 0.843 0.000000 31.3 # 2371374 100000 0 1.380 0.838 0.000000 31.3 # 2511886 100000 0 1.389 0.851 0.000000 31.2 # 2660725 100000 0 1.380 0.847 0.000000 31.2 # 2818383 100000 0 1.382 0.854 0.000000 31.1 # 2985383 100000 0 1.388 0.861 0.000000 31.0 # 3162278 100000 0 1.399 0.865 0.000000 31.0 # 3349654 100000 0 1.425 0.872 0.000000 30.9 # 3548134 100000 0 1.413 0.882 0.000000 30.8 # 3758374 100000 0 1.431 0.885 0.000000 30.8 # 3981072 100000 0 1.428 0.920 0.000000 30.7 # 4216965 100000 0 1.444 0.902 0.000000 30.6 # 4466836 100000 0 1.468 0.916 0.000000 30.5 # 4731513 100000 0 1.466 0.924 0.000000 30.5 # 5011872 100000 0 1.468 0.930 0.000000 30.4 # 5308844 100000 0 1.476 0.944 0.000000 30.3 # 5623413 100000 0 1.482 0.952 0.000000 30.2 # 5956621 100000 0 1.484 0.962 0.000000 30.1 # 6309573 100000 0 1.496 0.983 0.000000 30.1 # 6683439 100000 0 1.530 0.976 0.000000 30.0 # 7079458 100000 0 1.514 1.006 0.000000 29.9 # 7498942 100000 0 1.564 1.007 0.000000 29.9 # 7943282 100000 0 1.550 1.016 0.000000 29.8 # 8413951 100000 0 1.575 1.036 0.000000 29.7 # 8912509 100000 0 1.659 1.038 0.000000 29.7 # 9440609 100000 0 1.630 1.045 0.000000 29.6 # 10000000 100000 0 1.612 1.180 0.000000 29.6 # 10592537 100000 0 1.629 1.073 0.000000 29.5 # 11220185 100000 0 1.650 1.085 0.000000 29.5 # 11885022 100000 0 1.663 1.101 0.000000 29.5 # 12589254 100000 0 5.162 1.354 0.000000 29.4 # 13335214 100000 0 1.689 1.138 0.000000 29.4 # 14125375 100000 0 1.700 1.138 0.000000 29.3 # 14962357 100000 0 1.695 1.149 0.000000 29.3 # Total Duplicate strings = 0 # Begin JudyHSFreeArray()... # returned 438636072 bytes # Free 14962357 strings, 0.621 uSecs Ave/string # Pass 1 # Pass 2 # Pass 3 # Pass 4 # Pass 5 # Pass 6 # Pass 7 # Pass 8 # Pass 9 # TotInserts 0 0 InsTime GetTime 0 Ram/String 1 0 0 6.463 1.451 0 48.000 2 0 0 2.444 0.246 0 44.000 3 0 0 0.955 0.235 0 41.333 4 0 0 0.855 0.227 0 42.000 5 0 0 0.794 0.230 0 38.400 6 0 0 0.836 0.230 0 36.000 7 0 0 0.910 0.230 0 35.429 8 0 0 0.887 0.227 0 34.000 9 0 0 0.791 0.225 0 32.889 10 0 0 0.724 0.232 0 34.400 11 0 0 0.818 0.227 0 33.818 12 0 0 0.838 0.232 0 34.000 13 0 0 0.856 0.242 0 36.923 14 0 0 0.705 0.238 0 36.000 15 0 0 0.855 0.238 0 35.467 16 0 0 0.866 0.240 0 35.500 17 0 0 0.858 0.239 0 35.059 18 0 0 0.724 0.249 0 35.111 19 0 0 0.824 0.248 0 34.947 20 0 0 0.924 0.245 0 34.800 21 0 0 0.828 0.247 0 35.238 22 0 0 0.690 0.246 0 35.091 23 0 0 0.827 0.246 0 36.522 24 0 0 0.848 0.248 0 36.167 25 0 0 0.687 0.252 0 36.000 26 0 0 0.712 0.250 0 35.846 27 0 0 0.812 0.249 0 36.000 28 0 0 0.813 0.249 0 35.714 29 0 0 0.858 0.258 0 35.862 30 0 0 0.747 0.252 0 35.600 31 0 0 0.744 0.253 0 35.097 32 0 0 0.789 0.254 0 34.875 34 0 0 0.879 0.251 0 35.059 36 0 0 0.858 0.258 0 34.667 38 0 0 0.807 0.258 0 35.158 40 0 0 0.785 0.260 0 35.300 42 0 0 0.741 0.263 0 34.667 44 0 0 0.852 0.263 0 36.364 46 0 0 0.855 0.262 0 36.261 48 0 0 0.846 0.267 0 35.750 50 0 0 0.752 0.264 0 35.520 53 0 0 0.805 0.265 0 34.868 56 0 0 0.857 0.269 0 35.071 59 0 0 0.744 0.268 0 34.847 62 0 0 0.776 0.269 0 35.032 65 0 0 0.866 0.267 0 34.646 69 0 0 0.744 0.269 0 34.493 73 0 0 0.835 0.270 0 35.397 77 0 0 0.833 0.268 0 35.273 81 0 0 0.857 0.268 0 34.667 85 0 0 0.811 0.272 0 34.494 90 0 0 0.797 0.269 0 34.489 95 0 0 0.739 0.270 0 33.979 100 0 0 0.787 0.269 0 33.800 106 0 0 0.789 0.270 0 33.547 112 0 0 0.828 0.271 0 33.643 118 0 0 0.864 0.271 0 33.797 125 0 0 0.789 0.276 0 33.248 132 0 0 0.809 0.273 0 33.030 139 0 0 0.839 0.278 0 32.835 147 0 0 0.884 0.276 0 33.252 155 0 0 0.857 0.278 0 32.955 164 0 0 0.850 0.282 0 32.756 173 0 0 0.832 0.281 0 32.462 183 0 0 0.806 0.282 0 31.825 194 0 0 0.844 0.284 0 31.918 205 0 0 0.803 0.282 0 31.493 217 0 0 0.903 0.285 0 31.982 230 0 0 0.867 0.286 0 31.948 243 0 0 0.821 0.287 0 31.802 257 0 0 0.804 0.287 0 31.658 272 0 0 0.876 0.291 0 31.721 288 0 0 0.866 0.287 0 31.792 305 0 0 0.848 0.287 0 31.921 323 0 0 0.998 0.296 0 31.554 342 0 0 0.991 0.291 0 32.281 362 0 0 1.032 0.296 0 32.829 383 0 0 0.924 0.297 0 32.595 405 0 0 0.983 0.298 0 32.523 429 0 0 0.934 0.299 0 32.606 454 0 0 0.850 0.313 0 33.172 480 0 0 1.039 0.306 0 33.008 508 0 0 0.984 0.306 0 33.535 538 0 0 1.012 0.306 0 33.375 569 0 0 0.857 0.307 0 33.230 602 0 0 0.913 0.306 0 33.289 637 0 0 0.876 0.306 0 33.300 674 0 0 0.946 0.307 0 33.193 714 0 0 0.935 0.309 0 33.395 756 0 0 1.006 0.308 0 33.302 800 0 0 0.925 0.307 0 33.255 847 0 0 0.908 0.310 0 33.818 897 0 0 0.913 0.308 0 33.779 950 0 0 0.901 0.310 0 33.625 1006 0 0 0.866 0.310 0 33.435 1065 0 0 0.842 0.310 0 33.510 1128 0 0 0.880 0.312 0 33.394 1194 0 0 0.875 0.312 0 33.320 1264 0 0 0.855 0.314 0 33.278 1339 0 0 0.845 0.313 0 33.177 1418 0 0 0.857 0.314 0 33.078 1502 0 0 0.903 0.318 0 33.190 1591 0 0 0.899 0.319 0 33.360 1685 0 0 0.924 0.320 0 33.496 1784 0 0 0.898 0.320 0 33.404 1884 0 0 0.917 0.322 0 33.231 1995 0 0 0.885 0.324 0 33.211 2113 0 0 0.883 0.323 0 33.304 2239 0 0 0.851 0.324 0 33.402 2371 0 0 0.901 0.329 0 33.407 2512 0 0 0.937 0.328 0 33.460 2661 0 0 0.965 0.420 0 33.514 2818 0 0 0.986 0.419 0 33.469 2985 0 0 0.983 0.422 0 33.324 3162 0 0 0.992 0.426 0 33.264 3350 0 0 0.971 0.430 0 33.398 3548 0 0 0.982 0.434 0 33.359 3758 0 0 0.997 0.435 0 33.420 3981 0 0 0.999 0.440 0 33.516 4217 0 0 0.981 0.427 0 33.525 4467 0 0 1.000 0.420 0 33.595 4732 0 0 0.957 0.425 0 33.515 5012 0 0 0.950 0.435 0 33.534 5309 0 0 0.993 0.439 0 33.481 5623 0 0 0.971 0.441 0 33.435 5957 0 0 0.948 0.446 0 33.427 6310 0 0 0.982 0.451 0 33.374 6683 0 0 0.968 0.458 0 33.235 7079 0 0 0.963 0.469 0 33.154 7499 0 0 0.999 0.468 0 33.120 7943 0 0 1.007 0.425 0 33.031 8414 0 0 0.977 0.427 0 32.928 8913 0 0 1.039 0.433 0 32.851 9441 0 0 1.031 0.434 0 32.744 10000 0 0 1.010 0.437 0 32.649 10593 0 0 1.050 0.487 0 32.585 11220 0 0 1.007 0.437 0 32.440 11885 0 0 1.010 0.437 0 32.312 12589 0 0 0.973 0.440 0 32.236 13335 0 0 0.991 0.445 0 32.098 14125 0 0 0.984 0.444 0 31.988 14962 0 0 1.092 0.447 0 31.878 15849 0 0 0.994 0.444 0 31.790 16788 0 0 0.985 0.447 0 31.697 17783 0 0 0.994 0.451 0 31.628 18836 0 0 1.007 0.455 0 31.562 19953 0 0 1.002 0.459 0 31.544 21135 0 0 1.016 0.469 0 31.482 22387 0 0 1.016 0.474 0 31.438 23714 0 0 1.019 0.475 0 31.371 25119 0 0 1.052 0.483 0 31.315 26607 0 0 1.026 0.493 0 31.245 28184 0 0 1.033 0.496 0 31.192 29854 0 0 1.048 0.499 0 31.114 31623 0 0 1.053 0.510 0 31.061 33497 0 0 1.092 0.520 0 31.005 35481 0 0 1.075 0.527 0 30.960 37584 0 0 1.095 0.535 0 30.904 39811 0 0 1.127 0.543 0 30.849 42170 0 0 1.089 0.552 0 30.757 44668 0 0 1.119 0.559 0 30.711 47315 0 0 1.113 0.566 0 30.671 50119 0 0 1.129 0.576 0 30.635 53088 0 0 1.144 0.589 0 30.635 56234 0 0 1.171 0.597 0 30.595 59566 0 0 1.146 0.601 0 30.567 63096 0 0 1.152 0.607 0 30.533 66834 0 0 1.155 0.617 0 30.465 70795 0 0 1.172 0.629 0 30.434 74989 0 0 1.214 0.634 0 30.390 79433 0 0 1.199 0.643 0 30.414 84140 0 0 1.219 0.652 0 30.395 89125 0 0 1.238 0.658 0 30.416 94406 0 0 1.272 0.671 0 30.521 100000 0 0 1.300 0.672 0 30.589 105925 0 0 1.326 0.699 0 30.778 112202 0 0 1.363 0.705 0 31.016 118850 0 0 1.353 0.698 0 31.189 125893 0 0 1.351 0.702 0 31.389 133352 0 0 1.334 0.710 0 31.545 141254 0 0 1.312 0.710 0 31.709 149624 0 0 1.314 0.719 0 31.804 158489 0 0 1.286 0.731 0 31.886 167880 0 0 1.292 0.724 0 31.953 177828 0 0 1.269 0.733 0 32.006 188365 0 0 1.277 0.739 0 32.049 199526 0 0 1.277 0.742 0 32.057 211349 0 0 1.275 0.742 0 32.075 223872 0 0 1.260 0.750 0 32.078 237137 0 0 1.267 0.765 0 32.081 251189 0 0 1.270 0.761 0 32.079 266073 0 0 1.271 0.769 0 32.075 281838 0 0 1.276 0.772 0 32.063 298538 0 0 1.277 0.778 0 32.058 316228 0 0 1.316 0.788 0 32.033 334965 0 0 1.286 0.784 0 32.016 354813 0 0 1.294 0.788 0 32.052 375837 0 0 1.306 0.791 0 32.083 398107 0 0 1.305 0.785 0 32.123 421697 0 0 1.349 0.797 0 32.168 446684 0 0 1.314 0.794 0 32.219 473151 0 0 1.336 0.805 0 32.273 501187 0 0 1.304 0.806 0 32.318 530884 0 0 1.341 0.812 0 32.371 562341 0 0 1.318 0.813 0 32.419 595662 0 0 1.308 0.816 0 32.453 630957 0 0 1.297 0.818 0 32.474 668344 0 0 1.283 0.823 0 32.484 707946 0 0 1.328 0.817 0 32.481 749894 0 0 1.282 0.821 0 32.470 794328 0 0 1.324 0.818 0 32.449 841395 0 0 1.318 0.820 0 32.417 891251 0 0 1.317 0.813 0 32.375 944061 0 0 1.319 0.814 0 32.329 1000000 0 0 1.294 0.812 0 32.282 1059254 0 0 1.310 0.810 0 32.222 1122018 0 0 1.303 0.808 0 32.158 1188502 0 0 1.302 0.823 0 32.085 1258925 0 0 1.267 0.810 0 32.009 1333521 0 0 1.246 0.813 0 31.930 1412538 0 0 1.254 0.819 0 31.848 1496236 0 0 1.250 0.819 0 31.772 1584893 0 0 1.257 0.827 0 31.698 1678804 0 0 1.261 0.822 0 31.623 1778279 0 0 1.278 0.824 0 31.553 1883649 0 0 1.280 0.871 0 31.491 1995262 0 0 1.325 0.844 0 31.428 2113489 0 0 1.325 0.841 0 31.372 2238721 0 0 1.298 0.843 0 31.313 2371374 0 0 1.314 0.838 0 31.254 2511886 0 0 1.319 0.851 0 31.196 2660725 0 0 1.330 0.847 0 31.136 2818383 0 0 1.332 0.854 0 31.073 2985383 0 0 1.356 0.861 0 31.009 3162278 0 0 1.375 0.865 0 30.943 3349654 0 0 1.374 0.872 0 30.874 3548134 0 0 1.370 0.882 0 30.803 3758374 0 0 1.388 0.885 0 30.729 3981072 0 0 1.378 0.894 0 30.654 4216965 0 0 1.382 0.902 0 30.578 4466836 0 0 1.394 0.904 0 30.500 4731513 0 0 1.421 0.924 0 30.422 5011872 0 0 1.431 0.930 0 30.343 5308844 0 0 1.437 0.944 0 30.265 5623413 0 0 1.443 0.952 0 30.188 5956621 0 0 1.453 0.962 0 30.113 6309573 0 0 1.444 0.974 0 30.042 6683439 0 0 1.459 0.976 0 29.974 7079458 0 0 1.480 0.985 0 29.909 7498942 0 0 1.489 1.007 0 29.848 7943282 0 0 1.506 1.016 0 29.789 8413951 0 0 1.519 1.017 0 29.731 8912509 0 0 1.527 1.038 0 29.677 9440609 0 0 1.547 1.045 0 29.624 10000000 0 0 1.553 1.061 0 29.573 10592537 0 0 1.576 1.073 0 29.527 11220185 0 0 1.590 1.082 0 29.484 11885022 0 0 1.603 1.086 0 29.444 12589254 0 0 1.603 1.103 0 29.407 13335214 0 0 1.621 1.105 0 29.373 14125375 0 0 1.636 1.120 0 29.343 14962357 0 0 1.646 1.137 0 29.316 judy-1.0.5/test/Centrino_1.3Mhz_Plots/Hash_CO.plot0000644000175000017500000010564310204462077022054 0ustar troyhebetroyhebe# StringCompare -n14962357 -A Hash -H1048576 -P40 -L10 -C -M100000 /home/data/domnames.txt # This file is in a format to input to 'jbgraph' # XLABEL Stored # YLABEL Microseconds / Index # COLHEAD 1 Total Insert attempts # COLHEAD 2 Number Gets # COLHEAD 3 Duplicate strings # COLHEAD 4 Insert Time (uS) # COLHEAD 5 Get Time (uS) # COLHEAD 6 Hash Chain Length # COLHEAD 7 Average RAM/String # Linux localhost 2.6.3-4mdkenterprise #1 SMP Tue Mar 2 07:00:53 CET 2004 i686 # 32 Bit CPU # Processor speed compiled at 1299 Mhz # Hash record struct: sizeof(hrec_t) = 16 # Allocate Hash table = 1048576 elements # 11218731 (75.0%) non-Word_t aligned string buffers # Ram used for input data = 372621771 bytes # Average string length = 15.9 bytes # 3200000 bytes malloc() for 'cached' strings for Get measurement # Access Time = 0.103 uS average per string (mostly from Cache) # HashStr() Time = 0.270 uS average per string (mostly from Cache) # Access Time = 0.287 uS average per string (mostly from RAM) # HashStr() Time = 0.477 uS average per string (mostly from RAM) # Pass 0 # TotInserts DeltaGets DupStrs InsTime GetTime HChainLen Ram/String # 1 1 0 5775.911 1.182 1.000000 4194356.0 # 2 2 0 3.406 0.417 1.000000 2097190.0 # 3 3 0 1.251 0.374 1.000000 1398136.0 # 4 4 0 1.465 0.380 1.000000 1048610.0 # 5 5 0 1.154 0.363 1.000000 838893.6 # 6 6 0 0.996 0.347 1.000000 699082.0 # 7 7 0 1.109 0.356 1.000000 599217.7 # 8 8 0 1.564 0.347 1.000000 524318.5 # 9 9 0 1.189 0.355 1.000000 466064.4 # 10 10 0 1.176 0.352 1.000000 419460.8 # 11 11 0 1.268 0.359 1.000000 381330.9 # 12 12 0 1.264 0.364 1.000000 349556.0 # 13 13 0 1.357 0.363 1.000000 322669.2 # 14 14 0 1.467 0.364 1.000000 299623.7 # 15 15 0 1.070 0.366 1.000000 279650.9 # 16 16 0 1.404 0.375 1.000000 262175.0 # 17 17 0 1.544 0.367 1.000000 246754.4 # 18 18 0 0.851 0.364 1.000000 233047.1 # 19 19 0 1.139 0.366 1.000000 220783.2 # 20 20 0 1.238 0.366 1.000000 209745.4 # 21 21 0 1.195 0.363 1.000000 199758.9 # 22 22 0 1.176 0.365 1.000000 190680.4 # 23 23 0 13.957 0.366 1.000000 182391.1 # 24 24 0 1.159 0.361 1.000000 174792.5 # 25 25 0 1.288 0.356 1.000000 167801.8 # 26 26 0 1.179 0.357 1.000000 161348.9 # 27 27 0 1.204 0.361 1.000000 155374.4 # 28 28 0 1.125 0.359 1.000000 149826.1 # 29 29 0 1.052 0.359 1.000000 144660.8 # 30 30 0 2.443 0.368 1.000000 139839.6 # 31 31 0 1.527 0.368 1.000000 135330.2 # 32 32 0 1.390 0.365 1.000000 131102.0 # 34 34 0 1.179 0.365 1.000000 123391.6 # 36 36 0 1.034 0.366 1.000000 116538.3 # 38 38 0 1.010 0.368 1.000000 110406.4 # 40 40 0 1.142 0.367 1.000000 104887.5 # 42 42 0 0.941 0.366 1.000000 99894.2 # 44 44 0 1.292 0.368 1.000000 95355.0 # 46 46 0 1.072 0.369 1.000000 91210.5 # 48 48 0 0.946 0.365 1.000000 87411.2 # 50 50 0 1.057 0.375 1.000000 83916.0 # 53 53 0 1.134 0.368 1.000000 79168.0 # 56 56 0 1.022 0.367 1.000000 74928.4 # 59 59 0 0.736 0.364 1.000000 71119.7 # 62 62 0 1.059 0.364 1.000000 67680.0 # 65 65 0 1.049 0.364 1.000000 64557.7 # 69 69 0 1.011 0.365 1.000000 60816.9 # 73 73 0 0.864 0.359 1.000000 57485.9 # 77 77 0 0.998 0.359 1.000000 54501.0 # 81 81 0 0.989 0.361 1.000000 51811.2 # 85 85 0 0.977 0.362 1.000000 49374.4 # 90 90 0 1.068 0.369 1.000000 46633.3 # 95 95 0 0.741 0.366 1.000000 44180.3 # 100 100 0 0.886 0.364 1.000000 41972.7 # 106 106 0 0.892 0.362 1.000000 39598.4 # 112 112 0 0.932 0.361 1.000000 37478.6 # 118 118 0 0.902 0.363 1.000000 35574.5 # 125 125 0 0.973 0.363 1.000000 33584.0 # 132 132 0 1.011 0.362 1.000000 31804.5 # 139 139 0 1.878 0.366 1.000000 30204.3 # 147 147 0 0.888 0.361 1.000000 28562.1 # 155 155 0 1.028 0.362 1.000000 27089.4 # 164 164 0 0.903 2.031 1.000000 25604.5 # 173 173 0 1.077 0.372 1.000000 24273.9 # 183 183 0 0.920 0.362 1.000000 22949.1 # 194 194 0 0.882 0.364 1.000000 21649.6 # 205 205 0 0.909 0.363 1.000000 20489.5 # 217 217 0 0.903 0.363 1.000000 19358.1 # 230 230 0 0.888 0.362 1.000000 18265.5 # 243 243 0 0.885 0.360 1.000000 17289.9 # 257 257 0 1.200 0.360 1.000000 16349.6 # 272 272 0 1.403 0.362 1.000000 15449.7 # 288 288 0 0.915 0.368 1.000000 14593.1 # 305 305 0 0.926 0.365 1.000000 13781.5 # 323 323 0 0.933 0.366 1.000000 13015.2 # 342 342 0 0.931 0.387 1.000000 12293.8 # 362 362 0 0.889 0.367 1.000000 11616.2 # 383 383 0 1.089 0.367 1.000000 10981.0 # 405 405 0 0.866 0.368 1.000000 10386.1 # 429 429 0 0.915 0.368 1.000000 9806.8 # 454 454 0 0.875 0.369 1.000000 9268.3 # 480 480 0 0.898 0.366 1.000000 8767.9 # 508 508 0 1.044 0.380 1.000000 8286.3 # 538 538 0 0.859 0.368 1.000000 7825.8 # 569 569 0 0.917 0.366 1.000000 7401.0 # 602 602 0 0.987 0.365 1.000000 6996.9 # 637 637 0 0.888 0.364 1.000000 6614.1 # 674 674 0 0.918 0.375 1.001484 6252.6 # 714 714 0 0.983 0.367 1.001401 5904.0 # 756 756 0 0.860 0.373 1.001323 5577.6 # 800 800 0 0.874 0.365 1.001250 5272.5 # 847 847 0 0.963 0.372 1.001181 4981.5 # 897 897 0 0.883 0.363 1.001115 4705.5 # 950 950 0 0.968 0.372 1.001053 4444.6 # 1006 1006 0 0.911 0.364 1.000994 4198.8 # 1065 1065 0 1.088 0.366 1.001878 3967.9 # 1128 1128 0 0.888 0.369 1.001773 3747.9 # 1194 1194 0 0.942 0.372 1.001675 3542.4 # 1264 1264 0 0.864 0.365 1.001582 3347.8 # 1339 1339 0 0.908 0.367 1.001494 3162.0 # 1418 1418 0 0.913 0.366 1.001410 2987.4 # 1502 1502 0 0.849 0.367 1.001332 2822.0 # 1591 1591 0 0.922 0.369 1.001257 2665.8 # 1685 1685 0 0.903 0.369 1.001187 2518.7 # 1784 1784 0 0.880 0.370 1.001121 2380.6 # 1884 1884 0 0.879 0.375 1.001062 2255.7 # 1995 1995 0 0.921 0.388 1.001504 2131.9 # 2113 2113 0 0.895 0.379 1.001420 2014.5 # 2239 2239 0 0.858 0.380 1.001340 1902.7 # 2371 2371 0 0.884 0.386 1.001265 1798.4 # 2512 2512 0 0.918 0.392 1.001194 1699.1 # 2661 2661 0 0.865 0.411 1.001503 1605.6 # 2818 2818 0 0.897 0.407 1.002129 1517.8 # 2985 2985 0 0.859 0.444 1.002010 1434.5 # 3162 3162 0 0.931 0.439 1.001898 1355.9 # 3350 3350 0 0.863 0.428 1.002388 1281.5 # 3548 3548 0 0.879 0.434 1.002537 1211.6 # 3758 3758 0 0.934 0.450 1.002661 1145.5 # 3981 3981 0 0.908 0.459 1.002763 1083.0 # 4217 4217 0 0.908 0.469 1.003083 1024.1 # 4467 4467 0 0.905 0.477 1.002910 968.4 # 4732 4732 0 0.869 0.487 1.002747 915.8 # 5012 5012 0 0.918 0.499 1.003192 866.3 # 5309 5309 0 0.868 0.508 1.003390 819.5 # 5623 5623 0 0.887 0.515 1.003913 775.4 # 5957 5957 0 0.906 0.520 1.004532 733.6 # 6310 6310 0 0.887 0.559 1.004596 694.2 # 6683 6683 0 0.916 0.532 1.004788 657.1 # 7079 7079 0 0.897 0.535 1.004662 622.0 # 7499 7499 0 0.904 0.544 1.004534 588.8 # 7943 7943 0 0.911 0.618 1.004658 557.5 # 8414 8414 0 0.918 0.559 1.004635 528.0 # 8913 8913 0 1.030 0.614 1.004937 500.1 # 9441 9441 0 0.989 0.551 1.005614 473.7 # 10000 10000 0 0.930 0.552 1.005500 448.9 # 10593 10593 0 0.923 0.629 1.005947 425.4 # 11220 11220 0 0.929 0.556 1.005793 403.3 # 11885 11885 0 0.914 0.574 1.005890 382.4 # 12589 12589 0 0.906 0.583 1.006116 362.6 # 13335 13335 0 0.919 0.561 1.006224 344.0 # 14125 14125 0 0.912 0.576 1.006796 326.4 # 14962 14962 0 1.057 0.565 1.007018 309.8 # 15849 15849 0 0.903 0.568 1.007193 294.1 # 16788 16788 0 0.896 0.575 1.007744 279.3 # 17783 17783 0 1.004 0.572 1.008154 265.3 # 18836 18836 0 0.908 0.575 1.008335 252.1 # 19953 19953 0 0.918 0.593 1.008871 239.6 # 21135 21135 0 0.913 0.580 1.009558 227.9 # 22387 22387 0 0.911 0.593 1.010184 216.8 # 23714 23714 0 0.910 0.598 1.010880 206.3 # 25119 25119 0 0.901 0.605 1.011744 196.4 # 26607 26607 0 0.919 0.590 1.012553 187.1 # 28184 28184 0 0.896 0.598 1.013163 178.2 # 29854 29854 0 0.888 0.603 1.013633 169.9 # 31623 31623 0 1.012 0.597 1.014704 162.1 # 33497 33497 0 0.889 0.608 1.015554 154.6 # 35481 35481 0 0.902 0.617 1.016319 147.6 # 37584 37584 0 0.895 0.605 1.017481 141.0 # 39811 39811 0 0.896 0.617 1.018337 134.8 # 42170 42170 0 0.892 0.609 1.019753 128.9 # 44668 44668 0 0.893 0.617 1.021201 123.3 # 47315 47315 0 0.895 0.613 1.022678 118.1 # 50119 50119 0 0.894 0.627 1.024322 113.1 # 53088 53088 0 0.891 0.618 1.025599 108.4 # 56234 56234 0 0.937 0.632 1.026728 104.0 # 59566 59566 0 0.886 0.625 1.027734 99.8 # 63096 63096 0 1.071 0.627 1.029923 95.9 # 66834 66834 0 0.927 0.635 1.031825 92.2 # 70795 70795 0 0.883 0.634 1.033703 88.7 # 74989 74989 0 0.914 0.631 1.035152 85.4 # 79433 79433 0 0.879 0.632 1.037453 82.2 # 84140 84140 0 0.887 0.635 1.039458 79.3 # 89125 89125 0 0.884 0.636 1.042098 76.5 # 94406 94406 0 0.885 0.638 1.044764 73.8 # 100000 100000 0 0.881 0.639 1.047350 71.3 # 105925 100000 0 0.884 0.640 1.050080 69.0 # 112202 100000 0 0.919 0.662 1.053600 66.8 # 118850 100000 0 0.897 0.647 1.057100 64.7 # 125893 100000 0 0.901 0.652 1.059820 62.7 # 133352 100000 0 0.884 0.651 1.063240 60.9 # 141254 100000 0 0.888 0.650 1.067290 59.1 # 149624 100000 0 0.916 0.653 1.071780 57.4 # 158489 100000 0 0.940 0.657 1.075130 55.9 # 167880 100000 0 0.913 0.659 1.082310 54.4 # 177828 100000 0 0.899 0.671 1.085360 53.0 # 188365 100000 0 0.897 0.664 1.090720 51.7 # 199526 100000 0 0.915 0.668 1.096770 50.4 # 211349 100000 0 0.928 0.665 1.101930 49.3 # 223872 100000 0 0.934 0.670 1.108100 48.2 # 237137 100000 0 0.926 0.667 1.113690 47.1 # 251189 100000 0 0.955 0.675 1.119180 46.1 # 266073 100000 0 0.911 0.693 1.128930 45.2 # 281838 100000 0 0.918 0.676 1.136280 44.3 # 298538 100000 0 0.929 0.685 1.145900 43.5 # 316228 100000 0 0.922 0.686 1.153400 42.7 # 334965 100000 0 0.936 0.688 1.162440 41.9 # 354813 100000 0 0.956 0.694 1.172560 41.2 # 375837 100000 0 0.958 0.692 1.183690 40.6 # 398107 100000 0 0.959 0.699 1.193780 40.0 # 421697 100000 0 0.942 0.702 1.204740 39.4 # 446684 100000 0 0.955 0.700 1.215820 38.8 # 473151 100000 0 0.952 0.713 1.228310 38.3 # 501187 100000 0 0.962 0.713 1.241420 37.8 # 530884 100000 0 0.964 0.714 1.257920 37.3 # 562341 100000 0 0.979 0.711 1.272740 36.9 # 595662 100000 0 1.003 0.714 1.289160 36.5 # 630957 100000 0 1.015 0.722 1.303190 36.1 # 668344 100000 0 1.020 0.730 1.322380 35.7 # 707946 100000 0 1.026 0.737 1.341750 35.4 # 749894 100000 0 1.015 0.743 1.368090 35.0 # 794328 100000 0 1.019 0.744 1.384790 34.7 # 841395 100000 0 1.030 0.746 1.408600 34.4 # 891251 100000 0 1.045 0.753 1.434040 34.1 # 944061 100000 0 1.049 0.778 1.456490 33.9 # 1000000 100000 0 1.057 0.766 1.485870 33.6 # 1059254 100000 0 1.066 0.768 1.513600 33.4 # 1122018 100000 0 1.106 0.778 1.542830 33.2 # 1188502 100000 0 1.090 0.790 1.577200 33.0 # 1258925 100000 0 1.138 0.792 1.612530 32.8 # 1333521 100000 0 1.121 0.811 1.645650 32.6 # 1412538 100000 0 1.135 0.810 1.682130 32.4 # 1496236 100000 0 1.159 0.820 1.722840 32.2 # 1584893 100000 0 1.171 0.847 1.765690 32.1 # 1678804 100000 0 1.185 0.844 1.817750 31.9 # 1778279 100000 0 1.202 0.853 1.864700 31.8 # 1883649 100000 0 1.222 0.867 1.912490 31.7 # 1995262 100000 0 1.242 0.876 1.967780 31.5 # 2113489 100000 0 1.263 0.896 2.020420 31.4 # 2238721 100000 0 1.286 0.922 2.075790 31.3 # 2371374 100000 0 1.320 0.929 2.146300 31.2 # 2511886 100000 0 1.335 0.945 2.209570 31.1 # 2660725 100000 0 1.363 0.944 2.293110 31.0 # 2818383 100000 0 1.391 0.960 2.360800 30.9 # 2985383 100000 0 1.422 0.978 2.446730 30.8 # 3162278 100000 0 1.461 1.009 2.537540 30.8 # 3349654 100000 0 1.501 1.016 2.622900 30.7 # 3548134 100000 0 1.533 1.060 2.710860 30.6 # 3758374 100000 0 1.578 1.062 2.824550 30.5 # 3981072 100000 0 1.622 1.273 2.922530 30.5 # 4216965 100000 0 1.673 1.115 3.041830 30.4 # 4466836 100000 0 1.729 1.160 3.149510 30.4 # 4731513 100000 0 1.784 1.178 3.292520 30.3 # 5011872 100000 0 1.854 1.216 3.433090 30.3 # 5308844 100000 0 1.946 1.262 3.576600 30.2 # 5623413 100000 0 1.958 1.262 3.719150 30.2 # 5956621 100000 0 2.022 1.496 3.885680 30.1 # 6309573 100000 0 2.180 1.357 4.057750 30.1 # 6683439 100000 0 2.196 1.383 4.250390 30.1 # 7079458 100000 0 2.257 1.431 4.444160 30.0 # 7498942 100000 0 2.340 1.482 4.640880 30.0 # 7943282 100000 0 2.445 1.525 4.852800 29.9 # 8413951 100000 0 2.547 1.595 5.074780 29.9 # 8912509 100000 0 2.691 1.656 5.320130 29.9 # 9440609 100000 0 2.798 1.696 5.560000 29.9 # 10000000 100000 0 2.996 1.784 5.853460 29.8 # 10592537 100000 0 3.087 1.862 6.153020 29.8 # 11220185 100000 0 3.233 1.922 6.430500 29.8 # 11885022 100000 0 3.384 2.104 6.773630 29.8 # 12589254 100000 0 3.566 2.118 7.090330 29.7 # 13335214 100000 0 3.768 2.197 7.450920 29.7 # 14125375 100000 0 7.923 2.316 7.868460 29.7 # 14962357 100000 0 4.145 2.436 8.259020 29.7 # Total Duplicate strings = 0 # Begin HashFreeArray()... # returned 444133848 bytes # Free 14962357 strings, 0.312 uSecs Ave/string # Pass 1 # Pass 2 # Pass 3 # Pass 4 # Pass 5 # Pass 6 # Pass 7 # Pass 8 # Pass 9 # TotInserts 0 0 InsTime GetTime 0 Ram/String 1 0 0 5775.911 0.901 0 4194352.000 2 0 0 1.096 0.317 0 2097190.000 3 0 0 0.883 0.309 0 1398134.667 4 0 0 0.846 0.311 0 1048607.000 5 0 0 0.776 0.305 0 838890.400 6 0 0 0.911 0.296 0 699079.333 7 0 0 0.796 0.306 0 599215.429 8 0 0 0.711 0.302 0 524316.500 9 0 0 0.817 0.292 0 466061.333 10 0 0 0.633 0.295 0 419458.000 11 0 0 0.701 0.297 0 381328.000 12 0 0 0.732 0.307 0 349553.333 13 0 0 0.829 0.312 0 322667.385 14 0 0 0.778 0.317 0 299621.429 15 0 0 0.659 0.312 0 279648.267 16 0 0 0.871 0.319 0 262172.250 17 0 0 0.845 0.317 0 246752.000 18 0 0 0.851 0.321 0 233045.111 19 0 0 0.889 0.324 0 220781.263 20 0 0 0.923 0.329 0 209743.800 21 0 0 0.697 0.333 0 199757.905 22 0 0 0.646 0.329 0 190679.455 23 0 0 0.773 0.326 0 182390.261 24 0 0 1.035 0.325 0 174791.833 25 0 0 0.833 0.321 0 167801.120 26 0 0 0.834 0.323 0 161348.462 27 0 0 0.705 0.328 0 155373.778 28 0 0 0.666 0.331 0 149825.714 29 0 0 0.752 0.341 0 144660.414 30 0 0 0.728 0.342 0 139839.333 31 0 0 0.814 0.339 0 135329.290 32 0 0 0.931 0.339 0 131101.125 34 0 0 0.895 0.336 0 123391.412 36 0 0 0.888 0.339 0 116537.889 38 0 0 0.784 0.344 0 110406.526 40 0 0 0.985 0.348 0 104887.900 42 0 0 0.843 0.351 0 99894.381 44 0 0 0.914 0.348 0 95355.364 46 0 0 0.801 0.348 0 91210.609 48 0 0 0.875 0.347 0 87411.500 50 0 0 0.831 0.347 0 83916.240 53 0 0 0.856 0.346 0 79167.698 56 0 0 0.932 0.348 0 74928.286 59 0 0 0.736 0.346 0 71119.932 62 0 0 0.787 0.348 0 67680.000 65 0 0 0.862 0.348 0 64557.723 69 0 0 0.814 0.349 0 60817.043 73 0 0 0.864 0.350 0 57486.521 77 0 0 0.787 0.347 0 54501.662 81 0 0 0.900 0.351 0 51811.556 85 0 0 0.938 0.348 0 49374.824 90 0 0 0.947 0.347 0 46633.333 95 0 0 0.741 0.348 0 44180.337 100 0 0 0.844 0.347 0 41972.760 106 0 0 0.812 0.343 0 39598.604 112 0 0 0.899 0.347 0 37478.893 118 0 0 0.854 0.351 0 35574.508 125 0 0 0.914 0.351 0 33583.840 132 0 0 0.937 0.349 0 31804.333 139 0 0 0.902 0.352 0 30204.259 147 0 0 0.877 0.357 0 28562.122 155 0 0 0.853 0.358 0 27089.394 164 0 0 0.875 0.359 0 25604.463 173 0 0 0.833 0.359 0 24273.873 183 0 0 0.873 0.358 0 22948.962 194 0 0 0.848 0.357 0 21649.381 205 0 0 0.908 0.356 0 20489.190 217 0 0 0.876 0.358 0 19357.862 230 0 0 0.853 0.358 0 18265.443 243 0 0 0.884 0.358 0 17289.745 257 0 0 0.893 0.359 0 16349.479 272 0 0 0.857 0.358 0 15449.441 288 0 0 0.897 0.357 0 14592.708 305 0 0 0.848 0.356 0 13780.997 323 0 0 0.862 0.356 0 13014.625 342 0 0 0.891 0.357 0 12293.158 362 0 0 0.882 0.355 0 11615.613 383 0 0 0.876 0.356 0 10980.261 405 0 0 0.866 0.353 0 10385.363 429 0 0 0.863 0.353 0 9805.874 454 0 0 0.875 0.352 0 9267.436 480 0 0 0.881 0.351 0 8766.933 508 0 0 0.893 0.352 0 8285.331 538 0 0 0.859 0.352 0 7824.952 569 0 0 0.885 0.352 0 7400.239 602 0 0 0.881 0.354 0 6996.252 637 0 0 0.869 0.354 0 6613.495 674 0 0 0.887 0.356 0 6252.095 714 0 0 0.896 0.355 0 5903.445 756 0 0 0.860 0.356 0 5577.132 800 0 0 0.874 0.356 0 5271.980 847 0 0 0.890 0.357 0 4981.096 897 0 0 0.883 0.358 0 4705.137 950 0 0 0.871 0.357 0 4444.261 1006 0 0 0.887 0.358 0 4198.489 1065 0 0 0.853 0.358 0 3967.485 1128 0 0 0.873 0.357 0 3747.500 1194 0 0 0.866 0.361 0 3541.889 1264 0 0 0.864 0.359 0 3347.323 1339 0 0 0.860 0.356 0 3161.422 1418 0 0 0.860 0.356 0 2986.928 1502 0 0 0.849 0.358 0 2821.534 1591 0 0 0.877 0.364 0 2665.373 1685 0 0 0.844 0.363 0 2518.345 1784 0 0 0.865 0.367 0 2380.206 1884 0 0 0.861 0.364 0 2255.410 1995 0 0 0.861 0.366 0 2131.501 2113 0 0 0.866 0.370 0 2014.101 2239 0 0 0.843 0.375 0 1902.385 2371 0 0 0.864 0.376 0 1798.111 2512 0 0 0.840 0.382 0 1698.838 2661 0 0 0.843 0.385 0 1605.371 2818 0 0 0.846 0.391 0 1517.550 2985 0 0 0.843 0.398 0 1434.277 3162 0 0 0.850 0.404 0 1355.667 3350 0 0 0.835 0.411 0 1281.236 3548 0 0 0.828 0.420 0 1211.372 3758 0 0 0.835 0.431 0 1145.315 3981 0 0 0.836 0.442 0 1082.816 4217 0 0 0.825 0.454 0 1023.862 4467 0 0 0.844 0.465 0 968.220 4732 0 0 0.843 0.479 0 915.636 5012 0 0 0.822 0.486 0 866.150 5309 0 0 0.841 0.494 0 819.341 5623 0 0 0.837 0.503 0 775.233 5957 0 0 0.843 0.511 0 733.438 6310 0 0 0.845 0.522 0 694.063 6683 0 0 0.846 0.525 0 656.970 7079 0 0 0.853 0.530 0 621.868 7499 0 0 0.859 0.533 0 588.692 7943 0 0 0.848 0.536 0 557.414 8414 0 0 0.856 0.540 0 527.846 8913 0 0 0.865 0.545 0 499.951 9441 0 0 0.861 0.548 0 473.625 10000 0 0 0.866 0.547 0 448.798 10593 0 0 0.863 0.553 0 425.316 11220 0 0 0.869 0.551 0 403.170 11885 0 0 0.867 0.557 0 382.254 12589 0 0 0.887 0.553 0 362.524 13335 0 0 0.876 0.556 0 343.869 14125 0 0 0.876 0.562 0 326.281 14962 0 0 0.867 0.565 0 309.669 15849 0 0 0.871 0.564 0 293.998 16788 0 0 0.870 0.565 0 279.188 17783 0 0 0.874 0.571 0 265.211 18836 0 0 0.875 0.569 0 252.031 19953 0 0 0.873 0.577 0 239.567 21135 0 0 0.877 0.575 0 227.808 22387 0 0 0.870 0.577 0 216.718 23714 0 0 0.866 0.581 0 206.233 25119 0 0 0.874 0.589 0 196.347 26607 0 0 0.876 0.590 0 187.010 28184 0 0 0.871 0.594 0 178.199 29854 0 0 0.865 0.593 0 169.872 31623 0 0 0.872 0.597 0 162.009 33497 0 0 0.873 0.603 0 154.597 35481 0 0 0.870 0.605 0 147.609 37584 0 0 0.865 0.605 0 140.993 39811 0 0 0.871 0.606 0 134.766 42170 0 0 0.864 0.609 0 128.870 44668 0 0 0.865 0.614 0 123.302 47315 0 0 0.860 0.613 0 118.054 50119 0 0 0.864 0.618 0 113.093 53088 0 0 0.862 0.618 0 108.425 56234 0 0 0.863 0.621 0 104.002 59566 0 0 0.863 0.625 0 99.831 63096 0 0 0.862 0.627 0 95.893 66834 0 0 0.862 0.631 0 92.175 70795 0 0 0.859 0.630 0 88.667 74989 0 0 0.860 0.631 0 85.352 79433 0 0 0.863 0.632 0 82.232 84140 0 0 0.862 0.635 0 79.274 89125 0 0 0.861 0.636 0 76.479 94406 0 0 0.864 0.638 0 73.849 100000 0 0 0.864 0.639 0 71.366 105925 0 0 0.865 0.640 0 69.019 112202 0 0 0.863 0.645 0 66.805 118850 0 0 0.863 0.647 0 64.713 125893 0 0 0.868 0.647 0 62.739 133352 0 0 0.867 0.651 0 60.869 141254 0 0 0.871 0.650 0 59.111 149624 0 0 0.868 0.653 0 57.449 158489 0 0 0.872 0.656 0 55.878 167880 0 0 0.874 0.656 0 54.398 177828 0 0 0.880 0.661 0 53.002 188365 0 0 0.880 0.664 0 51.683 199526 0 0 0.879 0.663 0 50.439 211349 0 0 0.884 0.665 0 49.262 223872 0 0 0.887 0.663 0 48.152 237137 0 0 0.890 0.667 0 47.102 251189 0 0 0.892 0.668 0 46.115 266073 0 0 0.895 0.675 0 45.180 281838 0 0 0.898 0.676 0 44.298 298538 0 0 0.896 0.679 0 43.463 316228 0 0 0.905 0.678 0 42.674 334965 0 0 0.909 0.686 0 41.935 354813 0 0 0.907 0.690 0 41.231 375837 0 0 0.913 0.689 0 40.570 398107 0 0 0.918 0.694 0 39.944 421697 0 0 0.925 0.696 0 39.353 446684 0 0 0.932 0.694 0 38.796 473151 0 0 0.939 0.698 0 38.271 501187 0 0 0.942 0.706 0 37.772 530884 0 0 0.949 0.704 0 37.306 562341 0 0 0.957 0.711 0 36.863 595662 0 0 0.960 0.714 0 36.446 630957 0 0 0.967 0.722 0 36.050 668344 0 0 0.974 0.724 0 35.680 707946 0 0 0.980 0.725 0 35.329 749894 0 0 0.999 0.738 0 35.001 794328 0 0 0.996 0.738 0 34.687 841395 0 0 1.010 0.744 0 34.392 891251 0 0 1.016 0.748 0 34.112 944061 0 0 1.032 0.753 0 33.849 1000000 0 0 1.036 0.760 0 33.601 1059254 0 0 1.044 0.768 0 33.363 1122018 0 0 1.063 0.778 0 33.143 1188502 0 0 1.076 0.787 0 32.933 1258925 0 0 1.090 0.789 0 32.737 1333521 0 0 1.105 0.802 0 32.550 1412538 0 0 1.122 0.810 0 32.374 1496236 0 0 1.135 0.820 0 32.206 1584893 0 0 1.159 0.831 0 32.048 1678804 0 0 1.165 0.844 0 31.900 1778279 0 0 1.184 0.849 0 31.760 1883649 0 0 1.212 0.864 0 31.628 1995262 0 0 1.233 0.876 0 31.503 2113489 0 0 1.246 0.890 0 31.386 2238721 0 0 1.268 0.905 0 31.276 2371374 0 0 1.294 0.914 0 31.171 2511886 0 0 1.322 0.923 0 31.073 2660725 0 0 1.340 0.944 0 30.980 2818383 0 0 1.382 0.960 0 30.890 2985383 0 0 1.408 0.978 0 30.807 3162278 0 0 1.434 1.008 0 30.728 3349654 0 0 1.485 1.016 0 30.654 3548134 0 0 1.529 1.043 0 30.583 3758374 0 0 1.560 1.062 0 30.518 3981072 0 0 1.601 1.090 0 30.455 4216965 0 0 1.660 1.114 0 30.397 4466836 0 0 1.703 1.136 0 30.341 4731513 0 0 1.751 1.163 0 30.289 5011872 0 0 1.809 1.199 0 30.239 5308844 0 0 1.869 1.229 0 30.192 5623413 0 0 1.942 1.260 0 30.148 5956621 0 0 2.013 1.299 0 30.106 6309573 0 0 2.076 1.338 0 30.067 6683439 0 0 2.155 1.376 0 30.030 7079458 0 0 2.244 1.420 0 29.994 7498942 0 0 2.320 1.474 0 29.961 7943282 0 0 2.421 1.519 0 29.929 8413951 0 0 2.526 1.576 0 29.900 8912509 0 0 2.640 1.630 0 29.871 9440609 0 0 2.759 1.694 0 29.845 10000000 0 0 2.886 1.759 0 29.820 10592537 0 0 3.012 1.844 0 29.798 11220185 0 0 3.169 1.917 0 29.776 11885022 0 0 3.336 2.002 0 29.756 12589254 0 0 3.493 2.081 0 29.737 13335214 0 0 3.697 2.178 0 29.718 14125375 0 0 3.867 2.272 0 29.700 14962357 0 0 4.091 2.388 0 29.683 judy-1.0.5/test/Centrino_1.3Mhz_Plots/JLHash_CO.plot0000644000175000017500000010457510204462077022305 0ustar troyhebetroyhebe# StringCompare -n13335214 -A JLHash -P40 -L10 -C -M100000 /home/data/domnames.txt # This file is in a format to input to 'jbgraph' # XLABEL Stored # YLABEL Microseconds / Index # COLHEAD 1 Total Insert attempts # COLHEAD 2 Number Gets # COLHEAD 3 Duplicate strings # COLHEAD 4 Insert Time (uS) # COLHEAD 5 Get Time (uS) # COLHEAD 6 Hash Chain Length # COLHEAD 7 Average RAM/String # Linux localhost 2.6.3-4mdkenterprise #1 SMP Tue Mar 2 07:00:53 CET 2004 i686 # 32 Bit CPU # Processor speed compiled at 1299 Mhz # JLHash table virtual size = 4294967296 # 9999673 (75.0%) non-Word_t aligned string buffers # Ram used for input data = 333834600 bytes # Average string length = 16.0 bytes # 3400000 bytes malloc() for 'cached' strings for Get measurement # Access Time = 0.102 uS average per string (mostly from Cache) # HashStr() Time = 0.274 uS average per string (mostly from Cache) # Access Time = 0.285 uS average per string (mostly from RAM) # HashStr() Time = 0.474 uS average per string (mostly from RAM) # Pass 0 # TotInserts DeltaGets DupStrs InsTime GetTime HChainLen Ram/String # 1 1 0 38.004 1.742 1.000000 108.0 # 2 2 0 8.817 0.905 1.000000 74.0 # 3 3 0 1.388 0.705 1.000000 60.0 # 4 4 0 1.583 0.651 1.000000 58.0 # 5 5 0 1.148 0.616 1.000000 52.8 # 6 6 0 1.625 0.603 1.000000 52.7 # 7 7 0 1.283 0.587 1.000000 50.3 # 8 8 0 1.746 0.575 1.000000 52.0 # 9 9 0 0.979 0.549 1.000000 48.9 # 10 10 0 1.119 0.547 1.000000 47.6 # 11 11 0 1.020 0.528 1.000000 45.8 # 12 12 0 1.640 0.512 1.000000 46.7 # 13 13 0 1.132 0.495 1.000000 45.2 # 14 14 0 1.260 0.745 1.000000 44.3 # 15 15 0 6.118 0.481 1.000000 42.9 # 16 16 0 1.931 0.478 1.000000 45.8 # 17 17 0 1.107 0.473 1.000000 44.5 # 18 18 0 1.099 0.471 1.000000 44.0 # 19 19 0 1.057 0.463 1.000000 42.9 # 20 20 0 1.330 0.462 1.000000 42.2 # 21 21 0 1.196 0.458 1.000000 41.5 # 22 22 0 0.962 0.455 1.000000 40.7 # 23 23 0 1.169 0.459 1.000000 40.5 # 24 24 0 1.964 0.453 1.000000 42.5 # 25 25 0 1.238 0.442 1.000000 41.8 # 26 26 0 1.374 0.439 1.000000 41.1 # 27 27 0 0.962 0.439 1.000000 40.6 # 28 28 0 1.043 0.438 1.000000 40.1 # 29 29 0 1.311 0.430 1.000000 39.6 # 30 30 0 1.068 0.428 1.000000 38.9 # 31 31 0 1.206 0.427 1.000000 38.5 # 32 32 0 24.145 0.517 1.000000 44.2 # 34 34 0 2.551 0.435 1.000000 43.9 # 36 36 0 1.243 0.433 1.000000 43.7 # 38 38 0 1.180 0.432 1.000000 43.3 # 40 40 0 1.277 0.428 1.000000 42.9 # 42 42 0 1.069 0.425 1.000000 42.5 # 44 44 0 0.948 0.419 1.000000 42.0 # 46 46 0 1.188 0.420 1.000000 41.9 # 48 48 0 1.519 0.425 1.000000 42.0 # 50 50 0 1.245 0.424 1.000000 42.2 # 53 53 0 1.105 0.431 1.000000 42.3 # 56 56 0 1.429 0.431 1.000000 43.0 # 59 59 0 1.053 0.436 1.000000 42.6 # 62 62 0 1.337 0.445 1.000000 43.2 # 65 65 0 1.169 0.442 1.000000 43.6 # 69 69 0 1.654 0.441 1.000000 42.8 # 73 73 0 1.080 0.444 1.000000 42.5 # 77 77 0 0.877 0.438 1.000000 41.9 # 81 81 0 1.082 0.438 1.000000 41.8 # 85 85 0 1.091 0.437 1.000000 41.7 # 90 90 0 1.002 0.439 1.000000 41.2 # 95 95 0 1.798 0.438 1.000000 42.1 # 100 100 0 0.927 0.439 1.000000 41.8 # 106 106 0 1.140 0.439 1.000000 42.4 # 112 112 0 1.008 0.443 1.000000 42.5 # 118 118 0 0.959 0.498 1.000000 42.0 # 125 125 0 0.897 0.438 1.000000 41.5 # 132 132 0 0.982 0.438 1.000000 41.1 # 139 139 0 1.120 0.437 1.000000 41.7 # 147 147 0 1.073 0.438 1.000000 41.8 # 155 155 0 1.013 0.439 1.000000 41.8 # 164 164 0 0.974 0.441 1.000000 41.7 # 173 173 0 0.877 0.438 1.000000 41.3 # 183 183 0 1.440 0.440 1.000000 41.7 # 194 194 0 0.958 0.438 1.000000 41.5 # 205 205 0 1.000 0.438 1.000000 41.6 # 217 217 0 0.932 0.439 1.000000 41.4 # 230 230 0 1.010 0.441 1.000000 41.7 # 243 243 0 1.037 0.471 1.000000 41.8 # 257 257 0 1.065 0.448 1.000000 41.7 # 272 272 0 1.259 0.450 1.000000 41.8 # 288 288 0 1.060 0.453 1.000000 42.3 # 305 305 0 0.966 0.453 1.000000 42.0 # 323 323 0 0.946 0.453 1.000000 41.6 # 342 342 0 0.969 0.453 1.000000 41.7 # 362 362 0 1.142 0.457 1.000000 41.5 # 383 383 0 0.988 0.472 1.000000 41.4 # 405 405 0 1.023 0.454 1.000000 41.3 # 429 429 0 1.151 0.457 1.000000 41.4 # 454 454 0 0.990 0.471 1.000000 41.4 # 480 480 0 1.004 0.458 1.000000 41.3 # 508 508 0 1.014 0.463 1.000000 41.4 # 538 538 0 1.120 0.475 1.000000 41.2 # 569 569 0 0.997 0.464 1.000000 41.1 # 602 602 0 1.059 0.478 1.000000 40.9 # 637 637 0 1.095 0.468 1.000000 40.7 # 674 674 0 1.048 0.480 1.000000 40.6 # 714 714 0 1.072 0.470 1.000000 40.4 # 756 756 0 1.337 0.462 1.000000 40.2 # 800 800 0 1.015 0.459 1.000000 40.1 # 847 847 0 1.007 0.454 1.000000 40.0 # 897 897 0 1.079 0.464 1.000000 39.9 # 950 950 0 1.017 0.459 1.000000 39.8 # 1006 1006 0 1.135 0.458 1.000000 39.9 # 1065 1065 0 1.068 0.465 1.000000 39.9 # 1128 1128 0 0.997 0.467 1.000000 39.8 # 1194 1194 0 1.022 0.468 1.000000 39.5 # 1264 1264 0 1.074 0.465 1.000000 39.5 # 1339 1339 0 1.122 0.465 1.000000 39.3 # 1418 1418 0 1.164 0.468 1.000000 39.3 # 1502 1502 0 1.035 0.473 1.000000 39.2 # 1591 1591 0 1.042 0.473 1.000000 39.2 # 1685 1685 0 1.052 0.475 1.000000 39.2 # 1784 1784 0 1.119 0.476 1.000000 39.2 # 1884 1884 0 1.058 0.476 1.000000 39.1 # 1995 1995 0 1.042 0.478 1.000000 39.1 # 2113 2113 0 2.215 0.482 1.000000 38.9 # 2239 2239 0 1.072 0.637 1.000000 38.8 # 2371 2371 0 1.096 0.486 1.000000 38.7 # 2512 2512 0 1.110 0.486 1.000000 38.8 # 2661 2661 0 1.097 0.488 1.000000 38.8 # 2818 2818 0 1.156 0.490 1.000000 38.7 # 2985 2985 0 1.137 0.493 1.000000 38.7 # 3162 3162 0 1.143 0.498 1.000000 38.7 # 3350 3350 0 1.067 0.499 1.000000 38.5 # 3548 3548 0 1.121 0.500 1.000000 38.5 # 3758 3758 0 1.161 0.528 1.000000 38.6 # 3981 3981 0 1.103 0.512 1.000000 38.5 # 4217 4217 0 1.120 0.515 1.000000 38.5 # 4467 4467 0 1.116 0.520 1.000000 38.4 # 4732 4732 0 1.151 0.525 1.000000 38.4 # 5012 5012 0 1.124 0.527 1.000000 38.3 # 5309 5309 0 1.165 0.532 1.000000 38.3 # 5623 5623 0 1.654 0.542 1.000000 38.2 # 5957 5957 0 1.175 0.542 1.000000 38.2 # 6310 6310 0 1.221 0.547 1.000000 38.2 # 6683 6683 0 1.269 0.554 1.000000 38.3 # 7079 7079 0 1.224 0.553 1.000000 38.3 # 7499 7499 0 1.267 0.556 1.000000 38.4 # 7943 7943 0 1.344 0.556 1.000000 38.6 # 8414 8414 0 1.320 0.606 1.000000 38.8 # 8913 8913 0 1.485 0.556 1.000000 39.2 # 9441 9441 0 1.483 0.551 1.000000 39.7 # 10000 10000 0 1.336 0.549 1.000000 40.0 # 10593 10593 0 1.374 0.545 1.000000 40.3 # 11220 11220 0 1.361 0.605 1.000000 40.7 # 11885 11885 0 1.233 0.552 1.000000 40.8 # 12589 12589 0 1.201 0.546 1.000000 40.9 # 13335 13335 0 1.145 0.545 1.000000 40.9 # 14125 14125 0 1.169 0.594 1.000000 40.8 # 14962 14962 0 1.152 0.563 1.000000 40.8 # 15849 15849 0 1.137 0.558 1.000000 40.7 # 16788 16788 0 1.168 0.622 1.000000 40.7 # 17783 17783 0 1.159 0.579 1.000000 40.6 # 18836 18836 0 1.162 0.605 1.000000 40.5 # 19953 19953 0 1.270 0.582 1.000000 40.5 # 21135 21135 0 1.153 0.589 1.000000 40.4 # 22387 22387 0 1.321 0.601 1.000000 40.3 # 23714 23714 0 1.289 0.602 1.000000 40.3 # 25119 25119 0 1.256 0.639 1.000000 40.2 # 26607 26607 0 1.205 0.626 1.000000 40.1 # 28184 28184 0 1.200 0.625 1.000000 40.1 # 29854 29854 0 1.203 0.659 1.000000 40.2 # 31623 31623 0 1.213 0.651 1.000000 40.2 # 33497 33497 0 1.210 0.654 1.000000 40.4 # 35481 35481 0 1.208 0.681 1.000000 40.5 # 37584 37584 0 1.264 0.672 1.000000 40.6 # 39811 39811 0 1.222 0.693 1.000000 40.7 # 42170 42170 0 1.224 0.695 1.000000 40.7 # 44668 44668 0 1.225 0.710 1.000000 40.8 # 47315 47315 0 1.218 0.702 1.000000 40.8 # 50119 50119 0 1.231 0.722 1.000000 40.8 # 53088 53088 0 1.284 0.718 1.000000 40.8 # 56234 56234 0 1.228 0.729 1.000000 40.8 # 59566 59566 0 1.228 0.754 1.000000 40.7 # 63096 63096 0 1.234 0.750 1.000000 40.7 # 66834 66834 0 1.230 0.745 1.000000 40.6 # 70795 70795 0 1.236 0.752 1.000000 40.5 # 74989 74989 0 1.243 0.760 1.000000 40.4 # 79433 79433 0 1.289 0.762 1.000000 40.3 # 84140 84140 0 1.291 0.766 1.000000 40.2 # 89125 89125 0 1.254 0.768 1.000000 40.1 # 94406 94406 0 1.256 0.767 1.000011 40.0 # 100000 100000 0 1.255 0.769 1.000010 39.9 # 105925 100000 0 1.283 0.784 1.000010 39.8 # 112202 100000 0 1.305 0.787 1.000010 39.7 # 118850 100000 0 1.256 0.784 1.000010 39.5 # 125893 100000 0 1.336 0.792 1.000010 39.4 # 133352 100000 0 1.310 0.798 1.000010 39.3 # 141254 100000 0 1.292 0.806 1.000000 39.3 # 149624 100000 0 1.310 0.816 1.000000 39.2 # 158489 100000 0 1.326 0.823 1.000000 39.1 # 167880 100000 0 1.379 0.825 1.000010 39.1 # 177828 100000 0 1.355 0.833 1.000000 39.0 # 188365 100000 0 1.365 0.838 1.000010 38.9 # 199526 100000 0 1.398 0.845 1.000030 38.9 # 211349 100000 0 1.382 0.852 1.000030 38.8 # 223872 100000 0 1.411 0.853 1.000010 38.8 # 237137 100000 0 1.471 0.870 1.000030 38.7 # 251189 100000 0 1.403 0.869 1.000030 38.6 # 266073 100000 0 1.411 0.873 1.000020 38.6 # 281838 100000 0 1.417 0.875 1.000050 38.5 # 298538 100000 0 1.418 0.880 1.000040 38.4 # 316228 100000 0 1.424 0.892 1.000020 38.3 # 334965 100000 0 1.423 0.894 1.000040 38.3 # 354813 100000 0 1.435 0.895 1.000020 38.2 # 375837 100000 0 1.437 0.904 1.000070 38.1 # 398107 100000 0 1.419 0.914 1.000070 38.0 # 421697 100000 0 1.440 0.912 1.000100 37.9 # 446684 100000 0 1.426 0.954 1.000080 37.8 # 473151 100000 0 1.434 0.923 1.000080 37.7 # 501187 100000 0 1.465 0.931 1.000150 37.7 # 530884 100000 0 1.470 0.937 1.000060 37.6 # 562341 100000 0 1.469 0.943 1.000100 37.6 # 595662 100000 0 1.488 0.959 1.000100 37.5 # 630957 100000 0 1.500 0.956 1.000130 37.5 # 668344 100000 0 1.484 0.959 1.000070 37.4 # 707946 100000 0 1.517 0.965 1.000110 37.4 # 749894 100000 0 1.523 0.971 1.000070 37.3 # 794328 100000 0 1.533 0.985 1.000130 37.3 # 841395 100000 0 1.547 0.985 1.000180 37.3 # 891251 100000 0 1.558 0.991 1.000100 37.2 # 944061 100000 0 1.552 0.997 1.000130 37.2 # 1000000 100000 0 1.577 1.004 1.000100 37.2 # 1059254 100000 0 1.582 1.009 1.000140 37.1 # 1122018 100000 0 1.588 1.011 1.000070 37.1 # 1188502 100000 0 1.609 1.019 1.000130 37.1 # 1258925 100000 0 1.594 1.032 1.000200 37.1 # 1333521 100000 0 1.615 1.032 1.000130 37.1 # 1412538 100000 0 1.610 1.036 1.000150 37.1 # 1496236 100000 0 1.612 1.048 1.000150 37.1 # 1584893 100000 0 1.627 1.049 1.000190 37.0 # 1678804 100000 0 1.646 1.056 1.000210 37.0 # 1778279 100000 0 1.646 1.060 1.000310 36.9 # 1883649 100000 0 1.667 1.065 1.000230 36.9 # 1995262 100000 0 1.699 1.069 1.000350 36.9 # 2113489 100000 0 1.734 1.072 1.000300 37.0 # 2238721 100000 0 1.790 1.086 1.000240 37.1 # 2371374 100000 0 1.861 1.088 1.000250 37.4 # 2511886 100000 0 1.925 1.092 1.000320 37.8 # 2660725 100000 0 2.046 1.096 1.000320 38.4 # 2818383 100000 0 1.983 1.109 1.000320 39.0 # 2985383 100000 0 1.953 1.099 1.000460 39.6 # 3162278 100000 0 1.883 1.098 1.000430 40.1 # 3349654 100000 0 1.809 1.104 1.000420 40.4 # 3548134 100000 0 1.725 1.110 1.000490 40.6 # 3758374 100000 0 1.691 1.119 1.000330 40.6 # 3981072 100000 0 1.663 1.132 1.000410 40.6 # 4216965 100000 0 1.665 1.140 1.000460 40.6 # 4466836 100000 0 1.672 1.135 1.000550 40.5 # 4731513 100000 0 1.685 1.157 1.000490 40.5 # 5011872 100000 0 1.688 1.180 1.000520 40.4 # 5308844 100000 0 1.702 1.170 1.000580 40.3 # 5623413 100000 0 1.715 1.181 1.000570 40.2 # 5956621 100000 0 1.727 1.184 1.000820 40.2 # 6309573 100000 0 1.734 1.203 1.000690 40.1 # 6683439 100000 0 1.740 1.198 1.000910 40.0 # 7079458 100000 0 1.742 1.214 1.000800 40.0 # 7498942 100000 0 1.755 1.217 1.000750 40.0 # 7943282 100000 0 1.767 1.223 1.000940 40.0 # 8413951 100000 0 1.860 1.239 1.000920 40.1 # 8912509 100000 0 1.795 1.249 1.001020 40.2 # 9440609 100000 0 1.800 1.257 1.001150 40.3 # 10000000 100000 0 1.798 1.257 1.000990 40.3 # 10592537 100000 0 1.783 1.301 1.001150 40.4 # 11220185 100000 0 1.845 1.295 1.001400 40.4 # 11885022 100000 0 1.829 1.286 1.001310 40.4 # 12589254 100000 0 10.482 1.917 1.001420 40.4 # 13335214 100000 0 5.906 4.791 1.001610 40.3 # Total Duplicate strings = 0 # Begin JLHashFreeArray()... # returned 538058560 bytes # Free 13335214 strings, 1.065 uSecs Ave/string # Pass 1 # Pass 2 # Pass 3 # Pass 4 # Pass 5 # Pass 6 # Pass 7 # Pass 8 # Pass 9 # TotInserts 0 0 InsTime GetTime 0 Ram/String 1 0 0 3.635 0.601 0 48.000 2 0 0 2.086 0.268 0 40.000 3 0 0 0.989 0.349 0 41.333 4 0 0 0.952 0.324 0 42.000 5 0 0 0.765 0.330 0 39.200 6 0 0 1.010 0.354 0 39.333 7 0 0 0.748 0.363 0 37.714 8 0 0 1.226 0.362 0 41.500 9 0 0 0.823 0.364 0 40.889 10 0 0 0.774 0.373 0 40.400 11 0 0 0.794 0.365 0 40.000 12 0 0 1.554 0.366 0 42.333 13 0 0 0.743 0.370 0 41.231 14 0 0 0.817 0.375 0 40.286 15 0 0 0.798 0.384 0 38.933 16 0 0 1.259 0.382 0 42.000 17 0 0 0.716 0.382 0 41.647 18 0 0 0.751 0.380 0 41.333 19 0 0 0.785 0.383 0 40.211 20 0 0 0.875 0.382 0 39.800 21 0 0 0.798 0.380 0 39.619 22 0 0 0.875 0.381 0 39.273 23 0 0 0.751 0.388 0 39.130 24 0 0 1.964 0.388 0 41.167 25 0 0 0.880 0.382 0 40.480 26 0 0 0.908 0.387 0 39.846 27 0 0 0.740 0.389 0 39.556 28 0 0 0.842 0.388 0 39.429 29 0 0 0.895 0.390 0 39.034 30 0 0 0.877 0.387 0 38.800 31 0 0 0.781 0.388 0 38.452 32 0 0 7.634 0.424 0 43.375 34 0 0 0.995 0.398 0 43.294 36 0 0 0.886 0.409 0 42.667 38 0 0 0.915 0.413 0 42.421 40 0 0 0.905 0.416 0 42.200 42 0 0 0.895 0.417 0 42.857 44 0 0 0.769 0.418 0 42.727 46 0 0 0.858 0.416 0 42.435 48 0 0 1.019 0.414 0 42.250 50 0 0 0.946 0.415 0 41.920 53 0 0 0.985 0.413 0 42.340 56 0 0 1.024 0.417 0 42.643 59 0 0 0.876 0.415 0 42.712 62 0 0 0.992 0.412 0 43.097 65 0 0 0.931 0.419 0 43.077 69 0 0 0.884 0.424 0 42.899 73 0 0 0.967 0.422 0 42.685 77 0 0 0.831 0.428 0 42.857 81 0 0 0.860 0.416 0 42.864 85 0 0 0.864 0.416 0 43.529 90 0 0 0.866 0.419 0 43.156 95 0 0 0.968 0.422 0 42.653 100 0 0 0.927 0.425 0 42.160 106 0 0 0.997 0.427 0 42.075 112 0 0 0.880 0.430 0 42.250 118 0 0 0.959 0.429 0 42.373 125 0 0 0.897 0.428 0 42.656 132 0 0 0.982 0.430 0 42.364 139 0 0 0.892 0.430 0 41.899 147 0 0 1.004 0.437 0 42.395 155 0 0 0.962 0.433 0 42.348 164 0 0 0.945 0.436 0 42.146 173 0 0 0.877 0.438 0 41.734 183 0 0 0.890 0.440 0 41.727 194 0 0 0.958 0.438 0 41.794 205 0 0 1.000 0.438 0 41.795 217 0 0 0.923 0.439 0 41.604 230 0 0 0.996 0.441 0 42.070 243 0 0 0.991 0.452 0 42.091 257 0 0 0.939 0.448 0 41.696 272 0 0 0.981 0.450 0 41.559 288 0 0 1.022 0.453 0 41.667 305 0 0 0.966 0.453 0 41.902 323 0 0 0.946 0.453 0 41.895 342 0 0 0.969 0.453 0 42.058 362 0 0 1.064 0.457 0 42.188 383 0 0 0.988 0.464 0 42.057 405 0 0 1.023 0.454 0 42.272 429 0 0 1.066 0.457 0 42.256 454 0 0 0.990 0.468 0 41.947 480 0 0 1.004 0.458 0 41.917 508 0 0 1.014 0.463 0 41.819 538 0 0 1.068 0.471 0 41.465 569 0 0 0.997 0.464 0 41.244 602 0 0 1.059 0.478 0 41.143 637 0 0 1.095 0.468 0 41.017 674 0 0 1.048 0.480 0 40.914 714 0 0 1.062 0.470 0 40.734 756 0 0 1.337 0.462 0 40.439 800 0 0 1.015 0.459 0 40.220 847 0 0 1.007 0.454 0 40.142 897 0 0 1.016 0.464 0 40.143 950 0 0 1.017 0.459 0 40.029 1006 0 0 1.033 0.458 0 40.016 1065 0 0 1.033 0.465 0 39.985 1128 0 0 0.997 0.467 0 39.897 1194 0 0 1.007 0.467 0 39.863 1264 0 0 1.027 0.465 0 39.750 1339 0 0 1.022 0.465 0 39.555 1418 0 0 1.007 0.468 0 39.368 1502 0 0 1.035 0.473 0 39.204 1591 0 0 1.023 0.473 0 39.110 1685 0 0 1.027 0.475 0 39.119 1784 0 0 0.998 0.476 0 39.029 1884 0 0 1.028 0.476 0 39.096 1995 0 0 1.012 0.478 0 38.983 2113 0 0 1.023 0.482 0 39.000 2239 0 0 0.998 0.493 0 38.916 2371 0 0 1.006 0.486 0 38.962 2512 0 0 1.035 0.486 0 38.861 2661 0 0 1.027 0.488 0 38.825 2818 0 0 1.046 0.490 0 38.755 2985 0 0 1.029 0.493 0 38.596 3162 0 0 1.063 0.498 0 38.530 3350 0 0 1.036 0.499 0 38.427 3548 0 0 1.037 0.500 0 38.444 3758 0 0 1.068 0.528 0 38.506 3981 0 0 1.073 0.512 0 38.551 4217 0 0 1.079 0.515 0 38.367 4467 0 0 1.072 0.520 0 38.433 4732 0 0 1.083 0.525 0 38.343 5012 0 0 1.061 0.527 0 38.311 5309 0 0 1.085 0.532 0 38.320 5623 0 0 1.072 0.542 0 38.251 5957 0 0 1.103 0.542 0 38.209 6310 0 0 1.142 0.547 0 38.255 6683 0 0 1.096 0.554 0 38.122 7079 0 0 1.132 0.553 0 38.204 7499 0 0 1.208 0.556 0 38.365 7943 0 0 1.227 0.556 0 38.610 8414 0 0 1.225 0.588 0 38.839 8913 0 0 1.310 0.556 0 39.063 9441 0 0 1.319 0.551 0 39.620 10000 0 0 1.270 0.549 0 40.091 10593 0 0 1.271 0.545 0 40.405 11220 0 0 1.175 0.570 0 40.668 11885 0 0 1.125 0.552 0 40.855 12589 0 0 1.080 0.546 0 40.874 13335 0 0 1.057 0.545 0 40.788 14125 0 0 1.067 0.574 0 40.824 14962 0 0 1.061 0.563 0 40.771 15849 0 0 1.059 0.558 0 40.713 16788 0 0 1.057 0.585 0 40.635 17783 0 0 1.070 0.579 0 40.554 18836 0 0 1.071 0.598 0 40.488 19953 0 0 1.091 0.582 0 40.426 21135 0 0 1.099 0.589 0 40.368 22387 0 0 1.099 0.601 0 40.336 23714 0 0 1.104 0.602 0 40.275 25119 0 0 1.113 0.629 0 40.186 26607 0 0 1.126 0.626 0 40.160 28184 0 0 1.174 0.625 0 40.113 29854 0 0 1.152 0.656 0 40.181 31623 0 0 1.154 0.651 0 40.274 33497 0 0 1.156 0.654 0 40.354 35481 0 0 1.154 0.677 0 40.434 37584 0 0 1.159 0.672 0 40.553 39811 0 0 1.165 0.693 0 40.664 42170 0 0 1.164 0.695 0 40.727 44668 0 0 1.166 0.710 0 40.820 47315 0 0 1.167 0.702 0 40.855 50119 0 0 1.167 0.722 0 40.883 53088 0 0 1.169 0.718 0 40.892 56234 0 0 1.169 0.729 0 40.829 59566 0 0 1.169 0.748 0 40.793 63096 0 0 1.173 0.750 0 40.721 66834 0 0 1.169 0.745 0 40.633 70795 0 0 1.173 0.752 0 40.553 74989 0 0 1.176 0.760 0 40.462 79433 0 0 1.189 0.762 0 40.373 84140 0 0 1.187 0.766 0 40.280 89125 0 0 1.192 0.768 0 40.185 94406 0 0 1.199 0.767 0 40.075 100000 0 0 1.201 0.769 0 39.939 105925 0 0 1.195 0.784 0 39.811 112202 0 0 1.183 0.787 0 39.690 118850 0 0 1.192 0.784 0 39.577 125893 0 0 1.203 0.792 0 39.473 133352 0 0 1.213 0.798 0 39.383 141254 0 0 1.226 0.806 0 39.303 149624 0 0 1.243 0.816 0 39.233 158489 0 0 1.252 0.823 0 39.167 167880 0 0 1.267 0.825 0 39.100 177828 0 0 1.276 0.833 0 39.041 188365 0 0 1.284 0.838 0 38.987 199526 0 0 1.293 0.845 0 38.928 211349 0 0 1.304 0.852 0 38.867 223872 0 0 1.310 0.853 0 38.806 237137 0 0 1.320 0.870 0 38.750 251189 0 0 1.331 0.869 0 38.690 266073 0 0 1.329 0.873 0 38.620 281838 0 0 1.338 0.875 0 38.553 298538 0 0 1.339 0.880 0 38.477 316228 0 0 1.339 0.892 0 38.394 334965 0 0 1.349 0.894 0 38.310 354813 0 0 1.352 0.895 0 38.220 375837 0 0 1.348 0.904 0 38.126 398107 0 0 1.350 0.914 0 38.043 421697 0 0 1.359 0.912 0 37.948 446684 0 0 1.359 0.927 0 37.865 473151 0 0 1.372 0.923 0 37.786 501187 0 0 1.380 0.931 0 37.707 530884 0 0 1.385 0.937 0 37.640 562341 0 0 1.391 0.943 0 37.581 595662 0 0 1.403 0.953 0 37.533 630957 0 0 1.414 0.956 0 37.486 668344 0 0 1.427 0.959 0 37.438 707946 0 0 1.438 0.965 0 37.398 749894 0 0 1.449 0.971 0 37.357 794328 0 0 1.462 0.981 0 37.312 841395 0 0 1.481 0.985 0 37.273 891251 0 0 1.490 0.991 0 37.240 944061 0 0 1.509 0.997 0 37.206 1000000 0 0 1.522 1.004 0 37.181 1059254 0 0 1.532 1.009 0 37.168 1122018 0 0 1.538 1.011 0 37.153 1188502 0 0 1.544 1.019 0 37.148 1258925 0 0 1.555 1.028 0 37.151 1333521 0 0 1.557 1.031 0 37.142 1412538 0 0 1.566 1.036 0 37.120 1496236 0 0 1.571 1.044 0 37.091 1584893 0 0 1.582 1.049 0 37.050 1678804 0 0 1.591 1.056 0 36.997 1778279 0 0 1.597 1.060 0 36.944 1883649 0 0 1.628 1.065 0 36.896 1995262 0 0 1.667 1.069 0 36.898 2113489 0 0 1.697 1.072 0 36.960 2238721 0 0 1.750 1.085 0 37.110 2371374 0 0 1.819 1.086 0 37.407 2511886 0 0 1.867 1.090 0 37.835 2660725 0 0 1.901 1.094 0 38.385 2818383 0 0 1.905 1.091 0 39.012 2985383 0 0 1.867 1.089 0 39.605 3162278 0 0 1.805 1.089 0 40.094 3349654 0 0 1.727 1.092 0 40.422 3548134 0 0 1.657 1.096 0 40.599 3758374 0 0 1.610 1.106 0 40.658 3981072 0 0 1.588 1.111 0 40.640 4216965 0 0 1.578 1.122 0 40.590 4466836 0 0 1.587 1.130 0 40.530 4731513 0 0 1.595 1.134 0 40.461 5011872 0 0 1.607 1.145 0 40.391 5308844 0 0 1.625 1.154 0 40.316 5623413 0 0 1.642 1.167 0 40.240 5956621 0 0 1.652 1.176 0 40.164 6309573 0 0 1.669 1.188 0 40.084 6683439 0 0 1.710 1.198 0 40.011 7079458 0 0 1.711 1.208 0 39.956 7498942 0 0 1.719 1.217 0 39.961 7943282 0 0 1.727 1.223 0 40.035 8413951 0 0 1.727 1.233 0 40.119 8912509 0 0 1.726 1.243 0 40.194 9440609 0 0 1.737 1.248 0 40.263 10000000 0 0 1.723 1.251 0 40.323 10592537 0 0 1.718 1.259 0 40.370 11220185 0 0 1.715 1.265 0 40.399 11885022 0 0 1.710 1.270 0 40.407 12589254 0 0 1.704 1.276 0 40.389 13335214 0 0 1.697 1.277 0 40.347 judy-1.0.5/test/Centrino_1.3Mhz_Plots/JudySL_CO.plot0000644000175000017500000010553510204462077022343 0ustar troyhebetroyhebe# StringCompare -n16788040 -A JudySL -P40 -L10 -C -M100000 /home/data/domnames.txt # This file is in a format to input to 'jbgraph' # XLABEL Stored # YLABEL Microseconds / Index # COLHEAD 1 Total Insert attempts # COLHEAD 2 Number Gets # COLHEAD 3 Duplicate strings # COLHEAD 4 Insert Time (uS) # COLHEAD 5 Get Time (uS) # COLHEAD 6 Hash Chain Length # COLHEAD 7 Average RAM/String # Linux localhost 2.6.3-4mdkenterprise #1 SMP Tue Mar 2 07:00:53 CET 2004 i686 # 32 Bit CPU # Processor speed compiled at 1299 Mhz # 12587648 (75.0%) non-Word_t aligned string buffers # Ram used for input data = 418243455 bytes # Average string length = 15.9 bytes # 3200000 bytes malloc() for 'cached' strings for Get measurement # Access Time = 0.101 uS average per string (mostly from Cache) # HashStr() Time = 0.270 uS average per string (mostly from Cache) # Access Time = 0.296 uS average per string (mostly from RAM) # HashStr() Time = 0.482 uS average per string (mostly from RAM) # Pass 0 # TotInserts DeltaGets DupStrs InsTime GetTime HChainLen Ram/String # 1 1 0 24.309 5.002 0.000000 16.0 # 2 2 0 21.507 0.328 0.000000 26.0 # 3 3 0 1.485 0.184 0.000000 25.3 # 4 4 0 1.438 0.173 0.000000 28.0 # 5 5 0 1.045 0.183 0.000000 25.6 # 6 6 0 1.435 0.172 0.000000 27.3 # 7 7 0 0.820 0.166 0.000000 25.1 # 8 8 0 1.261 0.157 0.000000 27.5 # 9 9 0 1.092 0.159 0.000000 26.2 # 10 10 0 0.993 0.154 0.000000 25.6 # 11 11 0 1.030 0.156 0.000000 24.4 # 12 12 0 2.002 0.157 0.000000 26.7 # 13 13 0 1.041 0.153 0.000000 25.5 # 14 14 0 0.993 0.151 0.000000 25.1 # 15 15 0 1.127 0.152 0.000000 24.5 # 16 16 0 6.505 0.167 0.000000 28.5 # 17 17 0 1.215 0.163 0.000000 28.0 # 18 18 0 1.001 0.159 0.000000 27.3 # 19 19 0 0.945 0.163 0.000000 26.5 # 20 20 0 0.935 0.159 0.000000 25.8 # 21 21 0 1.032 0.159 0.000000 25.5 # 22 22 0 1.381 0.160 0.000000 25.3 # 23 23 0 1.505 0.167 0.000000 25.4 # 24 24 0 2.011 0.165 0.000000 27.5 # 25 25 0 1.118 0.160 0.000000 27.0 # 26 26 0 0.883 0.162 0.000000 26.8 # 27 27 0 1.025 0.158 0.000000 26.4 # 28 28 0 1.024 0.164 0.000000 25.9 # 29 29 0 0.938 0.163 0.000000 25.9 # 30 30 0 1.272 0.159 0.000000 25.9 # 31 31 0 1.132 0.165 0.000000 25.4 # 32 32 0 26.102 0.294 0.000000 31.5 # 34 34 0 1.351 0.228 0.000000 31.2 # 36 36 0 1.230 0.228 0.000000 31.0 # 38 38 0 1.286 0.230 0.000000 31.3 # 40 40 0 1.182 0.225 0.000000 31.1 # 42 42 0 1.211 0.233 0.000000 31.4 # 44 44 0 1.158 0.285 0.000000 31.0 # 46 46 0 1.280 0.234 0.000000 30.8 # 48 48 0 1.042 0.235 0.000000 30.6 # 50 50 0 1.325 0.236 0.000000 30.8 # 53 53 0 1.140 0.238 0.000000 30.6 # 56 56 0 1.038 0.235 0.000000 30.3 # 59 59 0 1.012 0.234 0.000000 30.2 # 62 62 0 1.834 0.240 0.000000 30.5 # 65 65 0 1.084 0.239 0.000000 30.4 # 69 69 0 1.006 0.240 0.000000 30.2 # 73 73 0 0.838 0.240 0.000000 29.6 # 77 77 0 0.969 0.244 0.000000 29.8 # 81 81 0 1.057 0.241 0.000000 29.7 # 85 85 0 0.920 0.247 0.000000 29.6 # 90 90 0 0.873 0.245 0.000000 29.1 # 95 95 0 1.041 0.248 0.000000 29.1 # 100 100 0 1.169 0.252 0.000000 29.0 # 106 106 0 1.025 0.254 0.000000 29.4 # 112 112 0 0.992 0.314 0.000000 29.0 # 118 118 0 0.902 0.257 0.000000 28.6 # 125 125 0 1.013 0.256 0.000000 28.8 # 132 132 0 1.438 0.258 0.000000 28.7 # 139 139 0 0.984 0.257 0.000000 28.8 # 147 147 0 1.134 0.260 0.000000 29.5 # 155 155 0 1.127 0.264 0.000000 29.5 # 164 164 0 0.975 0.261 0.000000 29.1 # 173 173 0 0.924 0.267 0.000000 28.6 # 183 183 0 1.115 0.267 0.000000 28.6 # 194 194 0 1.188 0.272 0.000000 29.1 # 205 205 0 1.063 0.272 0.000000 28.7 # 217 217 0 1.030 0.273 0.000000 28.7 # 230 230 0 0.879 0.274 0.000000 28.2 # 243 243 0 1.329 0.274 0.000000 28.1 # 257 257 0 1.788 0.279 0.000000 28.9 # 272 272 0 0.900 0.277 0.000000 28.6 # 288 288 0 1.180 0.276 0.000000 28.8 # 305 305 0 1.091 0.276 0.000000 28.6 # 323 323 0 1.082 0.284 0.000000 28.4 # 342 342 0 1.313 0.277 0.000000 28.9 # 362 362 0 1.203 0.280 0.000000 28.8 # 383 383 0 1.041 0.282 0.000000 28.8 # 405 405 0 1.047 0.283 0.000000 28.9 # 429 429 0 0.988 0.285 0.000000 28.7 # 454 454 0 1.055 0.286 0.000000 28.5 # 480 480 0 1.300 0.287 0.000000 28.8 # 508 508 0 1.050 0.291 0.000000 28.6 # 538 538 0 1.133 0.300 0.000000 28.5 # 569 569 0 1.041 0.289 0.000000 28.3 # 602 602 0 1.161 0.294 0.000000 28.3 # 637 637 0 1.178 0.298 0.000000 28.5 # 674 674 0 1.167 0.287 0.000000 28.5 # 714 714 0 1.180 0.287 0.000000 28.5 # 756 756 0 1.364 0.286 0.000000 28.7 # 800 800 0 1.087 0.290 0.000000 28.4 # 847 847 0 1.186 0.290 0.000000 28.3 # 897 897 0 1.218 0.277 0.000000 30.2 # 950 950 0 1.147 0.276 0.000000 30.1 # 1006 1006 0 1.059 0.283 0.000000 29.9 # 1065 1065 0 1.245 0.280 0.000000 29.7 # 1128 1128 0 1.164 0.286 0.000000 29.5 # 1194 1194 0 1.136 0.282 0.000000 29.3 # 1264 1264 0 1.176 0.282 0.000000 29.3 # 1339 1339 0 1.160 0.287 0.000000 30.5 # 1418 1418 0 1.123 0.289 0.000000 30.3 # 1502 1502 0 1.163 0.285 0.000000 30.0 # 1591 1591 0 1.284 0.286 0.000000 30.0 # 1685 1685 0 1.158 0.288 0.000000 30.0 # 1784 1784 0 1.149 0.289 0.000000 30.7 # 1884 1884 0 1.093 0.289 0.000000 30.4 # 1995 1995 0 1.241 0.292 0.000000 30.2 # 2113 2113 0 1.217 0.297 0.000000 30.1 # 2239 2239 0 1.161 0.297 0.000000 30.6 # 2371 2371 0 1.135 0.296 0.000000 30.4 # 2512 2512 0 1.093 0.301 0.000000 30.2 # 2661 2661 0 1.096 0.302 0.000000 30.0 # 2818 2818 0 1.193 0.359 0.000000 30.4 # 2985 2985 0 1.238 0.303 0.000000 30.2 # 3162 3162 0 1.119 0.303 0.000000 29.9 # 3350 3350 0 1.229 0.302 0.000000 30.3 # 3548 3548 0 1.257 0.307 0.000000 30.1 # 3758 3758 0 1.177 0.311 0.000000 29.9 # 3981 3981 0 1.293 0.311 0.000000 30.3 # 4217 4217 0 1.178 0.316 0.000000 30.0 # 4467 4467 0 1.215 0.318 0.000000 30.2 # 4732 4732 0 1.200 0.321 0.000000 30.0 # 5012 5012 0 1.187 0.326 0.000000 29.7 # 5309 5309 0 1.276 0.330 0.000000 29.9 # 5623 5623 0 1.208 0.330 0.000000 30.0 # 5957 5957 0 1.234 0.337 0.000000 29.8 # 6310 6310 0 1.297 0.338 0.000000 30.0 # 6683 6683 0 1.245 0.344 0.000000 29.8 # 7079 7079 0 1.275 0.350 0.000000 29.9 # 7499 7499 0 1.287 0.352 0.000000 29.6 # 7943 7943 0 1.257 0.356 0.000000 29.7 # 8414 8414 0 1.249 0.357 0.000000 29.7 # 8913 8913 0 1.263 0.362 0.000000 29.5 # 9441 9441 0 1.230 0.363 0.000000 29.3 # 10000 10000 0 1.226 0.369 0.000000 29.1 # 10593 10593 0 1.257 0.371 0.000000 28.9 # 11220 11220 0 1.308 0.377 0.000000 28.8 # 11885 11885 0 1.276 0.409 0.000000 28.6 # 12589 12589 0 1.283 0.398 0.000000 28.4 # 13335 13335 0 1.318 0.450 0.000000 28.5 # 14125 14125 0 1.309 0.392 0.000000 28.5 # 14962 14962 0 1.280 0.395 0.000000 28.3 # 15849 15849 0 1.304 0.400 0.000000 28.2 # 16788 16788 0 1.295 0.405 0.000000 28.0 # 17783 17783 0 1.324 0.411 0.000000 27.9 # 18836 18836 0 1.338 0.416 0.000000 27.8 # 19953 19953 0 1.353 0.426 0.000000 27.8 # 21135 21135 0 1.342 0.429 0.000000 27.8 # 22387 22387 0 1.365 0.448 0.000000 27.8 # 23714 23714 0 1.343 0.451 0.000000 27.8 # 25119 25119 0 1.361 0.452 0.000000 27.8 # 26607 26607 0 1.482 0.469 0.000000 27.7 # 28184 28184 0 1.368 0.479 0.000000 27.7 # 29854 29854 0 1.350 0.477 0.000000 27.6 # 31623 31623 0 1.477 0.511 0.000000 27.6 # 33497 33497 0 1.397 0.501 0.000000 27.5 # 35481 35481 0 1.496 0.515 0.000000 27.5 # 37584 37584 0 1.404 0.529 0.000000 27.4 # 39811 39811 0 1.420 0.543 0.000000 27.4 # 42170 42170 0 1.443 0.554 0.000000 27.4 # 44668 44668 0 1.439 0.568 0.000000 27.3 # 47315 47315 0 1.469 0.592 0.000000 27.3 # 50119 50119 0 1.473 0.593 0.000000 27.3 # 53088 53088 0 1.524 0.623 0.000000 27.2 # 56234 56234 0 1.491 0.617 0.000000 27.2 # 59566 59566 0 1.510 0.631 0.000000 27.1 # 63096 63096 0 1.508 0.644 0.000000 27.1 # 66834 66834 0 1.517 0.667 0.000000 27.0 # 70795 70795 0 1.549 0.688 0.000000 26.9 # 74989 74989 0 1.614 0.689 0.000000 26.9 # 79433 79433 0 1.573 0.701 0.000000 26.8 # 84140 84140 0 1.596 0.715 0.000000 26.8 # 89125 89125 0 1.594 0.731 0.000000 26.8 # 94406 94406 0 1.602 0.742 0.000000 26.7 # 100000 100000 0 1.631 0.755 0.000000 26.7 # 105925 100000 0 1.646 0.773 0.000000 26.6 # 112202 100000 0 1.691 0.788 0.000000 26.6 # 118850 100000 0 1.721 0.808 0.000000 26.5 # 125893 100000 0 1.695 0.810 0.000000 26.5 # 133352 100000 0 1.785 0.823 0.000000 26.5 # 141254 100000 0 1.755 0.835 0.000000 26.4 # 149624 100000 0 1.781 0.859 0.000000 26.4 # 158489 100000 0 1.784 0.868 0.000000 26.4 # 167880 100000 0 1.762 0.889 0.000000 26.3 # 177828 100000 0 1.789 0.896 0.000000 26.3 # 188365 100000 0 1.820 0.904 0.000000 26.2 # 199526 100000 0 1.830 0.914 0.000000 26.1 # 211349 100000 0 1.870 0.930 0.000000 26.1 # 223872 100000 0 1.861 0.944 0.000000 26.0 # 237137 100000 0 1.862 0.967 0.000000 26.0 # 251189 100000 0 1.894 0.975 0.000000 25.9 # 266073 100000 0 1.906 0.985 0.000000 25.9 # 281838 100000 0 1.942 1.006 0.000000 25.8 # 298538 100000 0 1.997 1.027 0.000000 25.8 # 316228 100000 0 1.965 1.029 0.000000 25.7 # 334965 100000 0 1.966 1.042 0.000000 25.7 # 354813 100000 0 1.975 1.054 0.000000 25.6 # 375837 100000 0 1.999 1.074 0.000000 25.6 # 398107 100000 0 2.026 1.083 0.000000 25.6 # 421697 100000 0 2.046 1.094 0.000000 25.5 # 446684 100000 0 2.057 1.117 0.000000 25.5 # 473151 100000 0 2.069 1.124 0.000000 25.4 # 501187 100000 0 2.083 1.135 0.000000 25.4 # 530884 100000 0 2.112 1.153 0.000000 25.3 # 562341 100000 0 2.116 1.164 0.000000 25.3 # 595662 100000 0 2.148 1.179 0.000000 25.2 # 630957 100000 0 2.182 1.195 0.000000 25.2 # 668344 100000 0 2.206 1.207 0.000000 25.2 # 707946 100000 0 2.183 1.228 0.000000 25.1 # 749894 100000 0 2.186 1.233 0.000000 25.1 # 794328 100000 0 2.216 1.251 0.000000 25.0 # 841395 100000 0 2.243 1.260 0.000000 25.0 # 891251 100000 0 2.254 1.270 0.000000 25.0 # 944061 100000 0 2.272 1.285 0.000000 24.9 # 1000000 100000 0 2.274 1.304 0.000000 24.9 # 1059254 100000 0 2.300 1.312 0.000000 24.8 # 1122018 100000 0 2.307 1.339 0.000000 24.8 # 1188502 100000 0 2.321 1.345 0.000000 24.7 # 1258925 100000 0 2.341 1.349 0.000000 24.7 # 1333521 100000 0 2.351 1.373 0.000000 24.7 # 1412538 100000 0 2.367 1.383 0.000000 24.6 # 1496236 100000 0 2.396 1.393 0.000000 24.6 # 1584893 100000 0 2.407 1.404 0.000000 24.5 # 1678804 100000 0 2.427 1.415 0.000000 24.5 # 1778279 100000 0 2.432 1.432 0.000000 24.4 # 1883649 100000 0 2.460 1.444 0.000000 24.4 # 1995262 100000 0 2.459 1.461 0.000000 24.4 # 2113489 100000 0 2.493 1.471 0.000000 24.3 # 2238721 100000 0 2.502 1.496 0.000000 24.3 # 2371374 100000 0 2.530 1.508 0.000000 24.3 # 2511886 100000 0 2.538 1.516 0.000000 24.2 # 2660725 100000 0 2.551 1.539 0.000000 24.2 # 2818383 100000 0 2.578 1.543 0.000000 24.1 # 2985383 100000 0 2.590 1.562 0.000000 24.1 # 3162278 100000 0 2.617 1.576 0.000000 24.1 # 3349654 100000 0 2.625 1.615 0.000000 24.0 # 3548134 100000 0 2.650 1.621 0.000000 24.0 # 3758374 100000 0 2.679 1.642 0.000000 23.9 # 3981072 100000 0 2.701 1.659 0.000000 23.9 # 4216965 100000 0 2.722 1.671 0.000000 23.9 # 4466836 100000 0 2.752 1.690 0.000000 23.8 # 4731513 100000 0 2.772 1.707 0.000000 23.8 # 5011872 100000 0 2.792 1.730 0.000000 23.7 # 5308844 100000 0 3.166 1.753 0.000000 23.7 # 5623413 100000 0 2.819 1.757 0.000000 23.7 # 5956621 100000 0 2.841 1.776 0.000000 23.6 # 6309573 100000 0 2.864 1.804 0.000000 23.6 # 6683439 100000 0 2.885 1.807 0.000000 23.5 # 7079458 100000 0 2.910 1.849 0.000000 23.5 # 7498942 100000 0 2.932 1.865 0.000000 23.4 # 7943282 100000 0 2.956 1.880 0.000000 23.4 # 8413951 100000 0 2.989 1.914 0.000000 23.3 # 8912509 100000 0 3.009 1.928 0.000000 23.3 # 9440609 100000 0 3.035 1.950 0.000000 23.2 # 10000000 100000 0 3.067 1.981 0.000000 23.2 # 10592537 100000 0 3.109 2.017 0.000000 23.1 # 11220185 100000 0 3.118 2.044 0.000000 23.1 # 11885022 100000 0 3.151 2.074 0.000000 23.0 # 12589254 100000 0 3.184 2.092 0.000000 23.0 # 13335214 100000 0 3.202 2.133 0.000000 22.9 # 14125375 100000 0 3.230 2.148 0.000000 22.8 # 14962357 100000 0 3.258 2.190 0.000000 22.8 # 15848932 100000 0 3.281 2.220 0.000000 22.7 # 16788040 100000 0 3.319 2.228 0.000000 22.6 # Total Duplicate strings = 0 # Begin JudySLFreeArray()... # returned 380043160 bytes # Free 16788040 strings, 0.615 uSecs Ave/string # Pass 1 # Pass 2 # Pass 3 # Pass 4 # Pass 5 # Pass 6 # Pass 7 # Pass 8 # Pass 9 # TotInserts 0 0 InsTime GetTime 0 Ram/String 1 0 0 4.734 0.951 0 20.000 2 0 0 4.802 0.251 0 24.000 3 0 0 0.851 0.143 0 26.667 4 0 0 0.893 0.150 0 28.000 5 0 0 0.708 0.151 0 28.000 6 0 0 0.871 0.145 0 28.667 7 0 0 0.661 0.151 0 26.286 8 0 0 1.261 0.149 0 30.000 9 0 0 0.634 0.150 0 28.000 10 0 0 0.647 0.151 0 28.000 11 0 0 0.634 0.143 0 26.909 12 0 0 1.137 0.149 0 29.000 13 0 0 0.640 0.153 0 28.308 14 0 0 0.634 0.148 0 27.429 15 0 0 0.644 0.149 0 27.200 16 0 0 1.163 0.161 0 30.750 17 0 0 0.707 0.153 0 30.353 18 0 0 0.669 0.152 0 29.556 19 0 0 0.694 0.155 0 29.053 20 0 0 0.675 0.153 0 28.800 21 0 0 0.664 0.155 0 28.762 22 0 0 0.732 0.160 0 28.000 23 0 0 0.631 0.154 0 27.478 24 0 0 0.905 0.158 0 29.500 25 0 0 0.661 0.158 0 28.960 26 0 0 0.681 0.159 0 28.615 27 0 0 0.695 0.158 0 28.148 28 0 0 0.706 0.156 0 27.714 29 0 0 0.672 0.161 0 27.172 30 0 0 0.663 0.159 0 27.067 31 0 0 0.686 0.159 0 26.710 32 0 0 0.978 0.177 0 33.625 34 0 0 0.814 0.174 0 33.294 36 0 0 0.962 0.218 0 33.111 38 0 0 0.774 0.222 0 32.632 40 0 0 0.839 0.220 0 32.000 42 0 0 0.798 0.225 0 32.190 44 0 0 0.848 0.226 0 31.636 46 0 0 0.844 0.229 0 30.957 48 0 0 0.828 0.226 0 31.167 50 0 0 0.802 0.230 0 30.480 53 0 0 0.811 0.230 0 30.415 56 0 0 0.897 0.234 0 29.714 59 0 0 0.863 0.233 0 29.492 62 0 0 0.925 0.236 0 29.742 65 0 0 0.858 0.235 0 29.231 69 0 0 0.848 0.238 0 29.449 73 0 0 0.784 0.240 0 29.151 77 0 0 0.855 0.237 0 28.883 81 0 0 0.887 0.241 0 29.185 85 0 0 0.894 0.247 0 29.271 90 0 0 0.873 0.245 0 29.289 95 0 0 0.849 0.248 0 29.600 100 0 0 0.859 0.252 0 29.640 106 0 0 0.943 0.254 0 29.547 112 0 0 0.872 0.258 0 29.071 118 0 0 0.902 0.257 0 29.119 125 0 0 0.833 0.256 0 28.960 132 0 0 0.873 0.258 0 28.515 139 0 0 0.918 0.257 0 28.259 147 0 0 0.888 0.260 0 27.918 155 0 0 0.869 0.264 0 28.077 164 0 0 0.936 0.261 0 28.000 173 0 0 0.907 0.267 0 27.838 183 0 0 0.870 0.267 0 27.366 194 0 0 0.916 0.272 0 27.485 205 0 0 0.950 0.272 0 28.078 217 0 0 0.915 0.273 0 28.111 230 0 0 0.879 0.274 0 27.826 243 0 0 0.973 0.274 0 27.934 257 0 0 0.944 0.279 0 28.000 272 0 0 0.900 0.277 0 27.676 288 0 0 0.999 0.276 0 27.444 305 0 0 0.918 0.276 0 27.370 323 0 0 1.051 0.284 0 27.641 342 0 0 1.090 0.277 0 28.082 362 0 0 1.065 0.280 0 27.878 383 0 0 1.041 0.282 0 28.010 405 0 0 1.026 0.283 0 28.425 429 0 0 0.988 0.285 0 28.177 454 0 0 1.055 0.286 0 28.467 480 0 0 1.094 0.287 0 28.042 508 0 0 1.050 0.291 0 28.126 538 0 0 1.096 0.298 0 28.416 569 0 0 1.041 0.289 0 28.359 602 0 0 1.161 0.294 0 28.332 637 0 0 1.178 0.298 0 28.509 674 0 0 1.167 0.287 0 28.641 714 0 0 1.170 0.287 0 28.958 756 0 0 1.270 0.286 0 28.841 800 0 0 1.087 0.290 0 28.610 847 0 0 1.186 0.290 0 28.434 897 0 0 1.218 0.277 0 30.100 950 0 0 1.106 0.276 0 30.097 1006 0 0 1.059 0.283 0 29.920 1065 0 0 1.129 0.280 0 29.923 1128 0 0 1.058 0.286 0 29.652 1194 0 0 1.067 0.282 0 29.471 1264 0 0 1.176 0.282 0 29.256 1339 0 0 1.092 0.287 0 29.028 1418 0 0 1.081 0.289 0 28.996 1502 0 0 1.093 0.285 0 30.088 1591 0 0 1.036 0.286 0 29.715 1685 0 0 1.063 0.288 0 29.550 1784 0 0 1.094 0.289 0 29.330 1884 0 0 1.084 0.289 0 29.246 1995 0 0 1.066 0.292 0 30.129 2113 0 0 1.097 0.297 0 29.925 2239 0 0 1.128 0.297 0 29.747 2371 0 0 1.103 0.296 0 29.545 2512 0 0 1.082 0.301 0 30.013 2661 0 0 1.080 0.302 0 29.844 2818 0 0 1.135 0.322 0 29.612 2985 0 0 1.074 0.303 0 29.994 3162 0 0 1.099 0.303 0 29.736 3350 0 0 1.100 0.302 0 29.586 3548 0 0 1.092 0.307 0 29.948 3758 0 0 1.133 0.311 0 29.824 3981 0 0 1.127 0.311 0 29.521 4217 0 0 1.144 0.316 0 29.796 4467 0 0 1.165 0.318 0 29.630 4732 0 0 1.137 0.321 0 29.863 5012 0 0 1.149 0.326 0 29.686 5309 0 0 1.137 0.330 0 29.922 5623 0 0 1.110 0.330 0 29.685 5957 0 0 1.152 0.337 0 29.730 6310 0 0 1.149 0.338 0 29.636 6683 0 0 1.169 0.344 0 29.757 7079 0 0 1.188 0.350 0 29.522 7499 0 0 1.172 0.352 0 29.485 7943 0 0 1.184 0.356 0 29.481 8414 0 0 1.177 0.357 0 29.364 8913 0 0 1.173 0.362 0 29.487 9441 0 0 1.176 0.363 0 29.274 10000 0 0 1.182 0.369 0 29.111 10593 0 0 1.205 0.371 0 28.880 11220 0 0 1.197 0.377 0 28.883 11885 0 0 1.200 0.409 0 28.710 12589 0 0 1.207 0.398 0 28.586 13335 0 0 1.224 0.420 0 28.478 14125 0 0 1.213 0.392 0 28.337 14962 0 0 1.224 0.395 0 28.230 15849 0 0 1.243 0.400 0 28.074 16788 0 0 1.244 0.405 0 27.968 17783 0 0 1.261 0.411 0 27.827 18836 0 0 1.272 0.416 0 27.712 19953 0 0 1.283 0.426 0 27.697 21135 0 0 1.265 0.429 0 27.584 22387 0 0 1.287 0.448 0 27.546 23714 0 0 1.296 0.451 0 27.511 25119 0 0 1.298 0.452 0 27.519 26607 0 0 1.313 0.469 0 27.518 28184 0 0 1.325 0.479 0 27.524 29854 0 0 1.323 0.477 0 27.444 31623 0 0 1.338 0.511 0 27.434 33497 0 0 1.346 0.501 0 27.402 35481 0 0 1.368 0.515 0 27.335 37584 0 0 1.365 0.529 0 27.333 39811 0 0 1.377 0.543 0 27.306 42170 0 0 1.382 0.554 0 27.303 44668 0 0 1.404 0.568 0 27.259 47315 0 0 1.414 0.592 0 27.225 50119 0 0 1.417 0.593 0 27.198 53088 0 0 1.448 0.619 0 27.141 56234 0 0 1.452 0.617 0 27.096 59566 0 0 1.447 0.631 0 27.072 63096 0 0 1.474 0.644 0 27.052 66834 0 0 1.487 0.667 0 27.033 70795 0 0 1.506 0.683 0 26.991 74989 0 0 1.518 0.689 0 26.935 79433 0 0 1.525 0.701 0 26.883 84140 0 0 1.546 0.715 0 26.842 89125 0 0 1.556 0.731 0 26.823 94406 0 0 1.565 0.742 0 26.731 100000 0 0 1.589 0.755 0 26.702 105925 0 0 1.608 0.773 0 26.692 112202 0 0 1.627 0.788 0 26.645 118850 0 0 1.634 0.807 0 26.616 125893 0 0 1.645 0.810 0 26.572 133352 0 0 1.658 0.823 0 26.512 141254 0 0 1.670 0.835 0 26.464 149624 0 0 1.688 0.857 0 26.408 158489 0 0 1.700 0.866 0 26.358 167880 0 0 1.730 0.882 0 26.324 177828 0 0 1.730 0.896 0 26.276 188365 0 0 1.749 0.904 0 26.217 199526 0 0 1.769 0.914 0 26.156 211349 0 0 1.780 0.930 0 26.109 223872 0 0 1.791 0.944 0 26.065 237137 0 0 1.809 0.961 0 26.013 251189 0 0 1.828 0.971 0 25.967 266073 0 0 1.840 0.984 0 25.922 281838 0 0 1.870 0.997 0 25.863 298538 0 0 1.883 1.009 0 25.818 316228 0 0 1.897 1.023 0 25.746 334965 0 0 1.913 1.037 0 25.691 354813 0 0 1.917 1.049 0 25.659 375837 0 0 1.939 1.061 0 25.606 398107 0 0 1.957 1.075 0 25.560 421697 0 0 1.977 1.086 0 25.502 446684 0 0 1.994 1.103 0 25.468 473151 0 0 2.009 1.113 0 25.425 501187 0 0 2.019 1.127 0 25.383 530884 0 0 2.036 1.139 0 25.343 562341 0 0 2.060 1.151 0 25.294 595662 0 0 2.073 1.162 0 25.255 630957 0 0 2.093 1.177 0 25.212 668344 0 0 2.100 1.189 0 25.170 707946 0 0 2.116 1.203 0 25.128 749894 0 0 2.139 1.216 0 25.089 794328 0 0 2.147 1.229 0 25.046 841395 0 0 2.163 1.239 0 25.009 891251 0 0 2.171 1.252 0 24.968 944061 0 0 2.196 1.267 0 24.935 1000000 0 0 2.206 1.283 0 24.885 1059254 0 0 2.215 1.293 0 24.840 1122018 0 0 2.237 1.304 0 24.795 1188502 0 0 2.254 1.318 0 24.749 1258925 0 0 2.268 1.332 0 24.703 1333521 0 0 2.285 1.346 0 24.658 1412538 0 0 2.303 1.357 0 24.623 1496236 0 0 2.314 1.371 0 24.592 1584893 0 0 2.333 1.383 0 24.544 1678804 0 0 2.354 1.402 0 24.498 1778279 0 0 2.366 1.415 0 24.459 1883649 0 0 2.388 1.426 0 24.411 1995262 0 0 2.407 1.435 0 24.367 2113489 0 0 2.417 1.451 0 24.324 2238721 0 0 2.434 1.464 0 24.292 2371374 0 0 2.448 1.481 0 24.247 2511886 0 0 2.467 1.494 0 24.212 2660725 0 0 2.486 1.511 0 24.176 2818383 0 0 2.499 1.522 0 24.141 2985383 0 0 2.521 1.541 0 24.100 3162278 0 0 2.541 1.556 0 24.056 3349654 0 0 2.564 1.572 0 24.010 3548134 0 0 2.584 1.589 0 23.966 3758374 0 0 2.603 1.610 0 23.929 3981072 0 0 2.624 1.633 0 23.896 4216965 0 0 2.646 1.645 0 23.859 4466836 0 0 2.668 1.656 0 23.822 4731513 0 0 2.688 1.681 0 23.792 5011872 0 0 2.714 1.702 0 23.741 5308844 0 0 2.739 1.724 0 23.701 5623413 0 0 2.757 1.747 0 23.659 5956621 0 0 2.783 1.766 0 23.619 6309573 0 0 2.806 1.785 0 23.568 6683439 0 0 2.830 1.805 0 23.533 7079458 0 0 2.873 1.838 0 23.488 7498942 0 0 2.891 1.861 0 23.440 7943282 0 0 2.911 1.880 0 23.395 8413951 0 0 2.936 1.904 0 23.344 8912509 0 0 2.962 1.928 0 23.296 9440609 0 0 2.983 1.950 0 23.243 10000000 0 0 3.010 1.981 0 23.191 10592537 0 0 3.039 2.016 0 23.139 11220185 0 0 3.070 2.043 0 23.082 11885022 0 0 3.096 2.068 0 23.025 12589254 0 0 3.121 2.092 0 22.965 13335214 0 0 3.144 2.124 0 22.904 14125375 0 0 3.165 2.148 0 22.842 14962357 0 0 3.191 2.176 0 22.777 15848932 0 0 3.212 2.209 0 22.712 16788040 0 0 3.284 2.226 0 22.637 judy-1.0.5/test/malloc-pre2.8a.c0000644000175000017500000051736510204462077016506 0ustar troyhebetroyhebe/* [insert usage description etc here] preliminary version 2.8.x */ /* WIN32 sets up defaults for MS environment and compilers. Otherwise defaults are for unix. */ /* #define WIN32 */ #ifdef WIN32 #define WIN32_LEAN_AND_MEAN #include /* No-op failure action */ #define MALLOC_FAILURE_ACTION /* Win32 doesn't supply or need the following headers */ #define LACKS_UNISTD_H #define LACKS_SYS_PARAM_H #define LACKS_SYS_MMAN_H /* Use the supplied emulation of sbrk */ #define MORECORE sbrk #define MORECORE_CONTIGUOUS 1 #define MORECORE_FAILURE ((void*)(-1)) /* Use the supplied emulation of mmap and munmap */ #define HAVE_MMAP 1 #define MUNMAP_FAILURE (-1) #define MMAP_CLEARS 1 /* These values don't really matter in windows mmap emulation */ #define MAP_PRIVATE 1 #define MAP_ANONYMOUS 2 #define PROT_READ 1 #define PROT_WRITE 2 /* Emulation functions defined at the end of this file */ /* If USE_MALLOC_LOCK, use supplied critical-section-based lock functions */ #ifdef USE_MALLOC_LOCK static int slwait(int *sl); static int slrelease(int *sl); #endif static long getpagesize(void); static long getregionsize(void); static void *sbrk(long size); static void *mmap(void *ptr, long size, long prot, long type, long handle, long arg); static long munmap(void *ptr, long size); static void vminfo (unsigned long*free, unsigned long*reserved, unsigned long*committed); static int cpuinfo (int whole, unsigned long*kernel, unsigned long*user); #endif #include /* Void_t* is the pointer type that malloc should say it returns */ #ifndef Void_t #define Void_t void #endif /*Void_t*/ #include /* for size_t */ #ifdef __cplusplus extern "C" { #endif /* define LACKS_UNISTD_H if your system does not have a . */ /* #define LACKS_UNISTD_H */ #ifndef LACKS_UNISTD_H #include #endif /* define LACKS_SYS_PARAM_H if your system does not have a . */ /* #define LACKS_SYS_PARAM_H */ #include /* needed for malloc_stats */ #include /* needed for optional MALLOC_FAILURE_ACTION */ /* Debugging: Because freed chunks may be overwritten with bookkeeping fields, this malloc will often die when freed memory is overwritten by user programs. This can be very effective (albeit in an annoying way) in helping track down dangling pointers. If you compile with -DDEBUG, a number of assertion checks are enabled that will catch more memory errors. You probably won't be able to make much sense of the actual assertion errors, but they should help you locate incorrectly overwritten memory. The checking is fairly extensive, and will slow down execution noticeably. Calling malloc_stats or mallinfo with DEBUG set will attempt to check every non-mmapped allocated and free chunk in the course of computing the summmaries. (By nature, mmapped regions cannot be checked very much automatically.) Setting DEBUG may also be helpful if you are trying to modify this code. The assertions in the check routines spell out in more detail the assumptions and invariants underlying the algorithms. Setting DEBUG does NOT provide an automated mechanism for checking that all accesses to malloced memory stay within their bounds. However, there are several add-ons and adaptations of this or other mallocs available that do this. */ #if DEBUG #include /* #define assert(x) if(!(x)) abort() */ #else #define assert(x) ((void)0) #endif /* The unsigned integer type used for comparing any two chunk sizes. This should be at least as wide as size_t, but should not be signed. */ #ifndef CHUNK_SIZE_T #define CHUNK_SIZE_T unsigned long #endif #define MAX_CHUNK_SIZE ((CHUNK_SIZE_T)(-1UL)) /* The unsigned integer type used to hold addresses when they are are manipulated as integers. Except that it is not defined on all systems, intptr_t would suffice. */ #ifndef PTR_UINT #define PTR_UINT unsigned long #endif /* INTERNAL_SIZE_T is the word-size used for internal bookkeeping of chunk sizes. The default version is the same as size_t. While not strictly necessary, it is best to define this as an unsigned type, even if size_t is a signed type. This may avoid some artificial size limitations on some systems. On a 64-bit machine, you may be able to reduce malloc overhead by defining INTERNAL_SIZE_T to be a 32 bit `unsigned int' at the expense of not being able to handle more than 2^32 of malloced space. If this limitation is acceptable, you are encouraged to set this unless you are on a platform requiring 16byte alignments. In this case the alignment requirements turn out to negate any potential advantages of decreasing size_t word size. Implementors: Beware of the possible combinations of: - INTERNAL_SIZE_T might be signed or unsigned, might be 32 or 64 bits, and might be the same width as int or as long - size_t might have different width and signedness as INTERNAL_SIZE_T - int and long might be 32 or 64 bits, and might be the same width To deal with this, most comparisons and difference computations among INTERNAL_SIZE_Ts should cast them to CHUNK_SIZE_T, being aware of the fact that casting an unsigned int to a wider long does not sign-extend. (This also makes checking for negative numbers awkward.) Some of these casts result in harmless compiler warnings on some systems. */ #ifndef INTERNAL_SIZE_T #define INTERNAL_SIZE_T size_t #endif /* The corresponding word size */ #define SIZE_SZ (sizeof(INTERNAL_SIZE_T)) /* MALLOC_ALIGNMENT is the minimum alignment for malloc'ed chunks. It must be a power of two at least 2 * SIZE_SZ, even on machines for which smaller alignments would suffice. It may be defined as larger than this though. Note however that code and data structures are optimized for the case of 8-byte alignment. */ #ifndef MALLOC_ALIGNMENT #define MALLOC_ALIGNMENT (2 * SIZE_SZ) #endif /* The corresponding bit mask value */ #define MALLOC_ALIGN_MASK (MALLOC_ALIGNMENT - 1) /* REALLOC_ZERO_BYTES_FREES should be set if a call to realloc with zero bytes should be the same as a call to free. Some people think it should. Otherwise, since this malloc returns a unique pointer for malloc(0), so does realloc(p, 0). */ /* #define REALLOC_ZERO_BYTES_FREES */ /* TRIM_FASTBINS controls whether free() of a very small chunk can immediately lead to trimming. Setting to true (1) can reduce memory footprint, but will almost always slow down programs that use a lot of small chunks. Define this only if you are willing to give up some speed to more aggressively reduce system-level memory footprint when releasing memory in programs that use many small chunks. You can get essentially the same effect by setting MXFAST to 0, but this can lead to even greater slowdowns in programs using many small chunks. TRIM_FASTBINS is an in-between compile-time option, that disables only those chunks bordering topmost memory from being placed in fastbins. */ #ifndef TRIM_FASTBINS #define TRIM_FASTBINS 0 #endif /* USE_DL_PREFIX will prefix all public routines with the string 'dl'. This is necessary when you only want to use this malloc in one part of a program, using your regular system malloc elsewhere. */ /* #define USE_DL_PREFIX */ /* USE_MALLOC_LOCK causes wrapper functions to surround each callable routine with pthread mutex lock/unlock. USE_MALLOC_LOCK forces USE_PUBLIC_MALLOC_WRAPPERS to be defined */ /* #define USE_MALLOC_LOCK */ /* If USE_PUBLIC_MALLOC_WRAPPERS is defined, every public routine is actually a wrapper function that first calls MALLOC_PREACTION, then calls the internal routine, and follows it with MALLOC_POSTACTION. This is needed for locking, but you can also use this, without USE_MALLOC_LOCK, for purposes of interception, instrumentation, etc. It is a sad fact that using wrappers often noticeably degrades performance of malloc-intensive programs. */ #ifdef USE_MALLOC_LOCK #define USE_PUBLIC_MALLOC_WRAPPERS #else /* #define USE_PUBLIC_MALLOC_WRAPPERS */ #endif /* Two-phase name translation. All of the actual routines are given mangled names. When wrappers are used, they become the public callable versions. When DL_PREFIX is used, the callable names are prefixed. */ #ifndef USE_PUBLIC_MALLOC_WRAPPERS #define cALLOc public_cALLOc #define fREe public_fREe #define cFREe public_cFREe #define mALLOc public_mALLOc #define mEMALIGn public_mEMALIGn #define rEALLOc public_rEALLOc #define vALLOc public_vALLOc #define pVALLOc public_pVALLOc #define mALLINFo public_mALLINFo #define mALLOPt public_mALLOPt #define mTRIm public_mTRIm #define mSTATs public_mSTATs #define mUSABLe public_mUSABLe #define iCALLOc public_iCALLOc #define iCOMALLOc public_iCOMALLOc #endif #ifdef USE_DL_PREFIX #define public_cALLOc dlcalloc #define public_fREe dlfree #define public_cFREe dlcfree #define public_mALLOc dlmalloc #define public_mEMALIGn dlmemalign #define public_rEALLOc dlrealloc #define public_vALLOc dlvalloc #define public_pVALLOc dlpvalloc #define public_mALLINFo dlmallinfo #define public_mALLOPt dlmallopt #define public_mTRIm dlmalloc_trim #define public_mSTATs dlmalloc_stats #define public_mUSABLe dlmalloc_usable_size #define public_iCALLOc dlindependent_calloc #define public_iCOMALLOc dlindependent_comalloc #else /* USE_DL_PREFIX */ #define public_cALLOc calloc #define public_fREe free #define public_cFREe cfree #define public_mALLOc malloc #define public_mEMALIGn memalign #define public_rEALLOc realloc #define public_vALLOc valloc #define public_pVALLOc pvalloc #define public_mALLINFo mallinfo #define public_mALLOPt mallopt #define public_mTRIm malloc_trim #define public_mSTATs malloc_stats #define public_mUSABLe malloc_usable_size #define public_iCALLOc independent_calloc #define public_iCOMALLOc independent_comalloc #endif /* USE_DL_PREFIX */ /* HAVE_MEMCPY should be defined if you are not otherwise using ANSI STD C, but still have memcpy and memset in your C library and want to use them in calloc and realloc. Otherwise simple macro versions are defined below. USE_MEMCPY should be defined as 1 if you actually want to have memset and memcpy called. People report that the macro versions are faster than libc versions on some systems. Even if USE_MEMCPY is set to 1, loops to copy/clear small chunks (of <= 36 bytes) are manually unrolled in realloc and calloc. */ #define HAVE_MEMCPY #ifndef USE_MEMCPY #ifdef HAVE_MEMCPY #define USE_MEMCPY 1 #else #define USE_MEMCPY 0 #endif #endif #if (defined(HAVE_MEMCPY)) #ifdef WIN32 /* On Win32 memset and memcpy are already declared in windows.h */ #else void* memset(void*, int, size_t); void* memcpy(void*, const void*, size_t); #endif #endif /* MALLOC_FAILURE_ACTION is the action to take before "return 0" when malloc fails to be able to return memory, either because memory is exhausted or because of illegal arguments. By default, sets errno if running on STD_C platform, else does nothing. */ #ifndef MALLOC_FAILURE_ACTION #define MALLOC_FAILURE_ACTION \ errno = ENOMEM; #endif /* MORECORE-related declarations. By default, rely on sbrk */ #ifdef LACKS_UNISTD_H #if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) extern Void_t* sbrk(ptrdiff_t); #endif #endif /* MORECORE is the name of the routine to call to obtain more memory from the system. See below for general guidance on writing alternative MORECORE functions, as well as a version for WIN32 and a sample version for pre-OSX macos. */ #ifndef MORECORE #define MORECORE sbrk #endif /* MORECORE_FAILURE is the value returned upon failure of MORECORE as well as mmap. Since it cannot be an otherwise valid memory address, and must reflect values of standard sys calls, you probably ought not try to redefine it. */ #ifndef MORECORE_FAILURE #define MORECORE_FAILURE (-1) #endif /* If MORECORE_CONTIGUOUS is true, take advantage of fact that consecutive calls to MORECORE with positive arguments always return contiguous increasing addresses. This is true of unix sbrk. Even if not defined, when regions happen to be contiguous, malloc will permit allocations spanning regions obtained from different calls. But defining this when applicable enables some stronger consistency checks and space efficiencies. */ #ifndef MORECORE_CONTIGUOUS #define MORECORE_CONTIGUOUS 1 #endif /* Define MORECORE_CANNOT_TRIM if your version of MORECORE cannot release space back to the system when given negative arguments. This is generally necessary only if you are using a hand-crafted MORECORE function that cannot handle negative arguments. */ /* #define MORECORE_CANNOT_TRIM */ /* Define HAVE_MMAP as true to optionally make malloc() use mmap() to allocate very large blocks. These will be returned to the operating system immediately after a free(). Also, if mmap is available, it is used as a backup strategy in cases where MORECORE fails to provide space from system. This malloc is best tuned to work with mmap for large requests. If you do not have mmap, operations involving very large chunks (1MB or so) may be slower than you'd like. */ #define HAVE_MMAP 0 #ifndef HAVE_MMAP #define HAVE_MMAP 1 #endif #if HAVE_MMAP /* Standard unix mmap using /dev/zero clears memory so calloc doesn't need to. */ #ifndef MMAP_CLEARS #define MMAP_CLEARS 1 #endif #else /* no mmap */ #ifndef MMAP_CLEARS #define MMAP_CLEARS 0 #endif #endif /* MMAP_AS_MORECORE_SIZE is the minimum mmap size argument to use if sbrk fails, and mmap is used as a backup (which is done only if HAVE_MMAP). The value must be a multiple of page size. This backup strategy generally applies only when systems have "holes" in address space, so sbrk cannot perform contiguous expansion, but there is still space available on system. On systems for which this is known to be useful (i.e. most linux kernels), this occurs only when programs allocate huge amounts of memory. Between this, and the fact that mmap regions tend to be limited, the size should be large, to avoid too many mmap calls and thus avoid running out of kernel resources. */ #ifndef MMAP_AS_MORECORE_SIZE #define MMAP_AS_MORECORE_SIZE (1024 * 1024) #endif /* Define HAVE_MREMAP to make realloc() use mremap() to re-allocate large blocks. This is currently only possible on Linux with kernel versions newer than 1.3.77. */ #ifndef HAVE_MREMAP #ifdef linux #define HAVE_MREMAP 1 #else #define HAVE_MREMAP 0 #endif #endif /* HAVE_MMAP */ /* The system page size. To the extent possible, this malloc manages memory from the system in page-size units. Note that this value is cached during initialization into a field of malloc_state. So even if malloc_getpagesize is a function, it is only called once. The following mechanics for getpagesize were adapted from bsd/gnu getpagesize.h. If none of the system-probes here apply, a value of 4096 is used, which should be OK: If they don't apply, then using the actual value probably doesn't impact performance. */ #ifndef malloc_getpagesize #ifndef LACKS_UNISTD_H # include #endif # ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */ # ifndef _SC_PAGE_SIZE # define _SC_PAGE_SIZE _SC_PAGESIZE # endif # endif # ifdef _SC_PAGE_SIZE # define malloc_getpagesize sysconf(_SC_PAGE_SIZE) # else # if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE) extern size_t getpagesize(); # define malloc_getpagesize getpagesize() # else # ifdef WIN32 /* use supplied emulation of getpagesize */ # define malloc_getpagesize getpagesize() # else # ifndef LACKS_SYS_PARAM_H # include # endif # ifdef EXEC_PAGESIZE # define malloc_getpagesize EXEC_PAGESIZE # else # ifdef NBPG # ifndef CLSIZE # define malloc_getpagesize NBPG # else # define malloc_getpagesize (NBPG * CLSIZE) # endif # else # ifdef NBPC # define malloc_getpagesize NBPC # else # ifdef PAGESIZE # define malloc_getpagesize PAGESIZE # else /* just guess */ # define malloc_getpagesize (4096) # endif # endif # endif # endif # endif # endif # endif #endif /* This version of malloc supports the standard SVID/XPG mallinfo routine that returns a struct containing usage properties and statistics. It should work on any SVID/XPG compliant system that has a /usr/include/malloc.h defining struct mallinfo. (If you'd like to install such a thing yourself, cut out the preliminary declarations as described above and below and save them in a malloc.h file. But there's no compelling reason to bother to do this.) The main declaration needed is the mallinfo struct that is returned (by-copy) by mallinfo(). The SVID/XPG malloinfo struct contains a bunch of fields that are not even meaningful in this version of malloc. These fields are are instead filled by mallinfo() with other numbers that might be of interest. HAVE_USR_INCLUDE_MALLOC_H should be set if you have a /usr/include/malloc.h file that includes a declaration of struct mallinfo. If so, it is included; else an SVID2/XPG2 compliant version is declared below. These must be precisely the same for mallinfo() to work. The original SVID version of this struct, defined on most systems with mallinfo, declares all fields as ints. But some others define as unsigned long. If your system defines the fields using a type of different width than listed here, you must #include your system version and #define HAVE_USR_INCLUDE_MALLOC_H. */ /* #define HAVE_USR_INCLUDE_MALLOC_H */ #ifdef HAVE_USR_INCLUDE_MALLOC_H #include "/usr/include/malloc.h" #else /* SVID2/XPG mallinfo structure */ struct mallinfo { int arena; /* non-mmapped space allocated from system */ int ordblks; /* number of free chunks */ int smblks; /* number of fastbin blocks */ int hblks; /* number of mmapped regions */ int hblkhd; /* space in mmapped regions */ int usmblks; /* maximum total allocated space */ int fsmblks; /* space available in freed fastbin blocks */ int uordblks; /* total allocated space */ int fordblks; /* total free space */ int keepcost; /* top-most, releasable (via malloc_trim) space */ }; /* SVID/XPG defines four standard parameter numbers for mallopt, normally defined in malloc.h. Only one of these (M_MXFAST) is used in this malloc. The others (M_NLBLKS, M_GRAIN, M_KEEP) don't apply, so setting them has no effect. But this malloc also supports other options in mallopt described below. */ #endif /* ---------- description of public routines ------------ */ /* malloc(size_t n) Returns a pointer to a newly allocated chunk of at least n bytes, or null if no space is available. Additionally, on failure, errno is set to ENOMEM on ANSI C systems. If n is zero, malloc returns a minumum-sized chunk. (The minimum size is 16 bytes on most 32bit systems, and 24 or 32 bytes on 64bit systems.) On most systems, size_t is an unsigned type, so calls with negative arguments are interpreted as requests for huge amounts of space, which will often fail. The maximum supported value of n differs across systems, but is in all cases less than the maximum representable value of a size_t. */ Void_t* public_mALLOc(size_t); /* free(Void_t* p) Releases the chunk of memory pointed to by p, that had been previously allocated using malloc or a related routine such as realloc. It has no effect if p is null. It can have arbitrary (i.e., bad!) effects if p has already been freed. Unless disabled (using mallopt), freeing very large spaces will when possible, automatically trigger operations that give back unused memory to the system, thus reducing program footprint. */ void public_fREe(Void_t*); /* calloc(size_t n_elements, size_t element_size); Returns a pointer to n_elements * element_size bytes, with all locations set to zero. */ Void_t* public_cALLOc(size_t, size_t); /* realloc(Void_t* p, size_t n) Returns a pointer to a chunk of size n that contains the same data as does chunk p up to the minimum of (n, p's size) bytes, or null if no space is available. The returned pointer may or may not be the same as p. The algorithm prefers extending p when possible, otherwise it employs the equivalent of a malloc-copy-free sequence. If p is null, realloc is equivalent to malloc. If space is not available, realloc returns null, errno is set (if on ANSI) and p is NOT freed. if n is for fewer bytes than already held by p, the newly unused space is lopped off and freed if possible. Unless the #define REALLOC_ZERO_BYTES_FREES is set, realloc with a size argument of zero (re)allocates a minimum-sized chunk. Large chunks that were internally obtained via mmap will always be reallocated using malloc-copy-free sequences unless the system supports MREMAP (currently only linux). The old unix realloc convention of allowing the last-free'd chunk to be used as an argument to realloc is not supported. */ Void_t* public_rEALLOc(Void_t*, size_t); /* memalign(size_t alignment, size_t n); Returns a pointer to a newly allocated chunk of n bytes, aligned in accord with the alignment argument. The alignment argument should be a power of two. If the argument is not a power of two, the nearest greater power is used. 8-byte alignment is guaranteed by normal malloc calls, so don't bother calling memalign with an argument of 8 or less. Overreliance on memalign is a sure way to fragment space. */ Void_t* public_mEMALIGn(size_t, size_t); /* valloc(size_t n); Equivalent to memalign(pagesize, n), where pagesize is the page size of the system. If the pagesize is unknown, 4096 is used. */ Void_t* public_vALLOc(size_t); /* mallopt(int parameter_number, int parameter_value) Sets tunable parameters The format is to provide a (parameter-number, parameter-value) pair. mallopt then sets the corresponding parameter to the argument value if it can (i.e., so long as the value is meaningful), and returns 1 if successful else 0. SVID/XPG/ANSI defines four standard param numbers for mallopt, normally defined in malloc.h. Only one of these (M_MXFAST) is used in this malloc. The others (M_NLBLKS, M_GRAIN, M_KEEP) don't apply, so setting them has no effect. But this malloc also supports four other options in mallopt. See below for details. Briefly, supported parameters are as follows (listed defaults are for "typical" configurations). Symbol param # default allowed param values M_MXFAST 1 64 0-64 (0 disables fastbins) M_TRIM_THRESHOLD -1 256*1024 any (-1U disables trimming) M_TOP_PAD -2 0 any M_MMAP_THRESHOLD -3 256*1024 any (or 0 if no MMAP support) M_MMAP_MAX -4 65536 any (0 disables use of mmap) */ int public_mALLOPt(int, int); /* mallinfo() Returns (by copy) a struct containing various summary statistics: arena: current total non-mmapped bytes allocated from system ordblks: the number of free chunks smblks: the number of fastbin blocks (i.e., small chunks that have been freed but not use resused or consolidated) hblks: current number of mmapped regions hblkhd: total bytes held in mmapped regions usmblks: the maximum total allocated space. This will be greater than current total if trimming has occurred. fsmblks: total bytes held in fastbin blocks uordblks: current total allocated space (normal or mmapped) fordblks: total free space keepcost: the maximum number of bytes that could ideally be released back to system via malloc_trim. ("ideally" means that it ignores page restrictions etc.) Because these fields are ints, but internal bookkeeping may be kept as longs, the reported values may wrap around zero and thus be inaccurate. */ struct mallinfo public_mALLINFo(void); /* independent_calloc(size_t n_elements, size_t element_size, Void_t* chunks[]); independent_calloc is similar to calloc, but instead of returning a single cleared space, it returns an array of pointers to n_elements independent elements that can hold contents of size elem_size, each of which starts out cleared, and can be independently freed, realloc'ed etc. The elements are guaranteed to be adjacently allocated (this is not guaranteed to occur with multiple callocs or mallocs), which may also improve cache locality in some applications. The "chunks" argument is optional (i.e., may be null, which is probably the most typical usage). If it is null, the returned array is itself dynamically allocated and should also be freed when it is no longer needed. Otherwise, the chunks array must be of at least n_elements in length. It is filled in with the pointers to the chunks. In either case, independent_calloc returns this pointer array, or null if the allocation failed. If n_elements is zero and "chunks" is null, it returns a chunk representing an array with zero elements (which should be freed if not wanted). Each element must be individually freed when it is no longer needed. If you'd like to instead be able to free all at once, you should instead use regular calloc and assign pointers into this space to represent elements. (In this case though, you cannot independently free elements.) independent_calloc simplifies and speeds up implementations of many kinds of pools. It may also be useful when constructing large data structures that initially have a fixed number of fixed-sized nodes, but the number is not known at compile time, and some of the nodes may later need to be freed. For example: struct Node { int item; struct Node* next; }; struct Node* build_list() { struct Node** pool; int n = read_number_of_nodes_needed(); if (n <= 0) return 0; pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0); if (pool == 0) die(); // organize into a linked list... struct Node* first = pool[0]; for (i = 0; i < n-1; ++i) pool[i]->next = pool[i+1]; free(pool); // Can now free the array (or not, if it is needed later) return first; } */ Void_t** public_iCALLOc(size_t, size_t, Void_t**); /* independent_comalloc(size_t n_elements, size_t sizes[], Void_t* chunks[]); independent_comalloc allocates, all at once, a set of n_elements chunks with sizes indicated in the "sizes" array. It returns an array of pointers to these elements, each of which can be independently freed, realloc'ed etc. The elements are guaranteed to be adjacently allocated (this is not guaranteed to occur with multiple callocs or mallocs), which may also improve cache locality in some applications. The "chunks" argument is optional (i.e., may be null). If it is null the returned array is itself dynamically allocated and should also be freed when it is no longer needed. Otherwise, the chunks array must be of at least n_elements in length. It is filled in with the pointers to the chunks. In either case, independent_comalloc returns this pointer array, or null if the allocation failed. If n_elements is zero and chunks is null, it returns a chunk representing an array with zero elements (which should be freed if not wanted). Each element must be individually freed when it is no longer needed. If you'd like to instead be able to free all at once, you should instead use a single regular malloc, and assign pointers at particular offsets in the aggregate space. (In this case though, you cannot independently free elements.) independent_comallac differs from independent_calloc in that each element may have a different size, and also that it does not automatically clear elements. independent_comalloc can be used to speed up allocation in cases where several structs or objects must always be allocated at the same time. For example: struct Head { ... } struct Foot { ... } void send_message(char* msg) { int msglen = strlen(msg); size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) }; void* chunks[3]; if (independent_comalloc(3, sizes, chunks) == 0) die(); struct Head* head = (struct Head*)(chunks[0]); char* body = (char*)(chunks[1]); struct Foot* foot = (struct Foot*)(chunks[2]); // ... } In general though, independent_comalloc is worth using only for larger values of n_elements. For small values, you probably won't detect enough difference from series of malloc calls to bother. Overuse of independent_comalloc can increase overall memory usage, since it cannot reuse existing noncontiguous small chunks that might be available for some of the elements. */ Void_t** public_iCOMALLOc(size_t, size_t*, Void_t**); /* pvalloc(size_t n); Equivalent to valloc(minimum-page-that-holds(n)), that is, round up n to nearest pagesize. */ Void_t* public_pVALLOc(size_t); /* cfree(Void_t* p); Equivalent to free(p). cfree is needed/defined on some systems that pair it with calloc, for odd historical reasons (such as: cfree is used in example code in the first edition of K&R). */ void public_cFREe(Void_t*); /* malloc_trim(size_t pad); If possible, gives memory back to the system (via negative arguments to sbrk) if there is unused memory at the `high' end of the malloc pool. You can call this after freeing large blocks of memory to potentially reduce the system-level memory requirements of a program. However, it cannot guarantee to reduce memory. Under some allocation patterns, some large free blocks of memory will be locked between two used chunks, so they cannot be given back to the system. The `pad' argument to malloc_trim represents the amount of free trailing space to leave untrimmed. If this argument is zero, only the minimum amount of memory to maintain internal data structures will be left (one page or less). Non-zero arguments can be supplied to maintain enough trailing space to service future expected allocations without having to re-obtain memory from the system. Malloc_trim returns 1 if it actually released any memory, else 0. On systems that do not support "negative sbrks", it will always rreturn 0. */ int public_mTRIm(size_t); /* malloc_usable_size(Void_t* p); Returns the number of bytes you can actually use in an allocated chunk, which may be more than you requested (although often not) due to alignment and minimum size constraints. You can use this many bytes without worrying about overwriting other allocated objects. This is not a particularly great programming practice. malloc_usable_size can be more useful in debugging and assertions, for example: p = malloc(n); assert(malloc_usable_size(p) >= 256); */ size_t public_mUSABLe(Void_t*); /* malloc_stats(); Prints on stderr the amount of space obtained from the system (both via sbrk and mmap), the maximum amount (which may be more than current if malloc_trim and/or munmap got called), and the current number of bytes allocated via malloc (or realloc, etc) but not yet freed. Note that this is the number of bytes allocated, not the number requested. It will be larger than the number requested because of alignment and bookkeeping overhead. Because it includes alignment wastage as being in use, this figure may be greater than zero even when no user-level chunks are allocated. The reported current and maximum system memory can be inaccurate if a program makes other calls to system memory allocation functions (normally sbrk) outside of malloc. malloc_stats prints only the most commonly interesting statistics. More information can be obtained by calling mallinfo. */ void public_mSTATs(); /* mallopt tuning options */ /* M_MXFAST is the maximum request size used for "fastbins", special bins that hold returned chunks without consolidating their spaces. This enables future requests for chunks of the same size to be handled very quickly, but can increase fragmentation, and thus increase the overall memory footprint of a program. This malloc manages fastbins very conservatively yet still efficiently, so fragmentation is rarely a problem for values less than or equal to the default. The maximum supported value of MXFAST is 64 (also the default). You wouldn't want it any higher than this anyway. Fastbins are designed especially for use with many small structs, objects or strings -- the default handles structs/objects/arrays with sizes up to 16 4byte fields, or small strings representing words, tokens, etc. Using fastbins for larger objects normally worsens fragmentation without improving speed. M_MXFAST is set in REQUEST size units. It is internally used in chunksize units, which adds padding and alignment. You can reduce M_MXFAST to 0 to disable all use of fastbins. This causes the malloc algorithm to be a closer approximation of fifo-best-fit in all cases, not just for larger requests, but will generally cause it to be slower. */ /* M_MXFAST is a standard SVID/XPG tuning option, usually listed in malloc.h */ #ifndef M_MXFAST #define M_MXFAST 1 #endif #ifndef DEFAULT_MXFAST #define DEFAULT_MXFAST 64 #endif /* M_TRIM_THRESHOLD is the maximum amount of unused top-most memory to keep before releasing via malloc_trim in free(). Automatic trimming is mainly useful in long-lived programs. Because trimming via sbrk can be slow on some systems, and can sometimes be wasteful (in cases where programs immediately afterward allocate more large chunks) the value should be high enough so that your overall system performance would improve by releasing this much memory. The trim threshold and the mmap control parameters (see below) can be traded off with one another. Trimming and mmapping are two different ways of releasing unused memory back to the system. Between these two, it is often possible to keep system-level demands of a long-lived program down to a bare minimum. For example, in one test suite of sessions measuring the XF86 X server on Linux, using a trim threshold of 128K and a mmap threshold of 192K led to near-minimal long term resource consumption. If you are using this malloc in a long-lived program, it should pay to experiment with these values. As a rough guide, you might set to a value close to the average size of a process (program) running on your system. Releasing this much memory would allow such a process to run in memory. Generally, it's worth it to tune for trimming rather tham memory mapping when a program undergoes phases where several large chunks are allocated and released in ways that can reuse each other's storage, perhaps mixed with phases where there are no such chunks at all. And in well-behaved long-lived programs, controlling release of large blocks via trimming versus mapping is usually faster. However, in most programs, these parameters serve mainly as protection against the system-level effects of carrying around massive amounts of unneeded memory. Since frequent calls to sbrk, mmap, and munmap otherwise degrade performance, the default parameters are set to relatively high values that serve only as safeguards. The trim value must be greater than page size to have any useful effect. To disable trimming completely, you can set to (unsigned long)(-1) Trim settings interact with fastbin (MXFAST) settings: Unless TRIM_FASTBINS is defined, automatic trimming never takes place upon freeing a chunk with size less than or equal to MXFAST. Trimming is instead delayed until subsequent freeing of larger chunks. However, you can still force an attempted trim by calling malloc_trim. Also, trimming is not generally possible in cases where the main arena is obtained via mmap. Note that the trick some people use of mallocing a huge space and then freeing it at program startup, in an attempt to reserve system memory, doesn't have the intended effect under automatic trimming, since that memory will immediately be returned to the system. */ #define M_TRIM_THRESHOLD -1 #ifndef DEFAULT_TRIM_THRESHOLD #define DEFAULT_TRIM_THRESHOLD (-1U) /* #define DEFAULT_TRIM_THRESHOLD (256 * 1024) */ #endif /* M_TOP_PAD is the amount of extra `padding' space to allocate or retain whenever sbrk is called. It is used in two ways internally: * When sbrk is called to extend the top of the arena to satisfy a new malloc request, this much padding is added to the sbrk request. * When malloc_trim is called automatically from free(), it is used as the `pad' argument. In both cases, the actual amount of padding is rounded so that the end of the arena is always a system page boundary. The main reason for using padding is to avoid calling sbrk so often. Having even a small pad greatly reduces the likelihood that nearly every malloc request during program start-up (or after trimming) will invoke sbrk, which needlessly wastes time. Automatic rounding-up to page-size units is normally sufficient to avoid measurable overhead, so the default is 0. However, in systems where sbrk is relatively slow, it can pay to increase this value, at the expense of carrying around more memory than the program needs. */ #define M_TOP_PAD -2 #ifndef DEFAULT_TOP_PAD #define DEFAULT_TOP_PAD (0) #endif /* M_MMAP_THRESHOLD is the request size threshold for using mmap() to service a request. Requests of at least this size that cannot be allocated using already-existing space will be serviced via mmap. (If enough normal freed space already exists it is used instead.) Using mmap segregates relatively large chunks of memory so that they can be individually obtained and released from the host system. A request serviced through mmap is never reused by any other request (at least not directly; the system may just so happen to remap successive requests to the same locations). Segregating space in this way has the benefits that: 1. Mmapped space can ALWAYS be individually released back to the system, which helps keep the system level memory demands of a long-lived program low. 2. Mapped memory can never become `locked' between other chunks, as can happen with normally allocated chunks, which means that even trimming via malloc_trim would not release them. 3. On some systems with "holes" in address spaces, mmap can obtain memory that sbrk cannot. However, it has the disadvantages that: 1. The space cannot be reclaimed, consolidated, and then used to service later requests, as happens with normal chunks. 2. It can lead to more wastage because of mmap page alignment requirements 3. It causes malloc performance to be more dependent on host system memory management support routines which may vary in implementation quality and may impose arbitrary limitations. Generally, servicing a request via normal malloc steps is faster than going through a system's mmap. The advantages of mmap nearly always outweigh disadvantages for "large" chunks, but the value of "large" varies across systems. The default is an empirically derived value that works well in most systems. */ #define M_MMAP_THRESHOLD -3 #ifndef DEFAULT_MMAP_THRESHOLD #define DEFAULT_MMAP_THRESHOLD (-1U) /*#define DEFAULT_MMAP_THRESHOLD (128 * 1024) */ #endif /* M_MMAP_MAX is the maximum number of requests to simultaneously service using mmap. This parameter exists because . Some systems have a limited number of internal tables for use by mmap, and using more than a few of them may degrade performance. The default is set to a value that serves only as a safeguard. Setting to 0 disables use of mmap for servicing large requests. If HAVE_MMAP is not set, the default value is 0, and attempts to set it to non-zero values in mallopt will fail. */ #define M_MMAP_MAX -4 #ifndef DEFAULT_MMAP_MAX #if HAVE_MMAP #define DEFAULT_MMAP_MAX (65536) #else #define DEFAULT_MMAP_MAX (0) #endif #endif #ifdef __cplusplus }; /* end of extern "C" */ #endif /* ======================================================================== To make a fully customizable malloc.h header file, cut everything above this line, put into file malloc.h, edit to suit, and #include it on the next line, as well as in programs that use this malloc. ======================================================================== */ /* #include "malloc.h" */ /* --------------------- public wrappers ---------------------- */ #ifdef USE_PUBLIC_MALLOC_WRAPPERS /* Declare all routines as internal */ static Void_t* mALLOc(size_t); static void fREe(Void_t*); static Void_t* rEALLOc(Void_t*, size_t); static Void_t* mEMALIGn(size_t, size_t); static Void_t* vALLOc(size_t); static Void_t* pVALLOc(size_t); static Void_t* cALLOc(size_t, size_t); static Void_t** iCALLOc(size_t, size_t, Void_t**); static Void_t** iCOMALLOc(size_t, size_t*, Void_t**); static void cFREe(Void_t*); static int mTRIm(size_t); static size_t mUSABLe(Void_t*); static void mSTATs(); static int mALLOPt(int, int); static struct mallinfo mALLINFo(void); /* MALLOC_PREACTION and MALLOC_POSTACTION should be defined to return 0 on success, and nonzero on failure. The return value of MALLOC_POSTACTION is currently ignored in wrapper functions since there is no reasonable default action to take on failure. */ #ifdef USE_MALLOC_LOCK #ifdef WIN32 static int mALLOC_MUTEx; #define MALLOC_PREACTION slwait(&mALLOC_MUTEx) #define MALLOC_POSTACTION slrelease(&mALLOC_MUTEx) #else #include static pthread_mutex_t mALLOC_MUTEx = PTHREAD_MUTEX_INITIALIZER; #define MALLOC_PREACTION pthread_mutex_lock(&mALLOC_MUTEx) #define MALLOC_POSTACTION pthread_mutex_unlock(&mALLOC_MUTEx) #endif /* USE_MALLOC_LOCK */ #else /* Substitute anything you like for these */ #define MALLOC_PREACTION (0) #define MALLOC_POSTACTION (0) #endif Void_t* public_mALLOc(size_t bytes) { Void_t* m; if (MALLOC_PREACTION != 0) { return 0; } m = mALLOc(bytes); if (MALLOC_POSTACTION != 0) { } return m; } void public_fREe(Void_t* m) { if (MALLOC_PREACTION != 0) { return; } fREe(m); if (MALLOC_POSTACTION != 0) { } } Void_t* public_rEALLOc(Void_t* m, size_t bytes) { if (MALLOC_PREACTION != 0) { return 0; } m = rEALLOc(m, bytes); if (MALLOC_POSTACTION != 0) { } return m; } Void_t* public_mEMALIGn(size_t alignment, size_t bytes) { Void_t* m; if (MALLOC_PREACTION != 0) { return 0; } m = mEMALIGn(alignment, bytes); if (MALLOC_POSTACTION != 0) { } return m; } Void_t* public_vALLOc(size_t bytes) { Void_t* m; if (MALLOC_PREACTION != 0) { return 0; } m = vALLOc(bytes); if (MALLOC_POSTACTION != 0) { } return m; } Void_t* public_pVALLOc(size_t bytes) { Void_t* m; if (MALLOC_PREACTION != 0) { return 0; } m = pVALLOc(bytes); if (MALLOC_POSTACTION != 0) { } return m; } Void_t* public_cALLOc(size_t n, size_t elem_size) { Void_t* m; if (MALLOC_PREACTION != 0) { return 0; } m = cALLOc(n, elem_size); if (MALLOC_POSTACTION != 0) { } return m; } Void_t** public_iCALLOc(size_t n, size_t elem_size, Void_t** chunks) { Void_t** m; if (MALLOC_PREACTION != 0) { return 0; } m = iCALLOc(n, elem_size, chunks); if (MALLOC_POSTACTION != 0) { } return m; } Void_t** public_iCOMALLOc(size_t n, size_t sizes[], Void_t** chunks) { Void_t** m; if (MALLOC_PREACTION != 0) { return 0; } m = iCOMALLOc(n, sizes, chunks); if (MALLOC_POSTACTION != 0) { } return m; } void public_cFREe(Void_t* m) { if (MALLOC_PREACTION != 0) { return; } cFREe(m); if (MALLOC_POSTACTION != 0) { } } int public_mTRIm(size_t s) { int result; if (MALLOC_PREACTION != 0) { return 0; } result = mTRIm(s); if (MALLOC_POSTACTION != 0) { } return result; } size_t public_mUSABLe(Void_t* m) { size_t result; if (MALLOC_PREACTION != 0) { return 0; } result = mUSABLe(m); if (MALLOC_POSTACTION != 0) { } return result; } void public_mSTATs() { if (MALLOC_PREACTION != 0) { return; } mSTATs(); if (MALLOC_POSTACTION != 0) { } } struct mallinfo public_mALLINFo() { struct mallinfo m; if (MALLOC_PREACTION != 0) { struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; return nm; } m = mALLINFo(); if (MALLOC_POSTACTION != 0) { } return m; } int public_mALLOPt(int p, int v) { int result; if (MALLOC_PREACTION != 0) { return 0; } result = mALLOPt(p, v); if (MALLOC_POSTACTION != 0) { } return result; } #endif /* ------------- Optional versions of memcopy ---------------- */ #if USE_MEMCPY /* Note: memcpy is ONLY invoked with non-overlapping regions, so the (usually slower) memmove is not needed. */ #define MALLOC_COPY(dest, src, nbytes) memcpy(dest, src, nbytes) #define MALLOC_ZERO(dest, nbytes) memset(dest, 0, nbytes) #else /* !USE_MEMCPY */ /* Use Duff's device for good zeroing/copying performance. */ #define MALLOC_ZERO(charp, nbytes) \ do { \ INTERNAL_SIZE_T* mzp = (INTERNAL_SIZE_T*)(charp); \ CHUNK_SIZE_T mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T); \ long mcn; \ if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \ switch (mctmp) { \ case 0: for(;;) { *mzp++ = 0; \ case 7: *mzp++ = 0; \ case 6: *mzp++ = 0; \ case 5: *mzp++ = 0; \ case 4: *mzp++ = 0; \ case 3: *mzp++ = 0; \ case 2: *mzp++ = 0; \ case 1: *mzp++ = 0; if(mcn <= 0) break; mcn--; } \ } \ } while(0) #define MALLOC_COPY(dest,src,nbytes) \ do { \ INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) src; \ INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) dest; \ CHUNK_SIZE_T mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T); \ long mcn; \ if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \ switch (mctmp) { \ case 0: for(;;) { *mcdst++ = *mcsrc++; \ case 7: *mcdst++ = *mcsrc++; \ case 6: *mcdst++ = *mcsrc++; \ case 5: *mcdst++ = *mcsrc++; \ case 4: *mcdst++ = *mcsrc++; \ case 3: *mcdst++ = *mcsrc++; \ case 2: *mcdst++ = *mcsrc++; \ case 1: *mcdst++ = *mcsrc++; if(mcn <= 0) break; mcn--; } \ } \ } while(0) #endif /* ------------------ MMAP support ------------------ */ #if HAVE_MMAP #include #ifndef LACKS_SYS_MMAN_H #include #endif #if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) #define MAP_ANONYMOUS MAP_ANON #endif /* Nearly all versions of mmap support MAP_ANONYMOUS, so the following is unlikely to be needed, but is supplied just in case. */ #ifndef MAP_ANONYMOUS static int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */ #define MMAP(addr, size, prot, flags) ((dev_zero_fd < 0) ? \ (dev_zero_fd = open("/dev/zero", O_RDWR), \ mmap((addr), (size), (prot), (flags), dev_zero_fd, 0)) : \ mmap((addr), (size), (prot), (flags), dev_zero_fd, 0)) #else #define MMAP(addr, size, prot, flags) \ (mmap((addr), (size), (prot), (flags)|MAP_ANONYMOUS, -1, 0)) #endif #endif /* HAVE_MMAP */ /* ----------------------- Chunk representations ----------------------- */ /* This struct declaration is misleading (but accurate and necessary). It declares a "view" into memory allowing access to necessary fields at known offsets from a given base. See explanation below. */ struct malloc_chunk { INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */ INTERNAL_SIZE_T size; /* Size in bytes, including overhead. */ struct malloc_chunk* fd; /* double links -- used only if free. */ struct malloc_chunk* bk; }; typedef struct malloc_chunk* mchunkptr; /* conversion from malloc headers to user pointers, and back */ #define chunk2mem(p) ((Void_t*)((char*)(p) + 2*SIZE_SZ)) #define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*SIZE_SZ)) /* malloc_chunk details: (The following includes lightly edited explanations by Colin Plumb.) Chunks of memory are maintained using a `boundary tag' method as described in e.g., Knuth or Standish. (See the paper by Paul Wilson ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a survey of such techniques.) Sizes of free chunks are stored both in the front of each chunk and at the end. This makes consolidating fragmented chunks into bigger chunks very fast. The size fields also hold bits representing whether chunks are free or in use. An allocated chunk looks like this: chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Size of previous chunk, if allocated | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Size of chunk, in bytes |P| mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | User data starts here... . . . . (malloc_usable_space() bytes) . . | nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ `foot:' | Size of chunk | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Where "chunk" is the front of the chunk for the purpose of most of the malloc code, but "mem" is the pointer that is returned to the user. "Nextchunk" is the beginning of the next contiguous chunk. Chunks always begin on even word boundries, so the mem portion (which is returned to the user) is also on an even word boundary, and thus at least double-word aligned. The P (PREV_INUSE) bit, stored in the unused low-order bit of the chunk size (which is always a multiple of two words), is an in-use bit for the *previous* chunk. If that bit is *clear*, then the word before the current chunk size contains the previous chunk size, and can be used to find the front of the previous chunk. The very first chunk allocated always has this bit set, preventing access to non-existent (or non-owned) memory. If prev_inuse is set for any given chunk, then you CANNOT determine the size of the previous chunk, and might even get a memory addressing fault when trying to do so. Note that the `foot' of the current chunk is actually represented as the prev_size of the NEXT chunk. This makes it easier to deal with alignments etc but can be very confusing when trying to extend or adapt this code. The two exceptions to all this are 1. The special chunk `top' doesn't bother using the trailing size field since there is no next contiguous chunk that would have to index off it. After initialization, `top' is forced to always exist. If it would become less than MINSIZE bytes long, it is replenished. 2. Chunks allocated via mmap, which have the second-lowest-order bit (IS_MMAPPED) set in their size fields. Because they are allocated one-by-one, each must contain its own trailing size field. */ /* --------------- Operations on size fields --------------- */ /* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */ #define PREV_INUSE 0x1 #if HAVE_MMAP /* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap */ #define IS_MMAPPED 0x2 #else #define IS_MMAPPED 0 #endif /* extract inuse bit of previous chunk */ #define prev_inuse(p) ((p)->size & PREV_INUSE) /* check for mmap()'ed chunk */ #define chunk_is_mmapped(p) ((p)->size & IS_MMAPPED) /* Bits to mask off when extracting size Note: IS_MMAPPED is intentionally not masked off from size field in macros for which mmapped chunks should never be seen. This should cause helpful core dumps to occur if it is tried by accident by people extending or adapting this malloc. */ #define SIZE_BITS (PREV_INUSE|IS_MMAPPED) /* Get size, ignoring use bits */ #define chunksize(p) ((CHUNK_SIZE_T)((p)->size & ~(SIZE_BITS))) /* Ptr to next physical malloc_chunk. */ #define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->size & ~PREV_INUSE))) /* Ptr to previous physical malloc_chunk */ #define prev_chunk(p) ((mchunkptr)( ((char*)(p)) - ((p)->prev_size) )) /* Treat space at ptr + offset as a chunk */ #define chunk_at_offset(p, s) ((mchunkptr)(((char*)(p)) + (s))) /* extract p's inuse bit */ #define inuse(p)\ ((((mchunkptr)(((char*)(p))+((p)->size & ~PREV_INUSE)))->size) & PREV_INUSE) /* set/clear chunk as being inuse without otherwise disturbing */ #define set_inuse(p)\ ((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size |= PREV_INUSE #define clear_inuse(p)\ ((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size &= ~(PREV_INUSE) /* check/set/clear inuse bits in known places */ #define inuse_bit_at_offset(p, s)\ (((mchunkptr)(((char*)(p)) + (s)))->size & PREV_INUSE) #define inuse_addr_at_offset(p, s)\ (INTERNAL_SIZE_T*)(&(((mchunkptr)(((char*)(p)) + (s)))->size)) #define set_inuse_bit_at_offset(p, s)\ (((mchunkptr)(((char*)(p)) + (s)))->size |= PREV_INUSE) #define clear_inuse_bit_at_offset(p, s)\ (((mchunkptr)(((char*)(p)) + (s)))->size &= ~(PREV_INUSE)) /* Set size at head, without disturbing its use bit */ #define set_head_size(p, s) ((p)->size = (((p)->size & PREV_INUSE) | (s))) /* Set size/use field */ #define set_head(p, s) ((p)->size = (s)) /* Set size at footer (only when chunk is not in use) */ #define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_size = (s)) /* ---------- Size and alignment checks and conversions ---------- */ /* The smallest possible chunk */ #define MIN_CHUNK_SIZE (sizeof(struct malloc_chunk)) /* The smallest size we can malloc is an aligned minimal chunk */ #define MINSIZE \ (CHUNK_SIZE_T)(((MIN_CHUNK_SIZE+MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)) /* Check if m has acceptable alignment */ #define aligned_OK(m) (((PTR_UINT)((m)) & (MALLOC_ALIGN_MASK)) == 0) /* Check if a request is so large that it would wrap around zero when padded and aligned. To simplify some other code, the bound is made low enough so that adding MINSIZE will also not wrap around sero. */ #define MAX_REQUEST_SIZE ((CHUNK_SIZE_T)(INTERNAL_SIZE_T)(-2 * MINSIZE)) #define request_out_of_range(req) \ ((CHUNK_SIZE_T)(req) >= MAX_REQUEST_SIZE) /* pad request bytes into a usable size -- internal version */ #define request2size(req) \ (((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE) ? \ MINSIZE : \ ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK) #define pad_request(req) \ (((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK) /* Same, except also perform argument check */ #define checked_request2size(req, sz) \ if (request_out_of_range(req)) { \ MALLOC_FAILURE_ACTION; \ return 0; \ } \ (sz) = request2size(req); typedef CHUNK_SIZE_T bin_index_t; typedef unsigned int bitmap_t; /* ---------- Overlaid Data types ---------- */ /* "Small" chunks are stored in circular doubly-linked lists, and look like this: chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Size of previous chunk | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ `head:' | Size of chunk, in bytes |P| mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Forward pointer to next chunk in list | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Back pointer to previous chunk in list | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Unused space (may be 0 bytes long) . . . . | nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ `foot:' | Size of chunk, in bytes | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Larger chunks are kept in a form of bitwise digital trees (aka tries) keyed on chunksizes, in which * As seen as trees, they contains no duplicates (i.e., no duplicate sizes). If a chunk with the same size an an existing node is inserted, it is linked off the existing node using pointers that work in the same way as fd/bk pointers of small chunks * The decision to go left or right when searching is based on a sliding bit, starting at the most significant bit distinguishing sizes in the tree, and sliding right each level. All left children of a node are smaller than all right children, but not necessarily smaller than the node. The worst case number of steps to add or remove a node is thus bounded by the number of bits differentiating chunks within bins. Under current bin calculations, this ranges from 6 up to 21 (for 32 bit sizes) or up to 53 (for 64 bit sizes). The typical case is of course much better. Tree chunks are overlaid in the same way as small chunks. Because malloc_tree_chunks are only for free chunks greater than 256 bytes, their zie doesn;t impose any constraints on user chunk sizes. chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Size of previous chunk | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ `head:' | Size of chunk, in bytes |P| mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Forward pointer to next chunk of same size | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Back pointer to previous chunk of same size | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Pointer to left child (child[0]) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Pointer to right child (child[1]) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Pointer to parent | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | bin index of this chunk | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Unused space . . | nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ `foot:' | Size of chunk, in bytes | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ struct malloc_tree_chunk { INTERNAL_SIZE_T prev_size; /* same as in malloc_chunk */ INTERNAL_SIZE_T size; struct malloc_tree_chunk* fd; /* double links -- used only if free. */ struct malloc_tree_chunk* bk; struct malloc_tree_chunk* child[2]; struct malloc_tree_chunk* parent; bin_index_t index; }; typedef struct malloc_tree_chunk* tchunkptr; typedef struct malloc_tree_chunk* tbinptr; /* -------------------- Internal data structures -------------------- All internal state is held in an instance of malloc_state defined below. There are no other static variables, except in two optional cases: * If USE_MALLOC_LOCK is defined, the mALLOC_MUTEx declared above. * If HAVE_MMAP is true, but mmap doesn't support MAP_ANONYMOUS, a dummy file descriptor for mmap. Beware of lots of tricks that minimize the total bookkeeping space requirements. The result is a little under 1K bytes (for 4byte pointers and size_t.) */ /* SmallBins An array of bin headers for free chunks. Most bins hold sizes that are unusual as malloc request sizes, but are more usual for fragments and consolidated sets of chunks, which is what these bins hold, so they can be found quickly. All procedures maintain the invariant that no consolidated chunk physically borders another one, so each chunk in a list is known to be preceeded and followed by either inuse chunks or the ends of memory. To simplify use in double-linked lists, each bin header acts as a malloc_chunk pointing to the real first node, if it exists (else juct pointing to itself). This avoids special-casing for headers. But to conserve space and improve locality, we allocate only the fd/bk pointers of bins, and then use repositioning tricks to treat these as the fields of a malloc_chunk*. */ typedef struct malloc_chunk* mbinptr; /* addressing */ #define bin_at(m, i) ((mbinptr)((char*)&((m)->bins[(i)<<1]) - (SIZE_SZ<<1))) /* analog of ++bin */ #define next_bin(b) ((mbinptr)((char*)(b) + (sizeof(mchunkptr)<<1))) /* inverse of bin_at */ #define bin2idx(m, b) \ ( ((int) (((char*)(b)) - (char*)(bin_at(m,0)))) / (2 * sizeof(mchunkptr))) /* Indexing Bins for sizes < MIN_TREEBIN_SIZE bytes contain chunks of all the same size, spaced 8 bytes apart. Larger bins are approximately logarithmically spaced. */ #define NBINS 32 #define SMALLBIN_WIDTH 8 #define MIN_TREEBIN_SIZE 256 /* bit-shift corresponding to MIN_TREEBIN_SIZE */ #define TREE_BIN_SHIFT 8 #define in_smallbin_range(sz) \ ((CHUNK_SIZE_T)(sz) <= (CHUNK_SIZE_T)(MIN_TREEBIN_SIZE-1)) #define MAX_SMALL_REQUEST (MIN_TREEBIN_SIZE-(SIZE_SZ+MALLOC_ALIGNMENT)) #define smallbin_index(sz) (bin_index_t)((sz) >> 3) #define size_for_smallindex(i) ((CHUNK_SIZE_T)(i) << 3) #define MIN_SMALLBIN_INDEX (smallbin_index(MINSIZE)) #define MIN_SMALLBIN_BIT (idx2bit(smallbin_index(MINSIZE))) /* There are 2 equally spaced treebins for each power of two from TREE_BIN_SHIFT to TREE_BIN_SHIFT+16. The last bin holds anything larger. */ static bin_index_t treebin_index(CHUNK_SIZE_T sz) { unsigned int m; unsigned int x = sz >> TREE_BIN_SHIFT; if (x == 0) return 0; if (x > 0xFFFF) return NBINS-1; /* On intel, use BSRL instruction to find highest bit */ #if defined(__GNUC__) && defined(i386) __asm__("bsrl %1,%0\n\t" : "=r" (m) : "g" (x)); return (m << 1) + ((sz >> (m + (TREE_BIN_SHIFT-1)) & 1)); #else { /* Based on branch-free nlz algorithm in chapter 5 of Henry S. Warren Jr's book "Hacker's Delight". */ unsigned int n = ((x - 0x100) >> 16) & 8; x <<= n; m = ((x - 0x1000) >> 16) & 4; n += m; x <<= m; m = ((x - 0x4000) >> 16) & 2; n += m; x = (x << m) >> 14; m = 13 - n + (x & ~(x>>1)); /* shift up n and use the next bit to make finer-granularity bins. */ return (m << 1) + ((sz >> (m + (TREE_BIN_SHIFT-1)) & 1)); } #endif } static bin_index_t bit2idx(bitmap_t x) { #if defined(__GNUC__) && defined(i386) int r; __asm__("bsfl %1,%0\n\t" : "=r" (r) : "g" (x)); return (bin_index_t)r; #else return (bin_index_t)(ffs(x)-1); #endif } #define bin_index(sz) \ ((in_smallbin_range(sz)) ? smallbin_index(sz) : treebin_index(sz)) /* The most significant bit distinguishing nodes in the tree associated with a given bin */ #define CHUNK_SIZE_BITS (sizeof(CHUNK_SIZE_T) * 8) #define bitshift_for_index(idx) \ (idx == NBINS-1)? \ CHUNK_SIZE_BITS-1 : \ (((idx) >> 1) + TREE_BIN_SHIFT-2) #define tbin_at(m,i) (&((m)->treebins[i])) #define minsize_for_treeindex(i) \ (((CHUNK_SIZE_T)(1) << (((i) >> 1) + TREE_BIN_SHIFT)) | \ (((CHUNK_SIZE_T)((i) & 1)) << \ ( ( (i) >> 1) + TREE_BIN_SHIFT - 1))) #define is_tbin(M, P) ((tbinptr*)(P) >= &((M)->treebins[0]) && \ (tbinptr*)(P) < &((M)->treebins[NBINS])) #define leftmost_child(t) \ (((t)->child[0] != 0)? ((t)->child[0]) : ((t)->child[1])) /* Fastbins An array of lists holding recently freed small chunks. Fastbins are not doubly linked. It is faster to single-link them, and since chunks are never removed from the middles of these lists, double linking is not necessary. Also, unlike regular bins, they are not even processed in FIFO order (they use faster LIFO) since ordering doesn't much matter in the transient contexts in which fastbins are normally used. Chunks in fastbins keep their inuse bit set, so they cannot be consolidated with other free chunks. malloc_consolidate releases all chunks in fastbins and consolidates them with other free chunks. */ typedef struct malloc_chunk* mfastbinptr; #define fastbin_at(m,i) (&((m)->fastbins[i])) /* offset 2 to use otherwise unindexable first 2 bins */ #define fastbin_index(sz) ((((unsigned int)(sz)) >> 3) - 2) /* The maximum fastbin request size we support */ #define MAX_FAST_REQUEST 64 #define MAX_FAST_SIZE (request2size(MAX_FAST_REQUEST)) #define NFASTBINS (fastbin_index(MAX_FAST_SIZE)+1) /* FASTCHUNKS_BIT held in max_fast indicates that there are probably some fastbin chunks. It is set true on entering a chunk into any fastbin, and cleared only in malloc_consolidate. */ #define FASTCHUNKS_BIT (2U) #define have_fastchunks(M) (((M)->max_fast & FASTCHUNKS_BIT)) #define set_fastchunks(M) ((M)->max_fast |= (FASTCHUNKS_BIT)) #define clear_fastchunks(M) ((M)->max_fast &= ~(FASTCHUNKS_BIT)) /* Set value of max_fast. Use impossibly small value if 0. */ #define set_max_fast(M, s) \ (M)->max_fast = (((s) == 0)? SMALLBIN_WIDTH: request2size(s)) | \ ((M)->max_fast & (FASTCHUNKS_BIT)) #define get_max_fast(M) \ ((M)->max_fast & ~(FASTCHUNKS_BIT)) /* Top The top-most available chunk (i.e., the one bordering the end of available memory) is treated specially. It is never included in any bin, is used only if no other chunk is available, and is released back to the system if it is very large (see M_TRIM_THRESHOLD). Top initially points to a dummy bin with zero size, thus forcing extension on the first malloc request, so we avoid having any special code in malloc to check whether it even exists yet. */ /* Binmap To help compensate for the large number of bins, a one-level index structure is used for bin-by-bin searching. `binmap' is a bitvector recording whether bins are definitely empty so they can be skipped over during during traversals. */ /* Conservatively use 32 bits per map word, even if on 64bit system */ #define idx2bit(i) ((bitmap_t)(1) << (i)) #define mark_smallbin(m,i) ((m)->smallbits |= idx2bit(i)) #define mark_treebin(m,i) ((m)->treebits |= idx2bit(i)) #define clear_smallbin(m,i) ((m)->smallbits &= ~idx2bit(i)) #define clear_treebin(m,i) ((m)->treebits &= ~idx2bit(i)) /* isolate the least set bit of a bitmap */ #define least_bit(x) ((x) & -(x)) /* create mask with all bits to left of least bit of x on */ #define left_bits(x) ((x<<1) | -(x<<1)) /* create mask with all bits to left of or equal to least bit of x on */ #define same_or_left_bits(x) ((x) | -(x)) /* sysctl is a status word holding dynamically discovered or controlled properties of the morecore function */ #define MORECORE_CONTIGUOUS_BIT (1U) #define TRIM_DISABLE_BIT (2U) #define MMAP_DISABLE_BIT (4U) #define contiguous(M) \ (((M)->sysctl & MORECORE_CONTIGUOUS_BIT)) #define set_contiguous(M) \ ((M)->sysctl |= MORECORE_CONTIGUOUS_BIT) #define set_noncontiguous(M) \ ((M)->sysctl &= ~MORECORE_CONTIGUOUS_BIT) #define disable_trim(M) \ ((M)->sysctl |= TRIM_DISABLE_BIT) #define enable_trim(M) \ ((M)->sysctl &= ~TRIM_DISABLE_BIT) #define trim_disabled(M) \ ((M)->sysctl & TRIM_DISABLE_BIT) #define enable_mmap(M) \ ((M)->sysctl &= ~MMAP_DISABLE_BIT) #define disable_mmap(M) \ ((M)->sysctl |= MMAP_DISABLE_BIT) #define mmap_disabled(M) \ ((M)->sysctl & MMAP_DISABLE_BIT) /* ----------- Internal state representation and initialization ----------- */ struct malloc_state { /* The maximum chunk size to be eligible for fastbin */ CHUNK_SIZE_T max_fast; /* Bitmap of bins */ bitmap_t smallbits; bitmap_t treebits; /* Base of the topmost chunk -- not otherwise kept in a bin */ mchunkptr top; /* Fastbins */ mfastbinptr fastbins[NFASTBINS]; /* Smallbins packed as described above */ mchunkptr bins[NBINS * 2]; /* Treebins */ tbinptr treebins[NBINS]; /* Padding to allow addressing past end of treebin array */ struct malloc_tree_chunk initial_top; /* Tunable parameters */ CHUNK_SIZE_T trim_threshold; INTERNAL_SIZE_T top_pad; INTERNAL_SIZE_T mmap_threshold; /* Memory map support */ int n_mmaps; int n_mmaps_max; int max_n_mmaps; /* Cache malloc_getpagesize */ unsigned int pagesize; /* Track properties of MORECORE */ unsigned int sysctl; /* Statistics */ INTERNAL_SIZE_T mmapped_mem; INTERNAL_SIZE_T sbrked_mem; INTERNAL_SIZE_T max_sbrked_mem; INTERNAL_SIZE_T max_mmapped_mem; INTERNAL_SIZE_T max_total_mem; }; typedef struct malloc_state *mstate; /* There is exactly one instance of this struct in this malloc. If you are adapting this malloc in a way that does NOT use a static malloc_state, you MUST explicitly zero-fill it before using. This malloc relies on the property that malloc_state is initialized to all zeroes (as is true of C statics). */ static struct malloc_state av_; /* never directly referenced */ /* All uses of av_ are via get_malloc_state(). At most one "call" to get_malloc_state is made per invocation of the public versions of malloc and free, but other routines that in turn invoke malloc and/or free may call more then once. Also, it is called in check* routines if DEBUG is set. */ #define get_malloc_state() (&(av_)) /* Initialize a malloc_state struct. This is called only in sysmalloc, to avoid it being inlined everywhere else, which causes useless code bloat. */ static void malloc_init_state(mstate av) { int i; mbinptr bin; /* Establish circular links for bins */ for (i = 0; i < NBINS; ++i) { bin = bin_at(av,i); bin->fd = bin->bk = bin; } av->top_pad = DEFAULT_TOP_PAD; av->n_mmaps_max = DEFAULT_MMAP_MAX; av->mmap_threshold = DEFAULT_MMAP_THRESHOLD; av->trim_threshold = DEFAULT_TRIM_THRESHOLD; #if MORECORE_CONTIGUOUS set_contiguous(av); #else set_noncontiguous(av); #endif set_max_fast(av, DEFAULT_MXFAST); av->top = (mchunkptr)(&(av->initial_top)); av->pagesize = malloc_getpagesize; } #define ensure_initialization(M) \ if ((M)->top == 0) sysmalloc(M, 0); /* Other internal utilities */ static Void_t* sysmalloc(mstate, CHUNK_SIZE_T); static int systrim(mstate, size_t); static Void_t** iALLOc(size_t, size_t*, int, Void_t**); static void insert_treenode(mstate, tchunkptr, CHUNK_SIZE_T); #if 0 static void unlink_treenode(mstate, tchunkptr); static void unlink_small_chunk(mstate av, mchunkptr p, CHUNK_SIZE_T size); #endif static void transfer_tree_links(tchunkptr oldt, tchunkptr newt); static tchunkptr find_replacement(tchunkptr t); static void unlink_chained_node(tchunkptr t); static void insert_small_chunk(mstate av, mchunkptr p, CHUNK_SIZE_T nb); static void insert_chunk(mstate av, mchunkptr p, CHUNK_SIZE_T nb); static mchunkptr take_from_smallbin(mstate av, mchunkptr bin, bitmap_t bit); static void unlink_chunk(mstate av, mchunkptr p, CHUNK_SIZE_T size); static void malloc_consolidate(mstate); #pragma no_inline(systrim) #if HAVE_MMAP static mchunkptr mmap_malloc(mstate, INTERNAL_SIZE_T); #endif /* Debugging support These routines make a number of assertions about the states of data structures that should be true at all times. If any are not true, it's very likely that a user program has somehow trashed memory. (It's also possible that there is a coding error in malloc. In which case, please report it!) */ #if ! DEBUG #define check_chunk(P) #define check_free_chunk(P) #define check_inuse_chunk(P) #define check_remalloced_chunk(P,N) #define check_malloced_chunk(P,N) #define check_malloc_state(M) #define check_tree(P) #else #define check_chunk(P) do_check_chunk(P) #define check_free_chunk(P) do_check_free_chunk(P) #define check_inuse_chunk(P) do_check_inuse_chunk(P) #define check_remalloced_chunk(P,N) do_check_remalloced_chunk(P,N) #define check_malloced_chunk(P,N) do_check_malloced_chunk(P,N) #define check_tree(P) do_check_tree(P) #define check_malloc_state(M) do_check_malloc_state(M) static void do_check_malloc_state(mstate); /* Find x in a treebin. Used in other check functions. */ static tchunkptr tree_find(tchunkptr x) { mstate av = get_malloc_state(); CHUNK_SIZE_T nb = chunksize(x); bin_index_t idx = treebin_index(nb); tbinptr* bin = tbin_at(av, idx); tchunkptr t = *bin; bin_index_t shift = bitshift_for_index(idx); CHUNK_SIZE_T allbits = 0; if (t == 0) return 0; while (t != 0) { CHUNK_SIZE_T size; if (t == x) return t; size = chunksize(t); assert((size & allbits) == allbits); if (size == nb) { tchunkptr p = t->bk; for (;;) { if (p == x) return p; else if (p == t) return 0; else p = p->bk; } } if (((nb >> shift) & 1) == 0) { t = t->child[0]; } else { t = t->child[1]; allbits |= 1U << shift; } --shift; } return 0; } /* Properties of all chunks */ static void do_check_chunk(mchunkptr p) { mstate av = get_malloc_state(); CHUNK_SIZE_T sz = chunksize(p); /* min and max possible addresses assuming contiguous allocation */ char* max_address = (char*)(av->top) + chunksize(av->top); char* min_address = max_address - av->sbrked_mem; if (!chunk_is_mmapped(p)) { /* Has legal address ... */ if (p != av->top) { if (contiguous(av)) { assert(((char*)p) >= min_address); assert(((char*)p + sz) <= ((char*)(av->top))); } } else { /* top size is always at least MINSIZE */ assert((CHUNK_SIZE_T)(sz) >= MINSIZE); /* top predecessor always marked inuse */ assert(prev_inuse(p)); } } else { #if HAVE_MMAP /* address is outside main heap */ if (contiguous(av) && av->top != (mchunkptr)(&(av->initial_top))) { assert(((char*)p) < min_address || ((char*)p) > max_address); } /* chunk is page-aligned */ assert(((p->prev_size + sz) & (av->pagesize-1)) == 0); /* mem is aligned */ assert(aligned_OK(chunk2mem(p))); #else /* force an appropriate assert violation if debug set */ assert(!chunk_is_mmapped(p)); #endif } } static void check_all_less(tchunkptr t, CHUNK_SIZE_T nb) { if (t == 0) return; assert(chunksize(t) < nb); check_all_less(t->child[0], nb); check_all_less(t->child[1], nb); } static void check_all_greater(tchunkptr t, CHUNK_SIZE_T nb) { if (t == 0) return; assert(chunksize(t) >= nb); check_all_greater(t->child[0], nb); check_all_greater(t->child[1], nb); } static INTERNAL_SIZE_T check_tree_fields(tchunkptr t) { INTERNAL_SIZE_T size = chunksize(t); assert(size >= MIN_TREEBIN_SIZE); do_check_chunk(((mchunkptr)t)); assert(!inuse(t)); assert(t->fd->bk == t); assert(t->bk->fd == t); assert(t->parent != t); assert(t->child[0] != t); assert(t->child[1] != t); if (t->child[0] != 0 && t->child[1] != 0) { check_all_less(t->child[0], chunksize(t->child[1])); check_all_greater(t->child[1], chunksize(t->child[0])); } return size; } static INTERNAL_SIZE_T do_check_tree(tchunkptr t) { tchunkptr p; tchunkptr h; INTERNAL_SIZE_T total = check_tree_fields(t); /* If t is on a same-sized list, another node on list must have a parent */ if (t->parent == 0) { h = t->bk; while (h != t && h->parent == 0) h = h->bk; assert(h != t); } else h = t; assert (h->parent->child[0] == h || h->parent->child[1] == h || *((tbinptr*)(h->parent)) == h); /* only one node on a same-sized list has parent or children */ p = h->bk; while (p != h) { assert(p->child[0] == 0); assert(p->child[1] == 0); assert(p->parent == 0); assert(chunksize(p) == chunksize(h)); total += check_tree_fields(p); p = p->bk; } if (h->child[0] != 0) { assert(h->child[0]->parent == h); total += do_check_tree(h->child[0]); } if (h->child[1] != 0) { assert(h->child[1]->parent == h); total += do_check_tree(h->child[1]); } return total; } static void do_check_links(mchunkptr p) { if (in_smallbin_range(chunksize(p))) { assert(p->fd->bk == p); assert(p->bk->fd == p); } else { do_check_tree((tchunkptr)p); } } /* Properties of free chunks */ static void do_check_free_chunk(mchunkptr p) { mstate av = get_malloc_state(); INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE; mchunkptr next = chunk_at_offset(p, sz); do_check_chunk(p); /* Chunk must claim to be free ... */ assert(!inuse(p)); assert (!chunk_is_mmapped(p)); /* Unless a special marker, must have OK fields */ if ((CHUNK_SIZE_T)(sz) >= MINSIZE) { assert((sz & MALLOC_ALIGN_MASK) == 0); assert(aligned_OK(chunk2mem(p))); /* ... matching footer field */ assert(next->prev_size == sz); /* ... and is fully consolidated */ assert(prev_inuse(p)); assert (next == av->top || inuse(next)); do_check_links(p); } else /* markers are always of size SIZE_SZ */ assert(sz == SIZE_SZ); } /* Properties of inuse chunks */ static void do_check_inuse_chunk(mchunkptr p) { mstate av = get_malloc_state(); mchunkptr next; do_check_chunk(p); if (chunk_is_mmapped(p)) return; /* mmapped chunks have no next/prev */ /* Check whether it claims to be in use ... */ assert(inuse(p)); next = next_chunk(p); /* ... and is surrounded by OK chunks. Since more things can be checked with free chunks than inuse ones, if an inuse chunk borders them and debug is on, it's worth doing them. */ if (!prev_inuse(p)) { /* Note that we cannot even look at prev unless it is not inuse */ mchunkptr prv = prev_chunk(p); assert(next_chunk(prv) == p); do_check_free_chunk(prv); } if (next == av->top) { assert(prev_inuse(next)); assert(chunksize(next) >= MINSIZE); } else if (!inuse(next)) do_check_free_chunk(next); } static void do_check_remalloced_chunk(mchunkptr p, INTERNAL_SIZE_T s) { INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE; do_check_inuse_chunk(p); /* Legal size ... */ assert((sz & MALLOC_ALIGN_MASK) == 0); assert((CHUNK_SIZE_T)(sz) >= MINSIZE); /* ... and alignment */ assert(aligned_OK(chunk2mem(p))); /* chunk is less than MINSIZE more than request */ assert((long)(sz) - (long)(s) >= 0); assert((long)(sz) - (long)(s + MINSIZE) < 0); } /* Properties of nonrecycled chunks at the point they are malloced */ static void do_check_malloced_chunk(mchunkptr p, INTERNAL_SIZE_T s) { /* same as recycled case ... */ do_check_remalloced_chunk(p, s); #if 0 do_check_malloc_state(get_malloc_state()); #endif /* ... plus, must obey implementation invariant that prev_inuse is always true of any allocated chunk; i.e., that each allocated chunk borders either a previously allocated and still in-use chunk, or the base of its memory arena. This is ensured by making all allocations from the the `lowest' part of any found chunk. */ assert(prev_inuse(p)); } static CHUNK_SIZE_T do_check_smallbin(mstate av, int i, mbinptr b) { mchunkptr p = b->bk; mchunkptr q; bin_index_t idx; INTERNAL_SIZE_T size; CHUNK_SIZE_T total = 0; unsigned int empty = (av->smallbits & (1 << i)) == 0; if (i >= 2) { if (empty) assert(p == b); if (p == b) assert(empty); if (p != b) assert(!empty); } for (; p != b; p = p->bk) { /* each chunk claims to be free */ do_check_free_chunk(p); size = chunksize(p); total += size; if (i >= 2) { /* chunk belongs in bin */ idx = smallbin_index(size); assert(idx == i); assert(p->bk == b || (CHUNK_SIZE_T)chunksize(p->bk) == (CHUNK_SIZE_T)chunksize(p)); } /* chunk is followed by a legal chain of inuse chunks */ for (q = next_chunk(p); (q != av->top && inuse(q) && (CHUNK_SIZE_T)(chunksize(q)) >= MINSIZE); q = next_chunk(q)) do_check_inuse_chunk(q); } return total; } /* Properties of malloc_state. This may be useful for debugging malloc, as well as detecting user programmer errors that somehow write into malloc_state. If you are extending or experimenting with this malloc, you can probably figure out how to hack this routine to print out or display chunk addresses, sizes, bins, and other instrumentation. */ static void do_check_malloc_state(mstate av) { int i; mbinptr b; CHUNK_SIZE_T total = 0; tchunkptr t; unsigned int empty; tbinptr* tb; int max_fast_bin; mchunkptr p; /* internal size_t must be no wider than pointer type */ assert(sizeof(INTERNAL_SIZE_T) <= sizeof(char*)); /* alignment is a power of 2 */ assert((MALLOC_ALIGNMENT & (MALLOC_ALIGNMENT-1)) == 0); /* cannot run remaining checks until fully initialized */ if (av->top == 0 || av->top == (mchunkptr)(&(av->initial_top))) return; /* pagesize is a power of 2 */ assert((av->pagesize & (av->pagesize-1)) == 0); /* check smallbins */ for (i = 1; i < NBINS; ++i) { b = bin_at(av, i); total += do_check_smallbin(av, i, b); } /* check treebins */ for (i = 0; i < NBINS; ++i) { tb = tbin_at(av, i); t = *tb; empty = (av->treebits & (1 << i)) == 0; if (t == 0) assert(empty); else if (t != 0) { assert(!empty); total += do_check_tree(t); } } /* top chunk is OK */ check_chunk(av->top); /* top not in tree */ if (!in_smallbin_range(chunksize(av->top))) assert(tree_find((tchunkptr)(av->top)) == 0); /* max_fast is in allowed range */ assert(get_max_fast(av) <= request2size(MAX_FAST_SIZE)); max_fast_bin = fastbin_index(av->max_fast); for (i = 0; i < NFASTBINS; ++i) { p = av->fastbins[i]; /* all bins past max_fast are empty */ if (i > max_fast_bin) assert(p == 0); while (p != 0) { /* each chunk claims to be inuse */ do_check_inuse_chunk(p); total += chunksize(p); /* chunk belongs in this bin */ assert(fastbin_index(chunksize(p)) == i); p = p->fd; } } /* sanity checks for statistics */ assert(total <= (CHUNK_SIZE_T)(av->max_total_mem)); assert(av->n_mmaps >= 0); assert(av->n_mmaps <= av->n_mmaps_max); assert(av->n_mmaps <= av->max_n_mmaps); assert((CHUNK_SIZE_T)(av->sbrked_mem) <= (CHUNK_SIZE_T)(av->max_sbrked_mem)); assert((CHUNK_SIZE_T)(av->mmapped_mem) <= (CHUNK_SIZE_T)(av->max_mmapped_mem)); assert((CHUNK_SIZE_T)(av->max_total_mem) >= (CHUNK_SIZE_T)(av->mmapped_mem) + (CHUNK_SIZE_T)(av->sbrked_mem)); } #endif /* ----------- Operations on trees ----------- */ /* Insert chunk into corresponding list or tree */ static void insert_treenode(mstate av, tchunkptr x, CHUNK_SIZE_T nb) { bin_index_t idx = treebin_index(nb); tbinptr* bin = tbin_at(av, idx); tchunkptr t = *bin; x->child[0] = 0; x->child[1] = 0; x->index = idx; if (t == 0) { av->treebits |= idx2bit(idx); *bin = x; x->parent = (tchunkptr)bin; x->fd = x; x->bk = x; } else { bin_index_t shift = bitshift_for_index(idx); tchunkptr b; check_tree(t); while (chunksize(t) != nb) { tchunkptr* pchild = &(t->child[(nb >> shift--) & 1]); if (*pchild != 0) { t = *pchild; } else { *pchild = x; x->parent = t; x->fd = x; x->bk = x; return; } } /* Link in same-sized node */ b = t->bk; x->parent = 0; x->fd = t; x->bk = b; b->fd = t->bk = x; } } static void transfer_tree_links(tchunkptr oldt, tchunkptr newt) { tchunkptr p = oldt->parent; newt->parent = p; if (p->child[0] == oldt) p->child[0] = newt; else if (p->child[1] == oldt) p->child[1] = newt; else *((tbinptr*)p) = newt; if ( (newt->child[0] = oldt->child[0]) != 0) newt->child[0]->parent = newt; if ( (newt->child[1] = oldt->child[1]) != 0) newt->child[1]->parent = newt; } static tchunkptr find_replacement(tchunkptr t) { /* Unless t is itself a leaf node, we must replace t with a leaf node (not merely one with an open left or right, as with binary search trees), to make sure that lefts and rights of descendents correspond properly to bit masks. We use the leftmost leaf of right child, or, if there is no right child, the rightmost leaf of left child. We could use any other leaf, but these choices will tend to maintain nicer trees. */ tchunkptr* cp; tchunkptr c; if ((c = *(cp = &(t->child[1]))) == 0) if ((c = *(cp = &(t->child[0]->child[1]))) == 0) c = *(cp = &(t->child[0])); assert(c != 0); for (;;) { if (c->child[0] != 0) c = *(cp = &(c->child[0])); else if (c->child[1] != 0) c = *(cp = &(c->child[1])); else { *cp = 0; /* unlink from parent */ return c; } } } static void unlink_leaf_node(mstate av, tchunkptr t) { tchunkptr p = t->parent; if (p->child[0] == t) p->child[0] = 0; else if (p->child[1] == t) p->child[1] = 0; else { assert(is_tbin(av, p)); *((tbinptr*)p) = 0; av->treebits &= ~idx2bit(t->index); } } static void unlink_chained_node(tchunkptr t) { tchunkptr bck = t->bk; tchunkptr fwd = t->fd; fwd->bk = bck; bck->fd = fwd; /* t's parent is nonnull if t was head of chain */ if (t->parent != 0) transfer_tree_links(t, fwd); check_tree(fwd); } /* ----------- other helper functions ----------- We expect these to be inlined */ static void insert_small_chunk(mstate av, mchunkptr p, CHUNK_SIZE_T nb) { bin_index_t idx = smallbin_index(nb); mchunkptr bck = bin_at(av, idx); mchunkptr fwd = bck->fd; mark_smallbin(av, idx); p->fd = fwd; p->bk = bck; fwd->bk = bck->fd = p; assert(in_smallbin_range(nb)); } static void insert_chunk(mstate av, mchunkptr p, CHUNK_SIZE_T nb) { if (in_smallbin_range(nb)) insert_small_chunk(av, p, nb); else insert_treenode(av, (tchunkptr)p, nb); } static mchunkptr take_from_smallbin(mstate av, mchunkptr bin, bitmap_t bit) { mchunkptr p = bin->bk; mchunkptr bck = p->bk; assert(p != bin); bin->bk = bck; bck->fd = bin; if (bck == bin) av->smallbits &= ~bit; return p; } static void unlink_chunk(mstate av, mchunkptr q, CHUNK_SIZE_T size) { mchunkptr fwd = q->fd; mchunkptr bck = q->bk; fwd->bk = bck; bck->fd = fwd; if (fwd == bck && in_smallbin_range(size)) { clear_smallbin(av, smallbin_index(size)); } else if (!in_smallbin_range(size)) { tchunkptr t = (tchunkptr)q; tchunkptr c = (tchunkptr)fwd; if (c == t) { if (t->child[0] == t->child[1]) { unlink_leaf_node(av, t); return; } else { c = find_replacement(t); } } else { if (t->parent == 0) { return; } } transfer_tree_links(t, c); check_tree(c); } } static Void_t* use_treechunk(mstate av, CHUNK_SIZE_T nb, tchunkptr bestchunk, CHUNK_SIZE_T bestsize, tchunkptr leaf) { CHUNK_SIZE_T rsize; if (bestchunk->bk != bestchunk) unlink_chained_node(bestchunk); else { unlink_leaf_node(av, leaf); if (leaf != bestchunk) transfer_tree_links(bestchunk, leaf); } rsize = bestsize - nb; if (rsize >= MINSIZE) { mchunkptr rem = chunk_at_offset(bestchunk, nb); set_head(bestchunk, nb | PREV_INUSE); set_head(rem, rsize | PREV_INUSE); set_foot(rem, rsize); insert_chunk(av, rem, rsize); } else { set_inuse_bit_at_offset(bestchunk, bestsize); } check_malloced_chunk((mchunkptr)(bestchunk), nb); return chunk2mem(bestchunk); } /* ------------------------------ malloc ------------------------------ */ Void_t* mALLOc(size_t bytes) { mstate av = get_malloc_state(); CHUNK_SIZE_T nb; checked_request2size(bytes, nb); if (nb <= (CHUNK_SIZE_T)(av->max_fast)) { mfastbinptr* fb = &(av->fastbins[(fastbin_index(nb))]); mchunkptr fp = *fb; if (fp != 0) { *fb = fp->fd; check_remalloced_chunk(fp, nb); return chunk2mem(fp); } } for (;;) { if (in_smallbin_range(nb)) { bin_index_t sidx = smallbin_index(nb); bitmap_t sbit = idx2bit(sidx); if (sbit <= av->smallbits) { mchunkptr p; if ((sbit & av->smallbits) != 0) { p = take_from_smallbin(av, bin_at(av,sidx), sbit); set_inuse_bit_at_offset(p, nb); } else { bitmap_t nbit = least_bit(left_bits(sbit) & av->smallbits); bin_index_t nidx = bit2idx(nbit); CHUNK_SIZE_T psize = size_for_smallindex(nidx); CHUNK_SIZE_T qsize = psize - nb; p = take_from_smallbin(av, bin_at(av, nidx), nbit); if (qsize < MINSIZE) { set_inuse_bit_at_offset(p, psize); } else { mchunkptr q = chunk_at_offset(p, nb); set_head(p, nb | PREV_INUSE); set_head(q, qsize | PREV_INUSE); set_foot(q, qsize); insert_small_chunk(av, q, qsize); } } check_malloced_chunk(p, nb); return chunk2mem(p); } if (av->treebits != 0) { bitmap_t vbit = least_bit(av->treebits); bin_index_t vidx = bit2idx(vbit); tbinptr* vbin = tbin_at(av, vidx); tchunkptr bestchunk = *vbin; tchunkptr c = leftmost_child(bestchunk); CHUNK_SIZE_T bestsize = chunksize(bestchunk); tchunkptr leaf; CHUNK_SIZE_T rsize; /* Fast path if remainder will replace bestchunk */ if (c == 0) { rsize = bestsize - nb; leaf = bestchunk; if (rsize >= minsize_for_treeindex(vidx) && bestchunk->bk == bestchunk) { tchunkptr r = (tchunkptr)(chunk_at_offset(bestchunk, nb)); set_head(bestchunk, nb | PREV_INUSE); set_head(r, rsize | PREV_INUSE); set_foot(r, rsize); *vbin = r; r->fd = r; r->bk = r; r->child[0] = 0; r->child[1] = 0; r->parent = (tchunkptr)vbin; r->index = vidx; check_malloced_chunk((mchunkptr)bestchunk, nb); return chunk2mem(bestchunk); } } else { do { CHUNK_SIZE_T csize = chunksize(c); if (csize < bestsize) { bestchunk = c; bestsize = csize; } leaf = c; c = leftmost_child(c); } while (c != 0); } return use_treechunk(av, nb, bestchunk, bestsize, leaf); } } else { bin_index_t tidx = treebin_index(nb); bitmap_t tbit = idx2bit(tidx); if (tbit <= av->treebits) { tchunkptr bestchunk = 0; CHUNK_SIZE_T bestsize = MAX_CHUNK_SIZE; tchunkptr leaf; bitmap_t vbit; for (;;) { if ((tbit & av->treebits) != 0) { tchunkptr t = *tbin_at(av, tidx); bin_index_t shift = bitshift_for_index(tidx); for (;;) { int dir; CHUNK_SIZE_T tsize = chunksize(t); leaf = t; if (tsize >= nb && tsize < bestsize) { bestchunk = t; bestsize = tsize; if (tsize == nb && t->bk != t) break; } dir = (shift == 0)? 0 : (nb >> shift--) & 1; t = leaf->child[dir]; if (t == 0) { shift = 0; /* if forced right, go leftmost from now on */ t = leaf->child[1-dir]; if (t == 0) break; } } if (bestchunk != 0) return use_treechunk(av, nb, bestchunk, bestsize, leaf); } if (have_fastchunks(av)) malloc_consolidate(av); else break; } vbit = least_bit(left_bits(tbit) & av->treebits); if (vbit != 0) { bin_index_t vidx = bit2idx(vbit); tbinptr* vbin = tbin_at(av, vidx); tchunkptr c = *vbin; do { CHUNK_SIZE_T csize = chunksize(c); leaf = c; if (csize < bestsize) { bestchunk = c; bestsize = csize; } c = leftmost_child(c); } while (c != 0); return use_treechunk(av, nb, bestchunk, bestsize, leaf); } } } /* If large enough, split off the chunk bordering the end of memory (held in av->top). This is called in accord with the best-fit search rule. In effect, av->top is treated as larger (and thus less well fitting) than any other available chunk since it can be extended to be as large as necessary (up to system limitations). We require that av->top always exists (i.e., has size >= MINSIZE) after initialization, so if it would otherwise be exhuasted by current request, it is replenished. (The main reason for ensuring it exists is that we may need MINSIZE space to put in fenceposts in sysmalloc.) */ if (av->top != 0) { mchunkptr topchunk = av->top; CHUNK_SIZE_T topsize = chunksize(topchunk); if (topsize >= nb + MINSIZE) { CHUNK_SIZE_T remainder_size = topsize - nb; mchunkptr remainder = chunk_at_offset(topchunk, nb); av->top = remainder; set_head(topchunk, nb | PREV_INUSE); set_head(remainder, remainder_size | PREV_INUSE); check_malloced_chunk(topchunk, nb); return chunk2mem(topchunk); } else if (have_fastchunks(av)) { malloc_consolidate(av); } else break; } else break; } return sysmalloc(av, nb); } /* ------------------------------ free ------------------------------ */ void fREe(Void_t* mem) { mstate av = get_malloc_state(); mchunkptr p = mem2chunk(mem); if (mem != 0) { INTERNAL_SIZE_T rawsize = p->size; CHUNK_SIZE_T size = chunksize(p); check_inuse_chunk(p); /* If eligible, place chunk on a fastbin so it can be found and used quickly in malloc. */ if ((CHUNK_SIZE_T)(size) <= (CHUNK_SIZE_T)(av->max_fast) #if TRIM_FASTBINS /* If TRIM_FASTBINS set, don't place chunks bordering top into fastbins */ && (chunk_at_offset(p, size) != av->top) #endif ) { mfastbinptr* fb; set_fastchunks(av); fb = &(av->fastbins[fastbin_index(size)]); p->fd = *fb; *fb = p; } else if ((rawsize & IS_MMAPPED) == 0) { mchunkptr nextchunk = chunk_at_offset(p, size); CHUNK_SIZE_T nextsize; if ((rawsize & PREV_INUSE) == 0) { CHUNK_SIZE_T prevsize = p->prev_size; size += prevsize; p = chunk_at_offset(p, -((long) prevsize)); unlink_chunk(av, p, prevsize); } nextsize = chunksize(nextchunk); if (nextchunk == av->top) { size += nextsize; set_head(p, size | PREV_INUSE); av->top = p; if (size >= av->trim_threshold) { systrim(av, av->top_pad); } } else { if (!inuse_bit_at_offset(nextchunk, nextsize)) { size += nextsize; unlink_chunk(av, nextchunk, nextsize); } else set_head(nextchunk, nextsize); set_head(p, size | PREV_INUSE); set_foot(p, size); insert_chunk(av, p, size); } } else { #if HAVE_MMAP int ret; INTERNAL_SIZE_T offset = p->prev_size; av->n_mmaps--; av->mmapped_mem -= (size + offset); ret = munmap((char*)p - offset, size + offset); /* munmap returns non-zero on failure */ assert(ret == 0); #endif } } } /* ------------------------- malloc_consolidate ------------------------- malloc_consolidate tears down chunks held in fastbins. */ static void malloc_consolidate(mstate av) { int i; clear_fastchunks(av); for (i = 0; i < NFASTBINS; ++i) { mfastbinptr* fb = &(av->fastbins[i]); mchunkptr p = *fb; if (p != 0) { *fb = 0; do { mchunkptr nextp = p->fd; INTERNAL_SIZE_T rawsize = p->size; CHUNK_SIZE_T size = chunksize(p); mchunkptr nextchunk = chunk_at_offset(p, size); CHUNK_SIZE_T nextsize; if ((rawsize & PREV_INUSE) == 0) { CHUNK_SIZE_T prevsize = p->prev_size; size += prevsize; p = chunk_at_offset(p, -((long) prevsize)); unlink_chunk(av, p, prevsize); } nextsize = chunksize(nextchunk); if (nextchunk == av->top) { size += nextsize; set_head(p, size | PREV_INUSE); av->top = p; } else { if (!inuse_bit_at_offset(nextchunk, nextsize)) { size += nextsize; unlink_chunk(av, nextchunk, nextsize); } else set_head(nextchunk, nextsize); set_head(p, size | PREV_INUSE); set_foot(p, size); insert_chunk(av, p, size); } p = nextp; } while (p != 0); } } } /* ------------------------------ realloc ------------------------------ */ Void_t* rEALLOc(Void_t* oldmem, size_t bytes) { mstate av = get_malloc_state(); INTERNAL_SIZE_T nb; /* padded request size */ mchunkptr oldp; /* chunk corresponding to oldmem */ CHUNK_SIZE_T oldsize; /* its size */ mchunkptr newp; /* chunk to return */ CHUNK_SIZE_T newsize; /* its size */ Void_t* newmem; /* corresponding user mem */ mchunkptr next; /* next contiguous chunk after oldp */ mchunkptr remainder; /* extra space at end of newp */ CHUNK_SIZE_T remainder_size; /* its size */ CHUNK_SIZE_T copysize; /* bytes to copy */ unsigned int ncopies; /* INTERNAL_SIZE_T words to copy */ INTERNAL_SIZE_T* s; /* copy source */ INTERNAL_SIZE_T* d; /* copy destination */ #ifdef REALLOC_ZERO_BYTES_FREES if (bytes == 0) { fREe(oldmem); return 0; } #endif /* realloc of null is supposed to be same as malloc */ if (oldmem == 0) return mALLOc(bytes); checked_request2size(bytes, nb); oldp = mem2chunk(oldmem); oldsize = chunksize(oldp); check_inuse_chunk(oldp); if (!chunk_is_mmapped(oldp)) { if ((CHUNK_SIZE_T)(oldsize) >= (CHUNK_SIZE_T)(nb)) { /* already big enough; split below */ newp = oldp; newsize = oldsize; } else { next = chunk_at_offset(oldp, oldsize); /* Try to expand forward into top */ if (next == av->top && (CHUNK_SIZE_T)(newsize = oldsize + chunksize(next)) >= (CHUNK_SIZE_T)(nb + MINSIZE)) { set_head_size(oldp, nb); av->top = chunk_at_offset(oldp, nb); set_head(av->top, (newsize - nb) | PREV_INUSE); return chunk2mem(oldp); } /* Try to expand forward into next chunk; split off remainder below */ else if (next != av->top && !inuse(next) && (CHUNK_SIZE_T)(newsize = oldsize + chunksize(next)) >= (CHUNK_SIZE_T)(nb)) { newp = oldp; unlink_chunk(av, next, chunksize(next)); } /* allocate, copy, free */ else { newmem = mALLOc(nb - MALLOC_ALIGN_MASK); if (newmem == 0) return 0; /* propagate failure */ newp = mem2chunk(newmem); newsize = chunksize(newp); /* Avoid copy if newp is next chunk after oldp. */ if (newp == next) { newsize += oldsize; newp = oldp; } else { /* Unroll copy of <= 36 bytes (72 if 8byte sizes) We know that contents have an odd number of INTERNAL_SIZE_T-sized words; minimally 3. */ copysize = oldsize - SIZE_SZ; s = (INTERNAL_SIZE_T*)(oldmem); d = (INTERNAL_SIZE_T*)(newmem); ncopies = copysize / sizeof(INTERNAL_SIZE_T); assert(ncopies >= 3); if (ncopies > 9) MALLOC_COPY(d, s, copysize); else { *(d+0) = *(s+0); *(d+1) = *(s+1); *(d+2) = *(s+2); if (ncopies > 4) { *(d+3) = *(s+3); *(d+4) = *(s+4); if (ncopies > 6) { *(d+5) = *(s+5); *(d+6) = *(s+6); if (ncopies > 8) { *(d+7) = *(s+7); *(d+8) = *(s+8); } } } } fREe(oldmem); check_inuse_chunk(newp); return chunk2mem(newp); } } } /* If possible, free extra space in old or extended chunk */ assert((CHUNK_SIZE_T)(newsize) >= (CHUNK_SIZE_T)(nb)); remainder_size = newsize - nb; if (remainder_size < MINSIZE) { /* not enough extra to split off */ set_head_size(newp, newsize); set_inuse_bit_at_offset(newp, newsize); } else { /* split remainder */ remainder = chunk_at_offset(newp, nb); set_head_size(newp, nb); set_head(remainder, remainder_size | PREV_INUSE); /* Mark remainder as inuse so free() won't complain */ set_inuse_bit_at_offset(remainder, remainder_size); fREe(chunk2mem(remainder)); } check_inuse_chunk(newp); return chunk2mem(newp); } /* Handle mmap cases */ else { #if HAVE_MMAP #if HAVE_MREMAP INTERNAL_SIZE_T offset = oldp->prev_size; size_t pagemask = av->pagesize - 1; char *cp; CHUNK_SIZE_T sum; /* Note the extra SIZE_SZ overhead */ newsize = (nb + offset + SIZE_SZ + pagemask) & ~pagemask; /* don't need to remap if still within same page */ if (oldsize == newsize - offset) return oldmem; cp = (char*)mremap((char*)oldp - offset, oldsize + offset, newsize, 1); if (cp != (char*)MORECORE_FAILURE) { newp = (mchunkptr)(cp + offset); set_head(newp, (newsize - offset)|IS_MMAPPED); assert(aligned_OK(chunk2mem(newp))); assert((newp->prev_size == offset)); /* update statistics */ sum = av->mmapped_mem += newsize - oldsize; if (sum > (CHUNK_SIZE_T)(av->max_mmapped_mem)) av->max_mmapped_mem = sum; sum += av->sbrked_mem; if (sum > (CHUNK_SIZE_T)(av->max_total_mem)) av->max_total_mem = sum; return chunk2mem(newp); } #endif /* Note the extra SIZE_SZ overhead. */ if ((CHUNK_SIZE_T)(oldsize) >= (CHUNK_SIZE_T)(nb + SIZE_SZ)) newmem = oldmem; /* do nothing */ else { /* Must alloc, copy, free. */ newmem = mALLOc(nb - MALLOC_ALIGN_MASK); if (newmem != 0) { MALLOC_COPY(newmem, oldmem, oldsize - 2*SIZE_SZ); fREe(oldmem); } } return newmem; #else /* If !HAVE_MMAP, but chunk_is_mmapped, user must have overwritten mem */ check_malloc_state(av); MALLOC_FAILURE_ACTION; return 0; #endif } } /* ------------------------------ memalign ------------------------------ */ Void_t* mEMALIGn(size_t alignment, size_t bytes) { INTERNAL_SIZE_T nb; /* padded request size */ char* m; /* memory returned by malloc call */ mchunkptr p; /* corresponding chunk */ char* brk; /* alignment point within p */ mchunkptr newp; /* chunk to return */ INTERNAL_SIZE_T newsize; /* its size */ INTERNAL_SIZE_T leadsize; /* leading space before alignment point */ mchunkptr remainder; /* spare room at end to split off */ CHUNK_SIZE_T remainder_size; /* its size */ INTERNAL_SIZE_T size; /* If need less alignment than we give anyway, just relay to malloc */ if (alignment <= MALLOC_ALIGNMENT) return mALLOc(bytes); /* Otherwise, ensure that it is at least a minimum chunk size */ if (alignment < MINSIZE) alignment = MINSIZE; /* Make sure alignment is power of 2 (in case MINSIZE is not). */ if ((alignment & (alignment - 1)) != 0) { size_t a = MALLOC_ALIGNMENT * 2; while ((CHUNK_SIZE_T)a < (CHUNK_SIZE_T)alignment) a <<= 1; alignment = a; } checked_request2size(bytes, nb); /* Strategy: find a spot within that chunk that meets the alignment request, and then possibly free the leading and trailing space. */ /* Call malloc with worst case padding to hit alignment. */ m = (char*)(mALLOc(nb + alignment + MINSIZE)); if (m == 0) return 0; /* propagate failure */ p = mem2chunk(m); if ((((PTR_UINT)(m)) % alignment) != 0) { /* misaligned */ /* Find an aligned spot inside chunk. Since we need to give back leading space in a chunk of at least MINSIZE, if the first calculation places us at a spot with less than MINSIZE leader, we can move to the next aligned spot -- we've allocated enough total room so that this is always possible. */ brk = (char*)mem2chunk((PTR_UINT)(((PTR_UINT)(m + alignment - 1)) & -((signed long) alignment))); if ((CHUNK_SIZE_T)(brk - (char*)(p)) < MINSIZE) brk += alignment; newp = (mchunkptr)brk; leadsize = brk - (char*)(p); newsize = chunksize(p) - leadsize; /* For mmapped chunks, just adjust offset */ if (chunk_is_mmapped(p)) { newp->prev_size = p->prev_size + leadsize; set_head(newp, newsize|IS_MMAPPED); return chunk2mem(newp); } /* Otherwise, give back leader, use the rest */ set_head(newp, newsize | PREV_INUSE); set_inuse_bit_at_offset(newp, newsize); set_head_size(p, leadsize); fREe(chunk2mem(p)); p = newp; assert (newsize >= nb && (((PTR_UINT)(chunk2mem(p))) % alignment) == 0); } /* Also give back spare room at the end */ if (!chunk_is_mmapped(p)) { size = chunksize(p); if ((CHUNK_SIZE_T)(size) > (CHUNK_SIZE_T)(nb + MINSIZE)) { remainder_size = size - nb; remainder = chunk_at_offset(p, nb); set_head(remainder, remainder_size | PREV_INUSE); set_head_size(p, nb); fREe(chunk2mem(remainder)); } } check_inuse_chunk(p); return chunk2mem(p); } /* ------------------------------ calloc ------------------------------ */ Void_t* cALLOc(size_t n_elements, size_t elem_size) { Void_t* mem = mALLOc(n_elements * elem_size); if (mem != 0) { mchunkptr p = mem2chunk(mem); INTERNAL_SIZE_T* d = (INTERNAL_SIZE_T*)mem; if (!chunk_is_mmapped(p)) { /* Unroll clear of <= 36 bytes (72 if 8byte sizes) We know that contents have an odd number of INTERNAL_SIZE_T-sized words; minimally 3. */ CHUNK_SIZE_T clearsize = chunksize(p) - SIZE_SZ; CHUNK_SIZE_T nclears = clearsize / sizeof(INTERNAL_SIZE_T); assert(nclears >= 3); if (nclears > 9) MALLOC_ZERO(d, clearsize); else { *(d+0) = 0; *(d+1) = 0; *(d+2) = 0; if (nclears > 4) { *(d+3) = 0; *(d+4) = 0; if (nclears > 6) { *(d+5) = 0; *(d+6) = 0; if (nclears > 8) { *(d+7) = 0; *(d+8) = 0; } } } } } #if ! MMAP_CLEARS else { /* Note the additional SIZE_SZ */ CHUNK_SIZE_T clearsize = chunksize(p) - 2*SIZE_SZ; MALLOC_ZERO(d, clearsize); } #endif } return mem; } /* ------------------------------ cfree ------------------------------ */ void cFREe(Void_t *mem) { fREe(mem); } /* ------------------------- independent_calloc ------------------------- */ Void_t** iCALLOc(size_t n_elements, size_t elem_size, Void_t* chunks[]) { size_t sz = elem_size; /* serves as 1-element array */ /* opts arg of 3 means all elements are same size, and should be cleared */ return iALLOc(n_elements, &sz, 3, chunks); } /* ------------------------- independent_comalloc ------------------------- */ Void_t** iCOMALLOc(size_t n_elements, size_t sizes[], Void_t* chunks[]) { return iALLOc(n_elements, sizes, 0, chunks); } /* ------------------------------ ialloc ------------------------------ ialloc provides common support for independent_X routines, handling all of the combinations that can result. The opts arg has: bit 0 set if all elements are same size (using sizes[0]) bit 1 set if elements should be zeroed */ static Void_t** iALLOc(size_t n_elements, size_t* sizes, int opts, Void_t* chunks[]) { mstate av = get_malloc_state(); INTERNAL_SIZE_T element_size; /* chunksize of each element, if all same */ INTERNAL_SIZE_T contents_size; /* total size of elements */ INTERNAL_SIZE_T array_size; /* request size of pointer array */ Void_t* mem; /* malloced aggregate space */ mchunkptr p; /* corresponding chunk */ CHUNK_SIZE_T remainder_size; /* remaining bytes while splitting */ Void_t** marray; /* either "chunks" or malloced ptr array */ mchunkptr array_chunk; /* chunk for malloced ptr array */ unsigned int mprops; /* to disable mmap */ CHUNK_SIZE_T size; size_t i; ensure_initialization(av); /* compute array length, if needed */ if (chunks != 0) { if (n_elements == 0) return chunks; /* nothing to do */ marray = chunks; array_size = 0; } else { /* if empty req, must still return chunk representing empty array */ if (n_elements == 0) return (Void_t**) mALLOc(0); marray = 0; array_size = request2size(n_elements * (sizeof(Void_t*))); } /* compute total element size */ if (opts & 0x1) { /* all-same-size */ element_size = request2size(*sizes); contents_size = n_elements * element_size; } else { /* add up all the sizes */ element_size = 0; contents_size = 0; for (i = 0; i != n_elements; ++i) contents_size += request2size(sizes[i]); } /* subtract out alignment bytes from total to minimize overallocation */ size = contents_size + array_size - MALLOC_ALIGN_MASK; /* Allocate the aggregate chunk. But first disable mmap so malloc won't use it, since we would not be able to later free/realloc space internal to a segregated mmap region. */ mprops = av->sysctl; /* disable mmap */ disable_mmap(av); mem = mALLOc(size); av->sysctl = mprops; /* reset mmap */ if (mem == 0) return 0; p = mem2chunk(mem); assert(!chunk_is_mmapped(p)); remainder_size = chunksize(p); if (opts & 0x2) { /* optionally clear the elements */ MALLOC_ZERO(mem, remainder_size - SIZE_SZ - array_size); } /* If not provided, allocate the pointer array as final part of chunk */ if (marray == 0) { array_chunk = chunk_at_offset(p, contents_size); marray = (Void_t**) (chunk2mem(array_chunk)); set_head(array_chunk, (remainder_size - contents_size) | PREV_INUSE); remainder_size = contents_size; } /* split out elements */ for (i = 0; ; ++i) { marray[i] = chunk2mem(p); if (i != n_elements-1) { if (element_size != 0) size = element_size; else size = request2size(sizes[i]); remainder_size -= size; set_head(p, size | PREV_INUSE); p = chunk_at_offset(p, size); } else { /* the final element absorbs any overallocation slop */ set_head(p, remainder_size | PREV_INUSE); break; } } #if DEBUG if (marray != chunks) { /* final element must have exactly exhausted chunk */ if (element_size != 0) assert(remainder_size == element_size); else assert(remainder_size == request2size(sizes[i])); check_inuse_chunk(mem2chunk(marray)); } for (i = 0; i != n_elements; ++i) check_inuse_chunk(mem2chunk(marray[i])); #endif return marray; } /* ------------------------------ valloc ------------------------------ */ Void_t* vALLOc(size_t bytes) { mstate av = get_malloc_state(); ensure_initialization(av); return mEMALIGn(av->pagesize, bytes); } /* ------------------------------ pvalloc ------------------------------ */ Void_t* pVALLOc(size_t bytes) { mstate av = get_malloc_state(); size_t pagesz; ensure_initialization(av); pagesz = av->pagesize; return mEMALIGn(pagesz, (bytes + pagesz - 1) & ~(pagesz - 1)); } /* ------------------------------ malloc_trim ------------------------------ */ int mTRIm(size_t pad) { mstate av = get_malloc_state(); return systrim(av, pad); } /* ------------------------- malloc_usable_size ------------------------- */ size_t mUSABLe(Void_t* mem) { mchunkptr p; if (mem != 0) { p = mem2chunk(mem); if (chunk_is_mmapped(p)) return chunksize(p) - 2*SIZE_SZ; else if (inuse(p)) return chunksize(p) - SIZE_SZ; } return 0; } /* ------------------------------ mallinfo ------------------------------ */ /* Recursive helper function for mallinfo */ static void count_tree_blocks(tchunkptr t, int* pcount, INTERNAL_SIZE_T* pavail) { while (t != 0) { tchunkptr p = t->bk; do { (*pcount)++; *pavail += chunksize(p); p = p->bk; } while (p != t); if (t->child[0] != 0) count_tree_blocks(t->child[0], pcount, pavail); t = t->child[1]; } } struct mallinfo mALLINFo() { mstate av = get_malloc_state(); struct mallinfo mi; INTERNAL_SIZE_T avail; INTERNAL_SIZE_T topsize; int nblocks; INTERNAL_SIZE_T fastavail; int nfastblocks; mchunkptr p; if (av->top == 0) { avail = 0; topsize = 0; nblocks = 0; } else { int i; check_malloc_state(av); topsize = chunksize(av->top); avail = topsize; nblocks = 1; /* top always exists */ /* traverse fastbins */ nfastblocks = 0; fastavail = 0; for (i = 0; i < NFASTBINS; ++i) { for (p = av->fastbins[i]; p != 0; p = p->fd) { ++nfastblocks; fastavail += chunksize(p); } } avail += fastavail; /* traverse small bins */ for (i = 2; i < NBINS; ++i) { mbinptr b = bin_at(av, i); mchunkptr p; for (p = b->bk; p != b; p = p->bk) { ++nblocks; avail += chunksize(p); } } /* traverse tree bins */ for (i = 0; i < NBINS; ++i) { tchunkptr t = *(tbin_at(av, i)); if (t != 0) count_tree_blocks(t, &nblocks, &avail); } } mi.smblks = nfastblocks; mi.smblks = 0; mi.ordblks = nblocks; mi.fordblks = avail; mi.uordblks = av->sbrked_mem - avail; mi.arena = av->sbrked_mem; mi.hblks = av->n_mmaps; mi.hblkhd = av->mmapped_mem; mi.fsmblks = 0; mi.keepcost = topsize; mi.usmblks = av->max_total_mem; return mi; } /* ------------------------------ malloc_stats ------------------------------ */ void mSTATs() { struct mallinfo mi = mALLINFo(); #ifdef WIN32 { CHUNK_SIZE_T free, reserved, committed; vminfo (&free, &reserved, &committed); fprintf(stderr, "free bytes = %10lu\n", free); fprintf(stderr, "reserved bytes = %10lu\n", reserved); fprintf(stderr, "committed bytes = %10lu\n", committed); } #endif fprintf(stderr, "max system bytes = %10lu\n", (CHUNK_SIZE_T)(mi.usmblks)); fprintf(stderr, "system bytes = %10lu\n", (CHUNK_SIZE_T)(mi.arena + mi.hblkhd)); fprintf(stderr, "in use bytes = %10lu\n", (CHUNK_SIZE_T)(mi.uordblks + mi.hblkhd)); #if 0 fprintf(stderr, "n0 = %10u\n", n0); fprintf(stderr, "n1 = %10u\n", n1); fprintf(stderr, "n2 = %10u\n", n2); fprintf(stderr, "n3 = %10u\n", n3); fprintf(stderr, "n4 = %10u\n", n4); fprintf(stderr, "n5 = %10u\n", n5); fprintf(stderr, "n6 = %10u\n", n6); fprintf(stderr, "n7 = %10u\n", n7); fprintf(stderr, "n8 = %10u\n", n8); #endif #ifdef WIN32 { CHUNK_SIZE_T kernel, user; if (cpuinfo (TRUE, &kernel, &user)) { fprintf(stderr, "kernel ms = %10lu\n", kernel); fprintf(stderr, "user ms = %10lu\n", user); } } #endif } /* ------------------------------ mallopt ------------------------------ */ int mALLOPt(int param_number, int value) { mstate av = get_malloc_state(); ensure_initialization(av); switch(param_number) { case M_MXFAST: malloc_consolidate(av); if (value >= 0 && value <= MAX_FAST_SIZE) { set_max_fast(av, value); return 1; } else return 0; case M_TRIM_THRESHOLD: av->trim_threshold = value; return 1; case M_TOP_PAD: av->top_pad = value; return 1; case M_MMAP_THRESHOLD: av->mmap_threshold = value; return 1; case M_MMAP_MAX: #if !HAVE_MMAP if (value != 0) return 0; #endif av->n_mmaps_max = value; return 1; default: return 0; } } /* ----------- Routines dealing with system allocation -------------- */ #if HAVE_MMAP static mchunkptr mmap_malloc(mstate av, INTERNAL_SIZE_T nb) { char* mm; /* return value from mmap call*/ CHUNK_SIZE_T sum; /* for updating stats */ mchunkptr p; /* the allocated/returned chunk */ long size; INTERNAL_SIZE_T front_misalign; /* unusable bytes at front of new space */ long correction; size_t pagemask = av->pagesize - 1; /* Round up size to nearest page. For mmapped chunks, the overhead is one SIZE_SZ unit larger than for normal chunks, because there is no following chunk whose prev_size field could be used. */ size = (nb + SIZE_SZ + MALLOC_ALIGN_MASK + pagemask) & ~pagemask; /* Don't try if size wraps around 0 */ if ((CHUNK_SIZE_T)(size) > (CHUNK_SIZE_T)(nb)) { mm = (char*)(MMAP(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE)); if (mm != (char*)(MORECORE_FAILURE)) { /* The offset to the start of the mmapped region is stored in the prev_size field of the chunk. This allows us to adjust returned start address to meet alignment requirements here and in memalign(), and still be able to compute proper address argument for later munmap in free() and realloc(). */ front_misalign = (INTERNAL_SIZE_T)chunk2mem(mm) & MALLOC_ALIGN_MASK; if (front_misalign > 0) { correction = MALLOC_ALIGNMENT - front_misalign; p = (mchunkptr)(mm + correction); p->prev_size = correction; set_head(p, (size - correction) |IS_MMAPPED); } else { p = (mchunkptr)mm; p->prev_size = 0; set_head(p, size|IS_MMAPPED); } /* update statistics */ if (++av->n_mmaps > av->max_n_mmaps) av->max_n_mmaps = av->n_mmaps; sum = av->mmapped_mem += size; if (sum > (CHUNK_SIZE_T)(av->max_mmapped_mem)) av->max_mmapped_mem = sum; sum += av->sbrked_mem; if (sum > (CHUNK_SIZE_T)(av->max_total_mem)) av->max_total_mem = sum; check_chunk(p); return p; } } return 0; } #endif /* sysmalloc handles malloc cases requiring more memory from the system. On entry, it is assumed that av->top does not have enough space to service request for nb bytes, thus requiring that av->top be extended or replaced. */ static Void_t* sysmalloc(mstate av, CHUNK_SIZE_T nb) { mchunkptr old_top; /* incoming value of av->top */ INTERNAL_SIZE_T old_size; /* its size */ char* old_end; /* its end address */ long size; /* arg to first MORECORE or mmap call */ char* brk; /* return value from MORECORE */ long correction; /* arg to 2nd MORECORE call */ char* snd_brk; /* 2nd return val */ INTERNAL_SIZE_T front_misalign; /* unusable bytes at front of new space */ INTERNAL_SIZE_T end_misalign; /* partial page left at end of new space */ char* aligned_brk; /* aligned offset into brk */ mchunkptr p; /* the allocated/returned chunk */ mchunkptr remainder; /* remainder from allocation */ CHUNK_SIZE_T remainder_size; /* its size */ CHUNK_SIZE_T sum; /* for updating stats */ size_t pagemask; /* Initialize av if necessary */ if (av->top == 0) { malloc_init_state(av); /* to allow call solely for initialization */ if (nb == 0) return 0; } #if HAVE_MMAP /* If have mmap, and the request size meets the mmap threshold, and the system supports mmap, and there are few enough currently allocated mmapped regions, try to directly map this request rather than expanding top. */ if ((CHUNK_SIZE_T)(nb) >= (CHUNK_SIZE_T)(av->mmap_threshold) && (av->n_mmaps < av->n_mmaps_max) && !mmap_disabled(av)) { Void_t* mp = mmap_malloc(av, nb); if (mp != 0) return chunk2mem(mp); } #endif pagemask = av->pagesize - 1; /* Record incoming configuration of top */ old_top = av->top; old_size = chunksize(old_top); old_end = (char*)(chunk_at_offset(old_top, old_size)); brk = snd_brk = (char*)(MORECORE_FAILURE); /* If not the first time through, we require old_size to be at least MINSIZE and to have prev_inuse set. */ assert((old_top == (mchunkptr)(&(av->initial_top)) && old_size == 0) || ((CHUNK_SIZE_T) (old_size) >= MINSIZE && prev_inuse(old_top))); /* Precondition: not enough current space to satisfy nb request */ assert((CHUNK_SIZE_T)(old_size) < (CHUNK_SIZE_T)(nb + MINSIZE)); /* Request enough space for nb + pad + overhead */ size = nb + av->top_pad + MINSIZE; /* If contiguous, we can subtract out existing space that we hope to combine with new space. We add it back later only if we don't actually get contiguous space. */ if (contiguous(av)) size -= old_size; /* Round to a multiple of page size. If MORECORE is not contiguous, this ensures that we only call it with whole-page arguments. And if MORECORE is contiguous and this is not first time through, this preserves page-alignment of previous calls. Otherwise, we correct to page-align below. */ size = (size + pagemask) & ~pagemask; /* Don't try to call MORECORE if argument is so big as to appear negative. Note that since mmap takes size_t arg, it may succeed below even if we cannot call MORECORE. */ if (size > 0) brk = (char*)(MORECORE(size)); /* If have mmap, try using it as a backup when MORECORE fails or cannot be used. This is worth doing on systems that have "holes" in address space, so sbrk cannot extend to give contiguous space, but space is available elsewhere. Note that we ignore mmap max count and threshold limits, since the space will not be used as a segregated mmap region. */ #if HAVE_MMAP if (brk == (char*)(MORECORE_FAILURE)) { /* Cannot merge with old top, so add its size back in */ if (contiguous(av)) size = (size + old_size + pagemask) & ~pagemask; /* If we are relying on mmap as backup, then use larger units */ if ((CHUNK_SIZE_T)(size) < (CHUNK_SIZE_T)(MMAP_AS_MORECORE_SIZE)) size = MMAP_AS_MORECORE_SIZE; /* Don't try if size wraps around 0 */ if ((CHUNK_SIZE_T)(size) > (CHUNK_SIZE_T)(nb)) { brk = (char*)(MMAP(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE)); if (brk != (char*)(MORECORE_FAILURE)) { /* We do not need, and cannot use, another sbrk call to find end */ snd_brk = brk + size; /* Record that we no longer have a contiguous sbrk region. After the first time mmap is used as backup, we do not ever rely on contiguous space since this could incorrectly bridge regions. */ set_noncontiguous(av); } } } #endif if (brk != (char*)(MORECORE_FAILURE)) { av->sbrked_mem += size; /* If MORECORE extends previous space, we can likewise extend top size. */ if (brk == old_end && snd_brk == (char*)(MORECORE_FAILURE)) { set_head(old_top, (size + old_size) | PREV_INUSE); } /* Otherwise, make adjustments: * If the first time through or noncontiguous, we need to call sbrk just to find out where the end of memory lies. * We need to ensure that all returned chunks from malloc will meet MALLOC_ALIGNMENT * If there was an intervening foreign sbrk, we need to adjust sbrk request size to account for fact that we will not be able to combine new space with existing space in old_top. * Almost all systems internally allocate whole pages at a time, in which case we might as well use the whole last page of request. So we allocate enough more memory to hit a page boundary now, which in turn causes future contiguous calls to page-align. */ else { front_misalign = 0; end_misalign = 0; correction = 0; aligned_brk = brk; /* If MORECORE returns an address lower than we have seen before, we know it isn't really contiguous. This and some subsequent checks help cope with non-conforming MORECORE functions and the presence of "foreign" calls to MORECORE from outside of malloc or by other threads. We cannot guarantee to detect these in all cases, but cope with the ones we do detect. */ if (contiguous(av) && old_size != 0 && brk < old_end) { set_noncontiguous(av); } /* handle contiguous cases */ if (contiguous(av)) { /* We can tolerate forward non-contiguities here (usually due to foreign calls) but treat them as part of our space for stats reporting. */ if (old_size != 0) av->sbrked_mem += brk - old_end; /* Guarantee alignment of first new chunk made from this space */ front_misalign = (INTERNAL_SIZE_T)chunk2mem(brk) & MALLOC_ALIGN_MASK; if (front_misalign > 0) { /* Skip over some bytes to arrive at an aligned position. We don't need to specially mark these wasted front bytes. They will never be accessed anyway because prev_inuse of av->top (and any chunk created from its start) is always true after initialization. */ correction = MALLOC_ALIGNMENT - front_misalign; aligned_brk += correction; } /* If this isn't adjacent to existing space, then we will not be able to merge with old_top space, so must add to 2nd request. */ correction += old_size; /* Extend the end address to hit a page boundary */ end_misalign = (INTERNAL_SIZE_T)(brk + size + correction); correction += ((end_misalign + pagemask) & ~pagemask) - end_misalign; assert(correction >= 0); snd_brk = (char*)(MORECORE(correction)); if (snd_brk == (char*)(MORECORE_FAILURE)) { /* If can't allocate correction, try to at least find out current brk. It might be enough to proceed without failing. */ correction = 0; snd_brk = (char*)(MORECORE(0)); } else if (snd_brk < brk) { /* If the second call gives noncontiguous space even though it says it won't, the only course of action is to ignore results of second call, and conservatively estimate where the first call left us. Also set noncontiguous, so this won't happen again, leaving at most one hole. Note that this check is intrinsically incomplete. Because MORECORE is allowed to give more space than we ask for, there is no reliable way to detect a noncontiguity producing a forward gap for the second call. */ snd_brk = brk + size; correction = 0; set_noncontiguous(av); } } /* handle non-contiguous cases */ else { /* MORECORE/mmap must correctly align */ assert(aligned_OK(chunk2mem(brk))); /* Find out current end of memory */ if (snd_brk == (char*)(MORECORE_FAILURE)) { snd_brk = (char*)(MORECORE(0)); av->sbrked_mem += snd_brk - brk - size; } } /* Adjust top based on results of second sbrk */ if (snd_brk != (char*)(MORECORE_FAILURE)) { av->top = (mchunkptr)aligned_brk; set_head(av->top, (snd_brk - aligned_brk + correction) | PREV_INUSE); av->sbrked_mem += correction; /* If not the first time through, we either have a gap due to foreign sbrk or a non-contiguous region. Insert a double fencepost at old_top to prevent consolidation with space we don't own. These fenceposts are artificial chunks that are marked as inuse and are in any case too small to use. We need two to make sizes and alignments work out. */ if (old_size != 0) { /* Shrink old_top to insert fenceposts, keeping size a multiple of MALLOC_ALIGNMENT. We know there is at least enough space in old_top to do this. */ old_size = (old_size - 3*SIZE_SZ) & ~MALLOC_ALIGN_MASK; set_head(old_top, old_size | PREV_INUSE); /* Note that the following assignments completely overwrite old_top when old_size was previously MINSIZE. This is intentional. We need the fencepost, even if old_top otherwise gets lost. */ chunk_at_offset(old_top, old_size )->size = SIZE_SZ|PREV_INUSE; chunk_at_offset(old_top, old_size + SIZE_SZ)->size = SIZE_SZ|PREV_INUSE; /* If possible, release the rest, suppressing trimming. */ if (old_size >= MINSIZE) { unsigned int mprops = av->sysctl; disable_trim(av); fREe(chunk2mem(old_top)); av->sysctl = mprops; } } } } /* Update statistics */ sum = av->sbrked_mem; if (sum > (CHUNK_SIZE_T)(av->max_sbrked_mem)) av->max_sbrked_mem = sum; sum += av->mmapped_mem; if (sum > (CHUNK_SIZE_T)(av->max_total_mem)) av->max_total_mem = sum; /* finally, do the allocation */ p = av->top; size = chunksize(p); /* check that one of the above allocation paths succeeded */ if ((CHUNK_SIZE_T)(size) >= (CHUNK_SIZE_T)(nb + MINSIZE)) { remainder_size = size - nb; remainder = chunk_at_offset(p, nb); av->top = remainder; set_head(p, nb | PREV_INUSE); set_head(remainder, remainder_size | PREV_INUSE); check_malloced_chunk(p, nb); check_malloc_state(av); return chunk2mem(p); } } /* catch all failure paths */ check_malloc_state(av); MALLOC_FAILURE_ACTION; return 0; } /* systrim is an inverse of sorts to sysmalloc. It gives memory back to the system (via negative arguments to sbrk) if there is unused memory at the `high' end of the malloc pool. It is called automatically by free() when top space exceeds the trim threshold. It is also called by the public malloc_trim routine. It returns 1 if it actually released any memory, else 0. */ static int systrim(mstate av, size_t pad) { long top_size; /* Amount of top-most memory */ long extra; /* Amount to release */ long released; /* Amount actually released */ char* current_brk; /* address returned by pre-check sbrk call */ char* new_brk; /* address returned by post-check sbrk call */ size_t pagesz; ensure_initialization(av); if (have_fastchunks(av)) malloc_consolidate(av); if (!trim_disabled(av)) { #ifndef MORECORE_CANNOT_TRIM pagesz = av->pagesize; top_size = chunksize(av->top); /* Release in pagesize units, keeping at least one page */ extra = ((top_size - pad - MINSIZE + (pagesz-1)) / pagesz - 1) * pagesz; if (extra > 0) { /* Only proceed if end of memory is where we last set it. This avoids problems if there were foreign sbrk calls. */ current_brk = (char*)(MORECORE(0)); if (current_brk == (char*)(av->top) + top_size) { /* Attempt to release memory. We ignore MORECORE return value, and instead call again to find out where new end of memory is. This avoids problems if first call releases less than we asked, of if failure somehow altered brk value. (We could still encounter problems if it altered brk in some very bad way, but the only thing we can do is adjust anyway, which will cause some downstream failure.) */ MORECORE(-extra); new_brk = (char*)(MORECORE(0)); if (new_brk != (char*)MORECORE_FAILURE) { released = (long)(current_brk - new_brk); if (released != 0) { /* Success. Adjust top. */ av->sbrked_mem -= released; set_head(av->top, (top_size - released) | PREV_INUSE); check_malloc_state(av); return 1; } } } } } #endif return 0; } /* -------------------- Alternative MORECORE functions -------------------- */ /* General Requirements for MORECORE. The MORECORE function must have the following properties: If MORECORE_CONTIGUOUS is false: * MORECORE must allocate in multiples of pagesize. It will only be called with arguments that are multiples of pagesize. * MORECORE(0) must return an address that is at least MALLOC_ALIGNMENT aligned. (Page-aligning always suffices.) else (i.e. If MORECORE_CONTIGUOUS is true): * Consecutive calls to MORECORE with positive arguments return increasing addresses, indicating that space has been contiguously extended. * MORECORE need not allocate in multiples of pagesize. Calls to MORECORE need not have args of multiples of pagesize. * MORECORE need not page-align. In either case: * MORECORE may allocate more memory than requested. (Or even less, but this will generally result in a malloc failure.) * MORECORE must not allocate memory when given argument zero, but instead return one past the end address of memory from previous nonzero call. This malloc does NOT call MORECORE(0) until at least one call with positive arguments is made, so the initial value returned is not important. * Even though consecutive calls to MORECORE need not return contiguous addresses, it must be OK for malloc'ed chunks to span multiple regions in those cases where they do happen to be contiguous. * MORECORE need not handle negative arguments -- it may instead just return MORECORE_FAILURE when given negative arguments. Negative arguments are always multiples of pagesize. MORECORE must not misinterpret negative args as large positive unsigned args. You can suppress all such calls from even occurring by defining MORECORE_CANNOT_TRIM, There is some variation across systems about the type of the argument to sbrk/MORECORE. If size_t is unsigned, then it cannot actually be size_t, because sbrk supports negative args, so it is normally the signed type of the same width as size_t (sometimes declared as "intptr_t", and sometimes "ptrdiff_t"). It doesn't much matter though. Internally, we use "long" as arguments, which should work across all reasonable possibilities. Additionally, if MORECORE ever returns failure for a positive request, and HAVE_MMAP is true, then mmap is used as a noncontiguous system allocator. This is a useful backup strategy for systems with holes in address spaces -- in this case sbrk cannot contiguously expand the heap, but mmap may be able to map noncontiguous space. If you'd like mmap to ALWAYS be used, you can define MORECORE to be a function that always returns MORECORE_FAILURE. Malloc only has limited ability to detect failures of MORECORE to supply contiguous space when it says it can. In particular, multithreaded programs that do not use locks may result in rece conditions across calls to MORECORE that result in gaps that cannot be detected as such, and subsequent corruption. If you are using this malloc with something other than sbrk (or its emulation) to supply memory regions, you probably want to set MORECORE_CONTIGUOUS as false. As an example, here is a custom allocator kindly contributed for pre-OSX macOS. It uses virtually but not necessarily physically contiguous non-paged memory (locked in, present and won't get swapped out). You can use it by uncommenting this section, adding some #includes, and setting up the appropriate defines above: #define MORECORE osMoreCore #define MORECORE_CONTIGUOUS 0 There is also a shutdown routine that should somehow be called for cleanup upon program exit. #define MAX_POOL_ENTRIES 100 #define MINIMUM_MORECORE_SIZE (64 * 1024) static int next_os_pool; void *our_os_pools[MAX_POOL_ENTRIES]; void *osMoreCore(int size) { void *ptr = 0; static void *sbrk_top = 0; if (size > 0) { if (size < MINIMUM_MORECORE_SIZE) size = MINIMUM_MORECORE_SIZE; if (CurrentExecutionLevel() == kTaskLevel) ptr = PoolAllocateResident(size + RM_PAGE_SIZE, 0); if (ptr == 0) { return (void *) MORECORE_FAILURE; } // save ptrs so they can be freed during cleanup our_os_pools[next_os_pool] = ptr; next_os_pool++; ptr = (void *) ((((CHUNK_SIZE_T) ptr) + RM_PAGE_MASK) & ~RM_PAGE_MASK); sbrk_top = (char *) ptr + size; return ptr; } else if (size < 0) { // we don't currently support shrink behavior return (void *) MORECORE_FAILURE; } else { return sbrk_top; } } // cleanup any allocated memory pools // called as last thing before shutting down driver void osCleanupMem(void) { void **ptr; for (ptr = our_os_pools; ptr < &our_os_pools[MAX_POOL_ENTRIES]; ptr++) if (*ptr) { PoolDeallocate(*ptr); *ptr = 0; } } */ /* -------------------------------------------------------------- Emulation of sbrk for win32. Donated by J. Walter . For additional information about this code, and malloc on Win32, see http://www.genesys-e.de/jwalter/ */ #ifdef WIN32 #ifdef _DEBUG /* #define TRACE */ #endif /* Support for USE_MALLOC_LOCK */ #ifdef USE_MALLOC_LOCK /* Wait for spin lock */ static int slwait (int *sl) { while (InterlockedCompareExchange ((void **) sl, (void *) 1, (void *) 0) != 0) Sleep (0); return 0; } /* Release spin lock */ static int slrelease (int *sl) { InterlockedExchange (sl, 0); return 0; } #ifdef NEEDED /* Spin lock for emulation code */ static int g_sl; #endif #endif /* USE_MALLOC_LOCK */ /* getpagesize for windows */ static long getpagesize (void) { static long g_pagesize = 0; if (! g_pagesize) { SYSTEM_INFO system_info; GetSystemInfo (&system_info); g_pagesize = system_info.dwPageSize; } return g_pagesize; } static long getregionsize (void) { static long g_regionsize = 0; if (! g_regionsize) { SYSTEM_INFO system_info; GetSystemInfo (&system_info); g_regionsize = system_info.dwAllocationGranularity; } return g_regionsize; } /* A region list entry */ typedef struct _region_list_entry { void *top_allocated; void *top_committed; void *top_reserved; long reserve_size; struct _region_list_entry *previous; } region_list_entry; /* Allocate and link a region entry in the region list */ static int region_list_append (region_list_entry **last, void *base_reserved, long reserve_size) { region_list_entry *next = HeapAlloc (GetProcessHeap (), 0, sizeof (region_list_entry)); if (! next) return FALSE; next->top_allocated = (char *) base_reserved; next->top_committed = (char *) base_reserved; next->top_reserved = (char *) base_reserved + reserve_size; next->reserve_size = reserve_size; next->previous = *last; *last = next; return TRUE; } /* Free and unlink the last region entry from the region list */ static int region_list_remove (region_list_entry **last) { region_list_entry *previous = (*last)->previous; if (! HeapFree (GetProcessHeap (), sizeof (region_list_entry), *last)) return FALSE; *last = previous; return TRUE; } #define CEIL(size,to) (((size)+(to)-1)&~((to)-1)) #define FLOOR(size,to) ((size)&~((to)-1)) #define SBRK_SCALE 0 /* #define SBRK_SCALE 1 */ /* #define SBRK_SCALE 2 */ /* #define SBRK_SCALE 4 */ /* sbrk for windows */ static void *sbrk (long size) { static long g_pagesize, g_my_pagesize; static long g_regionsize, g_my_regionsize; static region_list_entry *g_last; void *result = (void *) MORECORE_FAILURE; #ifdef TRACE printf ("sbrk %d\n", size); #endif #if defined (USE_MALLOC_LOCK) && defined (NEEDED) /* Wait for spin lock */ slwait (&g_sl); #endif /* First time initialization */ if (! g_pagesize) { g_pagesize = getpagesize (); g_my_pagesize = g_pagesize << SBRK_SCALE; } if (! g_regionsize) { g_regionsize = getregionsize (); g_my_regionsize = g_regionsize << SBRK_SCALE; } if (! g_last) { if (! region_list_append (&g_last, 0, 0)) goto sbrk_exit; } /* Assert invariants */ assert (g_last); assert ((char *) g_last->top_reserved - g_last->reserve_size <= (char *) g_last->top_allocated && g_last->top_allocated <= g_last->top_committed); assert ((char *) g_last->top_reserved - g_last->reserve_size <= (char *) g_last->top_committed && g_last->top_committed <= g_last->top_reserved && (unsigned) g_last->top_committed % g_pagesize == 0); assert ((unsigned) g_last->top_reserved % g_regionsize == 0); assert ((unsigned) g_last->reserve_size % g_regionsize == 0); /* Allocation requested? */ if (size >= 0) { /* Allocation size is the requested size */ long allocate_size = size; /* Compute the size to commit */ long to_commit = (char *) g_last->top_allocated + allocate_size - (char *) g_last->top_committed; /* Do we reach the commit limit? */ if (to_commit > 0) { /* Round size to commit */ long commit_size = CEIL (to_commit, g_my_pagesize); /* Compute the size to reserve */ long to_reserve = (char *) g_last->top_committed + commit_size - (char *) g_last->top_reserved; /* Do we reach the reserve limit? */ if (to_reserve > 0) { /* Compute the remaining size to commit in the current region */ long remaining_commit_size = (char *) g_last->top_reserved - (char *) g_last->top_committed; if (remaining_commit_size > 0) { /* Assert preconditions */ assert ((unsigned) g_last->top_committed % g_pagesize == 0); assert (0 < remaining_commit_size && remaining_commit_size % g_pagesize == 0); { /* Commit this */ void *base_committed = VirtualAlloc (g_last->top_committed, remaining_commit_size, MEM_COMMIT, PAGE_READWRITE); /* Check returned pointer for consistency */ if (base_committed != g_last->top_committed) goto sbrk_exit; /* Assert postconditions */ assert ((unsigned) base_committed % g_pagesize == 0); #ifdef TRACE printf ("Commit %p %d\n", base_committed, remaining_commit_size); #endif /* Adjust the regions commit top */ g_last->top_committed = (char *) base_committed + remaining_commit_size; } } { /* Now we are going to search and reserve. */ int contiguous = -1; int found = FALSE; MEMORY_BASIC_INFORMATION memory_info; void *base_reserved; long reserve_size; do { /* Assume contiguous memory */ contiguous = TRUE; /* Round size to reserve */ reserve_size = CEIL (to_reserve, g_my_regionsize); /* Start with the current region's top */ memory_info.BaseAddress = g_last->top_reserved; /* Assert preconditions */ assert ((unsigned) memory_info.BaseAddress % g_pagesize == 0); assert (0 < reserve_size && reserve_size % g_regionsize == 0); while (VirtualQuery (memory_info.BaseAddress, &memory_info, sizeof (memory_info))) { /* Assert postconditions */ assert ((unsigned) memory_info.BaseAddress % g_pagesize == 0); #ifdef TRACE printf ("Query %p %d %s\n", memory_info.BaseAddress, memory_info.RegionSize, memory_info.State == MEM_FREE ? "FREE": (memory_info.State == MEM_RESERVE ? "RESERVED": (memory_info.State == MEM_COMMIT ? "COMMITTED": "?"))); #endif /* Region is free, well aligned and big enough: we are done */ if (memory_info.State == MEM_FREE && (unsigned) memory_info.BaseAddress % g_regionsize == 0 && memory_info.RegionSize >= (unsigned) reserve_size) { found = TRUE; break; } /* From now on we can't get contiguous memory! */ contiguous = FALSE; /* Recompute size to reserve */ reserve_size = CEIL (allocate_size, g_my_regionsize); memory_info.BaseAddress = (char *) memory_info.BaseAddress + memory_info.RegionSize; /* Assert preconditions */ assert ((unsigned) memory_info.BaseAddress % g_pagesize == 0); assert (0 < reserve_size && reserve_size % g_regionsize == 0); } /* Search failed? */ if (! found) goto sbrk_exit; /* Assert preconditions */ assert ((unsigned) memory_info.BaseAddress % g_regionsize == 0); assert (0 < reserve_size && reserve_size % g_regionsize == 0); /* Try to reserve this */ base_reserved = VirtualAlloc (memory_info.BaseAddress, reserve_size, MEM_RESERVE, PAGE_NOACCESS); if (! base_reserved) { int rc = GetLastError (); if (rc != ERROR_INVALID_ADDRESS) goto sbrk_exit; } /* A null pointer signals (hopefully) a race condition with another thread. */ /* In this case, we try again. */ } while (! base_reserved); /* Check returned pointer for consistency */ if (memory_info.BaseAddress && base_reserved != memory_info.BaseAddress) goto sbrk_exit; /* Assert postconditions */ assert ((unsigned) base_reserved % g_regionsize == 0); #ifdef TRACE printf ("Reserve %p %d\n", base_reserved, reserve_size); #endif /* Did we get contiguous memory? */ if (contiguous) { long start_size = (char *) g_last->top_committed - (char *) g_last->top_allocated; /* Adjust allocation size */ allocate_size -= start_size; /* Adjust the regions allocation top */ g_last->top_allocated = g_last->top_committed; /* Recompute the size to commit */ to_commit = (char *) g_last->top_allocated + allocate_size - (char *) g_last->top_committed; /* Round size to commit */ commit_size = CEIL (to_commit, g_my_pagesize); } /* Append the new region to the list */ if (! region_list_append (&g_last, base_reserved, reserve_size)) goto sbrk_exit; /* Didn't we get contiguous memory? */ if (! contiguous) { /* Recompute the size to commit */ to_commit = (char *) g_last->top_allocated + allocate_size - (char *) g_last->top_committed; /* Round size to commit */ commit_size = CEIL (to_commit, g_my_pagesize); } } } /* Assert preconditions */ assert ((unsigned) g_last->top_committed % g_pagesize == 0); assert (0 < commit_size && commit_size % g_pagesize == 0); { /* Commit this */ void *base_committed = VirtualAlloc (g_last->top_committed, commit_size, MEM_COMMIT, PAGE_READWRITE); /* Check returned pointer for consistency */ if (base_committed != g_last->top_committed) goto sbrk_exit; /* Assert postconditions */ assert ((unsigned) base_committed % g_pagesize == 0); #ifdef TRACE printf ("Commit %p %d\n", base_committed, commit_size); #endif /* Adjust the regions commit top */ g_last->top_committed = (char *) base_committed + commit_size; } } /* Adjust the regions allocation top */ g_last->top_allocated = (char *) g_last->top_allocated + allocate_size; result = (char *) g_last->top_allocated - size; /* Deallocation requested? */ } else if (size < 0) { long deallocate_size = - size; /* As long as we have a region to release */ while ((char *) g_last->top_allocated - deallocate_size < (char *) g_last->top_reserved - g_last->reserve_size) { /* Get the size to release */ long release_size = g_last->reserve_size; /* Get the base address */ void *base_reserved = (char *) g_last->top_reserved - release_size; /* Assert preconditions */ assert ((unsigned) base_reserved % g_regionsize == 0); assert (0 < release_size && release_size % g_regionsize == 0); { /* Release this */ int rc = VirtualFree (base_reserved, 0, MEM_RELEASE); /* Check returned code for consistency */ if (! rc) goto sbrk_exit; #ifdef TRACE printf ("Release %p %d\n", base_reserved, release_size); #endif } /* Adjust deallocation size */ deallocate_size -= (char *) g_last->top_allocated - (char *) base_reserved; /* Remove the old region from the list */ if (! region_list_remove (&g_last)) goto sbrk_exit; } { /* Compute the size to decommit */ long to_decommit = (char *) g_last->top_committed - ((char *) g_last->top_allocated - deallocate_size); if (to_decommit >= g_my_pagesize) { /* Compute the size to decommit */ long decommit_size = FLOOR (to_decommit, g_my_pagesize); /* Compute the base address */ void *base_committed = (char *) g_last->top_committed - decommit_size; /* Assert preconditions */ assert ((unsigned) base_committed % g_pagesize == 0); assert (0 < decommit_size && decommit_size % g_pagesize == 0); { /* Decommit this */ int rc = VirtualFree ((char *) base_committed, decommit_size, MEM_DECOMMIT); /* Check returned code for consistency */ if (! rc) goto sbrk_exit; #ifdef TRACE printf ("Decommit %p %d\n", base_committed, decommit_size); #endif } /* Adjust deallocation size and regions commit and allocate top */ deallocate_size -= (char *) g_last->top_allocated - (char *) base_committed; g_last->top_committed = base_committed; g_last->top_allocated = base_committed; } } /* Adjust regions allocate top */ g_last->top_allocated = (char *) g_last->top_allocated - deallocate_size; /* Check for underflow */ if ((char *) g_last->top_reserved - g_last->reserve_size > (char *) g_last->top_allocated || g_last->top_allocated > g_last->top_committed) { /* Adjust regions allocate top */ g_last->top_allocated = (char *) g_last->top_reserved - g_last->reserve_size; goto sbrk_exit; } result = g_last->top_allocated; } /* Assert invariants */ assert (g_last); assert ((char *) g_last->top_reserved - g_last->reserve_size <= (char *) g_last->top_allocated && g_last->top_allocated <= g_last->top_committed); assert ((char *) g_last->top_reserved - g_last->reserve_size <= (char *) g_last->top_committed && g_last->top_committed <= g_last->top_reserved && (unsigned) g_last->top_committed % g_pagesize == 0); assert ((unsigned) g_last->top_reserved % g_regionsize == 0); assert ((unsigned) g_last->reserve_size % g_regionsize == 0); sbrk_exit: #if defined (USE_MALLOC_LOCK) && defined (NEEDED) /* Release spin lock */ slrelease (&g_sl); #endif return result; } /* mmap for windows */ static void *mmap (void *ptr, long size, long prot, long type, long handle, long arg) { static long g_pagesize; static long g_regionsize; #ifdef TRACE printf ("mmap %d\n", size); #endif #if defined (USE_MALLOC_LOCK) && defined (NEEDED) /* Wait for spin lock */ slwait (&g_sl); #endif /* First time initialization */ if (! g_pagesize) g_pagesize = getpagesize (); if (! g_regionsize) g_regionsize = getregionsize (); /* Assert preconditions */ assert ((unsigned) ptr % g_regionsize == 0); assert (size % g_pagesize == 0); /* Allocate this */ ptr = VirtualAlloc (ptr, size, MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE); if (! ptr) { ptr = (void *) MORECORE_FAILURE; goto mmap_exit; } /* Assert postconditions */ assert ((unsigned) ptr % g_regionsize == 0); #ifdef TRACE printf ("Commit %p %d\n", ptr, size); #endif mmap_exit: #if defined (USE_MALLOC_LOCK) && defined (NEEDED) /* Release spin lock */ slrelease (&g_sl); #endif return ptr; } /* munmap for windows */ static long munmap (void *ptr, long size) { static long g_pagesize; static long g_regionsize; int rc = MUNMAP_FAILURE; #ifdef TRACE printf ("munmap %p %d\n", ptr, size); #endif #if defined (USE_MALLOC_LOCK) && defined (NEEDED) /* Wait for spin lock */ slwait (&g_sl); #endif /* First time initialization */ if (! g_pagesize) g_pagesize = getpagesize (); if (! g_regionsize) g_regionsize = getregionsize (); /* Assert preconditions */ assert ((unsigned) ptr % g_regionsize == 0); assert (size % g_pagesize == 0); /* Free this */ if (! VirtualFree (ptr, 0, MEM_RELEASE)) goto munmap_exit; rc = 0; #ifdef TRACE printf ("Release %p %d\n", ptr, size); #endif munmap_exit: #if defined (USE_MALLOC_LOCK) && defined (NEEDED) /* Release spin lock */ slrelease (&g_sl); #endif return rc; } static void vminfo (CHUNK_SIZE_T *free, CHUNK_SIZE_T *reserved, CHUNK_SIZE_T *committed) { MEMORY_BASIC_INFORMATION memory_info; memory_info.BaseAddress = 0; *free = *reserved = *committed = 0; while (VirtualQuery (memory_info.BaseAddress, &memory_info, sizeof (memory_info))) { switch (memory_info.State) { case MEM_FREE: *free += memory_info.RegionSize; break; case MEM_RESERVE: *reserved += memory_info.RegionSize; break; case MEM_COMMIT: *committed += memory_info.RegionSize; break; } memory_info.BaseAddress = (char *) memory_info.BaseAddress + memory_info.RegionSize; } } static int cpuinfo (int whole, CHUNK_SIZE_T *kernel, CHUNK_SIZE_T *user) { if (whole) { __int64 creation64, exit64, kernel64, user64; int rc = GetProcessTimes (GetCurrentProcess (), (FILETIME *) &creation64, (FILETIME *) &exit64, (FILETIME *) &kernel64, (FILETIME *) &user64); if (! rc) { *kernel = 0; *user = 0; return FALSE; } *kernel = (CHUNK_SIZE_T) (kernel64 / 10000); *user = (CHUNK_SIZE_T) (user64 / 10000); return TRUE; } else { __int64 creation64, exit64, kernel64, user64; int rc = GetThreadTimes (GetCurrentThread (), (FILETIME *) &creation64, (FILETIME *) &exit64, (FILETIME *) &kernel64, (FILETIME *) &user64); if (! rc) { *kernel = 0; *user = 0; return FALSE; } *kernel = (CHUNK_SIZE_T) (kernel64 / 10000); *user = (CHUNK_SIZE_T) (user64 / 10000); return TRUE; } } #endif /* WIN32 */ /* ------------------------------------------------------------ History: V2.8.0 (not yet released) * Use trees for non-small bins Also requiring different size->bin algorithm V2.7.1 Thu Jul 25 10:58:03 2002 Doug Lea (dl at gee) * Allow tuning of FIRST_SORTED_BIN_SIZE * Use PTR_UINT as type for all ptr->int casts. Thanks to John Belmonte. * Better detection and support for non-contiguousness of MORECORE. Thanks to Andreas Mueller, Conal Walsh, and Wolfram Gloger * Bypass most of malloc if no frees. Thanks To Emery Berger. * Fix freeing of old top non-contiguous chunk im sysmalloc. * Raised default trim and map thresholds to 256K. * Fix mmap-related #defines. Thanks to Lubos Lunak. * Fix copy macros; added LACKS_FCNTL_H. Thanks to Neal Walfield. * Branch-free bin calculation * Default trim and mmap thresholds now 256K. V2.7.0 Sun Mar 11 14:14:06 2001 Doug Lea (dl at gee) * Introduce independent_comalloc and independent_calloc. Thanks to Michael Pachos for motivation and help. * Make optional .h file available * Allow > 2GB requests on 32bit systems. * new WIN32 sbrk, mmap, munmap, lock code from . Thanks also to Andreas Mueller , and Anonymous. * Allow override of MALLOC_ALIGNMENT (Thanks to Ruud Waij for helping test this.) * memalign: check alignment arg * realloc: don't try to shift chunks backwards, since this leads to more fragmentation in some programs and doesn't seem to help in any others. * Collect all cases in malloc requiring system memory into sysmalloc * Use mmap as backup to sbrk * Place all internal state in malloc_state * Introduce fastbins (although similar to 2.5.1) * Many minor tunings and cosmetic improvements * Introduce USE_PUBLIC_MALLOC_WRAPPERS, USE_MALLOC_LOCK * Introduce MALLOC_FAILURE_ACTION, MORECORE_CONTIGUOUS Thanks to Tony E. Bennett and others. * Include errno.h to support default failure action. V2.6.6 Sun Dec 5 07:42:19 1999 Doug Lea (dl at gee) * return null for negative arguments * Added Several WIN32 cleanups from Martin C. Fong * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h' (e.g. WIN32 platforms) * Cleanup header file inclusion for WIN32 platforms * Cleanup code to avoid Microsoft Visual C++ compiler complaints * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing memory allocation routines * Set 'malloc_getpagesize' for WIN32 platforms (needs more work) * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to usage of 'assert' in non-WIN32 code * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to avoid infinite loop * Always call 'fREe()' rather than 'free()' V2.6.5 Wed Jun 17 15:57:31 1998 Doug Lea (dl at gee) * Fixed ordering problem with boundary-stamping V2.6.3 Sun May 19 08:17:58 1996 Doug Lea (dl at gee) * Added pvalloc, as recommended by H.J. Liu * Added 64bit pointer support mainly from Wolfram Gloger * Added anonymously donated WIN32 sbrk emulation * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen * malloc_extend_top: fix mask error that caused wastage after foreign sbrks * Add linux mremap support code from HJ Liu V2.6.2 Tue Dec 5 06:52:55 1995 Doug Lea (dl at gee) * Integrated most documentation with the code. * Add support for mmap, with help from Wolfram Gloger (Gloger@lrz.uni-muenchen.de). * Use last_remainder in more cases. * Pack bins using idea from colin@nyx10.cs.du.edu * Use ordered bins instead of best-fit threshhold * Eliminate block-local decls to simplify tracing and debugging. * Support another case of realloc via move into top * Fix error occuring when initial sbrk_base not word-aligned. * Rely on page size for units instead of SBRK_UNIT to avoid surprises about sbrk alignment conventions. * Add mallinfo, mallopt. Thanks to Raymond Nijssen (raymond@es.ele.tue.nl) for the suggestion. * Add `pad' argument to malloc_trim and top_pad mallopt parameter. * More precautions for cases where other routines call sbrk, courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de). * Added macros etc., allowing use in linux libc from H.J. Lu (hjl@gnu.ai.mit.edu) * Inverted this history list V2.6.1 Sat Dec 2 14:10:57 1995 Doug Lea (dl at gee) * Re-tuned and fixed to behave more nicely with V2.6.0 changes. * Removed all preallocation code since under current scheme the work required to undo bad preallocations exceeds the work saved in good cases for most test programs. * No longer use return list or unconsolidated bins since no scheme using them consistently outperforms those that don't given above changes. * Use best fit for very large chunks to prevent some worst-cases. * Added some support for debugging V2.6.0 Sat Nov 4 07:05:23 1995 Doug Lea (dl at gee) * Removed footers when chunks are in use. Thanks to Paul Wilson (wilson@cs.texas.edu) for the suggestion. V2.5.4 Wed Nov 1 07:54:51 1995 Doug Lea (dl at gee) * Added malloc_trim, with help from Wolfram Gloger (wmglo@Dent.MED.Uni-Muenchen.DE). V2.5.3 Tue Apr 26 10:16:01 1994 Doug Lea (dl at g) V2.5.2 Tue Apr 5 16:20:40 1994 Doug Lea (dl at g) * realloc: try to expand in both directions * malloc: swap order of clean-bin strategy; * realloc: only conditionally expand backwards * Try not to scavenge used bins * Use bin counts as a guide to preallocation * Occasionally bin return list chunks in first scan * Add a few optimizations from colin@nyx10.cs.du.edu V2.5.1 Sat Aug 14 15:40:43 1993 Doug Lea (dl at g) * faster bin computation & slightly different binning * merged all consolidations to one part of malloc proper (eliminating old malloc_find_space & malloc_clean_bin) * Scan 2 returns chunks (not just 1) * Propagate failure in realloc if malloc returns 0 * Add stuff to allow compilation on non-ANSI compilers from kpv@research.att.com V2.5 Sat Aug 7 07:41:59 1993 Doug Lea (dl at g.oswego.edu) * removed potential for odd address access in prev_chunk * removed dependency on getpagesize.h * misc cosmetics and a bit more internal documentation * anticosmetics: mangled names in macros to evade debugger strangeness * tested on sparc, hp-700, dec-mips, rs6000 with gcc & native cc (hp, dec only) allowing Detlefs & Zorn comparison study (in SIGPLAN Notices.) Trial version Fri Aug 28 13:14:29 1992 Doug Lea (dl at g.oswego.edu) * Based loosely on libg++-1.2X malloc. (It retains some of the overall structure of old version, but most details differ.) */ judy-1.0.5/test/SLcompare.c0000644000175000017500000007603010204462077015734 0ustar troyhebetroyhebe// @(#) $Revision: 4.1 $ $Source: /judy/test/manual/SLcompare.c $ //======================================================================= // Author Douglas L. Baskins, June 2002. // Permission to use this code is freely granted, provided that this // statement is retained. // email - doug@sourcejudy.com //======================================================================= // Compile for choice of algorithm: // cc -static -O -o Judy -DJUDYMETHOD SLcompare.c -lJudy // cc -static -O -o Hash -DHASHMETHOD SLcompare.c // cc -static -O -o Splay -DSPLAYMETHOD SLcompare.c // cc -static -O -o Redblack -DREDBLACKMETHOD SLcompare.c // // Note: -static will generally get better performance because string // routines are slower with shared librarys. // // Usage: // // Judy // Hash // Splay // Redblack /* This program will give you a chance to measure the speed/space performance of 4 different string store/lookup algorithms on your data set. All are very fast and generally can scale to very large data sets. The memory efficiency is usually best with the Judy algorithm because it uses the opportunity to compress data in a digital tree. The Hashing is generally the fastest algorithm, however it looses its advantage when the number of stored exceeds about 5X the size of the hash table. Many thanks to J. Zobel for supplying the code for Hash, Splay and Redblack algorithms. I will be including more algorithms as people donate code for testing. The Judy code is available at: 9/2002 (dlb). This is the output of this program when run on a 750Mhz P3 laptop. This output is using a file available from www.google.com. It looks like 'http' web pages and was one of the files used in a March 2002 contest by www.google.com wc google/data/repos.00 3440314 14613027 162822437 google/data/repos.00 lines avg_linelen getline stored RAMused/line store/ln lookup/ln ADT 2807737 58.0 byts 0.856 uS 1455201 104.0 byts 4.859 uS 4.566 uS SPLAY 2807737 58.0 byts 0.862 uS 1455201 96.0 byts 2.523 uS 2.101 uS HASH 2807737 58.0 byts 0.856 uS 1455201 104.0 byts 4.601 uS 4.001 uS REDBLK 2807737 58.0 byts 0.875 uS 1455201 78.7 byts 3.898 uS 2.687 uS JUDY With = 1.46 million lines stored and 2.81 million non-blank lines, all the algorithms seem to keep their performance. The hash table is a perfect size for this data set. I suspect only the HASH algorithm will slow down with larger data sets unless the hash table is increased larger than 2**20 million entrys. I have now tried a data set with about 10 million unique lines on a 64 bit machine (google/data/repos.*). The speeds are about the same. Lookup times are in the 2-4 uSec range and this is probably insignificant compared to the application needing the data. I think all four methods are fine for speed, and Judy is a standout for its memory efficiency -- frequently using less memory than the strings alone. I plan on tuning JudySL in the near future. This should improve the performance of JudySL with short (a text word) strings. I have a data base of all (28.8 million) domain names on the internet as a test case. wc /data/domnames.txt 28826508 28826508 488227095 /data/domnames.txt For the curious, JudySL (I.E JSLI/G macros in this program) is simply an application subroutine that uses JudyL to the work. JudyL is a very scaleable word to word (or pointer) mapper. JudySL is implemented as a digital tree using JudyL arrays as 2^32 (or 2^64 in 64 bit machines) wide (virtual) nodes. Each level in the digital tree decodes the next 4 (or 8) bytes of the line/string until only one entry would be in the node. Then the remaining undecoded portion of the line is stored as a string from the parent node. A digital tree does not need rotation or balancing. In practice, digital trees are rarely use because of their poor memory efficiency in the nodes and a tendency to have large depths. These problems are solved in the Judy algorithm. For more details see application notes on: www.sourcejudy.com. And for the really curious, a technical paper is available in the application section. If you would like to be a reviewer, contact Doug Baskins at */ #include #include #include // printf #include #include #include // errno #include // mmap() #include // stat() #include // gettimeofday() // remove all uses of this in production code. int gDupCnt = 0; // counter for duplicate strings //======================================================================= // T I M I N G M A C R O S //======================================================================= // if your machine is one of the supported types in the following header // file then uncomment this corresponding to what the header file says. // This will give very high timing resolution. // // #define JU_xxxxxxx 1 // read timeit.h // #define JU_LINUX_IA32 1 // I.E. IA32 Linux // // // optional for high resolution times and compile with timeit.c // cc -static -O -o Judy -DJUDYMETHOD SLcompare.c timeit.c -lJudy // //#include "timeit.h" double DeltaUSec; // Global for remembering delta times #ifndef _TIMEIT_H // Note: I have found some Linux systems (2.4.18-6mdk) to have bugs in the // gettimeofday() routine. Sometimes it returns a negative ~2840 microseconds // instead of 0 or 1. If you use the above #include "timeit.h" and compile with // timeit.c and use -DJU_LINUX_IA32, that problem will be eliminated. This is // because for delta times less than .1 sec, the hardware free running timer // is used instead of gettimeofday(). I have found the negative time problem // appears about 40-50 times per second with consecutive gettimeofday() calls. #define TIMER_vars(T) struct timeval __TVBeg_##T, __TVEnd_##T #define STARTTm(T) gettimeofday(&__TVBeg_##T, NULL) #define ENDTm(D,T) \ { \ gettimeofday(&__TVEnd_##T, NULL); \ (D) = (double)(__TVEnd_##T.tv_sec - __TVBeg_##T.tv_sec) * 1E6 + \ ((double)(__TVEnd_##T.tv_usec - __TVBeg_##T.tv_usec)); \ } #endif // _TIMEIT_H //======================================================================= // M E M O R Y S I Z E M A C R O S //======================================================================= // Most mallocs have mallinfo() // define this if your malloc does not have mallinfo(); #define NOMALLINFO 1 double DeltaMem; // for remembering #ifndef NOMALLINFO #include // mallinfo() struct mallinfo malStart; #define STARTmem malStart = mallinfo() /* works with some mallocs */ #define ENDmem \ { \ struct mallinfo malEnd = mallinfo(); \ /* strange little dance from signed to unsigned to double */ \ unsigned int _un_int = malEnd.arena - malStart.arena; \ DeltaMem = _un_int; /* to double */ \ } #else // MALLINFO // this usually works for machines with less than 1-2Gb RAM. // (it does not include memory ACQUIRED by mmap()) char *malStart; #define STARTmem (malStart = (char *)sbrk(0)) #define ENDmem \ { \ char *malEnd = (char *)sbrk(0); \ DeltaMem = malEnd - malStart; \ } #endif // MALLINFO //======================================================================= // G E T S T R I N G F R O M mmap() F I L E M A C R O //======================================================================= // // From memory map POINTER store next '\n' terminated string to BUFFER // Delete spaces, tabs, returns and resulting blank lines. // POINTER must be check to be within memory mapped file range // // NOTE: This code will core-dump if a corrupt text file because // POINTER is not checked to exceed end of file. #define MAXLINE 10000 // max length line #define GETLINE(BUFFER,POINTER) \ { \ char _chr; \ int _count = 0; \ for (;;) /* forever */ \ { \ switch (_chr = *POINTER++) \ { \ case ' ': /* eat spaces */ \ case '\t': /* eat tabs */ \ case '\r': /* eat returns */ \ continue; \ case '\n': /* eat blank lines */ \ if (_count == 0) continue; \ case '\0': /* Done */ \ BUFFER[_count++] = '\0'; \ break; \ default: /* copy char */ \ if (_count == (MAXLINE - 1)) \ { /* cut into 2 lines */ \ BUFFER[_count++] = '\0'; \ POINTER--; \ break; \ } \ BUFFER[_count++] = _chr; \ continue; \ } \ break; \ } \ } //======================================================================= // J U D Y M E T H O D //======================================================================= #ifdef JUDYMETHOD #define ADTMETHOD "JUDY" #include #define MEMOVD 0 /* no overhead in Judy */ #define INITARRAY Pvoid_t JudyArray = NULL // store string into array #define STORESTRING(STRING) \ { \ PWord_t _PValue; \ JSLI(_PValue, JudyArray, (uint8_t *) STRING); \ if (++(*_PValue) != 1) gDupCnt++; /* count dup strings */ \ } // get pointer to Value associated with string #define GETSTRING(STRING) \ { \ PWord_t _PValue; \ JSLG(_PValue, JudyArray, (uint8_t *) STRING); \ if (_PValue == NULL) /* not found -- bug */ \ { \ printf("GETSTRING failed(Judy) -- BUG!\n\n"); \ exit(1); \ } \ } #endif // JUDYMETHOD // Note: this optimization by J. Zobel should not be necessary // with the -static compile option (linux). (dlb) #ifdef SLOW_STRCMP int scmp(char *s1, char *s2) { while (*s1 != '\0' && *s1 == *s2) { s1++; s2++; } return (*s1 - *s2); } #else // ! SLOW_STRCMP #define scmp strcmp #endif // ! SLOW_STRCMP //======================================================================= // H A S H M E T H O D //======================================================================= #ifdef HASHMETHOD #define ADTMETHOD "HASH" #define MEMOVD (sizeof(ht)) /* the hash table is overhead */ #define STORESTRING(STRING) hashinsert(ht, STRING) #define GETSTRING(STRING) \ { \ HASHREC *_return; \ _return = hashsearch(ht, STRING); \ if (_return == NULL) /* not found -- bug */ \ { \ printf("GETSTRING(hash) failed -- BUG!\n\n"); \ exit(1); \ } \ } /* Author J. Zobel, April 2001. Permission to use this code is freely granted, provided that this statement is retained. */ #define TSIZE (1LU << 20) /* many processors need this to be a pwr of 2 */ #define SEED 1159241 #define HASHFN bitwisehash #define INITARRAY static HASHREC *ht[TSIZE] #define SIZEOFINIT sizeof(ht[TSIZE]) typedef struct hashrec { char *word; struct hashrec *next; } HASHREC; /* Bitwise hash function. Note that tsize does not have to be prime. */ unsigned int bitwisehash(char *word, int tsize, unsigned int seed) { char c; unsigned int h; h = seed; for (; (c = *word) != '\0'; word++) { h ^= ((h << 5) + c + (h >> 2)); } return ((unsigned int)((h & 0x7fffffff) % tsize)); } #ifdef notdef // not needed if a static definition used in UNIX /* Create hash table, initialise ptrs to NULL */ HASHREC ** inithashtable() { int i; HASHREC **ht; ht = (HASHREC **) malloc(sizeof(HASHREC *) * TSIZE); for (i = 0; i < TSIZE; i++) ht[i] = (HASHREC *) NULL; return (ht); } #endif // notdef /* Search hash table for given string, return record if found, else NULL */ HASHREC * hashsearch(HASHREC ** ht, char *w) { HASHREC *htmp, *hprv; unsigned int hval = HASHFN(w, TSIZE, SEED); for (hprv = NULL, htmp = ht[hval]; htmp != NULL && scmp(htmp->word, w) != 0; hprv = htmp, htmp = htmp->next) { ; } if (hprv != NULL && htmp != NULL) /* move to front on access */ { hprv->next = htmp->next; htmp->next = ht[hval]; ht[hval] = htmp; } return (htmp); } /* Search hash table for given string, insert if not found */ void hashinsert(HASHREC ** ht, char *w) { HASHREC *htmp, *hprv; unsigned int hval = HASHFN(w, TSIZE, SEED); for (hprv = NULL, htmp = ht[hval]; htmp != NULL && scmp(htmp->word, w) != 0; hprv = htmp, htmp = htmp->next) { ; } if (htmp == NULL) { htmp = (HASHREC *) malloc(sizeof(HASHREC)); htmp->word = (char *)malloc(strlen(w) + 1); strcpy(htmp->word, w); htmp->next = NULL; if (hprv == NULL) ht[hval] = htmp; else hprv->next = htmp; /* new records are not moved to front */ } else { if (hprv != NULL) /* move to front on access */ { hprv->next = htmp->next; htmp->next = ht[hval]; ht[hval] = htmp; } gDupCnt++; /* count duplicate strings */ } return; } #endif // HASHMETHOD //======================================================================= // S P L A Y M E T H O D //======================================================================= #ifdef SPLAYMETHOD #define ADTMETHOD "SPLAY" #define MEMOVD 0 /* not enough overhead to count */ /* Author J. Zobel, April 2001. Permission to use this code is freely granted, provided that this statement is retained. */ #define ROTATEFAC 11 typedef struct wordrec { char *word; struct wordrec *left, *right; struct wordrec *par; } TREEREC; typedef struct ansrec { struct wordrec *root; struct wordrec *ans; } ANSREC; #define ONELEVEL(PAR,CURR,DIR,RID) \ { \ PAR->DIR = CURR->RID; \ if(PAR->DIR!=NULL) \ PAR->DIR->PAR = PAR; \ CURR->RID = PAR; \ PAR->PAR = CURR; \ CURR->PAR = NULL; \ } #define ZIGZIG(GPAR,PAR,CURR,DIR,RID) \ { \ CURR->PAR = GPAR->PAR; \ if (CURR->PAR != NULL) \ { \ if (CURR->PAR->DIR == GPAR) \ CURR->PAR->DIR = CURR; \ else \ CURR->PAR->RID = CURR; \ } \ GPAR->DIR = PAR->RID; \ if (GPAR->DIR != NULL) \ GPAR->DIR->PAR = GPAR; \ PAR->DIR = CURR->RID; \ if (CURR->RID != NULL) \ CURR->RID->PAR = PAR; \ CURR->RID = PAR; \ PAR->PAR = CURR; \ PAR->RID = GPAR; \ GPAR->PAR = PAR; \ } #define ZIGZAG(GPAR,PAR,CURR,DIR,RID) \ { \ CURR->PAR = GPAR->PAR; \ if (CURR->PAR != NULL) \ { \ if (CURR->PAR->DIR == GPAR) \ CURR->PAR->DIR = CURR; \ else \ CURR->PAR->RID = CURR; \ } \ PAR->RID = CURR->DIR; \ if (PAR->RID != NULL) \ PAR->RID->PAR = PAR; \ GPAR->DIR = CURR->RID; \ if (GPAR->DIR != NULL) \ GPAR->DIR->PAR = GPAR; \ CURR->DIR = PAR; \ PAR->PAR = CURR; \ CURR->RID = GPAR; \ GPAR->PAR = CURR; \ } int scount = ROTATEFAC; /* Search for word in a splay tree. If word is found, bring it to root, possibly intermittently. Structure ans is used to pass in the root, and to pass back both the new root (which may or may not be changed) and the looked-for record. */ void splaysearch(ANSREC * ans, char *word) { TREEREC *curr = ans->root, *par, *gpar; int val; scount--; if (ans->root == NULL) { ans->ans = NULL; return; } while (curr != NULL && (val = scmp(word, curr->word)) != 0) { if (val > 0) curr = curr->right; else curr = curr->left; } ans->ans = curr; if (curr == ans->root) { return; } if (scount <= 0 && curr != NULL) /* Move node towards root */ { scount = ROTATEFAC; while ((par = curr->par) != NULL) { if (par->left == curr) { if ((gpar = par->par) == NULL) { ONELEVEL(par, curr, left, right); } else if (gpar->left == par) { ZIGZIG(gpar, par, curr, left, right); } else { ZIGZAG(gpar, par, curr, right, left); } } else { if ((gpar = par->par) == NULL) { ONELEVEL(par, curr, right, left); } else if (gpar->left == par) { ZIGZAG(gpar, par, curr, left, right); } else { ZIGZIG(gpar, par, curr, right, left); } } } ans->root = curr; } return; } /* Insert word into a splay tree. If word is already present, bring it to root, possibly intermittently. Structure ans is used to pass in the root, and to pass back both the new root (which may or may not be changed) and the looked-for record. */ void splayinsert(ANSREC * ans, char *word) { TREEREC *curr = ans->root, *par, *gpar, *prev = NULL, *wcreate(); int val = 0; scount--; if (ans->root == NULL) { ans->ans = ans->root = wcreate(word, NULL); return; } while (curr != NULL && (val = scmp(word, curr->word)) != 0) { prev = curr; if (val > 0) curr = curr->right; else curr = curr->left; } if (curr == NULL) { if (val > 0) curr = prev->right = wcreate(word, prev); else curr = prev->left = wcreate(word, prev); } else gDupCnt++; /* count duplicate strings */ ans->ans = curr; if (scount <= 0) /* Move node towards root */ { scount = ROTATEFAC; while ((par = curr->par) != NULL) { if (par->left == curr) { if ((gpar = par->par) == NULL) { ONELEVEL(par, curr, left, right); } else if (gpar->left == par) { ZIGZIG(gpar, par, curr, left, right); } else { ZIGZAG(gpar, par, curr, right, left); } } else { if ((gpar = par->par) == NULL) { ONELEVEL(par, curr, right, left); } else if (gpar->left == par) { ZIGZAG(gpar, par, curr, left, right); } else { ZIGZIG(gpar, par, curr, right, left); } } } ans->root = curr; } return; } /* Create a node to hold a word */ TREEREC * wcreate(char *word, TREEREC * par) { TREEREC *tmp; tmp = (TREEREC *) malloc(sizeof(TREEREC)); tmp->word = (char *)malloc(strlen(word) + 1); strcpy(tmp->word, word); tmp->left = tmp->right = NULL; tmp->par = par; return (tmp); } #define INITARRAY ANSREC ans = {0} #define STORESTRING(STRING) splayinsert(&ans, STRING) #define GETSTRING(STRING) splaysearch(&ans, STRING) #endif // SPLAYMETHOD //======================================================================= // R E D B L A C K M E T H O D //======================================================================= #ifdef REDBLACKMETHOD #define ADTMETHOD "REDBLACK" #define MEMOVD 0 /* not enough overhead to count */ /* Author J. Zobel, April 2001. Permission to use this code is freely granted, provided that this statement is retained. */ typedef struct wordrec { char *word; struct wordrec *left, *right; struct wordrec *par; char colour; } TREEREC; typedef struct ansrec { struct wordrec *root; struct wordrec *ans; } ANSREC; #define RED 0 #define BLACK 1 /* Find word in a redblack tree */ void redblacksearch(ANSREC * ans, char *word) { TREEREC *curr = ans->root; int val; if (ans->root != NULL) { while (curr != NULL && (val = scmp(word, curr->word)) != 0) { if (val > 0) curr = curr->right; else curr = curr->left; } } ans->ans = curr; return; } /* Rotate the right child of par upwards */ /* Could be written as a macro, but not really necessary as it is only called on insertion */ void leftrotate(ANSREC * ans, TREEREC * par) { TREEREC *curr, *gpar; if ((curr = par->right) != NULL) { par->right = curr->left; if (curr->left != NULL) curr->left->par = par; curr->par = par->par; if ((gpar = par->par) == NULL) ans->root = curr; else { if (par == gpar->left) gpar->left = curr; else gpar->right = curr; } curr->left = par; par->par = curr; } } /* Rotate the left child of par upwards */ void rightrotate(ANSREC * ans, TREEREC * par) { TREEREC *curr, *gpar; if ((curr = par->left) != NULL) { par->left = curr->right; if (curr->right != NULL) curr->right->par = par; curr->par = par->par; if ((gpar = par->par) == NULL) ans->root = curr; else { if (par == gpar->left) gpar->left = curr; else gpar->right = curr; } curr->right = par; par->par = curr; } } /* Insert word into a redblack tree */ void redblackinsert(ANSREC * ans, char *word) { TREEREC *curr = ans->root, *par, *gpar, *prev = NULL, *wcreate(); int val; if (ans->root == NULL) { ans->ans = ans->root = wcreate(word, NULL); return; } while (curr != NULL && (val = scmp(word, curr->word)) != 0) { prev = curr; if (val > 0) curr = curr->right; else curr = curr->left; } ans->ans = curr; if (curr == NULL) /* Insert a new node, rotate up if necessary */ { if (val > 0) curr = prev->right = wcreate(word, prev); else curr = prev->left = wcreate(word, prev); curr->colour = RED; while ((par = curr->par) != NULL && (gpar = par->par) != NULL && curr->par->colour == RED) { if (par == gpar->left) { if (gpar->right != NULL && gpar->right->colour == RED) { par->colour = BLACK; gpar->right->colour = BLACK; gpar->colour = RED; curr = gpar; } else { if (curr == par->right) { curr = par; leftrotate(ans, curr); par = curr->par; } par->colour = BLACK; if ((gpar = par->par) != NULL) { gpar->colour = RED; rightrotate(ans, gpar); } } } else { if (gpar->left != NULL && gpar->left->colour == RED) { par->colour = BLACK; gpar->left->colour = BLACK; gpar->colour = RED; curr = gpar; } else { if (curr == par->left) { curr = par; rightrotate(ans, curr); par = curr->par; } par->colour = BLACK; if ((gpar = par->par) != NULL) { gpar->colour = RED; leftrotate(ans, gpar); } } } } if (curr->par == NULL) ans->root = curr; ans->root->colour = BLACK; } else gDupCnt++; /* count duplicate strings */ return; } /* Create a node to hold a word */ TREEREC * wcreate(char *word, TREEREC * par) { TREEREC *tmp; tmp = (TREEREC *) malloc(sizeof(TREEREC)); tmp->word = (char *)malloc(strlen(word) + 1); strcpy(tmp->word, word); tmp->left = tmp->right = NULL; tmp->par = par; return (tmp); } #define INITARRAY ANSREC ans = {0} #define STORESTRING(STRING) redblackinsert(&ans, STRING) #define GETSTRING(STRING) redblacksearch(&ans, STRING) #endif // REDBLACKMETHOD //======================================================================= // M A I N P R O G R A M -by- Doug Baskins //======================================================================= // error routine for system routines for accessing file #define FILERROR \ { \ printf("%s: Cannot open file \"%s\": %s " \ "(errno = %d)\n", argv[0], argv[1], strerror(errno), \ errno); \ fprintf(stderr, "%s: Cannot open file \"%s\": %s " \ "(errno = %d)\n", argv[0], argv[1], strerror(errno), \ errno); \ exit(1); \ } //======================================================================= // M E A S U R E A D T S P E E D and M E M O R Y U S A G E //======================================================================= int main(int argc, char *argv[]) { TIMER_vars(tm); // declare timer variables int fd; // to read file. struct stat statbuf; // to get size of file char *Pfile; // ram address of file size_t fsize; // file size in bytes char *FSmap; // start address of mapped file char *FEmap; // end address+1 of mapped file char String[MAXLINE]; // input buffer int StrCnt; // line counter int ii; // temp INITARRAY; // CHECK FOR REQUIRED INPUT FILE PARAMETER: if (argc != 2) { printf("Usage: %s \n", argv[0]); exit(1); } // GET FILE SIZE if (stat(argv[1], &statbuf) == -1) FILERROR; fsize = statbuf.st_size; // OPEN INPUT FILE: if ((fd = open(argv[1], O_RDONLY)) == -1) FILERROR; // MEMORY MAP FILE Pfile = (char *)mmap(NULL, fsize, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); if (Pfile == (char *)-1) FILERROR; FEmap = Pfile + fsize; // set end+1 address // print command name + run arguments printf("# "); for (ii = 0; ii < argc; ii++) printf("%s ", argv[ii]); printf("\n"); fflush(stdout); // file is in RAM, read again to measure time STARTTm(tm); // start timer for (StrCnt = 0, FSmap = Pfile; FSmap < FEmap; ) { GETLINE(String, FSmap); // 'read' next string StrCnt++; } ENDTm(DeltaUSec, tm); // end timer // // print header - 6 fields printf("# lines avg_linelen getline stored"); printf(" RAMused/line store/ln lookup/ln ADT\n"); // print numb lines filesize/line printf("%8u", StrCnt); // Number of lines printf(" %6.1f byts", (double)fsize / (double)StrCnt); // filesize/line fflush(stdout); // print time to read a line printf(" %5.3f uS", DeltaUSec / (double)StrCnt); fflush(stdout); // INPUT/STORE LOOP: // read each input line into String and store into ADT STARTmem; // current malloc() mem usage STARTTm(tm); // start timer for (FSmap = Pfile; FSmap < FEmap; ) { GETLINE(String, FSmap); // 'read' next string STORESTRING(String); } ENDTm(DeltaUSec, tm); // end timer ENDmem; // current malloc() mem usage // print number of non-duplicate lines printf(" %8u", StrCnt - gDupCnt); // duplicate lines // print RAM used by malloc() by ADT to store data printf(" %7.1f byts", (double)(DeltaMem + MEMOVD) / (double)(StrCnt - gDupCnt)); // print time per line to store the data printf(" %6.3f uS", DeltaUSec / (double)StrCnt); fflush(stdout); // READ BACK LOOP STARTTm(tm); // start timer for (FSmap = Pfile; FSmap < FEmap; ) { GETLINE(String, FSmap); // 'read' next string GETSTRING(String); } ENDTm(DeltaUSec, tm); // end timer // print time per line to lookup the data from the ADT printf(" %6.3f uS", DeltaUSec / (double)StrCnt); // store time/line printf(" %s\n", ADTMETHOD); return (0); // done } // main() judy-1.0.5/test/Judy1LTime.c0000644000175000017500000013006610204462077015776 0ustar troyhebetroyhebe// @(#) $Revision: 4.20 $ $Source: /judy/test/manual/Judy1LTime.c $ //======================================================================= // This program measures the performance of a Judy1 and JudyL Array. // -by- // Douglas L. Baskins (8/2001) doug@sourcejudy.com //======================================================================= #include // sbrk() #include // exit() #include // printf() #include // pow() #include // gettimeofday() #include // for Judy macros J*() #ifdef NOINLINE /* this is the 21st century? */ #define _INLINE_ static #else #define _INLINE_ inline #endif //======================================================================= // C O M P I L E D: //======================================================================= // // cc -static -O3 Judy1LTime.c -lJudy -lm // // the -static is for a little better performace on some platforms // // if optional high-resolution timers are desired: // // cc -static -O3 -DJU_LINUX_IA32 Judy1LTime.c -lJudy -lm // // and read below: // //======================================================================= // T I M I N G M A C R O S //======================================================================= // if your machine is one of the supported types in the following header // file then uncomment this corresponding to what the header file says. // This will give very high timing resolution. // // #define JU_xxxxxxx 1 // read timeit.h // #define JU_LINUX_IA32 1 // I.E. IA32 Linux // #include "timeit.h" // optional for high resolution times double DeltaUSec; // Global for remembering delta times #ifndef _TIMEIT_H // Note: I have found some Linux systems (2.4.18-6mdk) have bugs in the // gettimeofday() routine. Sometimes the difference of two consective calls // returns a negative ~2840 microseconds instead of 0 or 1. If you use the // above #include "timeit.h" and compile with timeit.c and use // -DJU_LINUX_IA32, that problem will be eliminated. This is because for // delta times less than .1 sec, the hardware free running timer is used // instead of gettimeofday(). I have found the negative time problem // appears about 40-50 times per second with numerous gettimeofday() calls. // You should just ignore negative times output. #define TIMER_vars(T) struct timeval __TVBeg_##T, __TVEnd_##T #define STARTTm(T) gettimeofday(&__TVBeg_##T, NULL) #define ENDTm(D,T) \ { \ gettimeofday(&__TVEnd_##T, NULL); \ (D) = (double)(__TVEnd_##T.tv_sec - __TVBeg_##T.tv_sec) * 1E6 + \ ((double)(__TVEnd_##T.tv_usec - __TVBeg_##T.tv_usec)); \ } #endif // _TIMEIT_H //======================================================================= // M E M O R Y S I Z E M A C R O S //======================================================================= // Most mallocs have mallinfo() // However, the size is an int, so just about worthless in 64 bit // machines with more than 4Gb ram. But needed on 32 bit machines // that have more than a 1Gbyte of memory, because malloc stops // using sbrk() about at that time (runs out of heap -- use mmap()). // un-define this if your malloc has mallinfo(); see above #define NOMALLINFO 1 double DeltaMem; #ifndef NOMALLINFO #include // mallinfo() struct mallinfo malStart; #define STARTmem malStart = mallinfo() /* works with some mallocs */ #define ENDmem \ { \ struct mallinfo malEnd = mallinfo(); \ /* strange little dance from signed to unsigned to double */ \ unsigned int _un_int = malEnd.arena - malStart.arena; \ DeltaMem = _un_int; /* to double */ \ } #else // MALLINFO // this usually works for machines with less than 1-2Gb RAM. // (it does not include memory ACQUIRED by mmap()) char *malStart; #define STARTmem (malStart = (char *)sbrk(0)) #define ENDmem \ { \ char *malEnd = (char *)sbrk(0); \ DeltaMem = malEnd - malStart; \ } #endif // MALLINFO //======================================================================= // Common macro to handle a failure #define FAILURE(STR, UL) \ { \ printf( "Error: %s %lu, file='%s', 'function='%s', line %d\n", \ STR, UL, __FILE__, __FUNCTI0N__, __LINE__); \ fprintf(stderr, "Error: %s %lu, file='%s', 'function='%s', line %d\n", \ STR, UL, __FILE__, __FUNCTI0N__, __LINE__); \ exit(1); \ } // Interations without improvement // Minimum of 2 loops, maximum of 1000000 #define MINLOOPS 2 #define MAXLOOPS 1000000 // Maximum or 10 loops with no improvement #define ICNT 10 // Structure to keep track of times typedef struct MEASUREMENTS_STRUCT { Word_t ms_delta; } ms_t , *Pms_t; // Specify prototypes for each test routine int NextNumb(Word_t *PNumber, double *PDNumb, double DMult, Word_t MaxN); Word_t TestJudyIns(void **J1, void **JL, Word_t Seed, Word_t Elems); Word_t TestJudyDup(void **J1, void **JL, Word_t Seed, Word_t Elems); int TestJudyDel(void **J1, void **JL, Word_t Seed, Word_t Elems); Word_t TestJudyGet(void *J1, void *JL, Word_t Seed, Word_t Elems); int TestJudyCount(void *J1, void *JL, Word_t LowIndex, Word_t Elems); Word_t TestJudyNext(void *J1, void *JL, Word_t LowIndex, Word_t Elems); int TestJudyPrev(void *J1, void *JL, Word_t HighIndex, Word_t Elems); Word_t TestJudyNextEmpty(void *J1, void *JL, Word_t LowIndex, Word_t Elems); Word_t TestJudyPrevEmpty(void *J1, void *JL, Word_t HighIndex, Word_t Elems); //======================================================================= // These are LFSF feedback taps for bitwidths of 10..64 sized numbers. // Tested with Seed=0xc1fc to 35 billion numbers //======================================================================= Word_t StartSeed = 0xc1fc; // default beginning number Word_t FirstSeed; Word_t MagicList[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0..9 0x27f, // 10 0x27f, // 11 0x27f, // 12 0x27f, // 13 0x27f, // 14 0x27f, // 15 0x1e71, // 16 0xdc0b, // 17 0xdc0b, // 18 0xdc0b, // 19 0xdc0b, // 20 0xc4fb, // 21 0xc4fb, // 22 0xc4fb, // 23 0x13aab, // 24 0x11ca3, // 25 0x11ca3, // 26 0x11ca3, // 27 0x13aab, // 28 0x11ca3, // 29 0xc4fb, // 30 0xc4fb, // 31 0x13aab, // 32 0x14e73, // 33 0x145d7, // 34 0x145f9, // 35 following tested with Seed=0xc1fc to 35 billion numbers 0x151ed, // 36 .. 41 0x151ed, // 37 0x151ed, // 38 0x151ed, // 39 0x151ed, // 40 0x146c3, // 41 .. 64 0x146c3, // 42 0x146c3, // 43 0x146c3, // 44 0x146c3, // 45 0x146c3, // 46 0x146c3, // 47 0x146c3, // 48 0x146c3, // 49 0x146c3, // 50 0x146c3, // 51 0x146c3, // 52 0x146c3, // 53 0x146c3, // 54 0x146c3, // 55 0x146c3, // 56 0x146c3, // 57 0x146c3, // 58 0x146c3, // 59 0x146c3, // 60 0x146c3, // 61 0x146c3, // 62 0x146c3, // 63 0x146c3 // 64 }; // Routine to "mirror" the input data word static Word_t Swizzle(Word_t word) { // BIT REVERSAL, Ron Gutman in Dr. Dobb's Journal, #316, Sept 2000, pp133-136 // #ifdef __LP64__ word = ((word & 0x00000000ffffffff) << 32) | ((word & 0xffffffff00000000) >> 32); word = ((word & 0x0000ffff0000ffff) << 16) | ((word & 0xffff0000ffff0000) >> 16); word = ((word & 0x00ff00ff00ff00ff) << 8) | ((word & 0xff00ff00ff00ff00) >> 8); word = ((word & 0x0f0f0f0f0f0f0f0f) << 4) | ((word & 0xf0f0f0f0f0f0f0f0) >> 4); word = ((word & 0x3333333333333333) << 2) | ((word & 0xcccccccccccccccc) >> 2); word = ((word & 0x5555555555555555) << 1) | ((word & 0xaaaaaaaaaaaaaaaa) >> 1); #else // not __LP64__ word = ((word & 0x0000ffff) << 16) | ((word & 0xffff0000) >> 16); word = ((word & 0x00ff00ff) << 8) | ((word & 0xff00ff00) >> 8); word = ((word & 0x0f0f0f0f) << 4) | ((word & 0xf0f0f0f0) >> 4); word = ((word & 0x33333333) << 2) | ((word & 0xcccccccc) >> 2); word = ((word & 0x55555555) << 1) | ((word & 0xaaaaaaaa) >> 1); #endif // not __LP64__ return (word); } double DeltaUSec1 = 0.0; // Global for measuring delta times double DeltaUSecL = 0.0; // Global for measuring delta times Word_t J1Flag = 0; // time Judy1 Word_t JLFlag = 0; // time JudyL Word_t dFlag = 0; // time Judy1Unset JudyLDel Word_t vFlag = 0; // time Searching Word_t CFlag = 0; // time Counting Word_t IFlag = 0; // time duplicate inserts/sets Word_t DFlag = 0; // bit reverse the data stream Word_t lFlag = 0; // do not do multi-insert tests Word_t aFlag = 0; // output active memory in array Word_t SkipN = 0; // default == Random skip Word_t TValues = 100000; // Maximum retrieve tests for timing Word_t nElms = 1000000; // Max population of arrays Word_t ErrorFlag = 0; Word_t PtsPdec = 40; // measurement points per decade // Stuff for LFSR (pseudo random number generator) Word_t RandomBit = ~0UL / 2 + 1; Word_t BValue = sizeof(Word_t) * 8; Word_t Magic; // for error routines -- notice misspelling, name conflicts with some compilers #undef __FUNCTI0N__ #define __FUNCTI0N__ "Random" _INLINE_ Word_t // so INLINING compilers get to look at it. Random(Word_t newseed) { if (newseed & RandomBit) { newseed += newseed; newseed ^= Magic; } else { newseed += newseed; } newseed &= RandomBit * 2 - 1; if (newseed == FirstSeed) FAILURE("LFSR failed", newseed); return (newseed); } _INLINE_ Word_t // so INLINING compilers get to look at it. GetNextIndex(Word_t Index) { if (SkipN) Index += SkipN; else Index = Random(Index); return (Index); } #undef __FUNCTI0N__ #define __FUNCTI0N__ "main" int main(int argc, char *argv[]) { // Names of Judy Arrays void *J1 = NULL; // Judy1 void *JL = NULL; // JudyL TIMER_vars(tm1); // declare timer variables Word_t Count1, CountL; Word_t Bytes; double Mult; Pms_t Pms; Word_t Seed; Word_t PtsPdec = 40; // points per decade Word_t Groups; // Number of measurement groups Word_t grp; Word_t Pop1; Word_t Meas; int Col; int c; extern char *optarg; //============================================================ // PARSE INPUT PARAMETERS //============================================================ while ((c = getopt(argc, argv, "n:S:T:P:b:B:dDC1LvIla")) != -1) { switch (c) { case 'n': // Max population of arrays nElms = strtoul(optarg, NULL, 0); // Size of Linear Array if (nElms == 0) FAILURE("No tests: -n", nElms); // Check if more than a trillion (64 bit only) if ((double)nElms > 1e12) FAILURE("Too many Indexes=", nElms); break; case 'S': // Step Size, 0 == Random SkipN = strtoul(optarg, NULL, 0); break; case 'T': // Maximum retrieve tests for timing TValues = strtoul(optarg, NULL, 0); break; case 'P': // measurement points per decade PtsPdec = strtoul(optarg, NULL, 0); break; case 'b': // May not work past 35 bits if changed StartSeed = strtoul(optarg, NULL, 0); break; case 'B': // expanse of data points (random only) BValue = strtoul(optarg, NULL, 0); if ((BValue > 64) || (MagicList[BValue] == 0) || (BValue > (sizeof(Word_t) * 8))) { ErrorFlag++; printf("\nIllegal number of random bits of %lu !!!\n", BValue); } break; case 'v': vFlag = 1; // time Searching break; case '1': // time Judy1 J1Flag = 1; break; case 'L': // time JudyL JLFlag = 1; break; case 'd': // time Judy1Unset JudyLDel dFlag = 1; break; case 'D': // bit reverse the data stream DFlag = 1; break; case 'C': // time Counting CFlag = 1; break; case 'I': // time duplicate insert/set IFlag = 1; break; case 'l': // do not loop in tests lFlag = 1; break; case 'a': // output active memory in Judy array aFlag = 1; break; default: ErrorFlag++; break; } } if (ErrorFlag) { printf("\n%s -n# -P# -S# -B# -T# -b # -DCpdI\n\n", argv[0]); printf("Where:\n"); printf("-n <#> number of indexes used in tests\n"); printf("-P <#> number measurement points per decade\n"); printf("-S <#> index skip amount, 0 = random\n"); printf("-B <#> # bits (10..%d) in random number generator\n", (int)sizeof(Word_t) * 8); printf("-L time JudyL\n"); printf("-1 time Judy1\n"); printf("-I time DUPLICATE Ins/Set times\n"); printf("-C time JudyCount tests\n"); printf("-v time Judy Search tests\n"); printf("-d time JudyDel/Unset instead of JudyFreeArray\n"); printf("-l do not loop on same Indexes\n"); printf("-T <#> max number indexes in read times - 0 == MAX\n"); printf("\n"); exit(1); } // If none, then both if (!JLFlag && !J1Flag) JLFlag = J1Flag = 1; // Set number of Random bits in LFSR RandomBit = 1UL << (BValue - 1); Magic = MagicList[BValue]; if (nElms > ((RandomBit - 2) * 2)) { printf ("# Number = -n%lu of Indexes reduced to max expanse of Random numbers\n", nElms); nElms = ((RandomBit - 2) * 2); } printf("# TITLE %s -n%lu -S%lu -T%lu -B%lu -P%lu", argv[0], nElms, SkipN, TValues, BValue, PtsPdec); if (J1Flag) printf(" -1"); if (JLFlag) printf(" -L"); if (DFlag) printf(" -D"); if (dFlag) printf(" -d"); if (CFlag) printf(" -C"); if (IFlag) printf(" -I"); if (lFlag) printf(" -l"); if (aFlag) printf(" -a"); printf("\n"); if (sizeof(Word_t) == 8) printf("#%s 64 Bit version\n", argv[0]); else if (sizeof(Word_t) == 4) printf("#%s 32 Bit version\n", argv[0]); printf("# XLABEL Population\n"); printf("# YLABEL Microseconds / Index\n"); //============================================================ // CALCULATE NUMBER OF MEASUREMENT GROUPS //============================================================ // Calculate Multiplier for number of points per decade Mult = pow(10.0, 1.0 / (double)PtsPdec); { double sum; Word_t numb, prevnumb; // Count number of measurements needed (10K max) sum = numb = 1; for (Groups = 2; Groups < 10000; Groups++) { if (NextNumb(&numb, &sum, Mult, nElms)) break; } // Get memory for measurements Pms = (Pms_t) calloc(Groups, sizeof(ms_t)); // Now calculate number of Indexes for each measurement point numb = sum = 1; prevnumb = 0; for (grp = 0; grp < Groups; grp++) { Pms[grp].ms_delta = numb - prevnumb; prevnumb = numb; NextNumb(&numb, &sum, Mult, nElms); } } // Groups = number of sizes //============================================================ // PRINT HEADER TO PERFORMANCE TIMERS //============================================================ printf("# COLHEAD 1 Population\n"); printf("# COLHEAD 2 Measurments\n"); printf("# COLHEAD 3 J1S\n"); printf("# COLHEAD 4 JLI\n"); printf("# COLHEAD 5 J1T\n"); printf("# COLHEAD 6 JLG\n"); Col = 7; if (IFlag) { printf("# COLHEAD %d J1S-dup\n", Col++); printf("# COLHEAD %d JLI-dup\n", Col++); } if (CFlag) { printf("# COLHEAD %d J1C\n", Col++); printf("# COLHEAD %d JLC\n", Col++); } if (vFlag) { printf("# COLHEAD %d J1N\n", Col++); printf("# COLHEAD %d JLN\n", Col++); printf("# COLHEAD %d J1P\n", Col++); printf("# COLHEAD %d JLP\n", Col++); printf("# COLHEAD %d J1NE\n", Col++); printf("# COLHEAD %d JLNE\n", Col++); printf("# COLHEAD %d J1PE\n", Col++); printf("# COLHEAD %d JLPE\n", Col++); } if (dFlag) { printf("# COLHEAD %d J1U\n", Col++); printf("# COLHEAD %d JLD\n", Col++); } printf("# COLHEAD %d J1MU/I\n", Col++); printf("# COLHEAD %d JLMU/I\n", Col++); if (aFlag) { printf("# COLHEAD %d J1MA/I\n", Col++); printf("# COLHEAD %d JLMA/I\n", Col++); } printf("# COLHEAD %d HEAP/I\n", Col++); printf("# %s\n", Judy1MallocSizes); printf("# %s\n", JudyLMallocSizes); printf("# Pop1 Measmts J1S JLI J1T JLG"); if (IFlag) printf(" dupJ1S dupJLI"); if (CFlag) printf(" J1C JLC"); if (vFlag) printf(" J1N JLN J1P JLP J1NE JLNE J1PE JLPE"); if (dFlag) printf(" J1U JLD"); printf(" J1MU/I JLMU/I"); if (aFlag) { printf(" J1MA/I JLMA/I"); } printf(" HEAP/I"); printf("\n"); //============================================================ // BEGIN TESTS AT EACH GROUP SIZE //============================================================ // Get the kicker to test the LFSR FirstSeed = Seed = StartSeed & (RandomBit * 2 - 1); STARTmem; for (Pop1 = grp = 0; grp < Groups; grp++) { Word_t LowIndex, HighIndex; Word_t Delta; Word_t NewSeed; Delta = Pms[grp].ms_delta; // Test J1S, JLI NewSeed = TestJudyIns(&J1, &JL, Seed, Delta); // Accumulate the Total population of arrays Pop1 += Delta; Meas = Pop1; // Only test the maximum of TValues if not zero if (TValues) Meas = (Pop1 < TValues) ? Pop1 : TValues; printf("%10lu %9lu", Pop1, Meas); printf(" %6.3f", DeltaUSec1); printf(" %6.3f", DeltaUSecL); // Test J1T, JLG LowIndex = TestJudyGet(J1, JL, FirstSeed, Meas); printf(" %6.3f", DeltaUSec1); printf(" %6.3f", DeltaUSecL); // Test J1T, JLI - duplicates if (IFlag) { LowIndex = TestJudyDup(&J1, &JL, FirstSeed, Meas); printf(" %6.3f", DeltaUSec1); printf(" %6.3f", DeltaUSecL); } if (CFlag) { TestJudyCount(J1, JL, LowIndex, Meas); printf(" %6.3f", DeltaUSec1); printf(" %6.3f", DeltaUSecL); } if (vFlag) { // Test J1N, JLN HighIndex = TestJudyNext(J1, JL, LowIndex, Meas); printf(" %6.3f", DeltaUSec1); printf(" %6.3f", DeltaUSecL); // Test J1P, JLP TestJudyPrev(J1, JL, HighIndex, Meas); printf(" %6.3f", DeltaUSec1); printf(" %6.3f", DeltaUSecL); // Test J1NE, JLNE TestJudyNextEmpty(J1, JL, LowIndex, Meas); printf(" %6.3f", DeltaUSec1); printf(" %6.3f", DeltaUSecL); // Test J1PE, JLPE TestJudyPrevEmpty(J1, JL, HighIndex, Meas); printf(" %6.3f", DeltaUSec1); printf(" %6.3f", DeltaUSecL); } // Test J1U, JLD if (dFlag) { TestJudyDel(&J1, &JL, FirstSeed, Meas); printf(" %6.3f", DeltaUSec1); printf(" %6.3f", DeltaUSecL); // Now put them back TestJudyIns(&J1, &JL, FirstSeed, Meas); } // Advance Index number set Seed = NewSeed; // Print the number of bytes used per Index printf(" %6.3f", (double)Judy1MemUsed(J1) / (double)Pop1); printf(" %6.3f", (double)JudyLMemUsed(JL) / (double)Pop1); if (aFlag) { printf(" %6.3f", (double)Judy1MemActive(J1) / (double)Pop1); printf(" %6.3f", (double)JudyLMemActive(JL) / (double)Pop1); } ENDmem; printf(" %6.3f", DeltaMem / (double)Pop1); printf("\n"); fflush(NULL); // assure data gets to file in case malloc fail } JLC(CountL, JL, 0, -1); // get the counts J1C(Count1, J1, 0, -1); if (JLFlag && J1Flag) { if (CountL != Count1) FAILURE("Judy1/LCount not equal", Count1); } if (Count1) { STARTTm(tm1); J1FA(Bytes, J1); // Free the Judy1 Array ENDTm(DeltaUSec1, tm1); DeltaUSec1 /= (double)Count1; printf("# Judy1FreeArray: %lu, %0.3f bytes/Index, %0.3f USec/Index\n", Count1, (double)Bytes / (double)Count1, DeltaUSec1); } if (CountL) { STARTTm(tm1); JLFA(Bytes, JL); // Free the JudyL Array ENDTm(DeltaUSecL, tm1); DeltaUSecL /= (double)CountL; printf("# JudyLFreeArray: %lu, %0.3f bytes/Index, %0.3f USec/Index\n", CountL, (double)Bytes / (double)CountL, DeltaUSecL); } exit(0); } #undef __FUNCTI0N__ #define __FUNCTI0N__ "TestJudyIns" Word_t TestJudyIns(void **J1, void **JL, Word_t Seed, Word_t Elements) { TIMER_vars(tm1); // declare timer variables Word_t TstIndex; Word_t elm; Word_t *PValue; Word_t Seed1 = 0; int Rc; double DDel; Word_t icnt; Word_t lp; Word_t Loops; if (Elements < 100) Loops = (MAXLOOPS / Elements) + MINLOOPS; else Loops = 1; if (lFlag) Loops = 1; // Judy1Set timings if (J1Flag) { for (DDel = 1e40, icnt = ICNT, lp = 0; lp < Loops; lp++) { if (lp != 0) { for (Seed1 = Seed, elm = 0; elm < Elements; elm++) { Seed1 = GetNextIndex(Seed1); if (DFlag) TstIndex = Swizzle(Seed1); else TstIndex = Seed1; J1U(Rc, *J1, TstIndex); } } STARTTm(tm1); for (Seed1 = Seed, elm = 0; elm < Elements; elm++) { Seed1 = GetNextIndex(Seed1); if (DFlag) TstIndex = Swizzle(Seed1); else TstIndex = Seed1; J1S(Rc, *J1, TstIndex); if (Rc == 0) FAILURE("Judy1Set failed - DUP Index at", elm); } ENDTm(DeltaUSec1, tm1); if (DDel > DeltaUSec1) { icnt = ICNT; DDel = DeltaUSec1; } else { if (--icnt == 0) break; } } DeltaUSec1 = DDel / (double)Elements; } // JudyLIns timings if (JLFlag) { for (DDel = 1e40, icnt = ICNT, lp = 0; lp < Loops; lp++) { if (lp != 0) { for (Seed1 = Seed, elm = 0; elm < Elements; elm++) { Seed1 = GetNextIndex(Seed1); if (DFlag) TstIndex = Swizzle(Seed1); else TstIndex = Seed1; JLD(Rc, *JL, TstIndex); } } STARTTm(tm1); for (Seed1 = Seed, elm = 0; elm < Elements; elm++) { Seed1 = GetNextIndex(Seed1); if (DFlag) TstIndex = Swizzle(Seed1); else TstIndex = Seed1; JLI(PValue, *JL, TstIndex); if (*PValue == TstIndex) FAILURE("JudyLIns failed - DUP Index", TstIndex); *PValue = TstIndex; // save Index in Value } ENDTm(DeltaUSecL, tm1); DeltaUSecL /= Elements; if (DDel > DeltaUSecL) { icnt = ICNT; DDel = DeltaUSecL; } else { if (--icnt == 0) break; } } } return (Seed1); // New seed } #undef __FUNCTI0N__ #define __FUNCTI0N__ "TestJudyDup" Word_t TestJudyDup(void **J1, void **JL, Word_t Seed, Word_t Elements) { TIMER_vars(tm1); // declare timer variables Word_t LowIndex = ~0UL; Word_t TstIndex; Word_t elm; Word_t *PValue; Word_t Seed1; int Rc; double DDel; Word_t icnt; Word_t lp; Word_t Loops; Loops = (MAXLOOPS / Elements) + MINLOOPS; if (J1Flag) { LowIndex = ~0UL; for (DDel = 1e40, icnt = ICNT, lp = 0; lp < Loops; lp++) { STARTTm(tm1); for (Seed1 = Seed, elm = 0; elm < Elements; elm++) { Seed1 = GetNextIndex(Seed1); if (DFlag) TstIndex = Swizzle(Seed1); else TstIndex = Seed1; if (TstIndex < LowIndex) LowIndex = TstIndex; J1S(Rc, *J1, TstIndex); if (Rc != 0) FAILURE("Judy1Test Rc != 0", (Word_t)Rc); } ENDTm(DeltaUSec1, tm1); if (DDel > DeltaUSec1) { icnt = ICNT; DDel = DeltaUSec1; } else { if (--icnt == 0) break; } } DeltaUSec1 = DDel / (double)Elements; } icnt = ICNT; if (JLFlag) { LowIndex = ~0UL; for (DDel = 1e40, lp = 0; lp < Loops; lp++) { STARTTm(tm1); for (Seed1 = Seed, elm = 0; elm < Elements; elm++) { Seed1 = GetNextIndex(Seed1); if (DFlag) TstIndex = Swizzle(Seed1); else TstIndex = Seed1; if (TstIndex < LowIndex) LowIndex = TstIndex; JLI(PValue, *JL, TstIndex); if (PValue == (Word_t *)NULL) FAILURE("JudyLGet ret PValue = NULL", 0L); if (*PValue != TstIndex) FAILURE("JudyLGet ret wrong Value at", elm); } ENDTm(DeltaUSecL, tm1); if (DDel > DeltaUSecL) { icnt = ICNT; DDel = DeltaUSecL; } else { if (--icnt == 0) break; } } DeltaUSecL = DDel / (double)Elements; } return (LowIndex); } #undef __FUNCTI0N__ #define __FUNCTI0N__ "TestJudyGet" Word_t TestJudyGet(void *J1, void *JL, Word_t Seed, Word_t Elements) { TIMER_vars(tm1); // declare timer variables Word_t LowIndex = ~0UL; Word_t TstIndex; Word_t elm; Word_t *PValue; Word_t Seed1; int Rc; double DDel; Word_t icnt; Word_t lp; Word_t Loops; Loops = (MAXLOOPS / Elements) + MINLOOPS; if (J1Flag) { LowIndex = ~0UL; for (DDel = 1e40, icnt = ICNT, lp = 0; lp < Loops; lp++) { STARTTm(tm1); for (Seed1 = Seed, elm = 0; elm < Elements; elm++) { Seed1 = GetNextIndex(Seed1); if (DFlag) TstIndex = Swizzle(Seed1); else TstIndex = Seed1; if (TstIndex < LowIndex) LowIndex = TstIndex; J1T(Rc, J1, TstIndex); if (Rc != 1) FAILURE("Judy1Test Rc != 1", (Word_t)Rc); } ENDTm(DeltaUSec1, tm1); if (DDel > DeltaUSec1) { icnt = ICNT; DDel = DeltaUSec1; } else { if (--icnt == 0) break; } } DeltaUSec1 = DDel / (double)Elements; } icnt = ICNT; if (JLFlag) { LowIndex = ~0UL; for (DDel = 1e40, lp = 0; lp < Loops; lp++) { STARTTm(tm1); for (Seed1 = Seed, elm = 0; elm < Elements; elm++) { Seed1 = GetNextIndex(Seed1); if (DFlag) TstIndex = Swizzle(Seed1); else TstIndex = Seed1; if (TstIndex < LowIndex) LowIndex = TstIndex; JLG(PValue, JL, TstIndex); if (PValue == (Word_t *)NULL) FAILURE("JudyLGet ret PValue = NULL", 0L); if (*PValue != TstIndex) FAILURE("JudyLGet ret wrong Value at", elm); } ENDTm(DeltaUSecL, tm1); if (DDel > DeltaUSecL) { icnt = ICNT; DDel = DeltaUSecL; } else { if (--icnt == 0) break; } } DeltaUSecL = DDel / (double)Elements; } return (LowIndex); } #undef __FUNCTI0N__ #define __FUNCTI0N__ "TestJudyCount" int TestJudyCount(void *J1, void *JL, Word_t LowIndex, Word_t Elements) { TIMER_vars(tm1); // declare timer variables Word_t elm; Word_t Count1, CountL; Word_t TstIndex = LowIndex; int Rc; double DDel; Word_t icnt; Word_t lp; Word_t Loops; Loops = (MAXLOOPS / Elements) + MINLOOPS; if (J1Flag) { for (DDel = 1e40, icnt = ICNT, lp = 0; lp < Loops; lp++) { TstIndex = LowIndex; STARTTm(tm1); for (elm = 0; elm < Elements; elm++) { J1C(Count1, J1, LowIndex, TstIndex); if (Count1 != (elm + 1)) FAILURE("J1C at", elm); J1N(Rc, J1, TstIndex); } ENDTm(DeltaUSec1, tm1); if (DDel > DeltaUSec1) { icnt = ICNT; DDel = DeltaUSec1; } else { if (--icnt == 0) break; } } DeltaUSec1 = DDel / (double)Elements; } if (JLFlag) { for (DDel = 1e40, icnt = ICNT, lp = 0; lp < Loops; lp++) { TstIndex = LowIndex; STARTTm(tm1); for (elm = 0; elm < Elements; elm++) { Word_t *PValue; JLC(CountL, JL, LowIndex, TstIndex); if (CountL != (elm + 1)) FAILURE("JLC at", elm); JLN(PValue, JL, TstIndex); } ENDTm(DeltaUSecL, tm1); if (DDel > DeltaUSecL) { icnt = ICNT; DDel = DeltaUSecL; } else { if (--icnt == 0) break; } } DeltaUSecL = DDel / (double)Elements; } return (0); } #undef __FUNCTI0N__ #define __FUNCTI0N__ "TestJudyNext" Word_t TestJudyNext(void *J1, void *JL, Word_t LowIndex, Word_t Elements) { TIMER_vars(tm1); // declare timer variables Word_t elm; double DDel; Word_t icnt; Word_t lp; Word_t Loops; Word_t Jindex; Loops = (MAXLOOPS / Elements) + MINLOOPS; if (J1Flag) { for (DDel = 1e40, icnt = ICNT, lp = 0; lp < Loops; lp++) { int Rc; Jindex = LowIndex; STARTTm(tm1); J1F(Rc, J1, Jindex); for (elm = 0; elm < Elements; elm++) { if (Rc != 1) FAILURE("Judy1Next Rc != 1 =", (Word_t)Rc); J1N(Rc, J1, Jindex); // Get next one } ENDTm(DeltaUSec1, tm1); if (DDel > DeltaUSec1) { icnt = ICNT; DDel = DeltaUSec1; } else { if (--icnt == 0) break; } } DeltaUSec1 = DDel / (double)Elements; } if (JLFlag) { for (DDel = 1e40, icnt = ICNT, lp = 0; lp < Loops; lp++) { Word_t *PValue; // Get an Index low enough for Elements Jindex = LowIndex; STARTTm(tm1); JLF(PValue, JL, Jindex); for (elm = 0; elm < Elements; elm++) { if (PValue == NULL) FAILURE("JudyLNext ret NULL PValue at", elm); JLN(PValue, JL, Jindex); // Get next one } ENDTm(DeltaUSecL, tm1); if (DDel > DeltaUSecL) { icnt = ICNT; DDel = DeltaUSecL; } else { if (--icnt == 0) break; } } DeltaUSecL = DDel / (double)Elements; } // perhaps a check should be done here -- if I knew what to expect. return (Jindex); // return last one } #undef __FUNCTI0N__ #define __FUNCTI0N__ "TestJudyPrev" int TestJudyPrev(void *J1, void *JL, Word_t HighIndex, Word_t Elements) { TIMER_vars(tm1); // declare timer variables Word_t elm; double DDel; Word_t icnt; Word_t lp; Word_t Loops; Loops = (MAXLOOPS / Elements) + MINLOOPS; if (J1Flag) { for (DDel = 1e40, icnt = ICNT, lp = 0; lp < Loops; lp++) { Word_t J1index = HighIndex; int Rc; STARTTm(tm1); J1L(Rc, J1, J1index); for (elm = 0; elm < Elements; elm++) { if (Rc != 1) FAILURE("Judy1Prev Rc != 1 =", (Word_t)Rc); J1P(Rc, J1, J1index); // Get previous one } ENDTm(DeltaUSec1, tm1); if (DDel > DeltaUSec1) { icnt = ICNT; DDel = DeltaUSec1; } else { if (--icnt == 0) break; } } DeltaUSec1 = DDel / (double)Elements; } if (JLFlag) { for (DDel = 1e40, icnt = ICNT, lp = 0; lp < Loops; lp++) { Word_t *PValue; Word_t JLindex = HighIndex; STARTTm(tm1); JLL(PValue, JL, JLindex); for (elm = 0; elm < Elements; elm++) { if (PValue == NULL) FAILURE("JudyLPrev ret NULL PValue at", elm); JLP(PValue, JL, JLindex); // Get previous one } ENDTm(DeltaUSecL, tm1); if (DDel > DeltaUSecL) { icnt = ICNT; DDel = DeltaUSecL; } else { if (--icnt == 0) break; } } DeltaUSecL = DDel / (double)Elements; } // perhaps a check should be done here -- if I knew what to expect. return (0); } #undef __FUNCTI0N__ #define __FUNCTI0N__ "TestJudyNextEmpty" // Returns number of consecutive Indexes Word_t TestJudyNextEmpty(void *J1, void *JL, Word_t LowIndex, Word_t Elements) { TIMER_vars(tm1); // declare timer variables Word_t elm; double DDel; Word_t icnt; Word_t lp; Word_t Loops; int Rc; // Return code Loops = (MAXLOOPS / Elements) + MINLOOPS; if (J1Flag) { for (DDel = 1e40, icnt = ICNT, lp = 0; lp < Loops; lp++) { Word_t Seed1 = LowIndex; STARTTm(tm1); for (elm = 0; elm < Elements; elm++) { Word_t J1index; J1index = Seed1; // Find next Empty Index, J1index is modified by J1NE J1NE(Rc, J1, J1index); // Rc = Judy1NextEmpty(J1, &J1index,PJE0) if (Rc != 1) FAILURE("Judy1NextEmpty Rcode != 1 =", (Word_t)Rc); Seed1 = GetNextIndex(Seed1); } ENDTm(DeltaUSec1, tm1); if (DDel > DeltaUSec1) { icnt = ICNT; DDel = DeltaUSec1; } else { if (--icnt == 0) break; } } DeltaUSec1 = DDel / (double)Elements; } if (JLFlag) { for (DDel = 1e40, icnt = ICNT, lp = 0; lp < Loops; lp++) { Word_t Seed1 = LowIndex; STARTTm(tm1); for (elm = 0; elm < Elements; elm++) { Word_t JLindex; JLindex = Seed1; // Find next Empty Index, JLindex is modified by JLNE JLNE(Rc, JL, JLindex); // Rc = JudyLNextEmpty(JL, &JLindex,PJE0) if (Rc != 1) FAILURE("JudyLNextEmpty Rcode != 1 =", (Word_t)Rc); Seed1 = GetNextIndex(Seed1); } ENDTm(DeltaUSecL, tm1); if (DDel > DeltaUSecL) { icnt = ICNT; DDel = DeltaUSecL; } else { if (--icnt == 0) break; } } DeltaUSecL = DDel / (double)Elements; } return (0); } // Routine to time and test JudyPrevEmpty routines #undef __FUNCTI0N__ #define __FUNCTI0N__ "TestJudyPrevEmpty" Word_t TestJudyPrevEmpty(void *J1, void *JL, Word_t HighIndex, Word_t Elements) { TIMER_vars(tm1); // declare timer variables Word_t elm; double DDel; Word_t icnt; Word_t lp; Word_t Loops; int Rc; Loops = (MAXLOOPS / Elements) + MINLOOPS; if (J1Flag) { for (DDel = 1e40, icnt = ICNT, lp = 0; lp < Loops; lp++) { Word_t Seed1 = HighIndex; STARTTm(tm1); for (elm = 0; elm < Elements; elm++) { Word_t J1index; J1index = Seed1; J1PE(Rc, J1, J1index); // Rc = Judy1PrevEmpty(J1, &J1index,PJE0) if (Rc != 1) FAILURE("Judy1PrevEmpty Rc != 1 =", (Word_t)Rc); Seed1 = GetNextIndex(Seed1); } ENDTm(DeltaUSec1, tm1); if (DDel > DeltaUSec1) { icnt = ICNT; DDel = DeltaUSec1; } else { if (--icnt == 0) break; } } DeltaUSec1 = DDel / (double)Elements; } if (JLFlag) { for (DDel = 1e40, icnt = ICNT, lp = 0; lp < Loops; lp++) { Word_t Seed1 = HighIndex; STARTTm(tm1); for (elm = 0; elm < Elements; elm++) { Word_t JLindex; JLindex = Seed1; // Find next Empty Index, JLindex is modified by JLPE JLPE(Rc, JL, JLindex); // Rc = JudyLPrevEmpty(JL, &JLindex,PJE0) if (Rc != 1) FAILURE("JudyLPrevEmpty Rcode != 1 =", (Word_t)Rc); Seed1 = GetNextIndex(Seed1); } ENDTm(DeltaUSecL, tm1); if (DDel > DeltaUSecL) { icnt = ICNT; DDel = DeltaUSecL; } else { if (--icnt == 0) break; } } DeltaUSecL = DDel / (double)Elements; } return (0); } #undef __FUNCTI0N__ #define __FUNCTI0N__ "TestJudyDel" int TestJudyDel(void **J1, void **JL, Word_t Seed, Word_t Elements) { TIMER_vars(tm1); // declare timer variables Word_t TstIndex; Word_t elm; Word_t Seed1; int Rc; if (J1Flag) { STARTTm(tm1); for (Seed1 = Seed, elm = 0; elm < Elements; elm++) { Seed1 = GetNextIndex(Seed1); if (DFlag) TstIndex = Swizzle(Seed1); else TstIndex = Seed1; J1U(Rc, *J1, TstIndex); if (Rc != 1) FAILURE("Judy1Unset ret Rcode != 1", (Word_t)Rc); } ENDTm(DeltaUSec1, tm1); DeltaUSec1 /= Elements; } STARTTm(tm1); if (JLFlag) { for (Seed1 = Seed, elm = 0; elm < Elements; elm++) { Seed1 = GetNextIndex(Seed1); if (DFlag) TstIndex = Swizzle(Seed1); else TstIndex = Seed1; JLD(Rc, *JL, TstIndex); if (Rc != 1) FAILURE("JudyLDel ret Rcode != 1", (Word_t)Rc); } ENDTm(DeltaUSecL, tm1); DeltaUSecL /= Elements; } return (0); } // Routine to get next size of Indexes int // return 1 if last number NextNumb(Word_t *PNumber, // pointer to returned next number double *PDNumb, // Temp double of above double DMult, // Multiplier Word_t MaxNumb) // Max number to return { // Save prev number double PrevPDNumb = *PDNumb; double DDiff; // Calc next number >= 1.0 beyond previous do { *PDNumb *= DMult; DDiff = *PDNumb - PrevPDNumb; } while (DDiff < 0.5); // Return it in integer format if (DDiff < 100.0) *PNumber += (Word_t)(DDiff + 0.5); else *PNumber = *PDNumb + 0.5; // Verify it did not exceed max number if (*PNumber >= MaxNumb) { // it did, so return max *PNumber = MaxNumb; return (1); // flag it } return (0); // more available } judy-1.0.5/test/Makefile.am0000644000175000017500000000031710624600161015724 0ustar troyhebetroyhebeEXTRA_DIST = $(TESTS) TEST_ENVIRONMENT = top_builddir=$(top_builddir) TESTS = Checkit DISTCLEANFILES = .deps Makefile CLEANFILES = Judy1LHCheck Judy1LHTime Makefile SL_Hash SL_Judy SL_Redblack SL_Splay judy-1.0.5/test/simple.c0000644000175000017500000000057610204462077015342 0ustar troyhebetroyhebe#include int main() { int Rc_int; int i; // Judy array to hold cached addresses Pvoid_t addrArray = (Pvoid_t) NULL; for(i = 0; i < 100000; i++) J1S(Rc_int, addrArray, (Word_t) i); for(i = 0; i < 100000; i++){ J1T(Rc_int, addrArray, (Word_t) i); if(!Rc_int){ printf("Something bad happened\n"); return -1; } } return 0; } judy-1.0.5/test/Checkit0000755000175000017500000000650010622113030015160 0ustar troyhebetroyhebe#!/bin/sh CC=${CC:-cc} echo echo "=== +++++++++ This test runs in 15 seconds on a PIII 750Mhz +++++++" LIBJUDY=`find ../ -name libJudy.a` JUDY_H=`find ../ -name Judy.h` echo "$CC -O SLcompare.c -DHASHMETHOD -o SL_Hash" $CC -O SLcompare.c -DHASHMETHOD -o SL_Hash echo "$CC -O SLcompare.c -DSPLAYMETHOD -o SL_Splay" $CC -O SLcompare.c -DSPLAYMETHOD -o SL_Splay echo "$CC -O SLcompare.c -DREDBLACKMETHOD -o SL_Redblack" $CC -O SLcompare.c -DREDBLACKMETHOD -o SL_Redblack echo echo Compiling with Judy library: $LIBJUDY echo echo "$CC -O -I../src SLcompare.c -DJUDYMETHOD -o SL_Judy $LIBJUDY -lm" $CC -O -I../src SLcompare.c -DJUDYMETHOD -o SL_Judy $LIBJUDY -lm RET=$? if [ $RET -ne 0 ] ; then echo "=== $? Failed: $CC SLcompare.c -DJUDYMETHOD" echo "=== $? Failed: $CC -O -I../src SLcompare.c -DJUDYMETHOD -o SL_Judy $LIBJUDY -lm" exit $? fi echo "$CC -O -I../src Judy1LHCheck.c -o Judy1LHCheck $LIBJUDY -lm" $CC -O -I../src Judy1LHCheck.c -o Judy1LHCheck $LIBJUDY -lm RET=$? if [ $RET -ne 0 ] ; then echo "=== $? Failed: $CC Judy1LHCheck.c" exit $? fi echo "$CC -O -I../src Judy1LHTime.c -DNOINLINE -o Judy1LHTime $LIBJUDY -lm" $CC -O -I../src Judy1LHTime.c -DNOINLINE -o Judy1LHTime $LIBJUDY -lm RET=$? if [ $RET -ne 0 ] ; then echo "=== $? Failed: $CC Judy1LHTime.c" exit $? fi # -OR- if Judy is installed, these can be compiled from anywhere: #cc -O SLcompare.c -DJUDYMETHOD -o SL_Judy -lJudy -lm #cc -O Judy1LHCheck.c -o Judy1LHCheck -lJudy -lm #cc -O Judy1LHTime.c -o Judy1LHTime -lJudy -lm echo "=== Pass: Compile of tests" echo echo " Validate Judy1/JudyL/JudyHS functions (except Judy*ByCount)" ./Judy1LHCheck -n 300000 -B20 > /dev/null RET=$? if [ $RET -ne 0 ] ; then echo "=== $? Failed: Judy1/JudyL/JudyHS validate program" exit $? fi echo "=== Pass: Judy1/JudyL/JudyHS validate program" echo echo " Do a few timings tests of Judy1/JudyL/JudyHS" echo # Pop1 is: current number of Indexes stored in Judy array # Measmts is: lookups to make measurement # J1 is: Judy1 # JL is: JudyL # /I is: per Index # MU is: Memory Used (allocated thru malloc(3)) # HEAP is: Memory change measured with sbrk(0) echo " Pop1 Measmts J1S JLI J1T JLG J1MU/I JLMU/I HEAP/I" ./Judy1LHTime -n 2000000 -P1 -B19 | grep -v "^#" echo "=== Pass: Judy1/JudyL/JudyHS performance program" echo echo " Do a few timings tests of JudySL and friends" echo # lines is: number of lines in source file # avg_linelen is: average bytes per line # getline is: average time go get a line and remove white space # StoreD is: number of unique lines stored into JudySL array # RAMused/line is: Memory change measured with sbrk(0) # store/ln is: average insert time (including duplicates) # lookup/ln is: average lookup time in same order as inserts # ADT is: Abstract Data Type method echo " lines avg_linelen getline StoreD RAMused/line store/ln lookup/ln ADT" ./SL_Hash StringCompare.c | grep HASH ./SL_Splay StringCompare.c | grep SPLAY ./SL_Redblack StringCompare.c | grep REDBLACK ./SL_Judy StringCompare.c | grep JUDY RET=$? if [ $RET -ne 0 ] ; then echo "=== $? Failed: JudySL if StoreD numbers are all the same" exit $? fi echo "=== Pass: JudySL if StoreD numbers are all the same" echo judy-1.0.5/test/timeit.c0000644000175000017500000001763110204462077015344 0ustar troyhebetroyhebe// @(#) $Revision: 4.12 $ $Source: /judy/judy/src/apps/benchmark/timeit.c,v $ // // Timer functions. // // YOU MUST COMPILE THIS WITH ONE OF THESE DEFINED: // // JU_HPUX_PA // JU_HPUX_IPF // JU_LINUX_IA32 // JU_LINUX_IPF // JU_WIN_IA32 // // If NONE of these are defined, this whole code section is ifdef'd out to // avoid compile/link errors due to usage here of objects not defined in // timeit.h. See end of file. // // TBD: Improve on this; possibly it's OK now not to ifdef this out, and get // default, low-res timing behavior; see timeit.h. // // Compile with -D_TIMEIT_TEST to include a main program for testing; see // main() below. #if (JU_HPUX_PA || JU_LINUX_IA32 || JU_LINUX_IPF) #define _TIMEIT_HIGHRES #endif #ifdef _TIMEIT_HIGHRES #include // Win32 uses a whole different paradigm. #include // for getopt(), which Win32 lacks. #include #include "timeit.h" double USecPerClock; // usec per control register count. // **************************************************************************** // F I N D C P U S P E E D // // Return microseconds per control/timer register count. Examples: // // 0.002 for 500 MHz processor // 0.001 for 1 GHz processor double find_CPU_speed(void) { double DeltaUSec; // Timing result in uSec. TIMER_vars(tm); // creates __TVBeg_tm, ... // (used for consistency with __START_HRTm) gettimeofday(&__TVBeg_tm, NULL); // get low-res time. __START_HRTm(tm); // get __start_tm (high-res). sleep(1); // time passes; 1 sec suffices. __END_HRTm(tm); // get __stop_tm (high-res). gettimeofday(&__TVEnd_tm, NULL); // get low-res time. // gettimeofday() returns usec; compute elapsed time: DeltaUSec = (((double) __TVEnd_tm.tv_sec * ((double) 1E6)) + (double) __TVEnd_tm.tv_usec) - (((double) __TVBeg_tm.tv_sec * ((double) 1E6)) + (double) __TVBeg_tm.tv_usec); // Control register returns ticks, and the ratio can now be computed: return (DeltaUSec / ((double) (__stop_tm - __start_tm))); } // find_CPU_speed() #else // _TIMEIT_HIGHRES void dummy() {} // avoid "empty source file" warnings when no _TIMEIT_TEST. #endif // **************************************************************************** // // Ifdef the test main() separately, including #includes, for platforms that do // not define find_CPU_speed() above. #ifdef _TIMEIT_TEST #include // Win32 uses a whole different paradigm. #include // for getopt(), which Win32 lacks. #include #include #include #include //#include // for MAXDOUBLE #define MAXDOUBLE (10e99) #include "timeit.h" // **************************************************************************** // M A I N // // Example code for timeit: // // To compile and test this program on HP-UX, run the next lines as commands. // // cc -Wl,-a,archive -DJU_HPUX_PA -D__HPUX__ -D_TIMEIT_TEST -o timeit timeit.c // timeit # run test program. // rm -f timeit # clean up after test. int main(int argc, char **argv) { int i = 0; // loop index. long i_max = 10; // number of loops. int preload = 1; // loops to throw away (preload cache). double ztime; // timer overhead. double usec[4]; // for early timing tests. double DeltaUSec; // timing result in usec. double prevtime; // from previous loop. double mintime; // minimum event time. struct timeval tmjunk; // for throw-away syscall. TIMER_vars(tm1); // overall timer variables. TIMER_vars(tm2); // misc + loop timer variables. // INITIALIZE: STARTTm(tm1); // whole program timer. i_max += preload; // The first arg is the number of iterations (default is i_max): if (argc > 1) { i = atoi(argv[1]) + preload; if (i > 0) i_max = (long)i; } // Calculate timer overhead (ztime): #ifdef _TIMEIT_HIGHRES (void) puts("Possible slight delay here due to find_CPU_speed()..."); #else (void) puts("No high-res clock or find_CPU_speed() for this platform."); #endif ztime = 0.0; for (i = 0; i < 100; ++i) // average many runs. { STARTTm(tm2); ENDTm(DeltaUSec, tm2); ztime += DeltaUSec; } ztime = ztime / ((double) i); // SIMPLE TESTS OF TIMER OVERHEAD: // // Make two passes at both the high-res (if any) and slower timers. (void) puts("\nTiming timers themselves: start, end, end"); #define PRINTPASS(Desc,Pass) \ (void) printf("%-8s pass %d: %f - %f = %f usec\n", Desc, Pass, \ usec[((Pass) * 2) - 1], usec[((Pass) * 2) - 2], \ usec[((Pass) * 2) - 1] - usec[((Pass) * 2) - 2]) #ifdef _TIMEIT_HIGHRES START_HRTm(tm2); END_HRTm(usec[0], tm2); // throw away in case of sleep(1) here. START_HRTm(tm2); END_HRTm(usec[0], tm2); END_HRTm(usec[1], tm2); START_HRTm(tm2); END_HRTm(usec[2], tm2); END_HRTm(usec[3], tm2); PRINTPASS("High-res", 1); PRINTPASS("High-res", 2); #endif STARTTm(tm2); ENDTm(usec[0], tm2); // throw away in case of sleep(1) here. STARTTm(tm2); ENDTm(usec[0], tm2); ENDTm(usec[1], tm2); STARTTm(tm2); ENDTm(usec[2], tm2); ENDTm(usec[3], tm2); PRINTPASS("Non-HR", 1); PRINTPASS("Non-HR", 2); // PRINT INITIAL INFO: #ifdef _TIMEIT_HIGHRES // Print the CPU speed: // // Note: USecPerClock is a global set by the first instance of STARTTm. You // can also get this number by calling find_CPU_speed(). (void) printf("\nClock step = %.3f nsec => %.1f MHz.\n", USecPerClock * 1000.0, 1.0 / USecPerClock); #endif // Print timer overhead even though it's been subtracted from the reported // results. (void) printf("Timer overhead subtracted from the times below = %f " "usec.\n", ztime); // DO A FAST TIMER CHECK: (void) puts("\nCheck timer precision by repeating the same action:"); (void) puts("Times in each group should be close together."); (void) puts("\nTiming something very fast: \"++i\":"); mintime = MAXDOUBLE; for (i = 1; i <= i_max; ++i) { prevtime = DeltaUSec; STARTTm(tm2); // start the timer. ++i; // statement to time. ENDTm(DeltaUSec, tm2); // stop the timer. DeltaUSec -= ztime; // remove timer overhead. // Throw away the first loop iteration to warm up the cache: if (--i > preload) { if (mintime == MAXDOUBLE) mintime = DeltaUSec; (void) printf("%3d. %8.3f nanosec,\tmintime diff %8.1f %%\n", i - preload, DeltaUSec * 1000.0, ((DeltaUSec - mintime) * 100) / mintime); if (DeltaUSec < mintime) mintime = DeltaUSec; } } // TIME A FUNCTION CALL: (void) puts("\nTiming a function: \"gettimeofday()\":"); mintime = MAXDOUBLE; for (i = 1; i <= i_max; ++i) { prevtime = DeltaUSec; STARTTm(tm2); // start the timer. gettimeofday(&tmjunk, NULL); // burn some cycles. ENDTm(DeltaUSec, tm2); // stop the timer. DeltaUSec -= ztime; // remove timer overhead. // Throw away the first loop iteration to warm up the cache: if (i > preload) { if (mintime == MAXDOUBLE) mintime = DeltaUSec; (void) printf("%3d. %8.3f usec,\tmintime diff %8.1f %%\n", i - preload, DeltaUSec, ((DeltaUSec - mintime) * 100) / mintime); if (DeltaUSec < mintime) mintime = DeltaUSec; } } // TIME SOMETHING SLOW: (void) puts("\nTiming something slow: \"sleep(1)\":"); mintime = MAXDOUBLE; for (i = 1; i <= i_max; ++i) { prevtime = DeltaUSec; STARTTm(tm2); // start the timer. sleep(1); ENDTm(DeltaUSec, tm2); // stop the timer. DeltaUSec -= ztime; // remove timer overhead. // Throw away the first loop iteration to warm up the cache: if (i > preload) { if (mintime == MAXDOUBLE) mintime = DeltaUSec; (void) printf("%3d. %8.3f sec,\tmintime diff %8.1f %%\n", i - preload, DeltaUSec/1E6, ((DeltaUSec - mintime) * 100) / mintime); if (DeltaUSec < mintime) mintime = DeltaUSec; } } // FINISH UP: // // Print program execution time: ENDTm(DeltaUSec, tm1); (void) printf("\nProgram execution time: %.3f sec\n", DeltaUSec / 1E6); return(0); } // main() #endif // #ifdef _TIMEIT_TEST judy-1.0.5/test/testjbgraph0000755000175000017500000000172610204462077016146 0ustar troyhebetroyhebe# run timing program to measure Judy1, JudyL and JudyHS performance # use jbgraph script to format output suitable for 'gnuplot' echo echo "This script takes 1 Minute to plot output on a 3.2Ghz Pentium P4C" # On Linux, higher resolution of times with -DCPUMHZ=3200 on 3.2Ghz # cc -O2 -DCPUMHZ=3200 Judy1LHTime.c -lJudy -lm -o Judy1LHTime # up to 1000000 population of random numbers with Judy1, JudyL, JudyHS ./Judy1LHTime -n 1000000 -1 -L -H > Judy1LHTime.plot # Plot the results: y-axis == uSec per Index, x-axis == number of Indexes # -NL == Plot No Log axis # -Lx == Plot Log in x axis # -y:1 == default min scale, 1 microsecond max scale # -x100: == 100 min scale, default max scale # -c6 -c7 -c8 == plot column 6,7,8 (J1T, JLG, JHSG) # Judy1LHTime.plot == file to plot ./jbgraph -NL -Lx -y:1 -x100: -c6 -c7 -c8 Judy1LHTime.plot # Performance of other ADT's can be explored with StringCompare.c, # but you should have a very large (>100MB) text file to input. judy-1.0.5/test/jbgraph0000755000175000017500000010032710204462077015243 0ustar troyhebetroyhebe#!/bin/sh # THIS SCRIPT IS A "WRAPPER" FOR: gnuplot # # - The data used is in "gnuplot" format to compare and contrast # - information for analysis in the Judy project. Circa: 05/12/2000. # Author: Bob Gobeille, # Original functionality. # Jer/ Eberhard, # Ongoing maintenance, added functionality. RCS_SCRIPT=' # @(#) $Revision: 2.24 $ $Source: /judy/src/apps/benchmark/jbgraph $ ' # SET VERBOSE TO QUIET, SILENT (DEFAULT): # # - then find out if verbose mode is to be set. OPT_v="${OPT_v:--q}" # Set verbose off, (default). v='eval #' # Set verbose off, (quiet). VERBOSE="`echo ${*} | tr ' ' '\012' | grep -- -v`" if [ "${VERBOSE}" = "-v" ]; then # -v verbose mode on. OPT_v="${VERBOSE}" # Will be "-v". v="" # Set verbose on. fi unset VERBOSE # Unset after last use. # CREATE NAMESPACE: # # - Set names of OUTPUT and WORK directories and files. C="`basename ${0:-jbgraph}`" # Command name of this script. C_PATH="${0}" # Called via this path. C_rc=".${C}.rc" # .rc file, local or ${HOME}. OUTPUT_DIR=./tmp/`echo ${C} | tr "[a-z]" "[A-Z]"` # output name in caps mkdir -p ${OUTPUT_DIR} # Create output directory. if [ ! -d "${OUTPUT_DIR}" ]; then # Ensure dir exists. echo "${C}.${0}: ERROR, unable to: mkdir -p ${OUTPUT_DIR}" exit 3 fi # UNCOMMENT THE DATE_TIME FORMAT YOU WANT TO USE: #DATE_TIME="`date +%y%m`" # Monthly Date/Time stamp. #DATE_TIME="`date +%y%m%d`" # Daily Date/Time stamp. DATE_TIME="`date +%y%m%d.%H%M`" # HourMinute Date/Time stamp. COMMAND="${OUTPUT_DIR}/${DATE_TIME}" # Output filename date/time stamp. WORK1="${COMMAND}.WORK1.$$" # Work file 1. WORK2="${COMMAND}.WORK2.$$" # Work file 2. WORK3="${COMMAND}.WORK3.$$" # Work file 3. WORK4="${COMMAND}.WORK4.$$" # Work file 4. # CREATE AND DISPLAY SCRIPT DEFAULTS AND INFO: export GNU_CMDFILE="${GNU_CMDFILE:-$COMMAND.GNU_CMDFILE}" # GNU_CMDFILE name ${v}touch ${COMMAND} # Ensure the output file exists. # Produce sample monitor and print commands. INFO="`echo \"${C}: follow output, or print by: rerun by executing the first commented line in: ${GNU_CMDFILE} head -1 ${GNU_CMDFILE} # or tail -f ${COMMAND} # tail and follow log file or tail ${COMMAND} # tail log file or print: fold -80 ${COMMAND} | pr -f -l66 -h${COMMAND} | remsh jerslash -l jer lp -odouble -o2\"`" if [ "${OPT_v}" = "-v" ]; then # -v verbose mode. echo "${INFO}" fi # DEFINE DEFAULTS, CONSTANTS, VARIABLES: # # - 80 Column line---------------------------------------------------01234567890 # Break line: BL is 70 columns of "-". BL="----------------------------------------------------------------------" EXT_OPT="${EXT_OPT:-}" # Allow external option setting. # GNU_GEOMETRY default: # - Note, this will respect an environment variable, which could be set as: # - export OPT_JBGRAPH_geometry="600x450+20+20" # 4x3 aspect ratio. OPT_JBGRAPH_geometry="${OPT_JBGRAPH_geometry:-1000x750+20+20}" GNU_GEOMETRY_DEF="1000x750+20+20" # 4x3 aspect ratio, default. GNU_GEOMETRY="-geometry ${OPT_JBGRAPH_geometry:-$GNU_GEOMETRY_DEF}" # GNU_PSFILE name, (default): GNU_PSFILE="${OPT_JBGRAPH_psfile:-$COMMAND.GNU_PSFILE}" LP_DEV_DEF="${LP_DEV:-pastel}" # Printer device (default). LP_OPT_DEF="${LP_OPT:--olandscape}" # Printer options (default). # PLOT AXIS NAMES: XLABEL="${XLABEL:-Population}" # Set default. YLABEL_MALLOC="${YLABEL:-Bytes}" # Set default. YLABEL_TIME="${YLABEL:-USec/index}" # Set default. YLABEL="${YLABEL:-$YLABEL_TIME}" # Set default. # ARRAY OF COLUMN NAMES: # # - Add column names here (from benchutils.c). # - These are the column names displayed on "gnuplot". CHA[0]="CHA=COLUMN HEADINGS ARRAY" CHA[1]="index number" CHA[2]="insert time per index" CHA[3]="dT/dI insert" CHA[4]="retrieve time per index" CHA[5]="dT/dI retrieve" CHA[6]="bytes used" CHA[8]="bytes free" CHA[9]="bytes alloced" CHA[7]="dM/dI change in memory per index" CHA[10]="leaf count" CHA[11]="leaf average size" CHA[12]="leaf memory used per index" CHA[13]="branch count" CHA[14]="branch average size" CHA[15]="branch memory used per index" CHA[16]="" CHA[17]="" CHA[18]="" CHA[19]="" CHA[21]="" CHA[22]="" CHA[23]="" CHA[24]="" CHA[25]="" CHA[26]="" CHA[27]="" CHA[28]="" CHA[29]="" CHA[30]="" CHA[31]="" CHA[32]="" CHA[33]="" CHA[34]="" CHA[35]="" CHA[36]="" CHA[37]="" CHA[38]="" CHA[39]="" CHA[40]="" CHA[41]="" CHA[42]="" CHA[43]="" CHA[44]="" CHA[45]="" CHA[46]="" CHA[47]="" CHA[48]="" CHA[49]="" CHA[50]="" CMN="0" # Column number for CHA data. # # SET DEFAULT OPTIONS: # OPT_E="-E" # -E use embedded options OPT_L="-L" # -L set logscale axis OPT_L_xaxis="x" # -L set logscale x axis OPT_L_yaxis="y" # -L set logscale y axis OPT_H="-H" # -H default column headings. # M A I N: MAIN PROGRAM: # # - Begin main script, functions first. { FUNCTION__getopt() # Use function getopt. { # PARSE THE COMMAND LINE FOR OPTIONS, USING GETOPT: # # - define USAGE message. # - use getopts. # Note: FUNCTION__getopt is run twice, in order to support: # FUNCTION_TITLE_COLHEAD() # Set Column headings from file. ${v}echo "${C}.${0}: beginning at `date`" # beginning of function USAGE="${C} [ -E -G -H -I -M -S -V -i -l -m -q -r -u -v ] [ -C GNU_CMDFILE ] [ -D LP_DEV ] [ -L axis ] [ -N not option ] (turn off option), Example: -NL [ -P GNU_PSFILE ] [ -c COLUMN_NUMBER ] [ -d differential_type ] [ -g GNU_GEOMETRY ] [ -o LP_OPT ] [ -x xRANGE ] [ -y yRANGE ] ${C}: wrapper for gnuplot -c plot column number. This is useful to plot by column number. -i plot insert; default if no other plots selected. CMN=2 -r plot retrievals; default if no other plots selected. CMN=4 -I plot memory used / index. CMN=12 -m plot memory malloced. CMN=9 -M plot memory used and free. CMN=8 -l plot leaf data. CMN=11 -d plot derivative data. Useful with -i, -r, -m. CMN=2,4,9 -x xRANGE, scale range; example: -x [1000:5000] or -x1000:5000 -y yRANGE, scale range; example: -y [1M:10M] or -y1M:10M 1[kK] = 1,000; 1[mM] = 1,000,000; 1[gG] = 1,000,000,000. -n number plot descriptions; Use column numbers before the description. -L set logscale axis; default, Example: Turn off logscale with -NL, then turn on, on only one axis: \"-NL -Lx\" or \"-NL -Ly\", Turn off both with -NL -G grid lines on. -H default column headings. -g geometry description. default=\"${GNU_GEOMETRY_DEF}\", # 4x3 aspect ratio. -E use embedded options, default, Turn off with -NE. Sets TITLE, COLHEAD, GETOPT from the FIRST data file encountered. Example: embedded options in the data file begin in column 1: # TITLE This is the title to pass to gnuplot # COLHEAD 1 This is the heading for column 1. # XLABEL This is the x-axis label # YLABEL This is the y-axis label # GETOPT -c2 -c3 -G # These are the options to use. -p print the plot. -o LP_OPT printer option(s); default \"${LP_OPT_DEF}\". Example: \"-ootray2\" will print on clear slides, emits \"-otray2\" Example: \"-on2\" will print two copies, emits \"-n2\" -D LP_DEV printer device; default \"${LP_DEV_DEF}\". -C GNU_CMDFILE name; default is generated and removed: ${OUTPUT_DIR}/{DATE_TIME}.GNU_CMDFILE Useful to do your own gnuplot command editing and debugging. -P GNU_PSFILE name. default is generated and removed: ${OUTPUT_DIR}/{DATE_TIME}.GNU_PSFILE -S Save files. Generated and working file names are deleted unless -S or -C is on. User provided file names are not deleted in any case (-C, -P). -q quiet mode, verbose mode off; default. -v verbose mode on. -V vi the plot file. quit using \"q\" -N not option; Turn specified option off. Example: -NL Note, -N is not available for all options. -NL Turn off: -L set logscale axis; default -NH Turn off: -H default column headings. -u Usage message. Sample usage: ${C} -i -f data/datafile # -i is the same as -c1. ${C} -c1 -f data/datafile # -i is the same as -c1. " ${v}echo "${C}.${0}: OPTIONS=${*}" # Parse options, using getopt: # # - "a" option, no parameter; "b:" indicates a parameter. # - Order of options is "man 5 ascii". getopt_PARM="?C:D:EGIL:MN:P:SVc:d:g:ilmno:prsuvx:y:" set -- `getopt ${getopt_PARM} $*` # Place options in argc/argv. if [ "${?}" != "0" ]; then # If getopt returns an errror. ${v}echo "${C}.${0}: \${?}=${?}, USAGE message from return code." echo "${USAGE}" exit 1 fi while [ ${#} -gt 0 ] # while there are options... do # ( for vi parenthesis matching ${v}echo "${C}.${0}: parsing option \"${1}\", then \"${2}\"" case ${1} in -C) OPT_C="${1}" OPT_C_PARM="${2}" # GNU_CMDFILE name. ${v}echo "${C}.${0}: OPT_C=${OPT_C}, # -C GNU_CMDFILE name." ${v}echo "${C}.${0}: OPT_C_PARM=${OPT_C_PARM}, # GNU_CMDFILE name." export GNU_CMDFILE="${OPT_C_PARM}" MSG="# GNU_CMDFILE name." ${v}echo "${C}.${0}: GNU_CMDFILE=${GNU_CMDFILE}, ${MSG}" shift ;; # ( for vi parenthesis matching -D) OPT_D="${1}" OPT_D_PARM="${2}" # LP_DEV name. ${v}echo "${C}.${0}: OPT_D=${OPT_D}, # -D LP_DEV printer device." #${v}echo "${C}.${0}: OPT_D_PARM=${OPT_D_PARM}, # LP_DEV name." LP_DEV="${OPT_D_PARM}" ${v}echo "${C}.${0}: LP_DEV=${LP_DEV}, # LP_DEV name." shift ;; # ( for vi parenthesis matching -E) OPT_E="${1}" ${v}echo "${C}.${0}: OPT_E=${OPT_E}, # -E use embedded options" ;; # ( for vi parenthesis matching -G) OPT_G="${1}" ${v}echo "${C}.${0}: OPT_G=${OPT_G}, # -G grid lines on." ;; # ( for vi parenthesis matching -H) OPT_H="${1}" ${v}echo "${C}.${0}: OPT_H=${OPT_H}, # -H default column headings." ;; # ( for vi parenthesis matching -I) OPT_I="${1}" ${v}echo "${C}.${0}: OPT_I=${OPT_I}, # -I Memory used / index." CMN="12" COL[$CMN]="${CMN}" ${v}echo "${C}.${0}: COL[$CMN]=${COL[$CMN]}" ;; # ( for vi parenthesis matching -L) OPT_L="${1}" ${v}echo "${C}.${0}: OPT_L=${OPT_L}, -L set logscale axis" OPT_L_PARM="${2}" # axis name, x or y if [ ${OPT_L_PARM} = "x" ]; then OPT_L_xaxis="${OPT_L_PARM}" elif [ ${OPT_L_PARM} = "y" ]; then OPT_L_yaxis="${OPT_L_PARM}" else MSG="must be either \"x\" or \"y\" axis. exit 5" echo "${C}.${0}: ERROR, OPT_L_PARM=${OPT_L_PARM} ${MSG}" exit 5 fi OPT_NL="" # -L turn off -NL. shift ;; # ( for vi parenthesis matching -M) OPT_M="${1}" ${v}echo "${C}.${0}: OPT_M=${OPT_M}, # -M Memory used and free." CMN="8" COL[$CMN]="${CMN}" ${v}echo "${C}.${0}: COL[$CMN]=${COL[$CMN]}" ;; # ( for vi parenthesis matching -N) OPT_N="${1}" OPT_N_PARM="${2}" # LP_DEV name. ${v}echo "${C}.${0}: OPT_N=${OPT_N}, # -N not option" ${v}echo "${C}.${0}: OPT_N_PARM=${OPT_N_PARM}, # Turn option off." if [ "${OPT_N_PARM}" = "E" ]; then OPT_E="" # -E use embedded options OPT_NE="-NE" # -NE turn off -E. elif [ "${OPT_N_PARM}" = "L" ]; then OPT_L="" # -L set logscale axis OPT_L_xaxis="" OPT_L_yaxis="" OPT_NL="-NL" # -NL turn off -L. elif [ "${OPT_N_PARM}" = "G" ]; then OPT_G="" # -G grid lines on. OPT_NG="-NG" # -NG turn off -G. elif [ "${OPT_N_PARM}" = "H" ]; then OPT_H="" # -H default column headings. OPT_NH="-NH" # -NH turn off -H. fi shift ;; # ( for vi parenthesis matching -P) OPT_P="${1}" OPT_P_PARM="${2}" # GNU_PSFILE name. ${v}echo "${C}.${0}: OPT_P=${OPT_P}, # -P GNU_PSFILE name." #${v}echo "${C}.${0}: OPT_P_PARM=${OPT_P_PARM}, # GNU_PSFILE name." GNU_PSFILE="${OPT_P_PARM}" ${v}echo "${C}.${0}: GNU_PSFILE=${GNU_PSFILE}, # GNU_PSFILE name." shift ;; # ( for vi parenthesis matching -S) OPT_S="${1}" ${v}echo "${C}.${0}: OPT_S=${OPT_S}, # -S save files." ;; # ( for vi parenthesis matching -V) OPT_V="${1}" ${v}echo "${C}.${0}: OPT_V=${OPT_V}, # -V vi the plot file." ;; # ( for vi parenthesis matching -c) OPT_c="${1}" OPT_c_PARM="${2}" # COLUMN_NUMBER. ${v}echo "${C}.${0}: OPT_c=${OPT_c}, # -c plot column number." ${v}echo "${C}.${0}: OPT_c_PARM=${OPT_c_PARM}, # COLUMN_NUMBER." if [ ${OPT_c_PARM} -ge ${#CHA[*]} ] || [ ${OPT_c_PARM} -le 0 ]; then MSG="must be greater than 0 and less than ${#CHA[*]}. exit 6" echo "${C}.${0}: ERROR, OPT_c_PARM=${OPT_c_PARM} ${MSG}" exit 6 fi CMN="${OPT_c_PARM}" COL[$CMN]="${CMN}" ${v}echo "${C}.${0}: COL[$CMN]=${COL[$CMN]}" shift ;; # ( for vi parenthesis matching -d) OPT_d="${1}" OPT_d_PARM="${2}" # DERIVATIVE_TYPE ${v}echo "${C}.${0}: OPT_d=${OPT_d}, # -d plot derivative type." ${v}echo "${C}.${0}: OPT_d_PARM=${OPT_d_PARM}, # DERIVITIVE_TYPE" if [ "${OPT_d_PARM}" = "i" ]; then OPT_di="${OPT_d_PARM}" CMN="3" elif [ "${OPT_d_PARM}" = "m" ]; then OPT_dm="${OPT_d_PARM}" CMN="7" elif [ "${OPT_d_PARM}" = "r" ]; then OPT_dr="${OPT_d_PARM}" CMN="5" else echo "${C}.${0}: ERROR, ${OPT_d_PARM} must be one of i, m, r." fi COL[$CMN]="${CMN}" ${v}echo "${C}.${0}: COL[$CMN]=${COL[$CMN]}" shift ;; # ( for vi parenthesis matching -g) OPT_g="${1}" OPT_g_PARM="${2}" # Option parameter ${v}echo "${C}.${0}: OPT_g=${OPT_g}, # -g geometry description." ${v}echo "${C}.${0}: OPT_g_PARM=${OPT_g_PARM}, # window geometry" GNU_GEOMETRY="-geometry ${OPT_g_PARM}" # Environment geometry. MSG="# window geometry" ${v}echo "${C}.${0}: GNU_GEOMETRY=${GNU_GEOMETRY}, ${MSG}" shift ;; # ( for vi parenthesis matching -i) OPT_i="${1}" ${v}echo "${C}.${0}: OPT_i=${OPT_i}, # -i plot insert." CMN="2" COL[$CMN]="${CMN}" ${v}echo "${C}.${0}: COL[$CMN]=${COL[$CMN]}" ;; # ( for vi parenthesis matching -l) OPT_l="${1}" ${v}echo "${C}.${0}: OPT_l=${OPT_l}, # -l plot leaf data." CMN="10" COL[$CMN]="${CMN}" ${v}echo "${C}.${0}: COL[$CMN]=${COL[$CMN]}" CMN="11" COL[$CMN]="${CMN}" ${v}echo "${C}.${0}: COL[$CMN]=${COL[$CMN]}" ;; # ( for vi parenthesis matching -m) OPT_m="${1}" ${v}echo "${C}.${0}: OPT_m=${OPT_m}, # -m plot memory malloced." CMN="9" COL[$CMN]="${CMN}" ${v}echo "${C}.${0}: COL[$CMN]=${COL[$CMN]}" ;; # ( for vi parenthesis matching -n) OPT_n="${1}" MSG="# -n number plot descriptions." ${v}echo "${C}.${0}: OPT_n=${OPT_n}, ${MSG}" ;; # ( for vi parenthesis matching -o) OPT_o="${1}" OPT_o_PARM="${2}" # Option parameter MSG="# -o LP_OPT printer option(s)." ${v}echo "${C}.${0}: OPT_o=${OPT_o}, ${MSG}" MSG="# -o LP_OPT printer option(s)." ${v}echo "${C}.${0}: OPT_o_PARM=${OPT_o_PARM}, ${MSG}" # Check for duplicates, only add to LP_OPT if not a duplicate. LP_SET="`echo ${LP_OPT} | adjust -m1 | grep -- -${OPT_o_PARM}`" if [ "${LP_SET}" != "-${OPT_o_PARM}" ]; then LP_OPT="${LP_OPT} -${OPT_o_PARM}" fi unset LP_SET ${v}echo "${C}.${0}: LP_OPT=${LP_OPT}, # LP_OPT printer option(s)." shift ;; # ( for vi parenthesis matching -p) OPT_p="${1}" ${v}echo "${C}.${0}: OPT_p=${OPT_p}, # -p print the plot." ;; # ( for vi parenthesis matching -q) OPT_v="${1}" v='eval #' # Set verbose off (quiet). ${v}echo "${C}.${0}: OPT_v=${OPT_v}, # -q quiet mode." ;; # ( for vi parenthesis matching -r) OPT_r="${1}" ${v}echo "${C}.${0}: OPT_r=${OPT_r}, # -r plot retrieve." CMN="4" COL[$CMN]="${CMN}" ${v}echo "${C}.${0}: COL[$CMN]=${COL[$CMN]}" ;; # ( for vi parenthesis matching -v) OPT_v="${1}" v="" # Set verbose on. ${v}echo "${C}.${0}: OPT_v=${OPT_v}, # -v verbose mode." ${v}echo ;; # ( for vi parenthesis matching -x) OPT_x="${1}" OPT_x_PARM="${2}" # Option parameter ${v}echo "${C}.${0}: OPT_x=${OPT_x}, # -x xRANGE, scale range." #${v}echo "${C}.${0}: OPT_x_PARM=${OPT_x_PARM}, # parameter desc." xRANGE="${OPT_x_PARM}" ${v}echo "${C}.${0}: xRANGE=${xRANGE}, # parameter desc." shift ;; # ( for vi parenthesis matching -y) OPT_y="${1}" OPT_y_PARM="${2}" # Option parameter ${v}echo "${C}.${0}: OPT_y=${OPT_y}, # -y yRANGE, scale range." #${v}echo "${C}.${0}: OPT_y_PARM=${OPT_y_PARM}, # parameter desc." yRANGE="${OPT_y_PARM}" ${v}echo "${C}.${0}: yRANGE=${yRANGE}, # parameter desc." shift ;; # ( for vi parenthesis matching -u) OPT_u="-u" ${v}echo "${C}.${0}: OPT_u=${OPT_u}, # -u Usage message." echo "${USAGE}" exit 4 ;; # ( for vi parenthesis matching -a) OPT_a="${1}" ${v}echo "${C}.${0}: OPT_a=${OPT_a}, # -a Option description." ;; # ( for vi parenthesis matching -b) OPT_b="${1}" OPT_b_PARM="${2}" # Option parameter ${v}echo "${C}.${0}: OPT_b=${OPT_b}, # -b Option description." ${v}echo "${C}.${0}: OPT_b_PARM=${OPT_b_PARM}, # parameter desc." shift ;; # ( for vi parenthesis matching --) shift # Remove the "--". break ;; # ( for vi parenthesis matching *) echo "${C}.${0}: Option not understood. \"${1}\"" echo "USAGE message follows: " echo "${USAGE}" # USAGE message exit 2 ;; esac shift done # The rest of the command line parameters are files: # If FILES is already set, leave it alone, else set it. # This is necessary due running getopt twice, to support parameters # embedded in the data files. if [ "${FILES}" = "" ]; then FILES="${FILES} ${*}" # May result in a blank, " ". if [ "${FILES}" = " " ]; then # If blank, " ", make it empty. FILES="" # Make FILES empty again. fi ${v}echo "${C}.${0}: FILES=${FILES}" fi # Set default options, if no applicable plot options were set. COL_CTR="${#COL[*]}" # Columns were turned on. ${v}echo "COL_CTR=${COL_CTR}, COL=${COL[*]}" if [ "${COL_CTR}" = "0" ]; then # Option not set ${v}echo "${C}.${0}: Setting default options." FUNCTION__getopt -c2 -c4 # Set default, if no options set. fi if [ "${OPT_C}" = "-C" ] || # If -C or -P, ensure -S. [ "${OPT_P}" = "-P" ]; then if [ "${OPT_S}" != "-S" ]; then FUNCTION__getopt -S # -S save files. fi fi # Save a shar copy of this script, if -S and -v are both on. # Turned off, may be useful later. # if [ ! -z "${OPT_S}" ] && # -S save files. # [ "${OPT_v}" = "-v" ]; then # -v verbose mode. # ${v}echo "${C}.${0}: start of shar of script" # shar -b ${C_PATH} >>${COMMAND}.shar # ${v}echo "${C}.${0}: end of shar of script\n" # fi ${v}echo "${C}.${0}: completed at `date`\n" # end of function } # FUNCTION__getopt() # Use function getopt. FUNCTION_gnuplot_init() # Initialize gnuplot command file. { # INITIALIZE GNU_CMDFILE # # - Pass options to gnuplot. # - Some options for gnuplot are set here (logscale, autoscale). ${v}echo "${C}.${0}: beginning at `date`" # beginning of function { echo "# ${C_PATH} ${*}" echo "# gnuplot ${GNU_GEOMETRY} ${GNU_CMDFILE}" if [ "${OPT_L}" = "-L" ]; then # -L set logscale axis echo "set logscale ${OPT_L_xaxis}${OPT_L_yaxis}" fi echo "set autoscale xy" echo "set data style lines" if [ ! -z "${OPT_G}" ]; then # Turn on grids. echo "set grid" fi # Naming convention... build some kind of TITLE name, if none given. TITLE="${TITLE:-JUDY BENCHMARK: $CMD_LINE }" # Set default. echo "set title \"${TITLE}\" 0,0 " if [ "${xRANGE}" != "" ]; then echo "set xrange `FUNCTION_units ${xRANGE}`" XLABEL="${XLABEL} ${xRANGE}" fi if [ "${yRANGE}" != "" ]; then echo "set yrange `FUNCTION_units ${yRANGE}`" YLABEL="${YLABEL} ${yRANGE}" fi echo "set xlabel \"${XLABEL}\" 0,0" echo "set ylabel \"${YLABEL}\" 0,0" echo "set label \"${XLOG}\" at 1,1" } >> ${GNU_CMDFILE} ${v}echo "${C}.${0}: completed at `date`\n" # end of function } # FUNCTION_gnuplot_init() # Initialize gnuplot command file. FUNCTION_gnuplot_plot() # Plot these files. { # FORMAT THE PLOT AND REPLOT COMMANDS # # - output to GNU_CMDFILE. ${v}echo "${C}.${0}: beginning at `date`" # beginning of function ${v}echo "${C}.${0}: FILES=${*}" Fgp_PARM="${*}" # Save what was passed in. Fgp_FILES="" # Initialize list of good files. for i in ${Fgp_PARM} do if [ -r "$i" ]; then # Check that files are readable. Fgp_FILES="${Fgp_FILES} ${i}" # Extend the list of good files. else echo "${C}.${0}: WARNING: file: ${i} cannot be read, ignored." fi done let j=1 while [ ${j} -lt ${#CHA[*]} ] # For each type of plot. do for i in ${Fgp_FILES} # For each file. do CMN="${COL[$j]}" if [ ! -z "${CMN}" ]; then { MSG="`basename ${i}`" if [ "${OPT_H}" = "-H" ]; then echo "${FIRST}plot \"${i}\" using 1:${CMN} t \"${CHA[${CMN}]} ${MSG}\"" elif [ "${OPT_NH}" = "-NH" ]; then echo "${FIRST}plot \"${i}\" using 1:${CMN} t \"${MSG}\"" fi } >> ${GNU_CMDFILE} FIRST="re" fi done let j=j+1 done # A bug in gnuplot sometimes prevents all replots from appearing. # This particularly happens when xrange is used. # Doing an extra replot will plot everything. echo replot >> ${GNU_CMDFILE} ${v}echo "${C}.${0}: completed at `date`\n" # end of function } # FUNCTION_gnuplot_plot() # Plot these files. FUNCTION_gnuplot_display() # Plots the datapoints. { # DISPLAY PLOT TO SCREEN: ${v}echo "${C}.${0}: beginning at `date`" # beginning of function if [ "${OPT_V}" = "-V" ]; then echo "hpterm -e vi -c \"vi ${GNU_CMDFILE} \"" hpterm -e vi -cvi ${GNU_CMDFILE} & fi if [ "${OPT_v}" = "-v" ]; then # -v verbose mode. echo "${C}.${0}: executing command: "; echo "\n\ gnuplot ${GNU_GEOMETRY} ${GNU_CMDFILE}" fi # Add additional parameters as necessary to setup for printing: if [ "${OPT_p}" = "-p" ]; then { echo set terminal postscript landscape color echo set output \"${GNU_PSFILE}\" echo replot } >> ${GNU_CMDFILE} fi LINE="" # External response while [ "${LINE}" != "q" ] do gnuplot ${GNU_GEOMETRY} ${GNU_CMDFILE} LINE="q" # Setup for quit. if [ "${OPT_V}" = "-V" ]; then echo "Pause: press return to vi again, \"q\" to quit ${C}" read -r LINE fi done ${v}echo "${C}.${0}: completed at `date`\n" # end of function } # FUNCTION_gnuplot_display() # Plots the datapoints. FUNCTION_gnuplot_print() # -p print the plot. { # # PRINT THE PLOT. # # - uses gnuplot command "replot". ${v}echo "${C}.${0}: beginning at `date`" # beginning of function ${v}echo "${C}.${0}: OPT_p=${OPT_p}, # -p print the plot." ${v}echo "${C}.${0}: OPT_P=${OPT_P}, # GNU_PSFILE name." GNU_PSFILE="${GNU_PSFILE:-$GNU_PSFILE_DEF}" ${v}echo "${C}.${0}: GNU_PSFILE=${GNU_PSFILE}, # GNU_PSFILE name." LP_DEV_PARM="-d ${LP_DEV:-$LP_DEV_DEF}" # Printer device parameter. LP_OPT_PARM="${LP_OPT:-$LP_OPT_DEF}" # Printer option parameters. echo "${C}.${0}: executing command: "; echo "\n\ echo lp ${LP_DEV_PARM} ${LP_OPT_PARM} ${GNU_PSFILE}" lp ${LP_DEV_PARM} ${LP_OPT_PARM} ${GNU_PSFILE} ${v}echo "${C}.${0}: completed at `date`\n" # end of function } # FUNCTION_gnuplot_print() # Print the plot. FUNCTION_TITLE_COLHEAD() # Set Column headings from file. { # # Parse the TITLE and COLUMN HEADINGS (CHA) from the data, if available. # Also parse other settable parameters, if available. # ${v}echo "${C}.${0}: beginning at `date`" # beginning of function FTC_FILES="${*}" # Local list of file names. ${v}echo "${C}.${0}: FTC_FILES=${FTC_FILES}" # Choose the first readable file. unset FTC_FILE # Hold the first readable filename. for F in ${FTC_FILES} /dev/null # /dev/null ensures there is a file. do if [ -r "${F}" ] && # Is this file readable? [ "${FTC_FILE}" = "" ]; then # We do not have one yet? FTC_FILE="${F}" # Hold the first readable filename. fi done # If FTC_FILE got set, use it to find TITLE, COLHEAD, XLABEL, YLABEL, et.al. if [ "${FTC_FILE}" != "" ]; then # Use this file. # Grab the FIRST TITLE line (head -1) and use it. TITLE="`grep '^# *TITLE' ${FTC_FILE} | head -1 | sed -e 's/^# *TITLE *//g'`" ${v}echo "${C}.${0}: TITLE=${TITLE}" # Grab the FIRST XLABEL line (head -1) and use it. XLABEL="`grep '^# *XLABEL' ${FTC_FILE} | head -1 | sed -e 's/^# *XLABEL *//g'`" ${v}echo "${C}.${0}: XLABEL=${XLABEL}" # Grab the FIRST YLABEL line (head -1) and use it. YLABEL="`grep '^# *YLABEL' ${FTC_FILE} | head -1 | sed -e 's/^# *YLABEL *//g'`" ${v}echo "${C}.${0}: YLABEL=${YLABEL}" # Find each COLHEAD, and put it in the correct CHA[INDEX]. let i=0 while [ ${i} -lt ${#CHA[*]} ] # For each COLHEAD do # Grab one COLHEAD line at a time, put it into CHA[]. # Note, "@" not allowed in COLHEAD string. LINE="`grep \"^#.*COLHEAD\" ${FTC_FILE} | # Find COLHEAD. sed -e 's/^#.*COLHEAD*//g' \ -e 's/^ *//g' \ -e 's/@//g' | # Remove COLHEAD. expand | sed -e 's/^0*//g' | # Remove leading zeros. grep ^${i} | # Find a line matching ${i}. head -1 `" # Make sure there is only 1. # Grab the INDEX number, could do numeric check if problems. INDEX="`echo ${LINE} | cut -d\" \" -f1`" # field 1 is number. # If INDEX is not empty, save this COLHEAD. if [ "${INDEX}" != "" ]; then # Grab the rest of the line and save it into CHA. REMAINDER="`echo ${LINE} | sed -e \"s@^${INDEX} *@@g\"`" CHA[${INDEX}]="${REMAINDER}" ${v}echo "${C}.${0}: CHA[${INDEX}]=\"${CHA[${INDEX}]}\"" fi let i=i+1 done # GETOPT, pull in options to be set for this data. GETOPT="`grep '^# *GETOPT' ${FTC_FILE} | head -1 | sed -e 's/^# *GETOPT *//g'`" if [ "${GETOPT}" != "" ]; then FUNCTION__getopt ${GETOPT} # Parse the options. fi unset GETOPT fi ${v}echo "${C}.${0}: completed at `date`\n" # end of function } # FUNCTION_TITLE_COLHEAD() # Set Column headings from file. FUNCTION_n() # -n number plot descriptions. { # ADD COLUMN NUMBER TO EACH ELEMENT IN CHA: # # - This is done for comparing plots, and/or debugging. ${v}echo "${C}.${0}: beginning at `date`" # beginning of function ${v}echo "${C}.${0}: OPT_n=${OPT_n}, # -n number plot descriptions" let i=0 while [ ${i} -lt ${#CHA[*]} ] do CHA[${i}]="${i} ${CHA[${i}]}" ${v}echo "${C}.${0}: CHA[${i}]=\"${CHA[${i}]}\"" let i=i+1 done ${v}echo "${C}.${0}: completed at `date`\n" # end of function } # FUNCTION_n() # -n number plot descriptions. FUNCTION_units() # Resolve units. { # # Expand units of the form 1K to 1000, 1M to 1000000, et.al. # Used to format the gnuplot parameters xRANGE and yRANGE. # gnuplot data format: "set xrange [1:1000000]" # Fu_IN="${1}" # Units in. echo "["${Fu_IN}"]" | sed -e "s/[kK]/000/g" | # 1,000 sed -e "s/[mM]/000000/g" | # 1,000,000 sed -e "s/[gG]/000000000/g" | # 1,000,000,000 sed -e "s/^\[\[/\["/g | # Ensure single leading bracket. sed -e "s/\]\]$/\]"/g # Ensure single trailing bracket. } FUNCTION_a() # -a Option description. { # # Replace with description of this function. # ${v}echo "${C}.${0}: beginning at `date`" # beginning of function ${v}echo "${C}.${0}: OPT_a=${OPT_a}, # -a Option description." ${v}echo "${C}.${0}: completed at `date`\n" # end of function } # FUNCTION_b() # -b Option description. { # # Replace with description of this function. # ${v}echo "${C}.${0}: beginning at `date`" # beginning of function ${v}echo "${C}.${0}: OPT_b=${OPT_b}, # -b Option description." MSG="# -b Parameter description." ${v}echo "${C}.${0}: OPT_b_PARM=${OPT_b_PARM}, ${MSG}" if [ -r "${OPT_b_PARM}" ]; then # Ensure this is a file. echo ${OPT_b_PARM} | while read -r FILE; do ${v}echo "${C}.${0}: FILE=${FILE}" done else # Or use elif (form of elseif). ${v}echo "${C}.${0}: ERROR, ${OPT_b_PARM} is not a readable file." fi ${v}echo "${C}.${0}: completed at `date`\n" # end of function } # # # MAIN: Main driver, main processing occurs here. # ${v}echo " \n${C}: beginning at `date`" # page overflow with each start. CMD_LINE="${0} ${*}" # Save command called and options. FUNCTION__getopt ${*} # Parse the options. if [ -z "${OPT_NE}" ] && # Not E is not turned on and E is... [ ! -z "${OPT_E}" ]; then # -E use embedded options FUNCTION_TITLE_COLHEAD ${FILES} # Set Column headings from file. fi FUNCTION__getopt ${*} >/dev/null 2>&1 # Parse the options. type banner >/dev/null 2>&1 # Check if banner exists. RC="${?}" # Save return code. if [ "${RC}" = "0" ]; then # if RC=0, banner exists. ${v}banner ${C} fi ${v}echo "${C}: RCS_SCRIPT=${RCS_SCRIPT}" ${v}echo "${C}: PWD=${PWD}" if [ ! -z "${OPT_n}" ]; then FUNCTION_n # -n number plot descriptions. fi # If GNU_CMDFILE exists, use it, do not create it. if [ ! -f ${GNU_CMDFILE} ]; then # ! -f = if this is not a file. if [ "${FILES}" = "" ]; then # If no files available MSG="and GNU_CMDFILE is not a file exit 7" echo "${C}: ERROR: no FILES to plot! ${MSG}" exit 7 break fi FUNCTION_gnuplot_init ${*} # Initialize gnuplot command file. FUNCTION_gnuplot_plot ${FILES} # Plot these files. echo pause -1 \'Pause: press return to continue.\' >> ${GNU_CMDFILE} echo # Place blank line in log file. fi FUNCTION_gnuplot_display # Plots the datapoints. if [ ! -z "${OPT_p}" ]; then FUNCTION_gnuplot_print # -p print the plot. fi # REMOVE FILES, CLEANUP: # # Remove the working files and filenames, unless "-S" is on. if [ "${OPT_S}" = "-S" ]; then # -S save files. echo "${C}: saving ${COMMAND}" echo "${C}: saving ${GNU_CMDFILE}" if [ "${OPT_p}" = "-p" ]; then echo "${C}: saving ${GNU_PSFILE}" fi else rm -f ${COMMAND} # Remove generated log file. rm -f ${GNU_CMDFILE} # Remove generated command file. rm -f ${GNU_PSFILE} # Remove generated .ps file. fi rm -fr ${COMMAND}.WORK*.$$ # Remove generated work files. ${v}echo "${C}: completed at `date`\n^L" # Message if -v (verbose): if [ "${OPT_v}" = "-v" ]; then # -v verbose mode. echo "${INFO}" fi # DONE: # # - If a log file needs to be kept, uncomment the corresponding (): } 2>&1 | tee -a ${COMMAND} # Use during testing. #) >>${COMMAND} 2>&1 & # Use for production. judy-1.0.5/doc/0000755000175000017500000000000010624600215013455 5ustar troyhebetroyhebejudy-1.0.5/doc/ext/0000755000175000017500000000000010624600177014264 5ustar troyhebetroyhebejudy-1.0.5/doc/ext/README_deliver0000644000175000017500000000143610204462077016661 0ustar troyhebetroyhebe# @(#) $Revision: 4.11 $ Judy_3.htm the Judy(3) overview manual entry in HTML format; normally placed where a web browser can read it Judy1_3.htm describes the Judy1*() macros Judy1_funcs_3.htm describes the Judy1*() functions JudyL_3.htm describes the JudyL*() macros JudyL_funcs_3.htm describes the JudyL*() functions JudySL_3.htm describes the JudySL*() macros JudySL_funcs_3.htm describes the JudySL*() functions JudyHS_3.htm describes the JudyHS*() macros JudyHS_funcs_3.htm describes the JudyHS*() functions # Note: The library package README file comes from the following file, but the # hierarchy of example sources package README files come from each # corresponding directory: README_deliver packaged with other Judy delivered files, renamed to just "README" in that context judy-1.0.5/doc/ext/JudyHS_3.htm0000644000175000017500000001656010204462077016375 0ustar troyhebetroyhebe JudyHS(3)
JudyHS(3) JudyHS(3)

NAME
JudyHS macros - C library for creating and accessing a dynamic array, using an array-of-bytes of Length as an Index and a word as a Value.

SYNOPSIS
cc [flags] sourcefiles -lJudy

#include <Judy.h>

Word_t  * PValue;                           // JudyHS array element
int       Rc_int;                           // return flag
Word_t    Rc_word;                          // full word return value
Pvoid_t   PJHSArray = (Pvoid_t) NULL;       // initialize JudyHS array
uint8_t * Index;                            // array-of-bytes pointer
Word_t    Length;                           // number of bytes in Index

JHSI( PValue,  PJHSArray, Index, Length);   // JudyHSIns()
JHSD( Rc_int,  PJHSArray, Index, Length);   // JudyHSDel()
JHSG( PValue,  PJHSArray, Index, Length);   // JudyHSGet()
JHSFA(Rc_word, PJHSArray);                  // JudyHSFreeArray()
DESCRIPTION
A JudyHS array is the equivalent of an array of word-sized value/pointers. An Index is a pointer to an array-of-bytes of specified length: Length. Rather than using a null terminated string, this difference from JudySL(3) allows strings to contain all bits (specifically the null character). This new addition (May 2004) to Judy arrays is a hybird using the best capabilities of hashing and Judy methods. JudyHS does not have a poor performance case where knowledge of the hash algorithm can be used to degrade the performance.

Since JudyHS is based on a hash method, Indexes are not stored in any particular order. Therefore the JudyHSFirst(), JudyHSNext(), JudyHSPrev() and JudyHSLast() neighbor search functions are not practical. The Length of each array-of-bytes can be from 0 to the limits of malloc() (about 2GB).

The hallmark of JudyHS is speed with scalability, but memory efficiency is excellent. The speed is very competitive with the best hashing methods. The memory efficiency is similar to a linked list of the same Indexes and Values. JudyHS is designed to scale from 0 to billions of Indexes.

A JudyHS array is allocated with a NULL pointer

Pvoid_t PJHSArray = (Pvoid_t) NULL;

Because the macro forms of the API have a simpler error handling interface than the equivalent functions, they are the preferred way to use JudyHS.

JHSI(PValue, PJHSArray, Index, Length) // JudyHSIns()
Given a pointer to a JudyHS array (PJHSArray), insert an Index string of length: Length and a Value into the JudyHS array: PJHSArray. If the Index is successfully inserted, the Value is initialized to 0. If the Index was already present, the Value is not modified.

Return PValue pointing to Value. Your program should use this pointer to read or modify the Value, for example:

Value = *PValue;
*PValue = 1234;

Note: JHSI() and JHSD can reorganize the JudyHS array. Therefore, pointers returned from previous JudyHS calls become invalid and must be re-acquired (using JHSG()).

JHSD(Rc_int, PJHSArray, Index, Length) // JudyHSDel()
Given a pointer to a JudyHS array (PJHSArray), delete the specified Index along with the Value from the JudyHS array.

Return Rc_int set to 1 if successfully removed from the array. Return Rc_int set to 0 if Index was not present.

JHSG(PValue, PJHSArray, Index, Length) // JudyHSGet()
Given a pointer to a JudyHS array (PJHSArray), find Value associated with Index.

Return PValue pointing to Index's Value. Return PValue set to NULL if the Index was not present.

JHSFA(Rc_word, PJHSArray) // JudyHSFreeArray()
Given a pointer to a JudyHS array (PJHSArray), free the entire array.

Return Rc_word set to the number of bytes freed and PJHSArray set to NULL.

ERRORS: See: Judy_3.htm#ERRORS

EXAMPLES
Show how to program with the JudyHS macros. This program will print duplicate lines and their line number from stdin.

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <Judy.h>

//  Compiled:
//  cc -O PrintDupLines.c -lJudy -o PrintDupLines

#define MAXLINE 1000000                 /* max fgets length of line */
uint8_t   Index[MAXLINE];               // string to check

int     // Usage:  PrintDupLines < file
main()
{
    Pvoid_t   PJArray = (PWord_t)NULL;  // Judy array.
    PWord_t   PValue;                   // Judy array element pointer.
    Word_t    Bytes;                    // size of JudyHS array.
    Word_t    LineNumb = 0;             // current line number
    Word_t    Dups = 0;                 // number of duplicate lines

    while (fgets(Index, MAXLINE, stdin) != (char *)NULL)
    {
        LineNumb++;                     // line number

        // store string into array
        JHSI(PValue, PJArray, Index, strlen(Index)); 
        if (PValue == PJERR)            // See ERRORS section
        {
            fprintf(stderr, "Out of memory -- exit\n");
            exit(1);
        }
        if (*PValue == 0)               // check if duplicate
        {
            Dups++;
            printf("Duplicate lines %lu:%lu:%s", *PValue, LineNumb, Index);
        }
        else
        {
            *PValue = LineNumb;         // store Line number
        }
    }
    printf("%lu Duplicates, free JudyHS array of %lu Lines\n", 
                    Dups, LineNumb - Dups);
    JHSFA(Bytes, PJArray);              // free JudyHS array
    printf("JudyHSFreeArray() free'ed %lu bytes of memory\n", Bytes);
    return (0);
}

AUTHOR
JudyHS was invented and implemented by Doug Baskins after retiring from Hewlett-Packard.

SEE ALSO
Judy(3), Judy1(3), JudyL(3), JudySL(3),
malloc(),
the Judy website, http://judy.sourceforge.net, for further information and Application Notes. judy-1.0.5/doc/ext/JudyL_3.htm0000644000175000017500000003530210204462077016251 0ustar troyhebetroyhebe JudyL(3)
JudyL(3) JudyL(3)

NAME
JudyL macros - C library for creating and accessing a dynamic array of words, using a word as an index.

SYNOPSIS
cc [flags] sourcefiles -lJudy

#include <Judy.h>

int      Rc_int;                          // return code - integer
Word_t   Rc_word;                         // return code - unsigned word
Word_t   Index, Index1, Index2, Nth;
PWord_t  PValue;                          // pointer to return value
Pvoid_t PJLArray = (Pvoid_t) NULL;        // initialize JudyL array

JLI( PValue,  PJLArray, Index);          // JudyLIns()
JLD( Rc_int,  PJLArray, Index);          // JudyLDel()
JLG( PValue,  PJLArray, Index);          // JudyLGet()
JLC( Rc_word, PJLArray, Index1, Index2); // JudyLCount()
JLBC(PValue,  PJLArray, Nth, Index);     // JudyLByCount()
JLFA(Rc_word, PJLArray);                 // JudyLFreeArray()
JLMU(Rc_word, PJLArray);                 // JudyLMemUsed()
JLF( PValue,  PJLArray, Index);          // JudyLFirst()
JLN( PValue,  PJLArray, Index);          // JudyLNext()
JLL( PValue,  PJLArray, Index);          // JudyLLast()
JLP( PValue,  PJLArray, Index);          // JudyLPrev()
JLFE(Rc_int,  PJLArray, Index);          // JudyLFirstEmpty()
JLNE(Rc_int,  PJLArray, Index);          // JudyLNextEmpty()
JLLE(Rc_int,  PJLArray, Index);          // JudyLLastEmpty()
JLPE(Rc_int,  PJLArray, Index);          // JudyLPrevEmpty()

DESCRIPTION
A JudyL array is the equivalent of an array of word-sized values. A Value is addressed by an Index (key). The array may be sparse, and the Index may be any word-sized number. Memory to support the array is allocated as index/value pairs are inserted, and released as index/value pairs are deleted. A JudyL array can also be thought of as a mapper, that is "map" a word to another word/pointer.

As with an ordinary array, there are no duplicate indexes in a JudyL array.

The value may be used as a scalar, or a pointer to a structure or block of data (or even another Judy array).

A JudyL array is allocated with a NULL pointer

Pvoid_t PJLArray = (Pvoid_t) NULL;

Using the macros described here, rather than the JudyL function calls, the default error handling sends a message to the standard error and terminates the program with exit(1);. For other error handling methods, see the ERRORS section. JLI( PValue, PJLArray, Index); // JudyLIns()

Because the macro forms are sometimes faster and have a simpler error handling interface than the equivalent JudyL functions, they are the preferred way of calling the JudyL functions.

JLI(PValue, PJLArray, Index) // JudyLIns()
Insert an Index and Value into the JudyL array PJLArray. If the Index is successfully inserted, the Value is initialized to 0. If the Index was already present, the Value is not modified.

Return PValue pointing to Value. Your program can use this pointer to read or modify Value until the next JLI() (insert), JLD() (delete) or JLFA() (freearray) is executed on PJLArray. Examples:

*PValue = 1234;
Value = *PValue;

Return PValue set to PJERR if a malloc() fail occured. Note: JLI() and JLD() reorganize the JudyL array. Therefore, PValue returned from previous JudyL calls become invalid and must be re-acquired.

JLD(Rc_int, PJLArray, Index) // JudyLDel()
Delete the Index/Value pair from the JudyL array.

Return Rc_int set to 1 if successful. Return Rc_int set to 0 if Index was not present. Return Rc_int set to JERR if a malloc() fail occured.

JLG(PValue, PJLArray, Index) // JudyLGet()
Get the pointer PValue associated with Index in the PJLArray Judy array.

Return PValue pointing to Value. Return PValue set to NULL if the Index was not present. Return PValue set to PJERR if a malloc() fail occured.

JLC(Rc_word, PJLArray, Index1, Index2) // JudyLCount()
Count the number of indexes present in the JudyL array PJLArray between Index1 and Index2 (inclusive).

Return Rc_word set to the count. A return value of 0 can be valid as a count.

To count all indexes present in a JudyL array, use:

JLC(Rc_word, PJLArray, 0, -1);

JLBC(PValue, PJLArray, Nth, Index) // JudyLByCount()
Locate the Nth index that is present in the JudyL array PJLArray (Nth = 1 returns the first index present).

Return PValue pointing to its Value and Index set to the Nth index if found, otherwise return PValue set to NULL (the value of Index is undefined).

JLFA(Rc_word, PJLArray) // JudyLFreeArray()
Given a pointer to a JudyL array, free the entire array (much faster than using a JLN(), JLD() loop).

Return Rc_word set to the number of bytes freed and PJLArray set to NULL.

JLMU(Rc_word, PJLArray) // JudyLMemUsed()
Return Rc_word set to the number of bytes of memory malloc()'ed by PJLArray. This is a very fast routine, and may be used before and after a JLI() or JLD() call with little performance impact.

JudyL Search Functions
JLF(), JLN(), JLL(), JLP() allow you to search for indexes in the array. You may search inclusively or exclusively, in either forward or reverse directions. If successful, Index is returned set to the found index, and PValue is returned set to a pointer to Index's Value. If unsuccessful, PValue is returned set to NULL, and Index contains no useful information. PValue must be tested for non-NULL prior to using Index, since a search failure is possible.

JLFE(), JLNE(), JLLE(), JLPE() allow you to search for indexes that are not present ("empty") in the array. You may search inclusively or exclusively, in either forward or reverse directions. If successful, Index is returned set to a not present ("empty") index, and Rc_int is returned set to 1. If unsuccessful, Rc_int is returned set to 0, and and Index contains no useful information. Rc_int must be checked prior to using Index, since a search failure is possible.

JLF(PValue, PJLArray, Index) // JudyLFirst()
Search (inclusive) for the first index present that is equal to or greater than the passed Index. (Start with Index = 0 to find the first index in the array.) JLF() is typically used to begin a sorted-order scan of the indexes present in a JudyL array.

JLN(PValue, PJLArray, Index) // JudyLNext()
Search (exclusive) for the next index present that is greater than the passed Index. JLN() is typically used to continue a sorted-order scan of the indexes present in a JudyL array, or to locate a "neighbor" of a given index.

JLL(PValue, PJLArray, Index) // JudyLLast()
Search (inclusive) for the last index present that is equal to or less than the passed Index. (Start with Index = -1, that is, all ones, to find the last index in the array.) JLL() is typically used to begin a reverse-sorted-order scan of the indexes present in a JudyL array.

JLP(PValue, PJLArray, Index) // JudyLPrev()
Search (exclusive) for the previous index present that is less than the passed Index. JLP() is typically used to continue a reverse-sorted-order scan of the indexes present in a JudyL array, or to locate a "neighbor" of a given index.

JLFE(Rc_int, PJLArray, Index) // JudyLFirstEmpty()
Search (inclusive) for the first index absent that is equal to or greater than the passed Index. (Start with Index = 0 to find the first index absent in the array.)

JLNE(Rc_int, PJLArray, Index) // JudyLNextEmpty()
Search (exclusive) for the next index absent that is greater than the passed Index.

JLLE(Rc_int, PJLArray, Index) // JudyLLastEmpty()
Search (inclusive) for the last index absent that is equal to or less than the passed Index. (Start with Index = -1, that is, all ones, to find the last index absent in the array.)

JLPE(Rc_int, PJLArray, Index) // JudyLPrevEmpty()
Search (exclusive) for the previous index absent that is less than the passed Index.

Multi-dimensional JudyL Arrays
Storing a pointer to another JudyL array in a JudyL array's Value is a simple way to support dynamic multi-dimensional arrays. These arrays (or trees) built using JudyL arrays are very fast and memory efficient. (In fact, that is how JudySL and JudyHS are implemented). An arbitrary number of dimensions can be realized this way. To terminate the number of dimensions (or tree), the Value pointer is marked to NOT point to another Judy array. A JLAP_INVALID flag is used in the least significant bit(s) of the pointer. After the flag JLAP_INVALID is removed, it is used as a pointer to the users data. The Judy.h header file defines JLAP_INVALID. See code fragment below.

Note: The current version of Judy.h changed this flag from 0x4 to 0x1 to allow for a malloc() that does not deliver memory on an 8 byte aligned boundry (such as old versions of valgrind).

The following example code segment can be used to determine whether or not a pointer points to another JudyL:

PValue = (PWord_t)PMultiDimArray;

for (Dim = 0; ;Dim++)
{
   if (PValue == (PWord_t)NULL) goto IndexNotFound;

   /* Advance to next dimension in array */
   JLG(PValue, (Pvoid_t)*PValue, Index[Dim]);

   /* Check if pointer to user buffer: */
   if (*PValue & JLAP_INVALID)) break;
}
UPointer = (UPointer_t) (*PValue & ~JLAP_INVALID);  // mask and cast.
printf("User object pointer is 0x%lx\n", (Word_t) UPointer);
       ...

Note: This works because malloc() guarantees to return a pointer with the least bit(s) == 0x0. You must remove JLAP_INVALID before using the pointer.

ERRORS: See: Judy_3.htm#ERRORS

EXAMPLE
Read a series of index/value pairs from the standard input, store in a JudyL array, and then print out in sorted order.

#include <stdio.h>
#include <Judy.h>

Word_t   Index;                     // array index
Word_t   Value;                     // array element value
Word_t * PValue;                    // pointer to array element value
int      Rc_int;                    // return code

Pvoid_t  PJLArray = (Pvoid_t) NULL; // initialize JudyL array

while (scanf("%lu %lu", &Index, &Value))
{
    JLI(PValue, PJLArray, Index);
    If (PValue == PJERR) goto process_malloc_failure;
    *PValue = Value;                 // store new value
}
// Next, visit all the stored indexes in sorted order, first ascending,
// then descending, and delete each index during the descending pass.

Index = 0;
JLF(PValue, PJLArray, Index);
while (PValue != NULL)
{
    printf("%lu %lu\n", Index, *PValue));
    JLN(PValue, PJLArray, Index);
}

Index = -1;
JLL(PValue, PJLArray, Index);
while (PValue != NULL)
{
    printf("%lu %lu\n", Index, *PValue));

    JLD(Rc_int, PJLArray, Index);
    if (Rc_int == JERR) goto process_malloc_failure;

    JLP(PValue, PJLArray, Index);
}

AUTHOR
Judy was invented by Doug Baskins and implemented by Hewlett-Packard.

SEE ALSO
Judy(3), Judy1(3), JudySL(3), JudyHS(3),
malloc(),
http://judy.sourceforge.net, for more information and Application Notes. judy-1.0.5/doc/ext/LICENSE0000644000175000017500000000000010204462077015256 0ustar troyhebetroyhebejudy-1.0.5/doc/ext/README0000644000175000017500000000143610204462077015147 0ustar troyhebetroyhebe# @(#) $Revision: 4.11 $ Judy_3.htm the Judy(3) overview manual entry in HTML format; normally placed where a web browser can read it Judy1_3.htm describes the Judy1*() macros Judy1_funcs_3.htm describes the Judy1*() functions JudyL_3.htm describes the JudyL*() macros JudyL_funcs_3.htm describes the JudyL*() functions JudySL_3.htm describes the JudySL*() macros JudySL_funcs_3.htm describes the JudySL*() functions JudyHS_3.htm describes the JudyHS*() macros JudyHS_funcs_3.htm describes the JudyHS*() functions # Note: The library package README file comes from the following file, but the # hierarchy of example sources package README files come from each # corresponding directory: README_deliver packaged with other Judy delivered files, renamed to just "README" in that context judy-1.0.5/doc/ext/JudySL_funcs_3.htm0000644000175000017500000001376010204462077017576 0ustar troyhebetroyhebe JudySL_funcs(3)
JudySL_funcs(3) JudySL_funcs(3)

NAME
JudySL functions - C library for creating and accessing a dynamic array, using a null-terminated string as an index (associative array)

SYNOPSIS

PPvoid_t JudySLIns(      PPvoid_t PPJSLArray, const uint8_t * Index, PJError_t PJError);
int      JudySLDel(      PPvoid_t PPJSLArray, const uint8_t * Index, PJError_t PJError);
PPvoid_t JudySLGet(      Pcvoid_t  PJSLArray, const uint8_t * Index, PJError_t PJError);
Word_t   JudySLFreeArray(PPvoid_t PPJSLArray, PJError_t PJError);
PPvoid_t JudySLFirst(    Pcvoid_t  PJSLArray,       uint8_t * Index, PJError_t PJError);
PPvoid_t JudySLNext(     Pcvoid_t  PJSLArray,       uint8_t * Index, PJError_t PJError);
PPvoid_t JudySLLast(     Pcvoid_t  PJSLArray,       uint8_t * Index, PJError_t PJError);
PPvoid_t JudySLPrev(     Pcvoid_t  PJSLArray,       uint8_t * Index, PJError_t PJError);

DESCRIPTION
A macro equivalent exists for each function call. Because the macro forms are sometimes faster and have a simpler error handling interface than the equivalent functions, they are the preferred way of calling the JudySL functions. See JudySL(3) for more information. The function call definitions are included here for completeness.

One of the difficulties in using the JudySL function calls lies in determining whether to pass a pointer or the address of a pointer. Since the functions that modify the JudySL array must also modify the pointer to the JudySL array, you must pass the address of the pointer rather than the pointer itself. This often leads to hard-to-debug programmatic errors. In practice, the macros allow the compiler to catch programming errors when pointers instead of addresses of pointers are passed.

The JudySL function calls have an additional parameter beyond those specified in the macro calls. This parameter is either a pointer to an error structure, or NULL (in which case the detailed error information is not returned).

In the following descriptions, the functions are described in terms of how the macros use them (only in the case of #define JUDYERROR_NOTEST 1). This is the suggested use of the macros after your program has been fully debugged. When the JUDYERROR_NOTEST macro is not specified, an error structure is declared to store error information returned from the JudySL functions when an error occurs.

Notice the placement of the & in the different functions.

JudySLIns(&PJSLArray, Index, &JError)
#define JSLI(PValue, PJSLArray, Index) \
   PValue = JudyLIns(&PJSLArray, Index, PJE0)

JudySLDel(&PJSLArray, Index, &JError)
#define JSLD(Rc_int, PJSLArray, Index) \
   Rc_int = JudySLDel(&PJSLArray, Index, PJE0)

JudySLGet(PJSLArray, Index, &JError)
#define JSLG(PValue, PJSLArray, Index) \
   PValue = JudySLIns(PJSLArray, Index, PJE0)

JudySLFreeArray(&PJSLArray, &JError)
#define JSLFA(Rc_word, PJSLArray) \
   Rc_word = JudySLFreeArray(&PJSLArray, PJE0)

JudySLFirst(PJSLArray, Index, &JError)
#define JSLF(PValue, PJSLArray, Index) \
   PValue = JudySLFirst(PJSLArray, Index, PJE0)

JudySLNext(PJSLArray, Index, &JError)
#define JSLN(PValue, PJSLArray, Index) \
   PValue = JudySLNext(PJSLArray, Index, PJE0)

JudySLLast(PJSLArray, Index, &JError)
#define JSLL(PValue, PJSLArray, Index) \
   PValue = JudySLLast(PJSLArray, Index, PJE0)

JudySLPrev(PJSLArray, Index, &JError)
#define JSLP(PValue, PJSLArray, Index) \
   PValue = JudySLPrev(PJSLArray, Index, PJE0)

Definitions for all the Judy functions, the types Pvoid_t, Pcvoid_t, PPvoid_t, Word_t , JError_t, and PJError_t, the constants NULL, JU_ERRNO_*, JERR, PPJERR, and PJE0 are provided in the Judy.h header file (/usr/include/Judy.h). Note: Callers should define JudySL arrays as type Pvoid_t, which can be passed by value to functions that take Pcvoid_t (constant Pvoid_t), and also by address to functions that take PPvoid_t.

The return type from most JudySL functions is PPvoid_t so that the values stored in the array can be pointers to other objects, which is a typical usage, or cast to a Word_t * when a pointer to a value is required instead of a pointer to a pointer.

AUTHOR
Judy was invented by Doug Baskins and implemented by Hewlett-Packard.

SEE ALSO
Judy(3), Judy1(3), JudyL(3), JudySL(3), JudyHS(3),
malloc(),
the Judy website, http://judy.sourceforge.net, for more information and Application Notes.
judy-1.0.5/doc/ext/JudySL_3.htm0000644000175000017500000002216210204462077016374 0ustar troyhebetroyhebe JudySL(3)
JudySL(3) JudySL(3)

NAME
JudySL macros - C library for creating and accessing a dynamic array, using a null-terminated string as an Index (associative array)

SYNOPSIS
cc [flags] sourcefiles -lJudy

#include <Judy.h>

#define MAXLINELEN 1000000           // define maximum string length

Word_t * PValue;                     // JudySL array element
uint8_t  Index[MAXLINELEN];          // string
int      Rc_int;                     // return value
Word_t   Rc_word;                    // full word return value

Pvoid_t PJSLArray = (Pvoid_t) NULL;  // initialize JudySL array

JSLI( PValue,  PJSLArray, Index);   // JudySLIns()
JSLD( Rc_int,  PJSLArray, Index);   // JudySLDel()
JSLG( PValue,  PJSLArray, Index);   // JudySLGet()
JSLFA(Rc_word, PJSLArray);          // JudySLFreeArray()
JSLF( PValue,  PJSLArray, Index);   // JudySLFirst()
JSLN( PValue,  PJSLArray, Index);   // JudySLNext()
JSLL( PValue,  PJSLArray, Index);   // JudySLLast()
JSLP( PValue,  PJSLArray, Index);   // JudySLPrev()

DESCRIPTION
A JudySL array is the equivalent of a sorted set of strings, each associated with a Value (word). A Value is addressed by an Index (key), which is a null-terminated character string of any length. Memory to support the array is allocated as index/value pairs are inserted, and released as index/value pairs are deleted. This is a form of associative array, where array elements are also sorted lexicographically (case-sensitive) by indexes. This could be thought of as

void * JudySLArray["Toto, I don't think we're in Kansas any more"];

A JudySL array is allocated with a NULL pointer

Pvoid_t PJSLArray = (Pvoid_t) NULL;
As with an ordinary array, there are no duplicate indexes (strings) in a JudySL array.

Using the macros described here, rather than the JudySL function calls, the default error handling sends a message to the standard error and terminates the program with exit(1).

JSLI(PValue, PJSLArray, Index) // JudySLIns()
Insert an Index string and Value in the JudySL array PJSLArray. If the Index is successfully inserted, the Value is initialized to 0. If the Index was already present, the Value is not modified.

Return PValue pointing to Index's Value. Your program must use this pointer to modify the Value, for example:

*PValue = 1234;

Note: JSLI() and JSLD reorganize the JudySL array. Therefore, pointers returned from previous JudySL calls become invalid and must be reacquired.

JSLD(Rc_int, PJSLArray, Index) // JudySLDel()
Delete the specified Index/Value pair (array element) from the JudySL array.

Return Rc_int set to 1 if successful. array and it was previously inserted. Return Rc_int set to 0 if Index was not present.

JSLG(PValue, PJSLArray, Index) // JudySLGet()
Get the pointer to Index's Value.

Return PValue pointing to Index's Value. Return PValue set to NULL if the Index was not present.

JSLFA(Rc_word, PJSLArray) // JudySLFreeArray()
Given a pointer to a JudySL array (PJSLArray), free the entire array (much faster than using a JSLN(), JSLD() loop.)

Return Rc_word set to the number of bytes freed and PJSLArray set to NULL.

JudySL Search Functions
The JudySL search functions allow you to search for indexes in the array. You may search inclusively or exclusively, in either forward or reverse directions.

If successful, Index is returned set to the found index, and PValue is returned set to a pointer to Index's Value. If unsuccessful, PValue is returned set to NULL, and Index contains no useful information. PValue must be tested for non-NULL prior to using Index, since a search failure is possible.

Note: To accomodate all possible returns, the Index buffer must be at least as large as the largest string stored in the array.

JSLF(PValue, PJSLArray, Index) // JudySLFirst()
Search (inclusive) for the first index present that is equal to or greater than the passed Index string. (Start with a null string to find the first index in the array.) JSLF() is typically used to begin a sorted-order scan of the valid indexes in a JudySL array.
uint8_t Index[MAXLINELEN];
strcpy (Index, "");
JSLF(PValue, PJSLArray, Index);

JSLN(PValue, PJSLArray, Index) // JudySLNext()
Search (exclusive) for the next index present that is greater than the passed Index string. JSLN() is typically used to continue a sorted-order scan of the valid indexes in a JudySL array, or to locate a "neighbor" of a given index.

JSLL(PValue, PJSLArray, Index) // JudySLLast()
Search (inclusive) for the last index present that is equal to or less than the passed Index string. (Start with a maximum-valued string to look up the last index in the array, such as a max-length string of 0xff bytes.) JSLL() is typically used to begin a reverse-sorted-order scan of the valid indexes in a JudySL array.

JSLP(PValue, PJSLArray, Index) // JudySLPrev()
Search (exclusive) for the previous index present that is less than the passed Index string. JSLP() is typically used to continue a reverse-sorted-order scan of the valid indexes in a JudySL array, or to locate a "neighbor" of a given index.

ERRORS: See: Judy_3.htm#ERRORS

EXAMPLE of a string sort routine

#include <stdio.h>
#include <Judy.h>

#define MAXLINE 1000000                 // max string (line) length

uint8_t   Index[MAXLINE];               // string to insert

int     // Usage:  JudySort < file_to_sort
main()
{
    Pvoid_t   PJArray = (PWord_t)NULL;  // Judy array.
    PWord_t   PValue;                   // Judy array element.
    Word_t    Bytes;                    // size of JudySL array.

    while (fgets(Index, MAXLINE, stdin) != (char *)NULL)
    {
        JSLI(PValue, PJArray, Index);   // store string into array
        if (PValue == PJERR)            // if out of memory?
        {                               // so do something
            printf("Malloc failed -- get more ram\n");
            exit(1);
        }
        ++(*PValue);                    // count instances of string
    }
    Index[0] = '\0';                    // start with smallest string.
    JSLF(PValue, PJArray, Index);       // get first string
    while (PValue != NULL)
    {
        while ((*PValue)--)             // print duplicates
            printf("%s", Index);
        JSLN(PValue, PJArray, Index);   // get next string
    }
    JSLFA(Bytes, PJArray);              // free array

    fprintf(stderr, "The JudySL array used %lu bytes of memory\n", Bytes);
    return (0);
}

AUTHOR
Judy was invented by Doug Baskins and implemented by Hewlett-Packard.

SEE ALSO
Judy(3), Judy1(3), JudyL(3), JudyHS(3),
malloc(),
the Judy website, http://judy.sourceforge.net, for further information and Application Notes.
judy-1.0.5/doc/ext/Judy1_funcs_3.htm0000644000175000017500000002065710204462077017423 0ustar troyhebetroyhebe Judy1_funcs(3)
Judy1_funcs(3) Judy1_funcs(3)

NAME
Judy1 functions - C library for creating and accessing a dynamic array of bits, using any value of a word as an index

SYNOPSIS
int    Judy1Set(       PPvoid_t PPJ1Array, Word_t   Index,  PJError_t PJError);
int    Judy1Unset(     PPvoid_t PPJ1Array, Word_t   Index,  PJError_t PJError);
int    Judy1Test(      Pcvoid_t  PJ1Array, Word_t   Index,  PJError_t PJError);
Word_t Judy1Count(     Pcvoid_t  PJ1Array, Word_t   Index1, Word_t    Index2, PJError_t PJError);
int    Judy1ByCount(   Pcvoid_t  PJ1Array, Word_t   Nth,    Word_t * PIndex,  PJError_t PJError);
Word_t Judy1FreeArray( PPvoid_t PPJ1Array, PJError_t PJError);
Word_t Judy1MemUsed(   Pcvoid_t  PJ1Array);
int    Judy1First(     Pcvoid_t  PJ1Array, Word_t * PIndex, PJError_t PJError);
int    Judy1Next(      Pcvoid_t  PJ1Array, Word_t * PIndex, PJError_t PJError);
int    Judy1Last(      Pcvoid_t  PJ1Array, Word_t * PIndex, PJError_t PJError);
int    Judy1Prev(      Pcvoid_t  PJ1Array, Word_t * PIndex, PJError_t PJError);
int    Judy1FirstEmpty(Pcvoid_t  PJ1Array, Word_t * PIndex, PJError_t PJError);
int    Judy1NextEmpty( Pcvoid_t  PJ1Array, Word_t * PIndex, PJError_t PJError);
int    Judy1LastEmpty( Pcvoid_t  PJ1Array, Word_t * PIndex, PJError_t PJError);
int    Judy1PrevEmpty( Pcvoid_t  PJ1Array, Word_t * PIndex, PJError_t PJError);

DESCRIPTION
A macro equivalent exists for each function call. Because the macro forms are sometimes faster and have a simpler error handling interface than the equivalent functions, they are the preferred way of calling the Judy1 functions. See Judy1(3) for more information. The function call definitions are included here for completeness.

One of the difficulties in using the Judy1 function calls lies in determining whether to pass a pointer or the address of a pointer. Since the functions that modify the Judy1 array must also modify the pointer to the Judy1 array, you must pass the address of the pointer rather than the pointer itself. This often leads to hard-to-debug programmatic errors. In practice, the macros allow the compiler to catch programming errors when pointers instead of addresses of pointers are passed.

The Judy1 function calls have an additional parameter beyond those specified in the macro calls. This parameter is either a pointer to an error structure, or NULL (in which case the detailed error information is not returned).

In the following descriptions, the functions are described in terms of how the macros use them (only in the case of #define JUDYERROR_NOTEST 1). This is the suggested use of the macros after your program has been fully debugged. When the JUDYERROR_NOTEST macro is not specified, an error structure is declared to store error information returned from the Judy1 functions when an error occurs.

Notice the placement of the & in the different functions.

Judy1Set(&PJ1Array, Index, &JError)
#define J1S(Rc_int, PJ1Array, Index) \
   Rc_int = Judy1Set(&PJ1Array, Index, PJE0)

Judy1Unset(&PJ1Array, Index, &JError)
#define J1U(Rc_int, PJ1Array, Index) \
   Rc_int = Judy1Unset(&PJ1Array, Index, PJE0)

Judy1Test(PJ1Array, Index, &JError)
#define J1T(Rc_int, PJ1Array, Index) \
   Rc_int = Judy1Test(PJ1Array, Index, PJE0)

Judy1Count(PJ1Array, Index1, Index2, &JError)
#define J1C(Rc_word, PJ1Array, Index1, Index2) \
   Rc_word = Judy1Count(PJ1Array, Index1, Index2, PJE0)

A return value of 0 can be an error, valid as a count, or it can indicate a special case for a fully-populated array (32-bit machines only). If necessary, the following code can be used to disambiguate this return:
JError_t JError;

Rc_word = Judy1Count(PJ1Array, Index1, Index2, &JError);
if (Rc_word == 0)
{
    if (JU_ERRNO(&JError) == JU_ERRNO_NONE)
        printf("Judy1 array population == 0\n");
    if (JU_ERRNO(&JError) == JU_ERRNO_FULL)
        printf("Judy1 array population == 2^32\n");
    if (JU_ERRNO(&JError) == JU_ERRNO_NULLPPARRAY)
        goto NullArray;
    if (JU_ERRNO(&JError) >  JU_ERRNO_NFMAX)
        goto Null_or_CorruptArray;
}

Judy1ByCount(PJ1Array, Nth, &Index, &JError)
#define J1BC(Rc_int, PJ1Array, Nth, Index) \
   Rc_int = Judy1ByCount(PJ1Array, Nth, &Index, PJE0)

Judy1FreeArray(&PJ1Array, &JError)
#define J1FA(Rc_word, PJ1Array) \
   Rc_word = Judy1FreeArray(&PJ1Array, PJE0)

Judy1MemUsed(PJ1Array)
#define J1MU(Rc_word, PJ1Array) \
   Rc_word = Judy1MemUsed(PJ1Array)

Judy1First(PJ1Array, &Index, &JError)
#define J1F(Rc_int, PJ1Array, Index) \
   Rc_int = Judy1First(PJ1Array, &Index, PJE0)

Judy1Next(PJ1Array, &Index, &JError)
#define J1N(Rc_int, PJ1Array, Index) \
   Rc_int = Judy1Next(PJ1Array, &Index, PJE0)

Judy1Last(PJ1Array, &Index, &JError)
#define J1L(Rc_int, PJ1Array, Index) \
   Rc_int = Judy1Last(PJ1Array, &Index, PJE0)

Judy1Prev(PJ1Array, &Index, &JError)
#define J1P(Rc_int, PJ1Array, Index) \
   Rc_int = Judy1Prev(PJ1Array, &Index, PJE0)

Judy1FirstEmpty(PJ1Array, &Index, &JError)
#define J1FE(Rc_int, PJ1Array, Index) \
   Rc_int = Judy1FirstEmpty(PJ1Array, &Index, PJE0)

Judy1NextEmpty(PJ1Array, &Index, &JError)
#define J1NE(Rc_int, PJ1Array, Index) \
   Rc_int = Judy1NextEmpty(PJ1Array, &Index, PJE0)

Judy1LastEmpty(PJ1Array, &Index, &JError)
#define J1LE(Rc_int, PJ1Array, Index) \
   Rc_int = Judy1LastEmpty(PJ1Array, &Index, PJE0)

Judy1PrevEmpty(PJ1Array, &Index, &JError)
#define J1PE(Rc_int, PJ1Array, Index) \
   Rc_int = Judy1PrevEmpty(PJ1Array, &Index, PJE0)

Definitions for all of the Judy functions, the types Pvoid_t, Pcvoid_t, PPvoid_t, Word_t, JError_t, and PJError_t, the constants NULL, JU_ERRNO_*, JERR, and PJE0, are provided in the Judy.h header file (/usr/include/Judy.h). Note: Callers should define Judy1 arrays as type Pvoid_t, which can be passed by value to functions that take Pcvoid_t (constant Pvoid_t), and also by address to functions that take PPvoid_t.

AUTHOR
Judy was invented by Doug Baskins and implemented by Hewlett-Packard.

SEE ALSO
Judy(3), JudyL(3), JudySL(3), JudyHS(3),
malloc(),
the Judy website, http://judy.sourceforge.net, for more information and Application Notes.
judy-1.0.5/doc/ext/Judy_3.htm0000644000175000017500000002701210204462077016134 0ustar troyhebetroyhebe Judy(3)
Judy(3) Judy(3)

NAME
Judy arrays - C library functions for creating and accessing dynamic arrays

SYNOPSIS
Judy1  - maps an Index (word) to a bit
JudyL  - maps an Index (word) to a Value (word/pointer)
JudySL - maps an Index (null terminated string) to a Value
JudyHS - maps an Index (array-of-bytes) of Length to a Value

DESCRIPTION
The Judy family of functions supports fully dynamic arrays. These arrays may be indexed by a 32- or 64-bit word (depending on processor word size), a null terminated string or an array-of-bytes plus length. A dynamic array (sparsely populated) can also be thought of as a mapping function or associative memory.

A Word_t is a typedef unsigned long int in Judy.h and must be the same size as sizeof(void *) I.E. a pointer.

Judy1 functions: Index is a Word_t and Value is just a bit or simply a flag that Index is present or missing from the array. This can be thought of as a huge bitmap.

JudyL functions: Index is a Word_t and Value is a Word_t. This makes JudyL a pure word-to-word/pointer mapper. JudySL and JudyHL are based on this property of JudyL.

JudySL functions: Index is a null-terminated string and Value is a Word_t.

JudyHS functions: Index is an array-of-bytes of length: Length. Value is a Word_t. This new addition (May 2004) to Judy is a hybird using the best features of hashing and Judy methods. The author believes JudyHS is a good replacement for a hashing method when resizing the hash table is done during population growth. A correctly tuned hash method with a static hash table size and population is unbeatable for speed. However, JudyHS will perform better than a hashing method with smaller and larger populations than the optimum hash table size. JudyHS does not have a degenerate performance case where knowledge of the hash algorithm can be exploited. (I.E. JudyHS does not use a linked list to handle hash collisions, it uses a tree of JudyL arrays and a virtual hash table size of 4 billion).

Judy arrays are both speed- and memory-efficient, with no tuning or configuration required, across a wide range of index set types (sequential, periodic, clustered, random). Judy's speed and memory usage are typically better than other data storage models such as skiplists, linked lists, binary, ternary, b-trees, or even hashing, and improves with very large data sets.

A Judy array is created merely by defining a null pointer and then storing (inserting) the first element into the array under that pointer. The memory used by a Judy array is nearly proportional to the population (number of elements).

Judy has two Application Program Interfaces (APIs): a C macro interface, and a function call interface. Because the macro forms are sometimes faster and have a simpler error handling interface than the equivalent functions, they are the preferred way of using the Judy functions.

Since an initial (empty) Judy array is represented by a null pointer, it is possible to construct an array of Judy arrays. In other words, a Judy array's Values (except Judy1) can be pointers to other Judy arrays. This makes it very simple to construct an array with an arbitrary number of dimensions or Index sizes. (JudySL and JudyHS are implemented using JudyL this way).

A 10 MINUTE TECHNICAL DESCRIPTION
may be found at http://judy.sourceforge.net/downloads/10minutes.htm

A 3 HOUR TECHNICAL DESCRIPTION (out of date and a bit corny)
may be found at http://judy.sourceforge.net/application/shop_interm.pdf

DOWNLOADS
Judy source downloads are available at http://sourceforge.net/projects/judy
Binarys may be built and installed in a minute or two after downloading

For versions including more platforms and/or new features see: http://judy.sourceforge.net/downloads/

AUTHOR
Judy was invented by Doug Baskins (dougbaskins .AT, yahoo.com) and implemented by Hewlett-Packard. (Note: Judy is named for the inventor's sister, after discarding many proposed names.)

FILES
Locations of interest include:
http://sourceforge.net/projects/judy -- project downloads
file:/usr/share/doc/Judy/ -- for HTML version of man pages.
/usr/share/doc/Judy/demo/ -- demonstration program source files.

The author attempted to write interesting application notes using advanced features of Judy. They may be found at "http://judy.sourceforge.net/application/ (Some may be out of date).

ERRORS
A lot of thought (and time) went into making error handling in Judy simple, while maintaining flexibility and capability. Error handling is a very boring subject even to write about. So read this short section and use the recommended second method. It generates the fastest code, uses the least amount of memory and requires you to write extra code only for insert/deletes functions. Also it is compatible with the other two methods. This method is for production code that may want to handle malloc() fails differently than the Judy default. If the Judy default method of handling malloc() fails are OK, then use the first method.

There are two (2) categories of Judy error returns, (or for any dynamic ADT):

1) User programming errors (bugs) such as memory corruption or invalid pointers.
2) Out-of-memory (malloc() failure) with Insert (Set) or Delete (Unset) when modifying a Judy array. Not all calls to insert and delete call malloc(), so they may succeed even when a call to malloc() would fail.

There are roughly three (3) methods of handling errors when using the macros:

1) Default Error Handling Method
The default is to print error messages to stderr, for example:

File 'YourCfile.c', line 1234: JudyLIns(), JU_ERRNO_* == 2, ID == 321
This indicates that an error occurred in the JudyLIns() function at line 321. Line 1234 is the line in 'YourCfile.c' where the JLI() call failed. JU_ERRNO_* == 2 is equal to JU_ERRNO_NOMEM (as defined in the Judy.h file). The ID number indicates the source line number in the function where the error originated. Your program then terminates with an exit(1);. By default, both categories of Judy error returns are printed this way. (The 'ID == 321' is for die hards that want more detail or for debugging Judy itself.)

2) Disable Macro Error Handling
When your program is "bug free", the only errors returned should be malloc() failures. Therefore all error returns can be treated as a malloc() failure. By using the below #define, all error testing and printing is turned off. Additional code needs to be added to the code that can have malloc() failures. Judy was designed to leave the same data in the array before the call if a malloc() fail occurs. (During testing of Judy, we found very few malloc()/OS's that were bug free after a malloc() failure. Sometimes it took weeks to discover because most systems go into a paging frenzy before running out of memory).
#define JUDYERROR_NOTEST 1
(in your program code), or
cc -DJUDYERROR_NOTEST sourcefile -lJudy
(on your command line).
// This is an example of how to program using method two (2).
    
JLI(PValue, PLArray, Index);
if (PValue == PJERR) goto out_of_memory_handling;
...

JLD(RC_int, PLArray, Index);
if (RC_int == JERR) goto out_of_memory_handling;
...

J1S(RC_int, P1Array, Index);
if (RC_int == JERR) goto out_of_memory_handling;
...

J1U(RC_int, P1Array, Index);
if (RC_int == JERR) goto out_of_memory_handling;
...

Note: Without 'JUDYERROR_NOTEST' defined, the 'goto out_of_memory_handling' will never be executed and will be optimized out by the compiler. The default method will be used -- Macro will print error information if an error occurs as explained above.

With 'JUDYERROR_NOTEST' defined, the 'goto out_of_memory_handling' will be executed when an error occurs -- which should only happen when malloc() fails.

3) User-Specified JUDYERROR() Macro Method
The JUDYERROR() macro (in Judy.h) provides flexibility for handling error returns as needed to suit your program while still using the Judy array macros instead of function calls. You can use a different JUDYERROR() macro to suit your needs. The following example is a possible alternative to the default. It is used to distinguish between the two types of errors (described above), and explicitly test for the remaining JU_ERRNO_NOMEM errors possible in your program.

// This is an example of Judy macro API to continue when out of memory 
// and print and exit(1) when any other error occurs.

#ifndef JUDYERROR_NOTEST
#include <stdio.h>  // needed for fprintf()

// This is the macro that the Judy macro APIs use for return codes of -1:

#define JUDYERROR(CallerFile, CallerLine, JudyFunc, JudyErrno, JudyErrID) \
{                                                                         \
    if ((JudyErrno) != JU_ERRNO_NOMEM) /* ! a malloc() failure */         \
    {                                                                     \
        (void) fprintf(stderr, "File '%s', line %d: %s(), "               \
            "JU_ERRNO_* == %d, ID == %d\n",                               \
            CallerFile, CallerLine,                                       \
            JudyFunc, JudyErrno, JudyErrID);                              \
        exit(1);                                                          \
    }                                                                     \
}
#endif // JUDYERROR_NOTEST not defined

This error handling macro must be included before the #include <Judy.h> statement in your program.

SEE ALSO
Judy1(3), JudyL(3), JudySL(3), JudyHS(3) judy-1.0.5/doc/ext/Judy1_3.htm0000644000175000017500000003151410204462077016217 0ustar troyhebetroyhebe Judy1(3)
Judy1(3) Judy1(3)

NAME
Judy1 macros - C library for creating and accessing a dynamic array of bits, using any value of a word as an index.

SYNOPSIS
cc [flags] sourcefiles -lJudy

#include <Judy.h>

int     Rc_int;                          // return code - integer
Word_t  Rc_word;                         // return code - unsigned word
Word_t  Index, Index1, Index2, Nth;

Pvoid_t PJ1Array = (Pvoid_t) NULL;       // initialize Judy1 array

J1S( Rc_int,  PJ1Array, Index);          // Judy1Set()
J1U( Rc_int,  PJ1Array, Index);          // Judy1Unset()
J1T( Rc_int,  PJ1Array, Index);          // Judy1Test()
J1C( Rc_word, PJ1Array, Index1, Index2); // Judy1Count()
J1BC(Rc_int,  PJ1Array, Nth, Index);     // Judy1ByCount()
J1FA(Rc_word, PJ1Array);                 // Judy1FreeArray()
J1MU(Rc_word, PJ1Array);                 // Judy1MemUsed()
J1F( Rc_int,  PJ1Array, Index);          // Judy1First()
J1N( Rc_int,  PJ1Array, Index);          // Judy1Next()
J1L( Rc_int,  PJ1Array, Index);          // Judy1Last()
J1P( Rc_int,  PJ1Array, Index);          // Judy1Prev()
J1FE(Rc_int,  PJ1Array, Index);          // Judy1FirstEmpty()
J1NE(Rc_int,  PJ1Array, Index);          // Judy1NextEmpty()
J1LE(Rc_int,  PJ1Array, Index);          // Judy1LastEmpty()
J1PE(Rc_int,  PJ1Array, Index);          // Judy1PrevEmpty()

DESCRIPTION
A Judy1 array is the equivalent of a bit array or bit map. A bit is addressed by an Index (key). The array may be sparse, and the Index may be any word-sized Value. If an index is present, it represents a set bit (a bit set represents an index present). If an index is absent, it represents an unset bit (a bit unset represents an absent index).

A Judy1 array is allocated with a NULL pointer

Pvoid_t PJ1Array = (Pvoid_t) NULL;
Memory to support the array is allocated as bits are set, and released as bits are unset. If the Judy1 pointer (PJ1Array) is NULL, all bits are unset (and the Judy1 array requires no memory).

As with an ordinary array, a Judy1 array contains no duplicate indexes.

Using the macros described here, rather than the Judy1 function calls, the default error handling sends a message to the standard error and terminates the program with exit(1). For other error handling methods, see the ERRORS section.

Because the macro forms are sometimes faster and have a simpler error handling interface than the equivalent functions, they are the preferred way of calling the Judy1 functions.

J1S(Rc_int, PJ1Array, Index); // Judy1Set()
Set Index's bit in the Judy1 array PJ1Array.

Return Rc_int set to 1 if Index's bit was previously unset (successful), otherwise 0 if the bit was already set (unsuccessful).

J1U(Rc_int, PJ1Array, Index); // Judy1Unset()
Unset Index's bit in the Judy1 array PJ1Array; that is, remove Index from the Judy1 array.

Return Rc_int set to 1 if Index's bit was previously set (successful), otherwise 0 if the bit was already unset (unsuccessful).

J1T(Rc_int, PJ1Array, Index); // Judy1Test()
Test if Index's bit is set in the Judy1 array PJ1Array.

Return Rc_int set to 1 if Index's bit is set (Index is present), 0 if it is unset (Index is absent).

J1C(Rc_word, PJ1Array, Index1, Index2); // Judy1Count()
Count the number of indexes present in the Judy1 array PJ1Array between Index1 and Index2 (inclusive).

Return Rc_word set to the count. A return Value of 0 can be valid as a count, or it can indicate a special case for fully populated array (32-bit machines only). See Judy1Count() for ways to resolve this.

To count all indexes present (population) in a Judy1 bit array, use:

J1C(Rc_word, PJ1Array, 0, -1);
Note: The -1 promotes to the maximum index, that is, all ones.

J1BC(Rc_int, PJ1Array, Nth, Index); // Judy1ByCount()
Locate the Nth index that is present in the Judy1 array PJ1Array (Nth = 1 returns the first index present). To refer to the last index in a fully populated array (all indexes present, which is rare), use Nth = 0.

Return Rc_int set to 1 and Index set to the Nth index if found, otherwise return Rc_int set to 0 (the Value of Index contains no useful information).

J1FA(Rc_word, PJ1Array); // Judy1FreeArray()
Free the entire Judy1 array PJ1Array (much faster than using a J1N(), J1U() loop).

Return Rc_word set to the number of bytes freed, and PJ1Array set to NULL.

J1MU(Rc_word, PJ1Array); // Judy1MemUsed()
Return Rc_word set to the number of bytes of memory currently in use by Judy1 array PJ1Array. This is a very fast routine, and may be used after a J1S() or J1U() call with little performance impact.

Judy1 Search Functions
The Judy1 search functions allow you to search for set or unset bits in the array. You may search inclusively or exclusively, in either forward or reverse directions. All of the search functions use a similar calling sequence. Rc_int is returned set to 1 for a successful search and the found Index is returned. Rc_int is returned set to 0 for an unsuccessful search, and Index contains no useful information. The return code Rc_int must be checked prior to using the returned Index, since a search failure is possible.

J1F(Rc_int, PJ1Array, Index); // Judy1First()
Search (inclusive) for the first index present that is equal to or greater than the passed Index. (Start with Index = 0 to find the first index in the array.) J1F() is typically used to begin a sorted-order scan of the indexes present in a Judy1 array.

J1N(Rc_int, PJ1Array, Index); // Judy1Next()
Search (exclusive) for the next index present that is greater than the passed Index. J1N() is typically used to continue a sorted-order scan of the indexes present in a Judy1 array, or to locate a "neighbor" of a given index.

J1L(Rc_int, PJ1Array, Index); // Judy1Last()
Search (inclusive) for the last index present that is equal to or less than the passed Index. (Start with Index = -1, that is, all ones, to find the last index in the array.) J1L() is typically used to begin a reverse-sorted-order scan of the indexes present in a Judy1 array.

J1P(Rc_int, PJ1Array, Index); // Judy1Prev()
Search (exclusive) for the previous index present that is less than the passed Index. J1P() is typically used to continue a reverse-sorted-order scan of the indexes present in a Judy1 array, or to locate a "neighbor" of a given index.

J1FE(Rc_int, PJ1Array, Index); // Judy1FirstEmpty()
Search (inclusive) for the first absent index that is equal to or greater than the passed Index. (Start with Index = 0 to find the first index absent in the array.)

J1NE(Rc_int, PJ1Array, Index); // Judy1NextEmpty()
Search (exclusive) for the next absent index that is greater than the passed Index.

J1LE(Rc_int, PJ1Array, Index); // Judy1LastEmpty()
Search (inclusive) for the last absent index that is equal to or less than the passed Index. (Start with Index = -1 to find the last index absent in the array.)

J1PE(Rc_int, PJ1Array, Index); // Judy1PrevEmpty()
Search (exclusive) for the previous absent index that is less than the passed Index.

ERRORS: See: Judy_3.htm#ERRORS

EXAMPLE
In the following example, errors in the J1S() or J1U() calls go to a user-defined procedure, process_malloc_failure. This is not needed when you use the default JUDYERROR() macro, since the default causes your program to exit on all failures, including malloc() failure.

#include <stdio.h>
#include <Judy.h>

int main()                       // Example program of Judy1 macro APIs
{
   Word_t Index;                 // index (or key)
   Word_t Rcount;                // count of indexes (or bits set)
   Word_t Rc_word;               // full word return value
   int    Rc_int;                // boolean values returned (0 or 1)

   Pvoid_t PJ1Array = (Pvoid_t) NULL; // initialize Judy1 array

   Index = 123456;
   J1S(Rc_int, J1Array, Index);  // set bit at 123456
   if (Rc_int == JERR) goto process_malloc_failure;
   if (Rc_int == 1) printf("OK - bit successfully set at %lu\n", Index);
   if (Rc_int == 0) printf("BUG - bit already set at %lu\n", Index);

   Index = 654321;
   J1T(Rc_int, J1Array, Index);  // test if bit set at 654321
   if (Rc_int == 1) printf("BUG - set bit at %lu\n", Index);
   if (Rc_int == 0) printf("OK - bit not set at %lu\n", Index);

   J1C(Rcount, J1Array, 0, -1);  // count all bits set in array
   printf("%lu bits set in Judy1 array\n", Rcount);

   Index = 0;
   J1F(Rc_int, J1Array, Index);  // find first bit set in array
   if (Rc_int == 1) printf("OK - first bit set is at %lu\n", Index);
   if (Rc_int == 0) printf("BUG - no bits set in array\n");

   J1MU(Rc_word, J1Array);       // how much memory was used?
   printf("%lu Indexes used %lu bytes of memory\n", Rcount, Rc_word);

   Index = 123456;
   J1U(Rc_int, J1Array, Index);  // unset bit at 123456
   if (Rc_int == JERR) goto process_malloc_failure;
   if (Rc_int == 1) printf("OK - bit successfully unset at %lu\n", Index);
   if (Rc_int == 0) printf("BUG - bit was not set at %lu\n", Index);

   return(0);
}

AUTHOR
Judy was invented by Doug Baskins and implemented by Hewlett-Packard.

SEE ALSO
Judy(3), JudyL(3), JudySL(3), JudyHS(3),
malloc(),
the Judy website, http://judy.sourceforge.net, for more information and Application Notes.
judy-1.0.5/doc/ext/COPYRIGHT0000644000175000017500000000000010204462077015544 0ustar troyhebetroyhebejudy-1.0.5/doc/ext/JudyHS_funcs_3.htm0000644000175000017500000001137110204462077017566 0ustar troyhebetroyhebe JudyHS_funcs(3)
JudyHS_funcs(3) JudyHS_funcs(3)

NAME
JudyHS functions - C library for creating and accessing a dynamic array, using an array-of-bytes of a length: Length as an Index and a word as a Value.

SYNOPSIS
PPvoid_t JudyHSIns(PPvoid_t PPJHS, void *Index, Word_t Length, PJError_t PJError);
int      JudyHSDel(PPvoid_t PPJHS, void *Index, Word_t Length, PJError_t PJError);
PPvoid_t JudyHSGet(Pcvoid_t  PJHS, void *Index, Word_t Length, PJError_t PJError);
Word_t   JudyHSFreeArray(PPvoid_t PPJHS, PJError_t PJError);

DESCRIPTION
A macro equivalent exists for each function call. Because the macro forms are sometimes faster and have a simpler error handling interface than the equivalent functions, they are the preferred way of calling the JudyHS functions. See JudyHS(3) for more information. The function call definitions are included here for completeness.

One of the difficulties in using the JudyHS function calls lies in determining whether to pass a pointer or the address of a pointer. Since the functions that modify the JudyHS array must also modify the pointer to the JudyHS array, you must pass the address of the pointer rather than the pointer itself. This often leads to hard-to-debug programmatic errors. In practice, the macros allow the compiler to catch programming errors when pointers instead of addresses of pointers are passed.

The JudyHS function calls have an additional parameter beyond those specified in the macro calls. This parameter is either a pointer to an error structure, or NULL (in which case the error information is not returned -- only PJERR in the return parameter).

In the following descriptions, the functions are described in terms of how the macros use them. This is the suggested use of the macros after your program has been fully debugged. When the JUDYERROR_NOTEST macro is not specified, an error structure is declared to store error information returned from the JudyHS functions when an error occurs.

Notice the placement of the & in the different functions.

JudyHSIns(&PJHS, Index, Length, &JError)
#define JHSI(PValue, PJHS, Index) \
   PValue = JudyLIns(&PJHS, Index, PJE0)

JudyHSDel(&PJHS, Index, Length, &JError)
#define JHSD(Rc_int, PJHS, Index, Length) \
   Rc_int = JudyHSDel(&PJHS, Index, Length, PJE0)

JudyHSGet(PJHS, Index, Length)
#define JHSG(PValue, PJHS, Index, Length) \
   PValue = JudyHSIns(PJHS, Index, Length)

JudyHSFreeArray(&PJHS, &JError)
#define JHSFA(Rc_word, PJHS) \
   Rc_word = JudyHSFreeArray(&PJHS, PJE0)

Definitions for all the Judy functions, the types Pvoid_t, Pcvoid_t, PPvoid_t, Word_t , JError_t, and PJError_t, the constants NULL, JU_ERRNO_*, JERR, PPJERR, and PJE0 are provided in the Judy.h header file (/usr/include/Judy.h). Note: Callers should define JudyHS arrays as type Pvoid_t, which can be passed by value to functions that take Pcvoid_t (constant Pvoid_t), and also by address to functions that take PPvoid_t.

The return type from most JudyHS functions is PPvoid_t so that the values stored in the array can be pointers to other objects, which is a typical usage, or cast to a Word_t * when a pointer to a value is required instead of a pointer to a pointer.

AUTHOR
JudyHS was invented and implemented by Doug Baskins after retiring from Hewlett-Packard.

SEE ALSO
Judy(3), Judy1(3), JudyL(3), JudySL(3), JudyHS(3),
malloc(),
the Judy website, http://judy.sourceforge.net, for more information and Application Notes.
judy-1.0.5/doc/ext/JudyL_funcs_3.htm0000644000175000017500000002013710204462077017447 0ustar troyhebetroyhebe JudyL_funcs(3)
JudyL_funcs(3) JudyL_funcs(3)

NAME
JudyL functions - C library for creating and accessing a dynamic array of words, using any value of a word as an index

SYNOPSIS
PPvoid_t JudyLIns(       PPvoid_t PPJLArray, Word_t    Index, PJError_t PJError);
int      JudyLDel(       PPvoid_t PPJLArray, Word_t    Index, PJError_t PJError);
PPvoid_t JudyLGet(       Pcvoid_t  PJLArray, Word_t    Index, PJError_t PJError);
Word_t   JudyLCount(     Pcvoid_t  PJLArray, Word_t    Index1, Word_t    Index2, PJError_t PJError);
PPvoid_t JudyLByCount(   Pcvoid_t  PJLArray, Word_t    Nth,  Word_t * PIndex,  PJError_t PJError);
Word_t   JudyLFreeArray( PPvoid_t PPJLArray, PJError_t PJError);
Word_t   JudyLMemUsed(   Pcvoid_t  PJLArray);
PPvoid_t JudyLFirst(     Pcvoid_t  PJLArray, Word_t * PIndex, PJError_t PJError);
PPvoid_t JudyLNext(      Pcvoid_t  PJLArray, Word_t * PIndex, PJError_t PJError);
PPvoid_t JudyLLast(      Pcvoid_t  PJLArray, Word_t * PIndex, PJError_t PJError);
PPvoid_t JudyLPrev(      Pcvoid_t  PJLArray, Word_t * PIndex, PJError_t PJError);
int      JudyLFirstEmpty(Pcvoid_t  PJLArray, Word_t * PIndex, PJError_t PJError);
int      JudyLNextEmpty( Pcvoid_t  PJLArray, Word_t * PIndex, PJError_t PJError);
int      JudyLLastEmpty( Pcvoid_t  PJLArray, Word_t * PIndex, PJError_t PJError);
int      JudyLPrevEmpty( Pcvoid_t  PJLArray, Word_t * PIndex, PJError_t PJError);

DESCRIPTION
A macro equivalent exists for each function call. Because the macro forms are sometimes faster and have a simpler error handling interface than the equivalent functions, they are the preferred way of calling the JudyL functions. See JudyL(3) for more information. The function call definitions are included here for completeness.

One of the difficulties in using the JudyL function calls lies in determining whether to pass a pointer or the address of a pointer. Since the functions that modify the JudyL array must also modify the pointer to the JudyL array, you must pass the address of the pointer rather than the pointer itself. This often leads to hard-to-debug programmatic errors. In practice, the macros allow the compiler to catch programming errors when pointers instead of addresses of pointers are passed.

The JudyL function calls have an additional parameter beyond those specified in the macro calls. This parameter is either a pointer to an error structure, or NULL (in which case the detailed error information is not returned).

In the following descriptions, the functions are described in terms of how the macros use them (only in the case of #define JUDYERROR_NOTEST 1). This is the suggested use of the macros after your program has been fully debugged. When the JUDYERROR_NOTEST macro is not specified, an error structure is declared to store error information returned from the JudyL functions when an error occurs.

Notice the placement of the & in the different functions.

JudyLIns(&PJLArray, Index, &JError)
#define JLI(PValue, PJLArray, Index)  \
   PValue = JudyLIns(&PJLArray, Index, PJE0)

JudyLDel(&PJLArray, Index, &JError)
#define JLD(Rc_int, PJLArray, Index)  \
   Rc_int = JudyLDel(&PJLArray, Index, PJE0)

JudyLGet(PJLArray, Index, &JError)
#define JLG(PValue, PJLArray, Index)  \
   PValue = JudyLGet(PJLArray, Index, PJE0)

JudyLCount(PJLArray, Index1, Index2, &JError)
#define JLC(Rc_word, PJLArray, Index1, Index2)  \
   Rc_word = JudyLCount(PJLArray, Index1, Index2, PJE0)

JudyLByCount(PJLArray, Nth, &Index, &JError)
#define JLBC(PValue, PJLArray, Nth, Index) \
   PValue = JudyLByCount(PJLArray, Nth, &Index, PJE0)

JudyLFreeArray(&PJLArray, &JError)
#define JLFA(Rc_word, PJLArray) \
   Rc_word = JudyLFreeArray(&PJLArray, PJE0)

JudyLMemUsed(PJLArray)
#define JLMU(Rc_word, PJLArray) \
   Rc_word = JudyLMemUsed(PJLArray)

JudyLFirst(PJLArray, &Index, &JError)
#define JLF(PValue, PJLArray, Index) \
   PValue = JudyLFirst(PJLArray, &Index, PJEO)

JudyLNext(PJLArray, &Index, &JError)
#define JLN(PValue, PJLArray, Index) \
   PValue = JudyLNext(PJLArray, &Index, PJEO)

JudyLLast(PJLArray, &Index, &JError)
#define JLL(PValue, PJLArray, Index) \
   PValue = JudyLLast(PJLArray, &Index, PJEO)

JudyLPrev(PJLArray, &Index, &JError)
#define JLP(PValue, PJLArray, Index) \
   PValue = JudyLPrev(PJLArray, &Index, PJEO)

JudyLFirstEmpty(PJLArray, &Index, &JError)
#define JLFE(Rc_int, PJLArray, Index) \
   Rc_int = JudyLFirstEmpty(PJLArray, &Index, PJEO)

JudyLNextEmpty(PJLArray, &Index, &JError)
#define JLNE(Rc_int, PJLArray, Index) \
   Rc_int = JudyLNextEmpty(PJLArray, &Index, PJEO)

JudyLLastEmpty(PJLArray, &Index, &JError)
#define JLLE(Rc_int, PJLArray, Index) \
   Rc_int = JudyLLastEmpty(PJLArray, &Index, PJEO)

JudyLPrevEmpty(PJLArray, &Index, &JError)
#define JLPE(Rc_int, PJLArray, Index) \
   Rc_int = JudyLPrevEmpty(PJLArray, &Index, PJEO)

Definitions for all the Judy functions, the types Pvoid_t, Pcvoid_t, PPvoid_t, Word_t, JError_t, and PJError_t, the constants NULL, JU_ERRNO_*, JERR, PPJERR, and PJE0, are provided in the Judy.h header file (/usr/include/Judy.h). Note: Callers should define JudyL arrays as type Pvoid_t, which can be passed by value to functions that take Pcvoid_t (constant Pvoid_t), and also by address to functions that take PPvoid_t.

The return type from most JudyL functions is PPvoid_t so that the values stored in the array can be pointers to other objects, which is a typical usage, or cast to a Word_t * when a pointer to a Value is required instead of a pointer to a pointer.

AUTHOR
Judy was invented by Doug Baskins and implemented by Hewlett-Packard.

SEE ALSO
Judy(3), Judy1(3), JudyL(3), JudySL(3), JudyHS(3),
malloc(),
the Judy website, http://judy.sourceforge.net, for more information and Application Notes.
judy-1.0.5/doc/int/0000755000175000017500000000000010624600177014256 5ustar troyhebetroyhebejudy-1.0.5/doc/int/10minutes.htm0000644000175000017500000003145310204462077016622 0ustar troyhebetroyhebe A 10-MINUTE DESCRIPTION OF HOW JUDY ARRAYS WORK AND WHY THEY ARE SO FAST

A 10-MINUTE DESCRIPTION OF HOW JUDY ARRAYS WORK AND WHY THEY ARE SO FAST

By Doug Baskins, doug@sourcejudy.com

October 16, 2001, Revised July 2002

As the inventor of the Judy algorithm I've been asked repeatedly, "What makes Judy so fast?" The answer is not simple, but finally I can share all of the details. (In June 2002, Judy was opened sourced with a LGPL license and hosted at http://sourceforge.net/projects/judy Let's see if I can give you a good understanding in 10 minutes. (The Judy data structures are very well described in another paper, the Judy Shop Manual , but it took me about three hours to read!)

A Judy tree is generally faster than and uses less memory than contemporary forms of trees such as binary (AVL) trees, b-trees, and skip-lists. When used in the "Judy Scalable Hashing" configuration, Judy is generally faster then a hashing method at all populations. (See also http://www.sourcejudy.com/application/ Judy_hashing.

Expanse , population , and density are not commonly used terms in tree search literature, so let's define them here:

  • Expanse is a range of possible keys, such as: 256..511
  • Population is the count of keys contained in an expanse, such as, 260, 300, 499, 500 = 4.
  • Density is used to describe the sparseness of an expanse of keys; density = population / expanse. A density of 1.0 means that all possible keys are set or valid in that expanse.

Node and branch are used interchangeably in this document.

Key and index are used interchangeably. A Judy tree is thought of as an unbounded Judy array at the API level. The expanse of JudyL or Judy1 arrays are bounded by the expanse of the word (32[64]-bits) used for the index/key. A JudySL array is only bounded by the length of the key string that can be stored in the machine.

A (CPU) cache-line fill is additional time required to do a read reference from RAM when a word is not found in cache. In today's computers the time for a cache-line fill is in the range of 50..2000 machine instructions. Therefore a cache-line fill should be avoided when fewer than 50 instructions can do the same job. (Modern machines tend to pipeline writes to RAM. They often take no additional time in the Judy design.)

Some of the reasons Judy outperforms binary trees, b-trees, and skip-lists:

  • Judy rarely compromises speed/space performance for simplicity (Judy will never be called simple except at the API).
  • Judy is designed to avoid cache-line fills wherever possible. (This is the main design criteria for Judy.)
  • A b-tree requires a search of each node (branch), resulting in more cache-line fills.
  • A binary-tree has many more levels (about 8X), resulting in more cache-line fills.
  • A skip-list is roughly equivalent to a degree-4 (4-ary) tree, resulting in more cache-line fills.
  • An "expanse"-based digital tree (of which Judy is a variation) never needs balancing as it grows.
  • A portion (8 bits) of the key is used to subdivide an expanse into sub-trees. Only the remainder of the key need exist in the sub-trees, if at all, resulting in key compression.

The Achilles heel of a simple digital tree is very poor memory utilization, especially when the N in N-ary (the degree or fanout of each branch) increases. The Judy tree design was able to solve this problem. In fact a Judy tree is more memory-efficient than almost any other competitive structure (including a simple linked list). A highly populated linear array[] is the notable exception.

From a speed point of view Judy is chiefly a 256-ary digital tree or trie (per D. Knuth Volume 3 definitions). A degree of 256-ary is a somewhat "magic" N-ary for a variety of reasons -- mostly because a byte (the least addressable memory unit) is 8 bits. Also a higher degree means reduced cache-line fills per access. You see the theme here -- avoid cache-line fills like the plague.

It is interesting to note that an early version of Judy used branch widening (sometimes called a level-compressed trie). Branch widening opportunities occur primarily in the upper level(s) of the tree. Since a tree is a hierarchy, the upper branches are likely to be in cache, thus branch widening did not significantly reduce the number of actual cache-line fills. Branch widening was removed in later versions of Judy. (However, Judy was also tuned to use as few instructions as possible when an access was likely to be in the cache.)

The presence of a CPU cache in modern machines has changed many of the ways to write a performance algorithm. To take advantage of a cache, it is important to leverage as much as possible. In a Judy tree, the presence of a cache results in 1..3 (or more) fewer cache-line fills per access than would be possible without a cache.

As a digression, note that a hash method loses the advantages of a cache as the size of the hash table approaches or exceeds the size of the cache. With very large hash tables, the cache is no help at all. Also, hash methods often use a linked list to handle collisions (synonyms) and typically use a slow hash algorithm (greater than 50ns) or suffer from numerous collisions. "Judy Scalable Hashing" is an effective replacement for common hash methods when very high performance is required for small in-cache data sets. (See also http://www.sourcejudy.com/application/ Judy_hashing.

With an expanse of 2^32 (or 256^4), a maximum of 4 cache-line fills would be required for a worst-case highly populated 256-ary digital tree access. In an expanse of 2^64 (or 256^8), 8 cache-line fills would be the worst case. In practice, Judy does much better than this. The reason is (in part) due to the fact "density" of the keys is seldom the lowest possible number in a "majority" of the sub-expanses. It takes high density combined with high population to increase the depth of a Judy tree. It would take a long time to explain why. The short version is an analogy with sand. It takes a lot of sand to build a tall sand pile, especially if it takes 256 grains to support 1 grain above it. In a 64-bit Judy, it would probably require more RAM than exists on this planet to get it to have 8 levels. A binary tree reaches 8 levels with a population of 256. It is truly remarkable to me how much research has been done on binary trees and still being taught.

Judy adapts efficiently to a wide range of populations and data set densities. Since the Judy data structure is a tree of trees, each sub-tree is a static expanse that is optimized to match the "character" or density of the keys it contains. To support this flexibility, in 32[64]-bit Judy there are approximately 25[85] major data structures and a similar number of minor structures. I am going to only describe a few of them so you can infer how density is synergistic with compression.

From a memory consumption (size) point of view, a Judy tree shares (does not duplicate) common digits of a key in a tree. This form of key compression is a natural outcome from using a digital tree. This would be very awkward to do in trees balanced by population and, as far as I know, has never been done. Each pointer traversed in a Judy tree points to ever smaller sub-expanses, while decoding another 8 bits of the key. (In a pure digital tree, the keys are not stored in the tree, they are inferred by position.)

Now let me try to describe the top of a small Judy (JudyL) tree and the bottom of a highly populated Judy1 tree. A Judy tree with a population of zero is simply a NULL pointer. A JudyL tree with a population of one key is a root pointer to a 2-word object containing a key and and associated value. A JudyL tree with a population of 2 keys, is 4-word object with 2 values and 2 sorted keys. A tree with a population of 3 keys, is an 8-word object with a count word + 3 values and 3 sorted keys.

This continues until the population grows to 32 keys. At this point an actual tree structure is formed with a "compressed" 256-ary node (branch) that decodes the first byte of each key. The value 32 was chosen because this is where a tree structure requires an equivalent number of cache-line fills. All objects below this top branch contain keys that are shortened by at least the first byte.

There are three kinds of branches. Two are 1-cache-line fill objects to traverse, and one is a 2-cache-line fill object to traverse. In every path down the tree and at all populations, a maximum of one of the 2-cache-line fill branches is used. This means it is sometimes possible to have 1 additional (the branch design often subtracts 1) cache-line fill than you would expect from a pure 256-ary branch traversal in an otherwise complete Judy tree.

On the other extreme, a highly populated Judy1 tree where the key has been decoded down to 1 byte, and the density of a 256-wide sub-expanse of keys grows to greater than 0.094 (25 keys / 256 expanse), a bitmap of 32 bytes (256 bits) is formed from an existing sorted array of 24 1-byte keys. (I am leaving out the handling of the values.) This results in a key using about an average of 1.3 (32/25) bytes of memory (up from 1.0). Note that increasing the density (population) at this point does NOT require more memory for keys. For example, when the density reaches 0.5 (population = 128 / expanse = 256), the memory consumed is about 2 bits ((32/128)*8) per key + some overhead (2.0+ words) for the tree structure.

Notice that to insert or delete a key is almost as simple as setting or clearing a bit. Also notice, the memory consumption is almost the same for both 32- and 64-bit Judy trees. Given the same set of keys, both 32- and 64-bit Judy trees have remarkably similar key-memory, depth, and performance. However, the memory consumption for 64-bit Judy is higher because the pointers and values (JudyL) are double the size.

In this short writeup it wasn't possible to describe all the data structure details such as: Root, JPM, narrow and rich pointers, linear, bitmap and uncompressed branches, value areas, immediate indexes, terminal nodes (leafs), least compressed form, memory management, fast leaf searches and counting trees.

Well I cannot describe Judy in 10 minutes -- what possessed me? I hope you understand some of what I have said and question me on the rest -- particularly those doubts. I will try to elaborate on parts where I get questions.

Doug Baskins
doug@sourcejudy.com

judy-1.0.5/doc/man/0000755000175000017500000000000010624600177014237 5ustar troyhebetroyhebejudy-1.0.5/doc/man/man3/0000755000175000017500000000000010624600177015075 5ustar troyhebetroyhebejudy-1.0.5/doc/Makefile.am0000644000175000017500000001455210624600161015520 0ustar troyhebetroyhebeman3_MANS = man/man3/Judy \ man/man3/Judy1 \ man/man3/Judy1_funcs \ man/man3/JudyL \ man/man3/JudyL_funcs \ man/man3/JudySL \ man/man3/JudySL_funcs \ man/man3/JudyHS \ man/man3/JudyHS_funcs \ man/man3/J1T \ man/man3/J1S \ man/man3/J1U \ man/man3/J1F \ man/man3/J1N \ man/man3/J1L \ man/man3/J1P \ man/man3/J1FE \ man/man3/J1NE \ man/man3/J1LE \ man/man3/J1PE \ man/man3/J1C \ man/man3/J1BC \ man/man3/J1FA \ man/man3/J1MU \ man/man3/Judy1Test \ man/man3/Judy1Set \ man/man3/Judy1Unset \ man/man3/Judy1First \ man/man3/Judy1Next \ man/man3/Judy1Last \ man/man3/Judy1Prev \ man/man3/Judy1FirstEmpty \ man/man3/Judy1NextEmpty \ man/man3/Judy1LastEmpty \ man/man3/Judy1PrevEmpty \ man/man3/Judy1Count \ man/man3/Judy1ByCount \ man/man3/Judy1FreeArray \ man/man3/Judy1MemUsed \ man/man3/JudyL \ man/man3/JLG \ man/man3/JLI \ man/man3/JLD \ man/man3/JLF \ man/man3/JLN \ man/man3/JLL \ man/man3/JLP \ man/man3/JLFE \ man/man3/JLNE \ man/man3/JLLE \ man/man3/JLPE \ man/man3/JLC \ man/man3/JLBC \ man/man3/JLFA \ man/man3/JLMU \ man/man3/JudyLGet \ man/man3/JudyLIns \ man/man3/JudyLDel \ man/man3/JudyLFirst \ man/man3/JudyLNext \ man/man3/JudyLLast \ man/man3/JudyLPrev \ man/man3/JudyLFirstEmpty \ man/man3/JudyLNextEmpty \ man/man3/JudyLLastEmpty \ man/man3/JudyLPrevEmpty \ man/man3/JudyLCount \ man/man3/JudyLByCount \ man/man3/JudyLFreeArray \ man/man3/JudyLMemUsed \ man/man3/JSLG \ man/man3/JSLI \ man/man3/JSLD \ man/man3/JSLF \ man/man3/JSLN \ man/man3/JSLL \ man/man3/JSLP \ man/man3/JSLFA \ man/man3/JudySLGet \ man/man3/JudySLIns \ man/man3/JudySLDel \ man/man3/JudySLFirst \ man/man3/JudySLNext \ man/man3/JudySLLast \ man/man3/JudySLPrev \ man/man3/JudySLFreeArray \ man/man3/JHSG \ man/man3/JHSI \ man/man3/JHSD \ man/man3/JHSFA \ man/man3/JudyHSGet \ man/man3/JudyHSIns \ man/man3/JudyHSDel \ man/man3/JudyHSFreeArray man/man3/Judy: ../tool/jhton ext/Judy_3.htm | grep -v '^[ ]*$$' | sed -e 's/\.C//' > man/man3/Judy man/man3/Judy1: ../tool/jhton ext/Judy1_3.htm | grep -v '^[ ]*$$' | sed -e 's/\.C//' > man/man3/Judy1 cd man/man3; ln -s Judy J1T cd man/man3; ln -s Judy J1S cd man/man3; ln -s Judy J1U cd man/man3; ln -s Judy J1F cd man/man3; ln -s Judy J1N cd man/man3; ln -s Judy J1L cd man/man3; ln -s Judy J1P cd man/man3; ln -s Judy J1FE cd man/man3; ln -s Judy J1NE cd man/man3; ln -s Judy J1LE cd man/man3; ln -s Judy J1PE cd man/man3; ln -s Judy J1C cd man/man3; ln -s Judy J1BC cd man/man3; ln -s Judy J1FA cd man/man3; ln -s Judy J1MU man/man3/Judy1_funcs: ../tool/jhton ext/Judy1_funcs_3.htm | grep -v '^[ ]*$$' | sed -e 's/\.C//' > man/man3/Judy1_funcs cd man/man3; ln -s Judy1_funcs Judy1Test cd man/man3; ln -s Judy1_funcs Judy1Set cd man/man3; ln -s Judy1_funcs Judy1Unset cd man/man3; ln -s Judy1_funcs Judy1First cd man/man3; ln -s Judy1_funcs Judy1Next cd man/man3; ln -s Judy1_funcs Judy1Last cd man/man3; ln -s Judy1_funcs Judy1Prev cd man/man3; ln -s Judy1_funcs Judy1FirstEmpty cd man/man3; ln -s Judy1_funcs Judy1NextEmpty cd man/man3; ln -s Judy1_funcs Judy1LastEmpty cd man/man3; ln -s Judy1_funcs Judy1PrevEmpty cd man/man3; ln -s Judy1_funcs Judy1Count cd man/man3; ln -s Judy1_funcs Judy1ByCount cd man/man3; ln -s Judy1_funcs Judy1FreeArray cd man/man3; ln -s Judy1_funcs Judy1MemUsed man/man3/JudyL: ../tool/jhton ext/JudyL_3.htm | grep -v '^[ ]*$$' | sed -e 's/\.C//' > man/man3/JudyL cd man/man3; ln -s JudyL JLG cd man/man3; ln -s JudyL JLI cd man/man3; ln -s JudyL JLD cd man/man3; ln -s JudyL JLF cd man/man3; ln -s JudyL JLN cd man/man3; ln -s JudyL JLL cd man/man3; ln -s JudyL JLP cd man/man3; ln -s JudyL JLFE cd man/man3; ln -s JudyL JLNE cd man/man3; ln -s JudyL JLLE cd man/man3; ln -s JudyL JLPE cd man/man3; ln -s JudyL JLC cd man/man3; ln -s JudyL JLBC cd man/man3; ln -s JudyL JLFA cd man/man3; ln -s JudyL JLMU man/man3/JudyL_funcs: ../tool/jhton ext/JudyL_funcs_3.htm | grep -v '^[ ]*$$' | sed -e 's/\.C//' > man/man3/JudyL_funcs cd man/man3; ln -s JudyL_funcs JudyLGet cd man/man3; ln -s JudyL_funcs JudyLIns cd man/man3; ln -s JudyL_funcs JudyLDel cd man/man3; ln -s JudyL_funcs JudyLFirst cd man/man3; ln -s JudyL_funcs JudyLNext cd man/man3; ln -s JudyL_funcs JudyLLast cd man/man3; ln -s JudyL_funcs JudyLPrev cd man/man3; ln -s JudyL_funcs JudyLFirstEmpty cd man/man3; ln -s JudyL_funcs JudyLNextEmpty cd man/man3; ln -s JudyL_funcs JudyLLastEmpty cd man/man3; ln -s JudyL_funcs JudyLPrevEmpty cd man/man3; ln -s JudyL_funcs JudyLCount cd man/man3; ln -s JudyL_funcs JudyLByCount cd man/man3; ln -s JudyL_funcs JudyLFreeArray cd man/man3; ln -s JudyL_funcs JudyLMemUsed man/man3/JudySL: ../tool/jhton ext/JudySL_3.htm | grep -v '^[ ]*$$' | sed -e 's/\.C//' > man/man3/JudySL cd man/man3; ln -s JudySL JSLG cd man/man3; ln -s JudySL JSLI cd man/man3; ln -s JudySL JSLD cd man/man3; ln -s JudySL JSLF cd man/man3; ln -s JudySL JSLN cd man/man3; ln -s JudySL JSLL cd man/man3; ln -s JudySL JSLP cd man/man3; ln -s JudySL JSLFA man/man3/JudySL_funcs: ../tool/jhton ext/JudySL_funcs_3.htm | grep -v '^[ ]*$$' | sed -e 's/\.C//' > man/man3/JudySL_funcs cd man/man3; ln -s JudySL_funcs JudySLGet cd man/man3; ln -s JudySL_funcs JudySLIns cd man/man3; ln -s JudySL_funcs JudySLDel cd man/man3; ln -s JudySL_funcs JudySLFirst cd man/man3; ln -s JudySL_funcs JudySLNext cd man/man3; ln -s JudySL_funcs JudySLLast cd man/man3; ln -s JudySL_funcs JudySLPrev cd man/man3; ln -s JudySL_funcs JudySLFreeArray man/man3/JudyHS: ../tool/jhton ext/JudyHS_3.htm | grep -v '^[ ]*$$' | sed -e 's/\.C//' > man/man3/JudyHS cd man/man3; ln -s JudyHS JHSG cd man/man3; ln -s JudyHS JHSI cd man/man3; ln -s JudyHS JHSD cd man/man3; ln -s JudyHS JHSFA man/man3/JudyHS_funcs: ../tool/jhton ext/JudyHS_funcs_3.htm | grep -v '^[ ]*$$' | sed -e 's/\.C//' > man/man3/JudyHS_funcs cd man/man3; ln -s JudyHS_funcs JudyHSGet cd man/man3; ln -s JudyHS_funcs JudyHSIns cd man/man3; ln -s JudyHS_funcs JudyHSDel cd man/man3; ln -s JudyHS_funcs JudyHSFreeArray CLEANFILES = man/man3/* judy-1.0.5/doc/Makefile.in0000644000175000017500000004120210624600215015521 0ustar troyhebetroyhebe# Makefile.in generated by automake 1.9.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ top_builddir = .. am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd INSTALL = @INSTALL@ install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = doc DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = SOURCES = DIST_SOURCES = man3dir = $(mandir)/man3 am__installdirs = "$(DESTDIR)$(man3dir)" NROFF = nroff MANS = $(man3_MANS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMDEP_FALSE = @AMDEP_FALSE@ AMDEP_TRUE = @AMDEP_TRUE@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO = @ECHO@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ F77 = @F77@ FFLAGS = @FFLAGS@ FLAVOR = @FLAVOR@ GREP = @GREP@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ MAKEINFO = @MAKEINFO@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ VERSION_INFO = @VERSION_INFO@ WARN_CFLAGS = @WARN_CFLAGS@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_F77 = @ac_ct_F77@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ man3_MANS = man/man3/Judy \ man/man3/Judy1 \ man/man3/Judy1_funcs \ man/man3/JudyL \ man/man3/JudyL_funcs \ man/man3/JudySL \ man/man3/JudySL_funcs \ man/man3/JudyHS \ man/man3/JudyHS_funcs \ man/man3/J1T \ man/man3/J1S \ man/man3/J1U \ man/man3/J1F \ man/man3/J1N \ man/man3/J1L \ man/man3/J1P \ man/man3/J1FE \ man/man3/J1NE \ man/man3/J1LE \ man/man3/J1PE \ man/man3/J1C \ man/man3/J1BC \ man/man3/J1FA \ man/man3/J1MU \ man/man3/Judy1Test \ man/man3/Judy1Set \ man/man3/Judy1Unset \ man/man3/Judy1First \ man/man3/Judy1Next \ man/man3/Judy1Last \ man/man3/Judy1Prev \ man/man3/Judy1FirstEmpty \ man/man3/Judy1NextEmpty \ man/man3/Judy1LastEmpty \ man/man3/Judy1PrevEmpty \ man/man3/Judy1Count \ man/man3/Judy1ByCount \ man/man3/Judy1FreeArray \ man/man3/Judy1MemUsed \ man/man3/JudyL \ man/man3/JLG \ man/man3/JLI \ man/man3/JLD \ man/man3/JLF \ man/man3/JLN \ man/man3/JLL \ man/man3/JLP \ man/man3/JLFE \ man/man3/JLNE \ man/man3/JLLE \ man/man3/JLPE \ man/man3/JLC \ man/man3/JLBC \ man/man3/JLFA \ man/man3/JLMU \ man/man3/JudyLGet \ man/man3/JudyLIns \ man/man3/JudyLDel \ man/man3/JudyLFirst \ man/man3/JudyLNext \ man/man3/JudyLLast \ man/man3/JudyLPrev \ man/man3/JudyLFirstEmpty \ man/man3/JudyLNextEmpty \ man/man3/JudyLLastEmpty \ man/man3/JudyLPrevEmpty \ man/man3/JudyLCount \ man/man3/JudyLByCount \ man/man3/JudyLFreeArray \ man/man3/JudyLMemUsed \ man/man3/JSLG \ man/man3/JSLI \ man/man3/JSLD \ man/man3/JSLF \ man/man3/JSLN \ man/man3/JSLL \ man/man3/JSLP \ man/man3/JSLFA \ man/man3/JudySLGet \ man/man3/JudySLIns \ man/man3/JudySLDel \ man/man3/JudySLFirst \ man/man3/JudySLNext \ man/man3/JudySLLast \ man/man3/JudySLPrev \ man/man3/JudySLFreeArray \ man/man3/JHSG \ man/man3/JHSI \ man/man3/JHSD \ man/man3/JHSFA \ man/man3/JudyHSGet \ man/man3/JudyHSIns \ man/man3/JudyHSDel \ man/man3/JudyHSFreeArray CLEANFILES = man/man3/* all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --gnu doc/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs distclean-libtool: -rm -f libtool uninstall-info-am: install-man3: $(man3_MANS) $(man_MANS) @$(NORMAL_INSTALL) test -z "$(man3dir)" || $(mkdir_p) "$(DESTDIR)$(man3dir)" @list='$(man3_MANS) $(dist_man3_MANS) $(nodist_man3_MANS)'; \ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ for i in $$l2; do \ case "$$i" in \ *.3*) list="$$list $$i" ;; \ esac; \ done; \ for i in $$list; do \ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ else file=$$i; fi; \ ext=`echo $$i | sed -e 's/^.*\\.//'`; \ case "$$ext" in \ 3*) ;; \ *) ext='3' ;; \ esac; \ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ inst=`echo $$inst | sed -e 's/^.*\///'`; \ inst=`echo $$inst | sed '$(transform)'`.$$ext; \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man3dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man3dir)/$$inst"; \ done uninstall-man3: @$(NORMAL_UNINSTALL) @list='$(man3_MANS) $(dist_man3_MANS) $(nodist_man3_MANS)'; \ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ for i in $$l2; do \ case "$$i" in \ *.3*) list="$$list $$i" ;; \ esac; \ done; \ for i in $$list; do \ ext=`echo $$i | sed -e 's/^.*\\.//'`; \ case "$$ext" in \ 3*) ;; \ *) ext='3' ;; \ esac; \ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ inst=`echo $$inst | sed -e 's/^.*\///'`; \ inst=`echo $$inst | sed '$(transform)'`.$$ext; \ echo " rm -f '$(DESTDIR)$(man3dir)/$$inst'"; \ rm -f "$(DESTDIR)$(man3dir)/$$inst"; \ done tags: TAGS TAGS: ctags: CTAGS CTAGS: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ list='$(DISTFILES)'; for file in $$list; do \ case $$file in \ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ esac; \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ if test "$$dir" != "$$file" && test "$$dir" != "."; then \ dir="/$$dir"; \ $(mkdir_p) "$(distdir)$$dir"; \ else \ dir=''; \ fi; \ if test -d $$d/$$file; then \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(MANS) installdirs: for dir in "$(DESTDIR)$(man3dir)"; do \ test -z "$$dir" || $(mkdir_p) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic distclean-libtool dvi: dvi-am dvi-am: html: html-am info: info-am info-am: install-data-am: install-man install-exec-am: install-info: install-info-am install-man: install-man3 installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-info-am uninstall-man uninstall-man: uninstall-man3 .PHONY: all all-am check check-am clean clean-generic clean-libtool \ distclean distclean-generic distclean-libtool distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-exec install-exec-am \ install-info install-info-am install-man install-man3 \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ uninstall uninstall-am uninstall-info-am uninstall-man \ uninstall-man3 man/man3/Judy: ../tool/jhton ext/Judy_3.htm | grep -v '^[ ]*$$' | sed -e 's/\.C//' > man/man3/Judy man/man3/Judy1: ../tool/jhton ext/Judy1_3.htm | grep -v '^[ ]*$$' | sed -e 's/\.C//' > man/man3/Judy1 cd man/man3; ln -s Judy J1T cd man/man3; ln -s Judy J1S cd man/man3; ln -s Judy J1U cd man/man3; ln -s Judy J1F cd man/man3; ln -s Judy J1N cd man/man3; ln -s Judy J1L cd man/man3; ln -s Judy J1P cd man/man3; ln -s Judy J1FE cd man/man3; ln -s Judy J1NE cd man/man3; ln -s Judy J1LE cd man/man3; ln -s Judy J1PE cd man/man3; ln -s Judy J1C cd man/man3; ln -s Judy J1BC cd man/man3; ln -s Judy J1FA cd man/man3; ln -s Judy J1MU man/man3/Judy1_funcs: ../tool/jhton ext/Judy1_funcs_3.htm | grep -v '^[ ]*$$' | sed -e 's/\.C//' > man/man3/Judy1_funcs cd man/man3; ln -s Judy1_funcs Judy1Test cd man/man3; ln -s Judy1_funcs Judy1Set cd man/man3; ln -s Judy1_funcs Judy1Unset cd man/man3; ln -s Judy1_funcs Judy1First cd man/man3; ln -s Judy1_funcs Judy1Next cd man/man3; ln -s Judy1_funcs Judy1Last cd man/man3; ln -s Judy1_funcs Judy1Prev cd man/man3; ln -s Judy1_funcs Judy1FirstEmpty cd man/man3; ln -s Judy1_funcs Judy1NextEmpty cd man/man3; ln -s Judy1_funcs Judy1LastEmpty cd man/man3; ln -s Judy1_funcs Judy1PrevEmpty cd man/man3; ln -s Judy1_funcs Judy1Count cd man/man3; ln -s Judy1_funcs Judy1ByCount cd man/man3; ln -s Judy1_funcs Judy1FreeArray cd man/man3; ln -s Judy1_funcs Judy1MemUsed man/man3/JudyL: ../tool/jhton ext/JudyL_3.htm | grep -v '^[ ]*$$' | sed -e 's/\.C//' > man/man3/JudyL cd man/man3; ln -s JudyL JLG cd man/man3; ln -s JudyL JLI cd man/man3; ln -s JudyL JLD cd man/man3; ln -s JudyL JLF cd man/man3; ln -s JudyL JLN cd man/man3; ln -s JudyL JLL cd man/man3; ln -s JudyL JLP cd man/man3; ln -s JudyL JLFE cd man/man3; ln -s JudyL JLNE cd man/man3; ln -s JudyL JLLE cd man/man3; ln -s JudyL JLPE cd man/man3; ln -s JudyL JLC cd man/man3; ln -s JudyL JLBC cd man/man3; ln -s JudyL JLFA cd man/man3; ln -s JudyL JLMU man/man3/JudyL_funcs: ../tool/jhton ext/JudyL_funcs_3.htm | grep -v '^[ ]*$$' | sed -e 's/\.C//' > man/man3/JudyL_funcs cd man/man3; ln -s JudyL_funcs JudyLGet cd man/man3; ln -s JudyL_funcs JudyLIns cd man/man3; ln -s JudyL_funcs JudyLDel cd man/man3; ln -s JudyL_funcs JudyLFirst cd man/man3; ln -s JudyL_funcs JudyLNext cd man/man3; ln -s JudyL_funcs JudyLLast cd man/man3; ln -s JudyL_funcs JudyLPrev cd man/man3; ln -s JudyL_funcs JudyLFirstEmpty cd man/man3; ln -s JudyL_funcs JudyLNextEmpty cd man/man3; ln -s JudyL_funcs JudyLLastEmpty cd man/man3; ln -s JudyL_funcs JudyLPrevEmpty cd man/man3; ln -s JudyL_funcs JudyLCount cd man/man3; ln -s JudyL_funcs JudyLByCount cd man/man3; ln -s JudyL_funcs JudyLFreeArray cd man/man3; ln -s JudyL_funcs JudyLMemUsed man/man3/JudySL: ../tool/jhton ext/JudySL_3.htm | grep -v '^[ ]*$$' | sed -e 's/\.C//' > man/man3/JudySL cd man/man3; ln -s JudySL JSLG cd man/man3; ln -s JudySL JSLI cd man/man3; ln -s JudySL JSLD cd man/man3; ln -s JudySL JSLF cd man/man3; ln -s JudySL JSLN cd man/man3; ln -s JudySL JSLL cd man/man3; ln -s JudySL JSLP cd man/man3; ln -s JudySL JSLFA man/man3/JudySL_funcs: ../tool/jhton ext/JudySL_funcs_3.htm | grep -v '^[ ]*$$' | sed -e 's/\.C//' > man/man3/JudySL_funcs cd man/man3; ln -s JudySL_funcs JudySLGet cd man/man3; ln -s JudySL_funcs JudySLIns cd man/man3; ln -s JudySL_funcs JudySLDel cd man/man3; ln -s JudySL_funcs JudySLFirst cd man/man3; ln -s JudySL_funcs JudySLNext cd man/man3; ln -s JudySL_funcs JudySLLast cd man/man3; ln -s JudySL_funcs JudySLPrev cd man/man3; ln -s JudySL_funcs JudySLFreeArray man/man3/JudyHS: ../tool/jhton ext/JudyHS_3.htm | grep -v '^[ ]*$$' | sed -e 's/\.C//' > man/man3/JudyHS cd man/man3; ln -s JudyHS JHSG cd man/man3; ln -s JudyHS JHSI cd man/man3; ln -s JudyHS JHSD cd man/man3; ln -s JudyHS JHSFA man/man3/JudyHS_funcs: ../tool/jhton ext/JudyHS_funcs_3.htm | grep -v '^[ ]*$$' | sed -e 's/\.C//' > man/man3/JudyHS_funcs cd man/man3; ln -s JudyHS_funcs JudyHSGet cd man/man3; ln -s JudyHS_funcs JudyHSIns cd man/man3; ln -s JudyHS_funcs JudyHSDel cd man/man3; ln -s JudyHS_funcs JudyHSFreeArray # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: judy-1.0.5/src/0000755000175000017500000000000010624600217013501 5ustar troyhebetroyhebejudy-1.0.5/src/apps/0000755000175000017500000000000010624600177014451 5ustar troyhebetroyhebejudy-1.0.5/src/apps/demo/0000755000175000017500000000000010624600177015375 5ustar troyhebetroyhebejudy-1.0.5/src/apps/demo/Makefile_deliver0000644000175000017500000000271110204462077020547 0ustar troyhebetroyhebe# @(#) $Revision: 4.11 $ $Source: /judy/src/apps/demo/Makefile_deliver $ # Makefile for Judy demo programs. # Locations of Judy header file and library; correct if necessary: # # Note the use of the archive version (libJudy.a) for speed, although the # difference from shared libs is not great on Linux. JUDY = /usr JUDY_INCDIR = $(JUDY)/include JUDY_LIBDIR = $(JUDY)/lib JUDY_HEADER = $(JUDY_INCDIR)/Judy.h JUDY_LIBBASE = Judy JUDY_LIB = $(JUDY_LIBDIR)/lib$(JUDY_LIBBASE).a DEBUG = -O CFLAGS = $(DEBUG) CC = cc # Place files locally by default: OBJS = interL.o interSL.o funhist.o JudySort.o EXECS = interL interSL funhist JudySort # === RULES === all: $(EXECS) debug:; make -f Makefile DEBUG='-g' # Unfortunately not all make programs understand filename generation via $(@F), # or at least $$(@F) on a dependencies line, so spell out each $EXECS target # separately: interL: interL.c $(JUDY_HEADER) $(JUDY_LIB) $(CC) $(CFLAGS) -I $(JUDY_INCDIR) $(@F).c \ -L$(JUDY_LIBDIR) -l$(JUDY_LIBBASE) -o $@ interSL: interSL.c $(JUDY_HEADER) $(JUDY_LIB) $(CC) $(CFLAGS) -I $(JUDY_INCDIR) $(@F).c \ -L$(JUDY_LIBDIR) -l$(JUDY_LIBBASE) -o $@ funhist: funhist.c $(JUDY_HEADER) $(JUDY_LIB) $(CC) $(CFLAGS) -I $(JUDY_INCDIR) $(@F).c \ -L$(JUDY_LIBDIR) -l$(JUDY_LIBBASE) -o $@ JudySort: JudySort.c $(JUDY_HEADER) $(JUDY_LIB) $(CC) $(CFLAGS) -I $(JUDY_INCDIR) $(@F).c \ -L$(JUDY_LIBDIR) -l$(JUDY_LIBBASE) -o $@ clean:; rm -rf core $(OBJS) $(EXECS) judy-1.0.5/src/apps/demo/funhist.c0000644000175000017500000001720310204462077017223 0ustar troyhebetroyhebe// @(#) $Revision: 4.5 $ $Source: /judy/src/apps/demo/funhist.c $ // // FUNCTION HISTOGRAM; JUDYL DEMO PROGRAM // // This program uses JudyL to create a histogram of data generated by the // function random(3M). Other functions could be substituted in. // // The program generates n random numbers, stores them in a JudyL array // and then prints a histogram. All aspects of the generation and // histogram are timed so the user can see how long various JudyL functions // take. // // // This demonstrates: // JLI (JudyLIns) // JLF (JudyLFirst) // JLL (JudyLLast) // JLN (JudyLNext) // JLC (JudyLCount) // JLBC (JudyLByCount) // how to access a JudyL value. // // Notice that using JudyL gives you fast stores and lookups as with hashing // but without having to define a hash function, initialize the hash table // or having to predetermine a good hash table size. It also gives you a // sorted list at the same time. // Also notice that JudyLCount is much faster than you can sequentially // count items in an array. // #include // random() #include // printf() #include // gettimeofday() #include // JL*() routines // Default number of iterations (number of random numbers generated) // This may be overridden on the command line #define DEFAULT_ITER 1000000 // The number of buckets the histogram is divided into. #define DEFAULT_HISTO_BUCKETS 32 // Macro for correction english output for plurals #define PLURAL(count) ((count == 1) ? "" : "s") // timing routines struct timeval TBeg, TEnd; #define STARTTm gettimeofday(&TBeg, NULL) #define ENDTm gettimeofday(&TEnd, NULL) #define DeltaUSec \ ((double)(TEnd.tv_sec - TBeg.tv_sec) * 1E6 + \ (TEnd.tv_usec - TBeg.tv_usec)) // End of timing routines int main(int argc, char **argv) { Pvoid_t PJArray = NULL; // main JudyL array // key is random number, value is repeat count Pvoid_t PJCount = NULL; // second JudyL array // key is repeat count (from PJArray) // value is count of items with the same // repeat count Word_t Index; // index in JudyLFirst/Next loop PWord_t PValue; // pointer to Judy array value PWord_t PGenCount; // pointer to generation count Word_t num_vals; // number of randoms to generate Word_t iter; // for loop iteration Word_t unique_nums; // number of unique randoms generated Word_t random_num; // random number Word_t median; // random number Word_t tmp1, tmp2; // temporary variable double random_gen_time; // time to generate random numbers Word_t histo_incr; // histogram increment unsigned long long ran_sum = 0; // sum of all generated randoms // TITLE printf("\nJudyL demonstration: random(3M) histogram\n"); // SET NUMBER OF RANDOMS TO GENERATE if (argc != 2) { // SET TO DEFAULT_ITER num_vals = DEFAULT_ITER; printf("Usage: %s [numvals]\n", argv[0]); printf(" Since you did not specify a number of values, %ld\n", num_vals); printf(" will be used as the number of random numbers to insert\n"); printf(" into the Judy array\n"); } else { // OVERRIDE NUMBER OF RANDOMS TO GENERATE num_vals = atol(argv[1]); } // TIME THE GENERATION OF ALL THE RANDOM NUMBERS. THIS TIME IS LATER // // This time is later subtracted from the insert loop time so that the // time it takes to do the actual JudyLIns can be isolated from the // total time. printf("\ntiming random number generation\n"); STARTTm; for (iter = num_vals; iter; iter--) { random(); } /* end of random number generator time */ ENDTm; random_gen_time = DeltaUSec; printf("It took %.3f sec to generate %ld random numbers\n", random_gen_time / 1000000, num_vals); printf(" (ie. %.3f uSec/number)\n\n", random_gen_time / num_vals); // REGENERATE RANDOMS AND INSERT THEM INTO A JUDYL ARRAY printf("Please wait while the random numbers are inserted into\n"); printf("a JudyL array (with a usage count) ...\n"); STARTTm; for (iter = num_vals; iter; iter--) { random_num = (Word_t)random(); JLI(PValue, PJArray, random_num); /* increment hit count */ (*PValue)++; /* sum the random number */ ran_sum += random_num; } /* end of random number generator time */ ENDTm; printf("That took %.3f uSec/Index.\n", (DeltaUSec - random_gen_time) / num_vals); // COUNT THE NUMBER OF ELEMENTS IN THE JUDYL ARRAY // IE. COUNT THE NUMBER OF UNIQUE RANDOM NUMBERS JLC(unique_nums, PJArray, 0, -1); printf("\nThere were %ld unique random numbers generated\n", unique_nums); // FIND HOW MANY NUMBERS WERE GENERATED ONCE, TWICE, ... // // Create a new JudyL array where the index is the count from PJArray // and the value is a count of the number of elements with that count. if (unique_nums != num_vals) { printf("\nLooping through the entire Judy array to create a\n"); printf("new Judy counting array (PJCount in the source code)\n"); printf("...\n"); STARTTm; Index = 0; JLF(PValue, PJArray, Index); while (PValue != (PWord_t)NULL) { JLI(PGenCount, PJCount, *PValue); (*PGenCount)++; // increment hit count JLN(PValue, PJArray, Index); } ENDTm; printf("That took %.3f Secs or %.3f uSec/Index\n\n", DeltaUSec / 1000000, DeltaUSec / unique_nums); // PRINT DUPLICATES HISTOGRAM printf("Duplicates Histogram:\n"); Index = 0; JLF(PValue, PJCount, Index); while (PValue != (PWord_t)NULL) { printf(" %ld numbers were generated %ld time%s\n", *PValue, Index, PLURAL(Index)); JLN(PValue, PJCount, Index); } } // PRINT DISTRIBUTION HISTOGRAM printf("\nCompute the random number distribution by counting index ranges\n"); histo_incr = ((Word_t)~0L / DEFAULT_HISTO_BUCKETS) >> 1; Index = 0L; for (iter = 0; iter < DEFAULT_HISTO_BUCKETS; iter++) { Word_t Count; JLC(Count, PJArray, Index, Index + histo_incr); printf(" %ld unique values from 0x%08lx - 0x%08lx\n", Count, Index, Index + histo_incr); Index += histo_incr + 1; } // PRINT MEAN (average), // MEDIAN (middle value, or average of two middle values) // RANGE (low and high value) tmp1 = (Word_t)(ran_sum / (long long)num_vals); printf(" mean: 0x%lx\n", tmp1); // If there were an even number of randoms generated, then average // the two middle numbers. Otherwise, the mean is the middle value if (num_vals & 1) { JLBC(PValue, PJArray, num_vals / 2, tmp1); JLBC(PValue, PJArray, (num_vals / 2) + 1, tmp2); median = (tmp1 + tmp2) / 2; } else { JLBC(PValue, PJArray, (num_vals + 1) / 2, median); } printf(" median: 0x%lx\n", median); Index = 0; JLF(PValue, PJArray, Index); printf("first random generated: 0x%lx\n", Index); Index = ~0; JLL(PValue, PJArray, Index); printf(" last random generated: 0x%lx\n", Index); return (0); } // main() judy-1.0.5/src/apps/demo/interSL.c0000644000175000017500000000772310204462077017131 0ustar troyhebetroyhebe// Copyright (C) 2000 - 2002 Hewlett-Packard Company // // This program is free software; you can redistribute it and/or modify it // under the term of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License // for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program; if not, write to the Free Software Foundation, // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // _________________ // @(#) $Revision: 4.5 $ $Source: /judy/src/apps/demo/interSL.c $ // // INTERACTIVE JUDYSL DEMO PROGRAM // // This program is a very simple interactive demonstration of JudySL. Text // keywords are entered. The program uses that text as a key into a JudySL // array and increments a usage count. // // Keys can be single keywords like, "mykey", or multiple words like, "now is // the time for the quick brown fox to take the bull by the horns". // // The program recognizes the following keywords as special: // // CMD_LIST lists all the currently entered keys and their counts // CMD_QUIT terminates the program // // This program demonstrates: // // JudySLIns // JudySLFirst // JudySLNext // how to access a JudySL value // // Note: Using JudySL gives you fast lookups as with hashing but without // having to define a hash function, and without having to predetermine the // hash table size. It also gives you a sorted list at the same time. #include #include #include #include "Judy.h" // Commands recognized by the program: #define CMD_LIST "list" #define CMD_QUIT "quit" #define PLURAL(count) ((count == 1) ? "" : "s") main() { char Index [BUFSIZ]; // value from user. void ** PPValue; // associated with Index. void * PArray = (Pvoid_t) NULL; // JudySL array. JError_t JError; // Judy error structure char * Pc; // place in string. // EMIT INSTRUCTIONS: (void) puts ("JudySL interactive demonstration:"); (void) puts ("When asked for input, enter some text or:"); (void) printf ("- \"%s\" to list previously entered text or\n", CMD_LIST); (void) printf ("- \"%s\" (or EOF) to quit the program\n\n", CMD_QUIT); // ACCEPT COMMANDS: while (1) { (void) printf ("\nEnter key/list/quit: "); (void) fflush (stdout); if (fgets (Index, BUFSIZ, stdin) == (char *) NULL) break; if ((Pc = strchr (Index, '\n')) != (char *) NULL) *Pc = '\0'; // strip trailing newline. // QUIT: if (! strcmp (Index, CMD_QUIT)) break; // LIST ALL INPUT IN ALPHABETICAL ORDER: if (! strcmp (Index, CMD_LIST)) { Index[0] = '\0'; for (PPValue = JudySLFirst (PArray, Index, 0); PPValue != (PPvoid_t) NULL; PPValue = JudySLNext (PArray, Index, 0)) { (void) printf (" \"%s\" stored %lu time%s\n", Index, *((PWord_t) PPValue), PLURAL (*((PWord_t) PPValue))); } continue; } // ALL OTHER VALUES ARE KEYS: // // Insert Index into the array. If Index already exists, JudySLIns() returns a // pointer to the old value. If Index doesn't already exist, then a slot is // created and a pointer to this slot (initialized to zero) is returned. if ((PPValue = JudySLIns (& PArray, Index, &JError)) == PPJERR) { // assume out of memory. (void) printf ("Error %d, cannot insert \"%s\" in array.\n", JU_ERRNO(&JError), Index); exit (1); } ++(*((PWord_t) PPValue)); // increment usage count. (void) printf (" \"%s\" stored %ld time%s\n", Index, *((PWord_t) PPValue), PLURAL (*((PWord_t) PPValue))); } // while 1 (continuous loop until user quits) exit (0); /*NOTREACHED*/ } // main() judy-1.0.5/src/apps/demo/JudySort.c0000644000175000017500000000212210204462077017320 0ustar troyhebetroyhebe#include #include #include #include // By Doug Baskins Aug 2002 - for JudySL man page int // Usage: JudySort < file_to_sort main() { Pvoid_t PJArray = (PWord_t)NULL; // Judy array. PWord_t PValue; // Judy array element. Word_t Bytes; // size of JudySL array. char Index[BUFSIZ]; // string to sort. while (fgets(Index, sizeof(Index), stdin) != (char *)NULL) { JSLI(PValue, PJArray, Index); // store string into array ++(*PValue); // count instances of string } Index[0] = '\0'; // start with smallest string. JSLF(PValue, PJArray, Index); // get first string while (PValue != NULL) { while ((*PValue)--) // print duplicates printf("%s", Index); JSLN(PValue, PJArray, Index); // get next string } JSLFA(Bytes, PJArray); // free array fprintf(stderr, "The JudySL array used %lu bytes of memory\n", Bytes); return (0); } judy-1.0.5/src/apps/demo/README_deliver0000644000175000017500000000100110204462077017756 0ustar troyhebetroyhebe# @(#) $Revision: 4.5 $ $Source: /judy/src/apps/demo/README_deliver $ # Demo programs to be included with the Judy distribution. run_demo Simple Judy example script; explains, shows source code, compiles and runs it. Makefile By default, makes all the demo programs. The libJudy.a and Judy.h locations might have to be changed (via cc -I options). funhist.c Function histogram program. interL.c Interactive JudyL program. interSL.c Interactive JudySL program. JudySort.c JudySL version of "sort -u". judy-1.0.5/src/apps/demo/run_demo0000755000175000017500000000245710204462077017142 0ustar troyhebetroyhebe# @(#) $Revision: 4.4 $ $Source: /judy/src/apps/demo/run_demo $ # Simple Judy example script. See the first block of text below, or just run # this with no arguments. BASE='interL' PROGRAM="$BASE.c" COMPILE="cc -I../.. -o $BASE $PROGRAM `find ../../ -name libJudy.a`" set -e # exit if anything goes wrong. # GREET THE USER: cat <<-'EOF' This script illustrates a simple program that calls the Judy library, shows how to compile it, and then runs it for you. The program reads numbers from standard input and stores them in a JudyL array as array indexes. The target value associated with each number (index) is the number of times it was duplicated in the input. Exit with ^D or ^C. Press RETURN to continue and view the program source code... EOF read input # SHOW THE SAMPLE C PROGRAM: echo '____________________________________' echo cat $PROGRAM echo echo 'Press RETURN to continue...' read input # COMPILE THE SAMPLE C PROGRAM: cat <<-EOF To compile this program with the Judy library already installed on your system, the simplest command line is: $COMPILE Press RETURN to continue and compile the program source code... EOF read input $COMPILE # RUN THE SAMPLE C PROGRAM: echo echo "Press RETURN to run the sample program \"$BASE\"..." read input ./$BASE judy-1.0.5/src/apps/demo/README0000644000175000017500000000150110204462077016251 0ustar troyhebetroyhebe# @(#) $Revision: 4.8 $ $Source: /judy/src/apps/demo/README $ # Demo programs to be included with the Judy distribution. README_deliver delivered with files from this directory, renamed to "README" run_demo simple Judy example script; explains, shows source code, compiles and runs it Makefile_deliver delivered as "Makefile"; by default, makes all the demo programs; the libJudy.a and Judy.h locations might have to be changed (via cc -I options) NOTE: This file contains "#ifdef" directives that look to make like comments, but don't expect the makefile to run prior to unifdef'ing in the makefile. That is, use the constructed version for a given platform. funhist.c function histogram program interL.c interactive JudyL program interSL.c interactive JudySL program JudySort.c JudySL version of "sort -u" judy-1.0.5/src/apps/demo/interL.c0000644000175000017500000000175010204462077017000 0ustar troyhebetroyhebe#include #include main() // Simple JudyL demo, see "run_demo" script; @(#) $Revision: 4.4 $ { Pvoid_t Parray = (Pvoid_t) NULL; // empty JudyL array. Word_t * Pvalue; // value for one index. char line[BUFSIZ]; // input line. Word_t index; // in JudyL array. printf("Interactive Judy demo program to input, sort, and list numbers.\n" "Enter a number: "); // fflush(stdout); ? while (fgets(line, BUFSIZ, stdin)) // input. { index = strtoul(line, NULL, 0); // note: bad input => 0. JLI(Pvalue, Parray, index); // insert index in JudyL array. ++(*Pvalue); // count duplicates. printf(" Index Dups\n"); // print all saved indexes: index = 0; // start search at zero. JLF(Pvalue, Parray, index); // find first saved index. while (Pvalue != NULL) { printf("%12lu %5lu\n", index, *Pvalue); JLN(Pvalue, Parray, index); // find next saved index. } printf("Next: "); // fflush(stdout); ? } } judy-1.0.5/src/apps/README0000644000175000017500000000160010204462077015325 0ustar troyhebetroyhebe# @(#) $Revision: 4.4 $ $Source: /judy/src/apps/README $ # # This tree contains sources for Judy-related applications, that is, for # sources including a main() function, suitable for building an executable # program. Some of these sources are packaged and delivered to Judy users # as an optional package of example sources. benchmark/ sources for benchmarking programs, that is, demos that yield performance metrics; including sources for metrics displayed on the Judy website demo/ sources for programs that demonstrate the use of Judy but are probably not useful as templates for writing Judy-based applications # misc/ other sources; none exist at this time; and as they come along, they might go in misc/ or in other, more-specific directories noship/ other example sources we are not free to deliver to Judy users, or which it's inappropriate or premature to deliver judy-1.0.5/src/Judy.h0000644000175000017500000006657710622113030014600 0ustar troyhebetroyhebe#ifndef _JUDY_INCLUDED #define _JUDY_INCLUDED // _________________ // // Copyright (C) 2000 - 2002 Hewlett-Packard Company // // This program is free software; you can redistribute it and/or modify it // under the term of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License // for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program; if not, write to the Free Software Foundation, // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // _________________ // @(#) $Revision: 4.52 $ $Source: /judy/src/Judy.h $ // // HEADER FILE FOR EXPORTED FEATURES IN JUDY LIBRARY, libJudy.* // // See the manual entries for details. // // Note: This header file uses old-style comments on #-directive lines and // avoids "()" on macro names in comments for compatibility with older cc -Aa // and some tools on some platforms. // PLATFORM-SPECIFIC #ifdef JU_WIN /* =============================================== */ typedef __int8 int8_t; typedef __int16 int16_t; typedef __int32 int32_t; typedef __int64 int64_t; typedef unsigned __int8 uint8_t; typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; typedef unsigned __int64 uint64_t; #else /* ================ ! JU_WIN ============================= */ // ISO C99: 7.8 Format conversion of integer types #include /* if this FAILS, try #include */ // ISO C99: 7.18 Integer types uint*_t //#include #endif /* ================ ! JU_WIN ============================= */ // ISO C99 Standard: 7.20 General utilities #include // ISO C99 Standard: 7.10/5.2.4.2.1 Sizes of integer types #include #ifdef __cplusplus /* support use by C++ code */ extern "C" { #endif // **************************************************************************** // DECLARE SOME BASE TYPES IN CASE THEY ARE MISSING: // // These base types include "const" where appropriate, but only where of // interest to the caller. For example, a caller cares that a variable passed // by reference will not be modified, such as, "const void * Pindex", but not // that the called function internally does not modify the pointer itself, such // as, "void * const Pindex". // // Note that its OK to pass a Pvoid_t to a Pcvoid_t; the latter is the same, // only constant. Callers need to do this so they can also pass & Pvoid_t to // PPvoid_t (non-constant). #ifndef _PCVOID_T #define _PCVOID_T typedef const void * Pcvoid_t; #endif #ifndef _PVOID_T #define _PVOID_T typedef void * Pvoid_t; typedef void ** PPvoid_t; #endif #ifndef _WORD_T #define _WORD_T typedef unsigned long Word_t, * PWord_t; // expect 32-bit or 64-bit words. #endif #ifndef NULL #define NULL 0 #endif // **************************************************************************** // SUPPORT FOR ERROR HANDLING: // // Judy error numbers: // // Note: These are an enum so theres a related typedef, but the numbers are // spelled out so you can map a number back to its name. typedef enum // uint8_t -- but C does not support this type of enum. { // Note: JU_ERRNO_NONE and JU_ERRNO_FULL are not real errors. They specify // conditions which are otherwise impossible return values from 32-bit // Judy1Count, which has 2^32 + 1 valid returns (0..2^32) plus one error // return. These pseudo-errors support the return values that cannot otherwise // be unambiguously represented in a 32-bit word, and will never occur on a // 64-bit system. JU_ERRNO_NONE = 0, JU_ERRNO_FULL = 1, JU_ERRNO_NFMAX = JU_ERRNO_FULL, // JU_ERRNO_NOMEM comes from malloc(3C) when Judy cannot obtain needed memory. // The system errno value is also set to ENOMEM. This error can be recoverable // if the calling application frees other memory. // // TBD: Currently there is no guarantee the Judy array has no memory leaks // upon JU_ERRNO_NOMEM. JU_ERRNO_NOMEM = 2, // Problems with parameters from the calling program: // // JU_ERRNO_NULLPPARRAY means PPArray was null; perhaps PArray was passed where // &PArray was intended. Similarly, JU_ERRNO_NULLPINDEX means PIndex was null; // perhaps &Index was intended. Also, JU_ERRNO_NONNULLPARRAY, // JU_ERRNO_NULLPVALUE, and JU_ERRNO_UNSORTED, all added later (hence with // higher numbers), mean: A non-null array was passed in where a null pointer // was required; PValue was null; and unsorted indexes were detected. JU_ERRNO_NULLPPARRAY = 3, // see above. JU_ERRNO_NONNULLPARRAY = 10, // see above. JU_ERRNO_NULLPINDEX = 4, // see above. JU_ERRNO_NULLPVALUE = 11, // see above. JU_ERRNO_NOTJUDY1 = 5, // PArray is not to a Judy1 array. JU_ERRNO_NOTJUDYL = 6, // PArray is not to a JudyL array. JU_ERRNO_NOTJUDYSL = 7, // PArray is not to a JudySL array. JU_ERRNO_UNSORTED = 12, // see above. // Errors below this point are not recoverable; further tries to access the // Judy array might result in EFAULT and a core dump: // // JU_ERRNO_OVERRUN occurs when Judy detects, upon reallocation, that a block // of memory in its own freelist was modified since being freed. JU_ERRNO_OVERRUN = 8, // JU_ERRNO_CORRUPT occurs when Judy detects an impossible value in a Judy data // structure: // // Note: The Judy data structure contains some redundant elements that support // this type of checking. JU_ERRNO_CORRUPT = 9 // Warning: At least some C or C++ compilers do not tolerate a trailing comma // above here. At least we know of one case, in aCC; see JAGad58928. } JU_Errno_t; // Judy errno structure: // // WARNING: For compatibility with possible future changes, the fields of this // struct should not be referenced directly. Instead use the macros supplied // below. // This structure should be declared on the stack in a threaded process. typedef struct J_UDY_ERROR_STRUCT { JU_Errno_t je_Errno; // one of the enums above. int je_ErrID; // often an internal source line number. Word_t je_reserved[4]; // for future backward compatibility. } JError_t, * PJError_t; // Related macros: // // Fields from error struct: #define JU_ERRNO(PJError) ((PJError)->je_Errno) #define JU_ERRID(PJError) ((PJError)->je_ErrID) // For checking return values from various Judy functions: // // Note: Define JERR as -1, not as the seemingly more portable (Word_t) // (~0UL), to avoid a compiler "overflow in implicit constant conversion" // warning. #define JERR (-1) /* functions returning int or Word_t */ #define PJERR ((Pvoid_t) (~0UL)) /* mainly for use here, see below */ #define PPJERR ((PPvoid_t) (~0UL)) /* functions that return PPvoid_t */ // Convenience macro for when detailed error information (PJError_t) is not // desired by the caller; a purposely short name: #define PJE0 ((PJError_t) NULL) // **************************************************************************** // JUDY FUNCTIONS: // // P_JE is a shorthand for use below: #define P_JE PJError_t PJError // **************************************************************************** // JUDY1 FUNCTIONS: extern int Judy1Test( Pcvoid_t PArray, Word_t Index, P_JE); extern int Judy1Set( PPvoid_t PPArray, Word_t Index, P_JE); extern int Judy1SetArray( PPvoid_t PPArray, Word_t Count, const Word_t * const PIndex, P_JE); extern int Judy1Unset( PPvoid_t PPArray, Word_t Index, P_JE); extern Word_t Judy1Count( Pcvoid_t PArray, Word_t Index1, Word_t Index2, P_JE); extern int Judy1ByCount( Pcvoid_t PArray, Word_t Count, Word_t * PIndex, P_JE); extern Word_t Judy1FreeArray( PPvoid_t PPArray, P_JE); extern Word_t Judy1MemUsed( Pcvoid_t PArray); extern Word_t Judy1MemActive( Pcvoid_t PArray); extern int Judy1First( Pcvoid_t PArray, Word_t * PIndex, P_JE); extern int Judy1Next( Pcvoid_t PArray, Word_t * PIndex, P_JE); extern int Judy1Last( Pcvoid_t PArray, Word_t * PIndex, P_JE); extern int Judy1Prev( Pcvoid_t PArray, Word_t * PIndex, P_JE); extern int Judy1FirstEmpty( Pcvoid_t PArray, Word_t * PIndex, P_JE); extern int Judy1NextEmpty( Pcvoid_t PArray, Word_t * PIndex, P_JE); extern int Judy1LastEmpty( Pcvoid_t PArray, Word_t * PIndex, P_JE); extern int Judy1PrevEmpty( Pcvoid_t PArray, Word_t * PIndex, P_JE); extern PPvoid_t JudyLGet( Pcvoid_t PArray, Word_t Index, P_JE); extern PPvoid_t JudyLIns( PPvoid_t PPArray, Word_t Index, P_JE); extern int JudyLInsArray( PPvoid_t PPArray, Word_t Count, const Word_t * const PIndex, const Word_t * const PValue, // **************************************************************************** // JUDYL FUNCTIONS: P_JE); extern int JudyLDel( PPvoid_t PPArray, Word_t Index, P_JE); extern Word_t JudyLCount( Pcvoid_t PArray, Word_t Index1, Word_t Index2, P_JE); extern PPvoid_t JudyLByCount( Pcvoid_t PArray, Word_t Count, Word_t * PIndex, P_JE); extern Word_t JudyLFreeArray( PPvoid_t PPArray, P_JE); extern Word_t JudyLMemUsed( Pcvoid_t PArray); extern Word_t JudyLMemActive( Pcvoid_t PArray); extern PPvoid_t JudyLFirst( Pcvoid_t PArray, Word_t * PIndex, P_JE); extern PPvoid_t JudyLNext( Pcvoid_t PArray, Word_t * PIndex, P_JE); extern PPvoid_t JudyLLast( Pcvoid_t PArray, Word_t * PIndex, P_JE); extern PPvoid_t JudyLPrev( Pcvoid_t PArray, Word_t * PIndex, P_JE); extern int JudyLFirstEmpty( Pcvoid_t PArray, Word_t * PIndex, P_JE); extern int JudyLNextEmpty( Pcvoid_t PArray, Word_t * PIndex, P_JE); extern int JudyLLastEmpty( Pcvoid_t PArray, Word_t * PIndex, P_JE); extern int JudyLPrevEmpty( Pcvoid_t PArray, Word_t * PIndex, P_JE); // **************************************************************************** // JUDYSL FUNCTIONS: extern PPvoid_t JudySLGet( Pcvoid_t, const uint8_t * Index, P_JE); extern PPvoid_t JudySLIns( PPvoid_t, const uint8_t * Index, P_JE); extern int JudySLDel( PPvoid_t, const uint8_t * Index, P_JE); extern Word_t JudySLFreeArray( PPvoid_t, P_JE); extern PPvoid_t JudySLFirst( Pcvoid_t, uint8_t * Index, P_JE); extern PPvoid_t JudySLNext( Pcvoid_t, uint8_t * Index, P_JE); extern PPvoid_t JudySLLast( Pcvoid_t, uint8_t * Index, P_JE); extern PPvoid_t JudySLPrev( Pcvoid_t, uint8_t * Index, P_JE); // **************************************************************************** // JUDYHSL FUNCTIONS: extern PPvoid_t JudyHSGet( Pcvoid_t, void *, Word_t); extern PPvoid_t JudyHSIns( PPvoid_t, void *, Word_t, P_JE); extern int JudyHSDel( PPvoid_t, void *, Word_t, P_JE); extern Word_t JudyHSFreeArray( PPvoid_t, P_JE); extern const char *Judy1MallocSizes; extern const char *JudyLMallocSizes; // **************************************************************************** // JUDY memory interface to malloc() FUNCTIONS: extern Word_t JudyMalloc(Word_t); // words reqd => words allocd. extern Word_t JudyMallocVirtual(Word_t); // words reqd => words allocd. extern void JudyFree(Pvoid_t, Word_t); // free, size in words. extern void JudyFreeVirtual(Pvoid_t, Word_t); // free, size in words. #define JLAP_INVALID 0x1 /* flag to mark pointer "not a Judy array" */ // **************************************************************************** // MACRO EQUIVALENTS FOR JUDY FUNCTIONS: // // The following macros, such as J1T, are shorthands for calling Judy functions // with parameter address-of and detailed error checking included. Since they // are macros, the error checking code is replicated each time the macro is // used, but it runs fast in the normal case of no error. // // If the caller does not like the way the default JUDYERROR macro handles // errors (such as an exit(1) call when out of memory), they may define their // own before the "#include ". A routine such as HandleJudyError // could do checking on specific error numbers and print a different message // dependent on the error. The following is one example: // // Note: the back-slashes are removed because some compilers will not accept // them in comments. // // void HandleJudyError(uint8_t *, int, uint8_t *, int, int); // #define JUDYERROR(CallerFile, CallerLine, JudyFunc, JudyErrno, JudyErrID) // { // HandleJudyError(CallerFile, CallerLine, JudyFunc, JudyErrno, JudyErrID); // } // // The routine HandleJudyError could do checking on specific error numbers and // print a different message dependent on the error. // // The macro receives five parameters that are: // // 1. CallerFile: Source filename where a Judy call returned a serious error. // 2. CallerLine: Line number in that source file. // 3. JudyFunc: Name of Judy function reporting the error. // 4. JudyErrno: One of the JU_ERRNO* values enumerated above. // 5. JudyErrID: The je_ErrID field described above. #ifndef JUDYERROR_NOTEST #ifndef JUDYERROR /* supply a default error macro */ #include #define JUDYERROR(CallerFile, CallerLine, JudyFunc, JudyErrno, JudyErrID) \ { \ (void) fprintf(stderr, "File '%s', line %d: %s(), " \ "JU_ERRNO_* == %d, ID == %d\n", \ CallerFile, CallerLine, \ JudyFunc, JudyErrno, JudyErrID); \ exit(1); \ } #endif /* JUDYERROR */ #endif /* JUDYERROR_NOTEST */ // If the JUDYERROR macro is not desired at all, then the following eliminates // it. However, the return code from each Judy function (that is, the first // parameter of each macro) must be checked by the caller to assure that an // error did not occur. // // Example: // // #define JUDYERROR_NOTEST 1 // #include // // or use this cc option at compile time: // // cc -DJUDYERROR_NOTEST ... // // Example code: // // J1S(Rc, PArray, Index); // if (Rc == JERR) goto ...error // // or: // // JLI(PValue, PArray, Index); // if (PValue == PJERR) goto ...error // Internal shorthand macros for writing the J1S, etc. macros: #ifdef JUDYERROR_NOTEST /* ============================================ */ // "Judy Set Error": #define J_SE(FuncName,Errno) ((void) 0) // Note: In each J_*() case below, the digit is the number of key parameters // to the Judy*() call. Just assign the Func result to the callers Rc value // without a cast because none is required, and this keeps the API simpler. // However, a family of different J_*() macros is needed to support the // different numbers of key parameters (0,1,2) and the Func return type. // // In the names below, "I" = integer result; "P" = pointer result. Note, the // Funcs for J_*P() return PPvoid_t, but cast this to a Pvoid_t for flexible, // error-free assignment, and then compare to PJERR. #define J_0I(Rc,PArray,Func,FuncName) \ { (Rc) = Func(PArray, PJE0); } #define J_1I(Rc,PArray,Index,Func,FuncName) \ { (Rc) = Func(PArray, Index, PJE0); } #define J_1P(PV,PArray,Index,Func,FuncName) \ { (PV) = (Pvoid_t) Func(PArray, Index, PJE0); } #define J_2I(Rc,PArray,Index,Arg2,Func,FuncName) \ { (Rc) = Func(PArray, Index, Arg2, PJE0); } #define J_2C(Rc,PArray,Index1,Index2,Func,FuncName) \ { (Rc) = Func(PArray, Index1, Index2, PJE0); } #define J_2P(PV,PArray,Index,Arg2,Func,FuncName) \ { (PV) = (Pvoid_t) Func(PArray, Index, Arg2, PJE0); } // Variations for Judy*Set/InsArray functions: #define J_2AI(Rc,PArray,Count,PIndex,Func,FuncName) \ { (Rc) = Func(PArray, Count, PIndex, PJE0); } #define J_3AI(Rc,PArray,Count,PIndex,PValue,Func,FuncName) \ { (Rc) = Func(PArray, Count, PIndex, PValue, PJE0); } #else /* ================ ! JUDYERROR_NOTEST ============================= */ #define J_E(FuncName,PJE) \ JUDYERROR(__FILE__, __LINE__, FuncName, JU_ERRNO(PJE), JU_ERRID(PJE)) #define J_SE(FuncName,Errno) \ { \ JError_t J_Error; \ JU_ERRNO(&J_Error) = (Errno); \ JU_ERRID(&J_Error) = __LINE__; \ J_E(FuncName, &J_Error); \ } // Note: In each J_*() case below, the digit is the number of key parameters // to the Judy*() call. Just assign the Func result to the callers Rc value // without a cast because none is required, and this keeps the API simpler. // However, a family of different J_*() macros is needed to support the // different numbers of key parameters (0,1,2) and the Func return type. // // In the names below, "I" = integer result; "P" = pointer result. Note, the // Funcs for J_*P() return PPvoid_t, but cast this to a Pvoid_t for flexible, // error-free assignment, and then compare to PJERR. #define J_0I(Rc,PArray,Func,FuncName) \ { \ JError_t J_Error; \ if (((Rc) = Func(PArray, &J_Error)) == JERR) \ J_E(FuncName, &J_Error); \ } #define J_1I(Rc,PArray,Index,Func,FuncName) \ { \ JError_t J_Error; \ if (((Rc) = Func(PArray, Index, &J_Error)) == JERR) \ J_E(FuncName, &J_Error); \ } #define J_1P(Rc,PArray,Index,Func,FuncName) \ { \ JError_t J_Error; \ if (((Rc) = (Pvoid_t) Func(PArray, Index, &J_Error)) == PJERR) \ J_E(FuncName, &J_Error); \ } #define J_2I(Rc,PArray,Index,Arg2,Func,FuncName) \ { \ JError_t J_Error; \ if (((Rc) = Func(PArray, Index, Arg2, &J_Error)) == JERR) \ J_E(FuncName, &J_Error); \ } // Variation for Judy*Count functions, which return 0, not JERR, for error (and // also for other non-error cases): // // Note: JU_ERRNO_NFMAX should only apply to 32-bit Judy1, but this header // file lacks the necessary ifdefs to make it go away otherwise, so always // check against it. #define J_2C(Rc,PArray,Index1,Index2,Func,FuncName) \ { \ JError_t J_Error; \ if ((((Rc) = Func(PArray, Index1, Index2, &J_Error)) == 0) \ && (JU_ERRNO(&J_Error) > JU_ERRNO_NFMAX)) \ { \ J_E(FuncName, &J_Error); \ } \ } #define J_2P(PV,PArray,Index,Arg2,Func,FuncName) \ { \ JError_t J_Error; \ if (((PV) = (Pvoid_t) Func(PArray, Index, Arg2, &J_Error)) \ == PJERR) J_E(FuncName, &J_Error); \ } // Variations for Judy*Set/InsArray functions: #define J_2AI(Rc,PArray,Count,PIndex,Func,FuncName) \ { \ JError_t J_Error; \ if (((Rc) = Func(PArray, Count, PIndex, &J_Error)) == JERR) \ J_E(FuncName, &J_Error); \ } #define J_3AI(Rc,PArray,Count,PIndex,PValue,Func,FuncName) \ { \ JError_t J_Error; \ if (((Rc) = Func(PArray, Count, PIndex, PValue, &J_Error)) \ == JERR) J_E(FuncName, &J_Error); \ } #endif /* ================ ! JUDYERROR_NOTEST ============================= */ // Some of the macros are special cases that use inlined shortcuts for speed // with root-level leaves: // This is a slower version with current processors, but in the future... #define J1T(Rc,PArray,Index) \ (Rc) = Judy1Test((Pvoid_t)(PArray), Index, PJE0) #define J1S( Rc, PArray, Index) \ J_1I(Rc, (&(PArray)), Index, Judy1Set, "Judy1Set") #define J1SA(Rc, PArray, Count, PIndex) \ J_2AI(Rc,(&(PArray)), Count, PIndex, Judy1SetArray, "Judy1SetArray") #define J1U( Rc, PArray, Index) \ J_1I(Rc, (&(PArray)), Index, Judy1Unset, "Judy1Unset") #define J1F( Rc, PArray, Index) \ J_1I(Rc, PArray, &(Index), Judy1First, "Judy1First") #define J1N( Rc, PArray, Index) \ J_1I(Rc, PArray, &(Index), Judy1Next, "Judy1Next") #define J1L( Rc, PArray, Index) \ J_1I(Rc, PArray, &(Index), Judy1Last, "Judy1Last") #define J1P( Rc, PArray, Index) \ J_1I(Rc, PArray, &(Index), Judy1Prev, "Judy1Prev") #define J1FE(Rc, PArray, Index) \ J_1I(Rc, PArray, &(Index), Judy1FirstEmpty, "Judy1FirstEmpty") #define J1NE(Rc, PArray, Index) \ J_1I(Rc, PArray, &(Index), Judy1NextEmpty, "Judy1NextEmpty") #define J1LE(Rc, PArray, Index) \ J_1I(Rc, PArray, &(Index), Judy1LastEmpty, "Judy1LastEmpty") #define J1PE(Rc, PArray, Index) \ J_1I(Rc, PArray, &(Index), Judy1PrevEmpty, "Judy1PrevEmpty") #define J1C( Rc, PArray, Index1, Index2) \ J_2C(Rc, PArray, Index1, Index2, Judy1Count, "Judy1Count") #define J1BC(Rc, PArray, Count, Index) \ J_2I(Rc, PArray, Count, &(Index), Judy1ByCount, "Judy1ByCount") #define J1FA(Rc, PArray) \ J_0I(Rc, (&(PArray)), Judy1FreeArray, "Judy1FreeArray") #define J1MU(Rc, PArray) \ (Rc) = Judy1MemUsed(PArray) #define JLG(PV,PArray,Index) \ (PV) = (Pvoid_t)JudyLGet((Pvoid_t)PArray, Index, PJE0) #define JLI( PV, PArray, Index) \ J_1P(PV, (&(PArray)), Index, JudyLIns, "JudyLIns") #define JLIA(Rc, PArray, Count, PIndex, PValue) \ J_3AI(Rc,(&(PArray)), Count, PIndex, PValue, JudyLInsArray, \ "JudyLInsArray") #define JLD( Rc, PArray, Index) \ J_1I(Rc, (&(PArray)), Index, JudyLDel, "JudyLDel") #define JLF( PV, PArray, Index) \ J_1P(PV, PArray, &(Index), JudyLFirst, "JudyLFirst") #define JLN( PV, PArray, Index) \ J_1P(PV, PArray, &(Index), JudyLNext, "JudyLNext") #define JLL( PV, PArray, Index) \ J_1P(PV, PArray, &(Index), JudyLLast, "JudyLLast") #define JLP( PV, PArray, Index) \ J_1P(PV, PArray, &(Index), JudyLPrev, "JudyLPrev") #define JLFE(Rc, PArray, Index) \ J_1I(Rc, PArray, &(Index), JudyLFirstEmpty, "JudyLFirstEmpty") #define JLNE(Rc, PArray, Index) \ J_1I(Rc, PArray, &(Index), JudyLNextEmpty, "JudyLNextEmpty") #define JLLE(Rc, PArray, Index) \ J_1I(Rc, PArray, &(Index), JudyLLastEmpty, "JudyLLastEmpty") #define JLPE(Rc, PArray, Index) \ J_1I(Rc, PArray, &(Index), JudyLPrevEmpty, "JudyLPrevEmpty") #define JLC( Rc, PArray, Index1, Index2) \ J_2C(Rc, PArray, Index1, Index2, JudyLCount, "JudyLCount") #define JLBC(PV, PArray, Count, Index) \ J_2P(PV, PArray, Count, &(Index), JudyLByCount, "JudyLByCount") #define JLFA(Rc, PArray) \ J_0I(Rc, (&(PArray)), JudyLFreeArray, "JudyLFreeArray") #define JLMU(Rc, PArray) \ (Rc) = JudyLMemUsed(PArray) #define JHSI(PV, PArray, PIndex, Count) \ J_2P(PV, (&(PArray)), PIndex, Count, JudyHSIns, "JudyHSIns") #define JHSG(PV, PArray, PIndex, Count) \ (PV) = (Pvoid_t) JudyHSGet(PArray, PIndex, Count) #define JHSD(Rc, PArray, PIndex, Count) \ J_2I(Rc, (&(PArray)), PIndex, Count, JudyHSDel, "JudyHSDel") #define JHSFA(Rc, PArray) \ J_0I(Rc, (&(PArray)), JudyHSFreeArray, "JudyHSFreeArray") #define JSLG( PV, PArray, Index) \ J_1P( PV, PArray, Index, JudySLGet, "JudySLGet") #define JSLI( PV, PArray, Index) \ J_1P( PV, (&(PArray)), Index, JudySLIns, "JudySLIns") #define JSLD( Rc, PArray, Index) \ J_1I( Rc, (&(PArray)), Index, JudySLDel, "JudySLDel") #define JSLF( PV, PArray, Index) \ J_1P( PV, PArray, Index, JudySLFirst, "JudySLFirst") #define JSLN( PV, PArray, Index) \ J_1P( PV, PArray, Index, JudySLNext, "JudySLNext") #define JSLL( PV, PArray, Index) \ J_1P( PV, PArray, Index, JudySLLast, "JudySLLast") #define JSLP( PV, PArray, Index) \ J_1P( PV, PArray, Index, JudySLPrev, "JudySLPrev") #define JSLFA(Rc, PArray) \ J_0I( Rc, (&(PArray)), JudySLFreeArray, "JudySLFreeArray") #ifdef __cplusplus } #endif #endif /* ! _JUDY_INCLUDED */ judy-1.0.5/src/JudyCommon/0000755000175000017500000000000010624600216015564 5ustar troyhebetroyhebejudy-1.0.5/src/JudyCommon/JudyMemActive.c0000644000175000017500000001522510204462077020450 0ustar troyhebetroyhebe// Copyright (C) 2000 - 2002 Hewlett-Packard Company // // This program is free software; you can redistribute it and/or modify it // under the term of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License // for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program; if not, write to the Free Software Foundation, // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // _________________ // @(#) $Revision: 4.7 $ $Source: /judy/src/JudyCommon/JudyMemActive.c $ // // Return number of bytes of memory used to support a Judy1/L array. // Compile with one of -DJUDY1 or -DJUDYL. #if (! (defined(JUDY1) || defined(JUDYL))) #error: One of -DJUDY1 or -DJUDYL must be specified. #endif #ifdef JUDY1 #include "Judy1.h" #else #include "JudyL.h" #endif #include "JudyPrivate1L.h" FUNCTION static Word_t j__udyGetMemActive(Pjp_t); // **************************************************************************** // J U D Y 1 M E M A C T I V E // J U D Y L M E M A C T I V E #ifdef JUDY1 FUNCTION Word_t Judy1MemActive #else FUNCTION Word_t JudyLMemActive #endif ( Pcvoid_t PArray // from which to retrieve. ) { if (PArray == (Pcvoid_t)NULL) return(0); if (JU_LEAFW_POP0(PArray) < cJU_LEAFW_MAXPOP1) // must be a LEAFW { Pjlw_t Pjlw = P_JLW(PArray); // first word of leaf. Word_t Words = Pjlw[0] + 1; // population. #ifdef JUDY1 return((Words + 1) * sizeof(Word_t)); #else return(((Words * 2) + 1) * sizeof(Word_t)); #endif } else { Pjpm_t Pjpm = P_JPM(PArray); return(j__udyGetMemActive(&Pjpm->jpm_JP) + sizeof(jpm_t)); } } // JudyMemActive() // **************************************************************************** // __ J U D Y G E T M E M A C T I V E FUNCTION static Word_t j__udyGetMemActive( Pjp_t Pjp) // top of subtree. { Word_t offset; // in a branch. Word_t Bytes = 0; // actual bytes used at this level. Word_t IdxSz; // bytes per index in leaves switch (JU_JPTYPE(Pjp)) { case cJU_JPBRANCH_L2: case cJU_JPBRANCH_L3: #ifdef JU_64BIT case cJU_JPBRANCH_L4: case cJU_JPBRANCH_L5: case cJU_JPBRANCH_L6: case cJU_JPBRANCH_L7: #endif case cJU_JPBRANCH_L: { Pjbl_t Pjbl = P_JBL(Pjp->jp_Addr); for (offset = 0; offset < (Pjbl->jbl_NumJPs); ++offset) Bytes += j__udyGetMemActive((Pjbl->jbl_jp) + offset); return(Bytes + sizeof(jbl_t)); } case cJU_JPBRANCH_B2: case cJU_JPBRANCH_B3: #ifdef JU_64BIT case cJU_JPBRANCH_B4: case cJU_JPBRANCH_B5: case cJU_JPBRANCH_B6: case cJU_JPBRANCH_B7: #endif case cJU_JPBRANCH_B: { Word_t subexp; Word_t jpcount; Pjbb_t Pjbb = P_JBB(Pjp->jp_Addr); for (subexp = 0; subexp < cJU_NUMSUBEXPB; ++subexp) { jpcount = j__udyCountBitsB(JU_JBB_BITMAP(Pjbb, subexp)); Bytes += jpcount * sizeof(jp_t); for (offset = 0; offset < jpcount; ++offset) { Bytes += j__udyGetMemActive(P_JP(JU_JBB_PJP(Pjbb, subexp)) + offset); } } return(Bytes + sizeof(jbb_t)); } case cJU_JPBRANCH_U2: case cJU_JPBRANCH_U3: #ifdef JU_64BIT case cJU_JPBRANCH_U4: case cJU_JPBRANCH_U5: case cJU_JPBRANCH_U6: case cJU_JPBRANCH_U7: #endif case cJU_JPBRANCH_U: { Pjbu_t Pjbu = P_JBU(Pjp->jp_Addr); for (offset = 0; offset < cJU_BRANCHUNUMJPS; ++offset) { if (((Pjbu->jbu_jp[offset].jp_Type) >= cJU_JPNULL1) && ((Pjbu->jbu_jp[offset].jp_Type) <= cJU_JPNULLMAX)) { continue; // skip null JP to save time. } Bytes += j__udyGetMemActive(Pjbu->jbu_jp + offset); } return(Bytes + sizeof(jbu_t)); } // -- Cases below here terminate and do not recurse. -- #if (defined(JUDYL) || (! defined(JU_64BIT))) case cJU_JPLEAF1: IdxSz = 1; goto LeafWords; #endif case cJU_JPLEAF2: IdxSz = 2; goto LeafWords; case cJU_JPLEAF3: IdxSz = 3; goto LeafWords; #ifdef JU_64BIT case cJU_JPLEAF4: IdxSz = 4; goto LeafWords; case cJU_JPLEAF5: IdxSz = 5; goto LeafWords; case cJU_JPLEAF6: IdxSz = 6; goto LeafWords; case cJU_JPLEAF7: IdxSz = 7; goto LeafWords; #endif LeafWords: #ifdef JUDY1 return(IdxSz * (JU_JPLEAF_POP0(Pjp) + 1)); #else return((IdxSz + sizeof(Word_t)) * (JU_JPLEAF_POP0(Pjp) + 1)); #endif case cJU_JPLEAF_B1: { #ifdef JUDY1 return(sizeof(jlb_t)); #else Bytes = (JU_JPLEAF_POP0(Pjp) + 1) * sizeof(Word_t); return(Bytes + sizeof(jlb_t)); #endif } JUDY1CODE(case cJ1_JPFULLPOPU1: return(0);) #ifdef JUDY1 #define J__Mpy 0 #else #define J__Mpy sizeof(Word_t) #endif case cJU_JPIMMED_1_01: return(0); case cJU_JPIMMED_2_01: return(0); case cJU_JPIMMED_3_01: return(0); #ifdef JU_64BIT case cJU_JPIMMED_4_01: return(0); case cJU_JPIMMED_5_01: return(0); case cJU_JPIMMED_6_01: return(0); case cJU_JPIMMED_7_01: return(0); #endif case cJU_JPIMMED_1_02: return(J__Mpy * 2); case cJU_JPIMMED_1_03: return(J__Mpy * 3); #if (defined(JUDY1) || defined(JU_64BIT)) case cJU_JPIMMED_1_04: return(J__Mpy * 4); case cJU_JPIMMED_1_05: return(J__Mpy * 5); case cJU_JPIMMED_1_06: return(J__Mpy * 6); case cJU_JPIMMED_1_07: return(J__Mpy * 7); #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_1_08: return(0); case cJ1_JPIMMED_1_09: return(0); case cJ1_JPIMMED_1_10: return(0); case cJ1_JPIMMED_1_11: return(0); case cJ1_JPIMMED_1_12: return(0); case cJ1_JPIMMED_1_13: return(0); case cJ1_JPIMMED_1_14: return(0); case cJ1_JPIMMED_1_15: return(0); #endif #if (defined(JUDY1) || defined(JU_64BIT)) case cJU_JPIMMED_2_02: return(J__Mpy * 2); case cJU_JPIMMED_2_03: return(J__Mpy * 3); #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_2_04: return(0); case cJ1_JPIMMED_2_05: return(0); case cJ1_JPIMMED_2_06: return(0); case cJ1_JPIMMED_2_07: return(0); #endif #if (defined(JUDY1) || defined(JU_64BIT)) case cJU_JPIMMED_3_02: return(J__Mpy * 2); #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_3_03: return(0); case cJ1_JPIMMED_3_04: return(0); case cJ1_JPIMMED_3_05: return(0); case cJ1_JPIMMED_4_02: return(0); case cJ1_JPIMMED_4_03: return(0); case cJ1_JPIMMED_5_02: return(0); case cJ1_JPIMMED_5_03: return(0); case cJ1_JPIMMED_6_02: return(0); case cJ1_JPIMMED_7_02: return(0); #endif } // switch (JU_JPTYPE(Pjp)) return(0); // to make some compilers happy. } // j__udyGetMemActive() judy-1.0.5/src/JudyCommon/JudyDel.c0000644000175000017500000026763610204462077017321 0ustar troyhebetroyhebe// Copyright (C) 2000 - 2002 Hewlett-Packard Company // // This program is free software; you can redistribute it and/or modify it // under the term of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License // for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program; if not, write to the Free Software Foundation, // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // _________________ // @(#) $Revision: 4.68 $ $Source: /judy/src/JudyCommon/JudyDel.c $ // // Judy1Unset() and JudyLDel() functions for Judy1 and JudyL. // Compile with one of -DJUDY1 or -DJUDYL. // // About HYSTERESIS: In the Judy code, hysteresis means leaving around a // nominally suboptimal (not maximally compressed) data structure after a // deletion. As a result, the shape of the tree for two identical index sets // can differ depending on the insert/delete path taken to arrive at the index // sets. The purpose is to minimize worst-case behavior (thrashing) that could // result from a series of intermixed insertions and deletions. It also makes // for MUCH simpler code, because instead of performing, "delete and then // compress," it can say, "compress and then delete," where due to hysteresis, // compression is not even attempted until the object IS compressible. // // In some cases the code has no choice and it must "ungrow" a data structure // across a "phase transition" boundary without hysteresis. In other cases the // amount (such as "hysteresis = 1") is indicated by the number of JP deletions // (in branches) or index deletions (in leaves) that can occur in succession // before compressing the data structure. (It appears that hysteresis <= 1 in // all cases.) // // In general no hysteresis occurs when the data structure type remains the // same but the allocated memory chunk for the node must shrink, because the // relationship is hardwired and theres no way to know how much memory is // allocated to a given data structure. Hysteresis = 0 in all these cases. // // TBD: Could this code be faster if memory chunk hysteresis were supported // somehow along with data structure type hysteresis? // // TBD: Should some of the assertions here be converted to product code that // returns JU_ERRNO_CORRUPT? // // TBD: Dougs code had an odd mix of function-wide and limited-scope // variables. Should some of the function-wide variables appear only in // limited scopes, or more likely, vice-versa? #if (! (defined(JUDY1) || defined(JUDYL))) #error: One of -DJUDY1 or -DJUDYL must be specified. #endif #ifdef JUDY1 #include "Judy1.h" #else #include "JudyL.h" #endif #include "JudyPrivate1L.h" DBGCODE(extern void JudyCheckPop(Pvoid_t PArray);) DBGCODE(extern void JudyCheckSorted(Pjll_t Pjll, Word_t Pop1, long IndexSize);) #ifdef TRACEJP #include "JudyPrintJP.c" #endif // These are defined to generic values in JudyCommon/JudyPrivateTypes.h: // // TBD: These should be exported from a header file, but perhaps not, as they // are only used here, and exported from JudyDecascade.c, which is a separate // file for profiling reasons (to prevent inlining), but which potentially // could be merged with this file, either in SoftCM or at compile-time: #ifdef JUDY1 extern int j__udy1BranchBToBranchL(Pjp_t Pjp, Pvoid_t Pjpm); #ifndef JU_64BIT extern int j__udy1LeafB1ToLeaf1(Pjp_t, Pvoid_t); #endif extern Word_t j__udy1Leaf1ToLeaf2(uint16_t *, Pjp_t, Word_t, Pvoid_t); extern Word_t j__udy1Leaf2ToLeaf3(uint8_t *, Pjp_t, Word_t, Pvoid_t); #ifndef JU_64BIT extern Word_t j__udy1Leaf3ToLeafW(Pjlw_t, Pjp_t, Word_t, Pvoid_t); #else extern Word_t j__udy1Leaf3ToLeaf4(uint32_t *, Pjp_t, Word_t, Pvoid_t); extern Word_t j__udy1Leaf4ToLeaf5(uint8_t *, Pjp_t, Word_t, Pvoid_t); extern Word_t j__udy1Leaf5ToLeaf6(uint8_t *, Pjp_t, Word_t, Pvoid_t); extern Word_t j__udy1Leaf6ToLeaf7(uint8_t *, Pjp_t, Word_t, Pvoid_t); extern Word_t j__udy1Leaf7ToLeafW(Pjlw_t, Pjp_t, Word_t, Pvoid_t); #endif #else // JUDYL extern int j__udyLBranchBToBranchL(Pjp_t Pjp, Pvoid_t Pjpm); extern int j__udyLLeafB1ToLeaf1(Pjp_t, Pvoid_t); extern Word_t j__udyLLeaf1ToLeaf2(uint16_t *, Pjv_t, Pjp_t, Word_t, Pvoid_t); extern Word_t j__udyLLeaf2ToLeaf3(uint8_t *, Pjv_t, Pjp_t, Word_t, Pvoid_t); #ifndef JU_64BIT extern Word_t j__udyLLeaf3ToLeafW(Pjlw_t, Pjv_t, Pjp_t, Word_t, Pvoid_t); #else extern Word_t j__udyLLeaf3ToLeaf4(uint32_t *, Pjv_t, Pjp_t, Word_t, Pvoid_t); extern Word_t j__udyLLeaf4ToLeaf5(uint8_t *, Pjv_t, Pjp_t, Word_t, Pvoid_t); extern Word_t j__udyLLeaf5ToLeaf6(uint8_t *, Pjv_t, Pjp_t, Word_t, Pvoid_t); extern Word_t j__udyLLeaf6ToLeaf7(uint8_t *, Pjv_t, Pjp_t, Word_t, Pvoid_t); extern Word_t j__udyLLeaf7ToLeafW(Pjlw_t, Pjv_t, Pjp_t, Word_t, Pvoid_t); #endif #endif // JUDYL // For convenience in the calling code; "M1" means "minus one": #ifndef JU_64BIT #define j__udyLeafM1ToLeafW j__udyLeaf3ToLeafW #else #define j__udyLeafM1ToLeafW j__udyLeaf7ToLeafW #endif // **************************************************************************** // __ J U D Y D E L W A L K // // Given a pointer to a JP, an Index known to be valid, the number of bytes // left to decode (== level in the tree), and a pointer to a global JPM, walk a // Judy (sub)tree to do an unset/delete of that index, and possibly modify the // JPM. This function is only called internally, and recursively. Unlike // Judy1Test() and JudyLGet(), the extra time required for recursion should be // negligible compared with the total. // // Return values: // // -1 error; details in JPM // // 0 Index already deleted (should never happen, Index is known to be valid) // // 1 previously valid Index deleted // // 2 same as 1, but in addition the JP now points to a BranchL containing a // single JP, which should be compressed into the parent branch (if there // is one, which is not the case for a top-level branch under a JPM) DBGCODE(uint8_t parentJPtype;) // parent branch JP type. FUNCTION static int j__udyDelWalk( Pjp_t Pjp, // current JP under which to delete. Word_t Index, // to delete. Word_t ParentLevel, // of parent branch. Pjpm_t Pjpm) // for returning info to top level. { Word_t pop1; // of a leaf. Word_t level; // of a leaf. uint8_t digit; // from Index, in current branch. Pjll_t PjllnewRaw; // address of newly allocated leaf. Pjll_t Pjllnew; int offset; // within a branch. int retcode; // return code: -1, 0, 1, 2. JUDYLCODE(Pjv_t PjvRaw;) // value area. JUDYLCODE(Pjv_t Pjv;) DBGCODE(level = 0;) ContinueDelWalk: // for modifying state without recursing. #ifdef TRACEJP JudyPrintJP(Pjp, "d", __LINE__); #endif switch (JU_JPTYPE(Pjp)) // entry: Pjp, Index. { // **************************************************************************** // LINEAR BRANCH: // // MACROS FOR COMMON CODE: // // Check for population too high to compress a branch to a leaf, meaning just // descend through the branch, with a purposeful off-by-one error that // constitutes hysteresis = 1. In other words, do not compress until the // branchs CURRENT population fits in the leaf, even BEFORE deleting one // index. // // Next is a label for branch-type-specific common code. Variables pop1, // level, digit, and Index are in the context. #define JU_BRANCH_KEEP(cLevel,MaxPop1,Next) \ if (pop1 > (MaxPop1)) /* hysteresis = 1 */ \ { \ assert((cLevel) >= 2); \ level = (cLevel); \ digit = JU_DIGITATSTATE(Index, cLevel); \ goto Next; \ } // Support for generic calling of JudyLeaf*ToLeaf*() functions: // // Note: Cannot use JUDYLCODE() because this contains a comma. #ifdef JUDY1 #define JU_PVALUEPASS // null. #else #define JU_PVALUEPASS Pjv, #endif // During compression to a leaf, check if a JP contains nothing but a // cJU_JPIMMED_*_01, in which case shortcut calling j__udyLeaf*ToLeaf*(): // // Copy the index bytes from the jp_DcdPopO field (with possible truncation), // and continue the branch-JP-walk loop. Variables Pjp and Pleaf are in the // context. #define JU_BRANCH_COPY_IMMED_EVEN(cLevel,Pjp,ignore) \ if (JU_JPTYPE(Pjp) == cJU_JPIMMED_1_01 + (cLevel) - 2) \ { \ *Pleaf++ = JU_JPDCDPOP0(Pjp); \ JUDYLCODE(*Pjv++ = (Pjp)->jp_Addr;) \ continue; /* for-loop */ \ } #define JU_BRANCH_COPY_IMMED_ODD(cLevel,Pjp,CopyIndex) \ if (JU_JPTYPE(Pjp) == cJU_JPIMMED_1_01 + (cLevel) - 2) \ { \ CopyIndex(Pleaf, (Word_t) (JU_JPDCDPOP0(Pjp))); \ Pleaf += (cLevel); /* index size = level */ \ JUDYLCODE(*Pjv++ = (Pjp)->jp_Addr;) \ continue; /* for-loop */ \ } // Compress a BranchL into a leaf one index size larger: // // Allocate a new leaf, walk the JPs in the old BranchL and pack their contents // into the new leaf (of type NewJPType), free the old BranchL, and finally // restart the switch to delete Index from the new leaf. (Note that all // BranchLs are the same size.) Variables Pjp, Pjpm, Pleaf, digit, and pop1 // are in the context. #define JU_BRANCHL_COMPRESS(cLevel,LeafType,MaxPop1,NewJPType, \ LeafToLeaf,Alloc,ValueArea, \ CopyImmed,CopyIndex) \ { \ LeafType Pleaf; \ Pjbl_t PjblRaw; \ Pjbl_t Pjbl; \ Word_t numJPs; \ \ if ((PjllnewRaw = Alloc(MaxPop1, Pjpm)) == 0) return(-1); \ Pjllnew = P_JLL(PjllnewRaw); \ Pleaf = (LeafType) Pjllnew; \ JUDYLCODE(Pjv = ValueArea(Pleaf, MaxPop1);) \ \ PjblRaw = (Pjbl_t) (Pjp->jp_Addr); \ Pjbl = P_JBL(PjblRaw); \ numJPs = Pjbl->jbl_NumJPs; \ \ for (offset = 0; offset < numJPs; ++offset) \ { \ CopyImmed(cLevel, (Pjbl->jbl_jp) + offset, CopyIndex); \ \ pop1 = LeafToLeaf(Pleaf, JU_PVALUEPASS \ (Pjbl->jbl_jp) + offset, \ JU_DIGITTOSTATE(Pjbl->jbl_Expanse[offset], \ cLevel), (Pvoid_t) Pjpm); \ Pleaf = (LeafType) (((Word_t) Pleaf) + ((cLevel) * pop1)); \ JUDYLCODE(Pjv += pop1;) \ } \ assert(((((Word_t) Pleaf) - ((Word_t) Pjllnew)) / (cLevel)) == (MaxPop1)); \ JUDYLCODE(assert((Pjv - ValueArea(Pjllnew, MaxPop1)) == (MaxPop1));) \ DBGCODE(JudyCheckSorted(Pjllnew, MaxPop1, cLevel);) \ \ j__udyFreeJBL(PjblRaw, Pjpm); \ \ Pjp->jp_Type = (NewJPType); \ Pjp->jp_Addr = (Word_t) PjllnewRaw; \ goto ContinueDelWalk; /* delete from new leaf */ \ } // Overall common code for initial BranchL deletion handling: // // Assert that Index is in the branch, then see if the BranchL should be kept // or else compressed to a leaf. Variables Index, Pjp, and pop1 are in the // context. #define JU_BRANCHL(cLevel,MaxPop1,LeafType,NewJPType, \ LeafToLeaf,Alloc,ValueArea,CopyImmed,CopyIndex) \ \ assert(! JU_DCDNOTMATCHINDEX(Index, Pjp, cLevel)); \ assert(ParentLevel > (cLevel)); \ \ pop1 = JU_JPBRANCH_POP0(Pjp, cLevel) + 1; \ JU_BRANCH_KEEP(cLevel, MaxPop1, BranchLKeep); \ assert(pop1 == (MaxPop1)); \ \ JU_BRANCHL_COMPRESS(cLevel, LeafType, MaxPop1, NewJPType, \ LeafToLeaf, Alloc, ValueArea, CopyImmed, CopyIndex) // END OF MACROS, START OF CASES: case cJU_JPBRANCH_L2: JU_BRANCHL(2, cJU_LEAF2_MAXPOP1, uint16_t *, cJU_JPLEAF2, j__udyLeaf1ToLeaf2, j__udyAllocJLL2, JL_LEAF2VALUEAREA, JU_BRANCH_COPY_IMMED_EVEN, ignore); case cJU_JPBRANCH_L3: JU_BRANCHL(3, cJU_LEAF3_MAXPOP1, uint8_t *, cJU_JPLEAF3, j__udyLeaf2ToLeaf3, j__udyAllocJLL3, JL_LEAF3VALUEAREA, JU_BRANCH_COPY_IMMED_ODD, JU_COPY3_LONG_TO_PINDEX); #ifdef JU_64BIT case cJU_JPBRANCH_L4: JU_BRANCHL(4, cJU_LEAF4_MAXPOP1, uint32_t *, cJU_JPLEAF4, j__udyLeaf3ToLeaf4, j__udyAllocJLL4, JL_LEAF4VALUEAREA, JU_BRANCH_COPY_IMMED_EVEN, ignore); case cJU_JPBRANCH_L5: JU_BRANCHL(5, cJU_LEAF5_MAXPOP1, uint8_t *, cJU_JPLEAF5, j__udyLeaf4ToLeaf5, j__udyAllocJLL5, JL_LEAF5VALUEAREA, JU_BRANCH_COPY_IMMED_ODD, JU_COPY5_LONG_TO_PINDEX); case cJU_JPBRANCH_L6: JU_BRANCHL(6, cJU_LEAF6_MAXPOP1, uint8_t *, cJU_JPLEAF6, j__udyLeaf5ToLeaf6, j__udyAllocJLL6, JL_LEAF6VALUEAREA, JU_BRANCH_COPY_IMMED_ODD, JU_COPY6_LONG_TO_PINDEX); case cJU_JPBRANCH_L7: JU_BRANCHL(7, cJU_LEAF7_MAXPOP1, uint8_t *, cJU_JPLEAF7, j__udyLeaf6ToLeaf7, j__udyAllocJLL7, JL_LEAF7VALUEAREA, JU_BRANCH_COPY_IMMED_ODD, JU_COPY7_LONG_TO_PINDEX); #endif // JU_64BIT // A top-level BranchL is different and cannot use JU_BRANCHL(): Dont try to // compress to a (LEAFW) leaf yet, but leave this for a later deletion // (hysteresis > 0); and the next JP type depends on the system word size; so // dont use JU_BRANCH_KEEP(): case cJU_JPBRANCH_L: { Pjbl_t Pjbl; Word_t numJPs; level = cJU_ROOTSTATE; digit = JU_DIGITATSTATE(Index, cJU_ROOTSTATE); // fall through: // COMMON CODE FOR KEEPING AND DESCENDING THROUGH A BRANCHL: // // Come here with level and digit set. BranchLKeep: Pjbl = P_JBL(Pjp->jp_Addr); numJPs = Pjbl->jbl_NumJPs; assert(numJPs > 0); DBGCODE(parentJPtype = JU_JPTYPE(Pjp);) // Search for a match to the digit (valid Index => must find digit): for (offset = 0; (Pjbl->jbl_Expanse[offset]) != digit; ++offset) assert(offset < numJPs - 1); Pjp = (Pjbl->jbl_jp) + offset; // If not at a (deletable) JPIMMED_*_01, continue the walk (to descend through // the BranchL): assert(level >= 2); if ((JU_JPTYPE(Pjp)) != cJU_JPIMMED_1_01 + level - 2) break; // At JPIMMED_*_01: Ensure the index is in the right expanse, then delete the // Immed from the BranchL: // // Note: A BranchL has a fixed size and format regardless of numJPs. assert(JU_JPDCDPOP0(Pjp) == JU_TRIMTODCDSIZE(Index)); JU_DELETEINPLACE(Pjbl->jbl_Expanse, numJPs, offset, ignore); JU_DELETEINPLACE(Pjbl->jbl_jp, numJPs, offset, ignore); DBGCODE(JudyCheckSorted((Pjll_t) (Pjbl->jbl_Expanse), numJPs - 1, 1);) // If only one index left in the BranchL, indicate this to the caller: return ((--(Pjbl->jbl_NumJPs) <= 1) ? 2 : 1); } // case cJU_JPBRANCH_L. // **************************************************************************** // BITMAP BRANCH: // // MACROS FOR COMMON CODE: // // Note the reuse of common macros here, defined earlier: JU_BRANCH_KEEP(), // JU_PVALUE*. // // Compress a BranchB into a leaf one index size larger: // // Allocate a new leaf, walk the JPs in the old BranchB (one bitmap subexpanse // at a time) and pack their contents into the new leaf (of type NewJPType), // free the old BranchB, and finally restart the switch to delete Index from // the new leaf. Variables Pjp, Pjpm, Pleaf, digit, and pop1 are in the // context. // // Note: Its no accident that the interface to JU_BRANCHB_COMPRESS() is // identical to JU_BRANCHL_COMPRESS(). Only the details differ in how to // traverse the branchs JPs. #define JU_BRANCHB_COMPRESS(cLevel,LeafType,MaxPop1,NewJPType, \ LeafToLeaf,Alloc,ValueArea, \ CopyImmed,CopyIndex) \ { \ LeafType Pleaf; \ Pjbb_t PjbbRaw; /* BranchB to compress */ \ Pjbb_t Pjbb; \ Word_t subexp; /* current subexpanse number */ \ BITMAPB_t bitmap; /* portion for this subexpanse */ \ Pjp_t Pjp2Raw; /* one subexpanses subarray */ \ Pjp_t Pjp2; \ \ if ((PjllnewRaw = Alloc(MaxPop1, Pjpm)) == 0) return(-1); \ Pjllnew = P_JLL(PjllnewRaw); \ Pleaf = (LeafType) Pjllnew; \ JUDYLCODE(Pjv = ValueArea(Pleaf, MaxPop1);) \ \ PjbbRaw = (Pjbb_t) (Pjp->jp_Addr); \ Pjbb = P_JBB(PjbbRaw); \ \ for (subexp = 0; subexp < cJU_NUMSUBEXPB; ++subexp) \ { \ if ((bitmap = JU_JBB_BITMAP(Pjbb, subexp)) == 0) \ continue; /* empty subexpanse */ \ \ digit = subexp * cJU_BITSPERSUBEXPB; \ Pjp2Raw = JU_JBB_PJP(Pjbb, subexp); \ Pjp2 = P_JP(Pjp2Raw); \ assert(Pjp2 != (Pjp_t) NULL); \ \ for (offset = 0; bitmap != 0; bitmap >>= 1, ++digit) \ { \ if (! (bitmap & 1)) \ continue; /* empty sub-subexpanse */ \ \ ++offset; /* before any continue */ \ \ CopyImmed(cLevel, Pjp2 + offset - 1, CopyIndex); \ \ pop1 = LeafToLeaf(Pleaf, JU_PVALUEPASS \ Pjp2 + offset - 1, \ JU_DIGITTOSTATE(digit, cLevel), \ (Pvoid_t) Pjpm); \ Pleaf = (LeafType) (((Word_t) Pleaf) + ((cLevel) * pop1)); \ JUDYLCODE(Pjv += pop1;) \ } \ j__udyFreeJBBJP(Pjp2Raw, /* pop1 = */ offset, Pjpm); \ } \ assert(((((Word_t) Pleaf) - ((Word_t) Pjllnew)) / (cLevel)) == (MaxPop1)); \ JUDYLCODE(assert((Pjv - ValueArea(Pjllnew, MaxPop1)) == (MaxPop1));) \ DBGCODE(JudyCheckSorted(Pjllnew, MaxPop1, cLevel);) \ \ j__udyFreeJBB(PjbbRaw, Pjpm); \ \ Pjp->jp_Type = (NewJPType); \ Pjp->jp_Addr = (Word_t) PjllnewRaw; \ goto ContinueDelWalk; /* delete from new leaf */ \ } // Overall common code for initial BranchB deletion handling: // // Assert that Index is in the branch, then see if the BranchB should be kept // or else compressed to a leaf. Variables Index, Pjp, and pop1 are in the // context. #define JU_BRANCHB(cLevel,MaxPop1,LeafType,NewJPType, \ LeafToLeaf,Alloc,ValueArea,CopyImmed,CopyIndex) \ \ assert(! JU_DCDNOTMATCHINDEX(Index, Pjp, cLevel)); \ assert(ParentLevel > (cLevel)); \ \ pop1 = JU_JPBRANCH_POP0(Pjp, cLevel) + 1; \ JU_BRANCH_KEEP(cLevel, MaxPop1, BranchBKeep); \ assert(pop1 == (MaxPop1)); \ \ JU_BRANCHB_COMPRESS(cLevel, LeafType, MaxPop1, NewJPType, \ LeafToLeaf, Alloc, ValueArea, CopyImmed, CopyIndex) // END OF MACROS, START OF CASES: // // Note: Its no accident that the macro calls for these cases is nearly // identical to the code for BranchLs. case cJU_JPBRANCH_B2: JU_BRANCHB(2, cJU_LEAF2_MAXPOP1, uint16_t *, cJU_JPLEAF2, j__udyLeaf1ToLeaf2, j__udyAllocJLL2, JL_LEAF2VALUEAREA, JU_BRANCH_COPY_IMMED_EVEN, ignore); case cJU_JPBRANCH_B3: JU_BRANCHB(3, cJU_LEAF3_MAXPOP1, uint8_t *, cJU_JPLEAF3, j__udyLeaf2ToLeaf3, j__udyAllocJLL3, JL_LEAF3VALUEAREA, JU_BRANCH_COPY_IMMED_ODD, JU_COPY3_LONG_TO_PINDEX); #ifdef JU_64BIT case cJU_JPBRANCH_B4: JU_BRANCHB(4, cJU_LEAF4_MAXPOP1, uint32_t *, cJU_JPLEAF4, j__udyLeaf3ToLeaf4, j__udyAllocJLL4, JL_LEAF4VALUEAREA, JU_BRANCH_COPY_IMMED_EVEN, ignore); case cJU_JPBRANCH_B5: JU_BRANCHB(5, cJU_LEAF5_MAXPOP1, uint8_t *, cJU_JPLEAF5, j__udyLeaf4ToLeaf5, j__udyAllocJLL5, JL_LEAF5VALUEAREA, JU_BRANCH_COPY_IMMED_ODD, JU_COPY5_LONG_TO_PINDEX); case cJU_JPBRANCH_B6: JU_BRANCHB(6, cJU_LEAF6_MAXPOP1, uint8_t *, cJU_JPLEAF6, j__udyLeaf5ToLeaf6, j__udyAllocJLL6, JL_LEAF6VALUEAREA, JU_BRANCH_COPY_IMMED_ODD, JU_COPY6_LONG_TO_PINDEX); case cJU_JPBRANCH_B7: JU_BRANCHB(7, cJU_LEAF7_MAXPOP1, uint8_t *, cJU_JPLEAF7, j__udyLeaf6ToLeaf7, j__udyAllocJLL7, JL_LEAF7VALUEAREA, JU_BRANCH_COPY_IMMED_ODD, JU_COPY7_LONG_TO_PINDEX); #endif // JU_64BIT // A top-level BranchB is different and cannot use JU_BRANCHB(): Dont try to // compress to a (LEAFW) leaf yet, but leave this for a later deletion // (hysteresis > 0); and the next JP type depends on the system word size; so // dont use JU_BRANCH_KEEP(): case cJU_JPBRANCH_B: { Pjbb_t Pjbb; // BranchB to modify. Word_t subexp; // current subexpanse number. Word_t subexp2; // in second-level loop. BITMAPB_t bitmap; // portion for this subexpanse. BITMAPB_t bitmask; // with digits bit set. Pjp_t Pjp2Raw; // one subexpanses subarray. Pjp_t Pjp2; Word_t numJPs; // in one subexpanse. level = cJU_ROOTSTATE; digit = JU_DIGITATSTATE(Index, cJU_ROOTSTATE); // fall through: // COMMON CODE FOR KEEPING AND DESCENDING THROUGH A BRANCHB: // // Come here with level and digit set. BranchBKeep: Pjbb = P_JBB(Pjp->jp_Addr); subexp = digit / cJU_BITSPERSUBEXPB; bitmap = JU_JBB_BITMAP(Pjbb, subexp); bitmask = JU_BITPOSMASKB(digit); assert(bitmap & bitmask); // Index valid => digits bit is set. DBGCODE(parentJPtype = JU_JPTYPE(Pjp);) // Compute digits offset into the bitmap, with a fast method if all bits are // set: offset = ((bitmap == (cJU_FULLBITMAPB)) ? digit % cJU_BITSPERSUBEXPB : j__udyCountBitsB(bitmap & JU_MASKLOWEREXC(bitmask))); Pjp2Raw = JU_JBB_PJP(Pjbb, subexp); Pjp2 = P_JP(Pjp2Raw); assert(Pjp2 != (Pjp_t) NULL); // valid subexpanse pointer. // If not at a (deletable) JPIMMED_*_01, continue the walk (to descend through // the BranchB): if (JU_JPTYPE(Pjp2 + offset) != cJU_JPIMMED_1_01 + level - 2) { Pjp = Pjp2 + offset; break; } // At JPIMMED_*_01: Ensure the index is in the right expanse, then delete the // Immed from the BranchB: assert(JU_JPDCDPOP0(Pjp2 + offset) == JU_TRIMTODCDSIZE(Index)); // If only one index is left in the subexpanse, free the JP array: if ((numJPs = j__udyCountBitsB(bitmap)) == 1) { j__udyFreeJBBJP(Pjp2Raw, /* pop1 = */ 1, Pjpm); JU_JBB_PJP(Pjbb, subexp) = (Pjp_t) NULL; } // Shrink JP array in-place: else if (JU_BRANCHBJPGROWINPLACE(numJPs - 1)) { assert(numJPs > 0); JU_DELETEINPLACE(Pjp2, numJPs, offset, ignore); } // JP array would end up too large; compress it to a smaller one: else { Pjp_t PjpnewRaw; Pjp_t Pjpnew; if ((PjpnewRaw = j__udyAllocJBBJP(numJPs - 1, Pjpm)) == (Pjp_t) NULL) return(-1); Pjpnew = P_JP(PjpnewRaw); JU_DELETECOPY(Pjpnew, Pjp2, numJPs, offset, ignore); j__udyFreeJBBJP(Pjp2Raw, numJPs, Pjpm); // old. JU_JBB_PJP(Pjbb, subexp) = PjpnewRaw; } // Clear digits bit in the bitmap: JU_JBB_BITMAP(Pjbb, subexp) ^= bitmask; // If the current subexpanse alone is still too large for a BranchL (with // hysteresis = 1), the delete is all done: if (numJPs > cJU_BRANCHLMAXJPS) return(1); // Consider shrinking the current BranchB to a BranchL: // // Check the numbers of JPs in other subexpanses in the BranchL. Upon reaching // the critical number of numJPs (which could be right at the start; again, // with hysteresis = 1), its faster to just watch for any non-empty subexpanse // than to count bits in each subexpanse. Upon finding too many JPs, give up // on shrinking the BranchB. for (subexp2 = 0; subexp2 < cJU_NUMSUBEXPB; ++subexp2) { if (subexp2 == subexp) continue; // skip current subexpanse. if ((numJPs == cJU_BRANCHLMAXJPS) ? JU_JBB_BITMAP(Pjbb, subexp2) : ((numJPs += j__udyCountBitsB(JU_JBB_BITMAP(Pjbb, subexp2))) > cJU_BRANCHLMAXJPS)) { return(1); // too many JPs, cannot shrink. } } // Shrink current BranchB to a BranchL: // // Note: In this rare case, ignore the return value, do not pass it to the // caller, because the deletion is already successfully completed and the // caller(s) must decrement population counts. The only errors expected from // this call are JU_ERRNO_NOMEM and JU_ERRNO_OVERRUN, neither of which is worth // forwarding from this point. See also 4.1, 4.8, and 4.15 of this file. (void) j__udyBranchBToBranchL(Pjp, Pjpm); return(1); } // case. // **************************************************************************** // UNCOMPRESSED BRANCH: // // MACROS FOR COMMON CODE: // // Note the reuse of common macros here, defined earlier: JU_PVALUE*. // // Compress a BranchU into a leaf one index size larger: // // Allocate a new leaf, walk the JPs in the old BranchU and pack their contents // into the new leaf (of type NewJPType), free the old BranchU, and finally // restart the switch to delete Index from the new leaf. Variables Pjp, Pjpm, // digit, and pop1 are in the context. // // Note: Its no accident that the interface to JU_BRANCHU_COMPRESS() is // nearly identical to JU_BRANCHL_COMPRESS(); just NullJPType is added. The // details differ in how to traverse the branchs JPs -- // // -- and also, what to do upon encountering a cJU_JPIMMED_*_01 JP. In // BranchLs and BranchBs the JP must be deleted, but in a BranchU its merely // converted to a null JP, and this is done by other switch cases, so the "keep // branch" situation is simpler here and JU_BRANCH_KEEP() is not used. Also, // theres no code to convert a BranchU to a BranchB since counting the JPs in // a BranchU is (at least presently) expensive, and besides, keeping around a // BranchU is form of hysteresis. #define JU_BRANCHU_COMPRESS(cLevel,LeafType,MaxPop1,NullJPType,NewJPType, \ LeafToLeaf,Alloc,ValueArea,CopyImmed,CopyIndex) \ { \ LeafType Pleaf; \ Pjbu_t PjbuRaw = (Pjbu_t) (Pjp->jp_Addr); \ Pjp_t Pjp2 = JU_JBU_PJP0(Pjp); \ Word_t ldigit; /* larger than uint8_t */ \ \ if ((PjllnewRaw = Alloc(MaxPop1, Pjpm)) == 0) return(-1); \ Pjllnew = P_JLL(PjllnewRaw); \ Pleaf = (LeafType) Pjllnew; \ JUDYLCODE(Pjv = ValueArea(Pleaf, MaxPop1);) \ \ for (ldigit = 0; ldigit < cJU_BRANCHUNUMJPS; ++ldigit, ++Pjp2) \ { \ /* fast-process common types: */ \ if (JU_JPTYPE(Pjp2) == (NullJPType)) continue; \ CopyImmed(cLevel, Pjp2, CopyIndex); \ \ pop1 = LeafToLeaf(Pleaf, JU_PVALUEPASS Pjp2, \ JU_DIGITTOSTATE(ldigit, cLevel), \ (Pvoid_t) Pjpm); \ Pleaf = (LeafType) (((Word_t) Pleaf) + ((cLevel) * pop1)); \ JUDYLCODE(Pjv += pop1;) \ } \ assert(((((Word_t) Pleaf) - ((Word_t) Pjllnew)) / (cLevel)) == (MaxPop1)); \ JUDYLCODE(assert((Pjv - ValueArea(Pjllnew, MaxPop1)) == (MaxPop1));) \ DBGCODE(JudyCheckSorted(Pjllnew, MaxPop1, cLevel);) \ \ j__udyFreeJBU(PjbuRaw, Pjpm); \ \ Pjp->jp_Type = (NewJPType); \ Pjp->jp_Addr = (Word_t) PjllnewRaw; \ goto ContinueDelWalk; /* delete from new leaf */ \ } // Overall common code for initial BranchU deletion handling: // // Assert that Index is in the branch, then see if a BranchU should be kept or // else compressed to a leaf. Variables level, Index, Pjp, and pop1 are in the // context. // // Note: BranchU handling differs from BranchL and BranchB as described above. #define JU_BRANCHU(cLevel,MaxPop1,LeafType,NullJPType,NewJPType, \ LeafToLeaf,Alloc,ValueArea,CopyImmed,CopyIndex) \ \ assert(! JU_DCDNOTMATCHINDEX(Index, Pjp, cLevel)); \ assert(ParentLevel > (cLevel)); \ DBGCODE(parentJPtype = JU_JPTYPE(Pjp);) \ \ pop1 = JU_JPBRANCH_POP0(Pjp, cLevel) + 1; \ \ if (pop1 > (MaxPop1)) /* hysteresis = 1 */ \ { \ level = (cLevel); \ Pjp = P_JP(Pjp->jp_Addr) + JU_DIGITATSTATE(Index, cLevel);\ break; /* descend to next level */ \ } \ assert(pop1 == (MaxPop1)); \ \ JU_BRANCHU_COMPRESS(cLevel, LeafType, MaxPop1, NullJPType, NewJPType, \ LeafToLeaf, Alloc, ValueArea, CopyImmed, CopyIndex) // END OF MACROS, START OF CASES: // // Note: Its no accident that the macro calls for these cases is nearly // identical to the code for BranchLs, with the addition of cJU_JPNULL* // parameters only needed for BranchUs. case cJU_JPBRANCH_U2: JU_BRANCHU(2, cJU_LEAF2_MAXPOP1, uint16_t *, cJU_JPNULL1, cJU_JPLEAF2, j__udyLeaf1ToLeaf2, j__udyAllocJLL2, JL_LEAF2VALUEAREA, JU_BRANCH_COPY_IMMED_EVEN, ignore); case cJU_JPBRANCH_U3: JU_BRANCHU(3, cJU_LEAF3_MAXPOP1, uint8_t *, cJU_JPNULL2, cJU_JPLEAF3, j__udyLeaf2ToLeaf3, j__udyAllocJLL3, JL_LEAF3VALUEAREA, JU_BRANCH_COPY_IMMED_ODD, JU_COPY3_LONG_TO_PINDEX); #ifdef JU_64BIT case cJU_JPBRANCH_U4: JU_BRANCHU(4, cJU_LEAF4_MAXPOP1, uint32_t *, cJU_JPNULL3, cJU_JPLEAF4, j__udyLeaf3ToLeaf4, j__udyAllocJLL4, JL_LEAF4VALUEAREA, JU_BRANCH_COPY_IMMED_EVEN, ignore); case cJU_JPBRANCH_U5: JU_BRANCHU(5, cJU_LEAF5_MAXPOP1, uint8_t *, cJU_JPNULL4, cJU_JPLEAF5, j__udyLeaf4ToLeaf5, j__udyAllocJLL5, JL_LEAF5VALUEAREA, JU_BRANCH_COPY_IMMED_ODD, JU_COPY5_LONG_TO_PINDEX); case cJU_JPBRANCH_U6: JU_BRANCHU(6, cJU_LEAF6_MAXPOP1, uint8_t *, cJU_JPNULL5, cJU_JPLEAF6, j__udyLeaf5ToLeaf6, j__udyAllocJLL6, JL_LEAF6VALUEAREA, JU_BRANCH_COPY_IMMED_ODD, JU_COPY6_LONG_TO_PINDEX); case cJU_JPBRANCH_U7: JU_BRANCHU(7, cJU_LEAF7_MAXPOP1, uint8_t *, cJU_JPNULL6, cJU_JPLEAF7, j__udyLeaf6ToLeaf7, j__udyAllocJLL7, JL_LEAF7VALUEAREA, JU_BRANCH_COPY_IMMED_ODD, JU_COPY7_LONG_TO_PINDEX); #endif // JU_64BIT // A top-level BranchU is different and cannot use JU_BRANCHU(): Dont try to // compress to a (LEAFW) leaf yet, but leave this for a later deletion // (hysteresis > 0); just descend through the BranchU: case cJU_JPBRANCH_U: DBGCODE(parentJPtype = JU_JPTYPE(Pjp);) level = cJU_ROOTSTATE; Pjp = P_JP(Pjp->jp_Addr) + JU_DIGITATSTATE(Index, cJU_ROOTSTATE); break; // **************************************************************************** // LINEAR LEAF: // // State transitions while deleting an Index, the inverse of the similar table // that appears in JudyIns.c: // // Note: In JudyIns.c this table is not needed and does not appear until the // Immed handling code; because once a Leaf is reached upon growing the tree, // the situation remains simpler, but for deleting indexes, the complexity // arises when leaves must compress to Immeds. // // Note: There are other transitions possible too, not shown here, such as to // a leaf one level higher. // // (Yes, this is very terse... Study it and it will make sense.) // (Note, parts of this diagram are repeated below for quick reference.) // // reformat JP here for Judy1 only, from word-1 to word-2 // | // JUDY1 && JU_64BIT JUDY1 || JU_64BIT | // V // (*) Leaf1 [[ => 1_15..08 ] => 1_07 => ... => 1_04 ] => 1_03 => 1_02 => 1_01 // Leaf2 [[ => 2_07..04 ] => 2_03 => 2_02 ] => 2_01 // Leaf3 [[ => 3_05..03 ] => 3_02 ] => 3_01 // JU_64BIT only: // Leaf4 [[ => 4_03..02 ]] => 4_01 // Leaf5 [[ => 5_03..02 ]] => 5_01 // Leaf6 [[ => 6_02 ]] => 6_01 // Leaf7 [[ => 7_02 ]] => 7_01 // // (*) For Judy1 & 64-bit, go directly from a LeafB1 to cJU_JPIMMED_1_15; skip // Leaf1, as described in Judy1.h regarding cJ1_JPLEAF1. // // MACROS FOR COMMON CODE: // // (De)compress a LeafX into a LeafY one index size (cIS) larger (X+1 = Y): // // This is only possible when the current leaf is under a narrow pointer // ((ParentLevel - 1) > cIS) and its population fits in a higher-level leaf. // Variables ParentLevel, pop1, PjllnewRaw, Pjllnew, Pjpm, and Index are in the // context. // // Note: Doing an "uplevel" doesnt occur until the old leaf can be compressed // up one level BEFORE deleting an index; that is, hysteresis = 1. // // Note: LeafType, MaxPop1, NewJPType, and Alloc refer to the up-level leaf, // not the current leaf. // // Note: 010327: Fixed bug where the jp_DcdPopO next-uplevel digit (byte) // above the current Pop0 value was not being cleared. When upleveling, one // digit in jp_DcdPopO "moves" from being part of the Dcd subfield to the Pop0 // subfield, but since a leaf maxpop1 is known to be <= 1 byte in size, the new // Pop0 byte should always be zero. This is easy to overlook because // JU_JPLEAF_POP0() "knows" to only use the LSB of Pop0 (for efficiency) and // ignore the other bytes... Until someone uses cJU_POP0MASK() instead of // JU_JPLEAF_POP0(), such as in JudyInsertBranch.c. // // TBD: Should JudyInsertBranch.c use JU_JPLEAF_POP0() rather than // cJU_POP0MASK(), for efficiency? Does it know for sure its a narrow pointer // under the leaf? Not necessarily. #define JU_LEAF_UPLEVEL(cIS,LeafType,MaxPop1,NewJPType,LeafToLeaf, \ Alloc,ValueArea) \ \ assert(((ParentLevel - 1) == (cIS)) || (pop1 >= (MaxPop1))); \ \ if (((ParentLevel - 1) > (cIS)) /* under narrow pointer */ \ && (pop1 == (MaxPop1))) /* hysteresis = 1 */ \ { \ Word_t D_cdP0; \ if ((PjllnewRaw = Alloc(MaxPop1, Pjpm)) == 0) return(-1); \ Pjllnew = P_JLL(PjllnewRaw); \ JUDYLCODE(Pjv = ValueArea((LeafType) Pjllnew, MaxPop1);) \ \ (void) LeafToLeaf((LeafType) Pjllnew, JU_PVALUEPASS Pjp, \ Index & cJU_DCDMASK(cIS), /* TBD, Doug says */ \ (Pvoid_t) Pjpm); \ DBGCODE(JudyCheckSorted(Pjllnew, MaxPop1, cIS + 1);) \ \ D_cdP0 = (~cJU_MASKATSTATE((cIS) + 1)) & JU_JPDCDPOP0(Pjp); \ JU_JPSETADT(Pjp, (Word_t)PjllnewRaw, D_cdP0, NewJPType); \ goto ContinueDelWalk; /* delete from new leaf */ \ } // For Leaf3, only support JU_LEAF_UPLEVEL on a 64-bit system, and for Leaf7, // there is no JU_LEAF_UPLEVEL: // // Note: Theres no way here to go from Leaf3 [Leaf7] to LEAFW on a 32-bit // [64-bit] system. Thats handled in the main code, because its different in // that a JPM is involved. #ifndef JU_64BIT // 32-bit. #define JU_LEAF_UPLEVEL64(cIS,LeafType,MaxPop1,NewJPType,LeafToLeaf, \ Alloc,ValueArea) // null. #else #define JU_LEAF_UPLEVEL64(cIS,LeafType,MaxPop1,NewJPType,LeafToLeaf, \ Alloc,ValueArea) \ JU_LEAF_UPLEVEL (cIS,LeafType,MaxPop1,NewJPType,LeafToLeaf, \ Alloc,ValueArea) #define JU_LEAF_UPLEVEL_NONE(cIS,LeafType,MaxPop1,NewJPType,LeafToLeaf, \ Alloc,ValueArea) // null. #endif // Compress a Leaf* with pop1 = 2, or a JPIMMED_*_02, into a JPIMMED_*_01: // // Copy whichever Index is NOT being deleted (and assert that the other one is // found; Index must be valid). This requires special handling of the Index // bytes (and value area). Variables Pjp, Index, offset, and Pleaf are in the // context, offset is modified to the undeleted Index, and Pjp is modified // including jp_Addr. #define JU_TOIMMED_01_EVEN(cIS,ignore1,ignore2) \ { \ Word_t D_cdP0; \ Word_t A_ddr = 0; \ uint8_t T_ype = JU_JPTYPE(Pjp); \ offset = (Pleaf[0] == JU_LEASTBYTES(Index, cIS)); /* undeleted Ind */ \ assert(Pleaf[offset ? 0 : 1] == JU_LEASTBYTES(Index, cIS)); \ D_cdP0 = (Index & cJU_DCDMASK(cIS)) | Pleaf[offset]; \ JUDYLCODE(A_ddr = Pjv[offset];) \ JU_JPSETADT(Pjp, A_ddr, D_cdP0, T_ype); \ } #define JU_TOIMMED_01_ODD(cIS,SearchLeaf,CopyPIndex) \ { \ Word_t D_cdP0; \ Word_t A_ddr = 0; \ uint8_t T_ype = JU_JPTYPE(Pjp); \ \ offset = SearchLeaf(Pleaf, 2, Index); \ assert(offset >= 0); /* Index must be valid */ \ CopyPIndex(D_cdP0, & (Pleaf[offset ? 0 : cIS])); \ D_cdP0 |= Index & cJU_DCDMASK(cIS); \ JUDYLCODE(A_ddr = Pjv[offset ? 0 : 1];) \ JU_JPSETADT(Pjp, A_ddr, D_cdP0, T_ype); \ } // Compress a Leaf* into a JPIMMED_*_0[2+]: // // This occurs as soon as its possible, with hysteresis = 0. Variables pop1, // Pleaf, offset, and Pjpm are in the context. // // TBD: Explain why hysteresis = 0 here, rather than > 0. Probably because // the insert code assumes if the population is small enough, an Immed is used, // not a leaf. // // The differences between Judy1 and JudyL with respect to value area handling // are just too large for completely common code between them... Oh well, some // big ifdefs follow. #ifdef JUDY1 #define JU_LEAF_TOIMMED(cIS,LeafType,MaxPop1,BaseJPType,ignore1,\ ignore2,ignore3,ignore4, \ DeleteCopy,FreeLeaf) \ \ assert(pop1 > (MaxPop1)); \ \ if ((pop1 - 1) == (MaxPop1)) /* hysteresis = 0 */ \ { \ Pjll_t PjllRaw = (Pjll_t) (Pjp->jp_Addr); \ DeleteCopy((LeafType) (Pjp->jp_1Index), Pleaf, pop1, offset, cIS); \ DBGCODE(JudyCheckSorted((Pjll_t) (Pjp->jp_1Index), pop1-1, cIS);) \ Pjp->jp_Type = (BaseJPType) - 1 + (MaxPop1) - 1; \ FreeLeaf(PjllRaw, pop1, Pjpm); \ return(1); \ } #else // JUDYL // Pjv is also in the context. #define JU_LEAF_TOIMMED(cIS,LeafType,MaxPop1,BaseJPType,ignore1,\ ignore2,ignore3,ignore4, \ DeleteCopy,FreeLeaf) \ \ assert(pop1 > (MaxPop1)); \ \ if ((pop1 - 1) == (MaxPop1)) /* hysteresis = 0 */ \ { \ Pjll_t PjllRaw = (Pjll_t) (Pjp->jp_Addr); \ Pjv_t PjvnewRaw; \ Pjv_t Pjvnew; \ \ if ((PjvnewRaw = j__udyLAllocJV(pop1 - 1, Pjpm)) \ == (Pjv_t) NULL) return(-1); \ JUDYLCODE(Pjvnew = P_JV(PjvnewRaw);) \ \ DeleteCopy((LeafType) (Pjp->jp_LIndex), Pleaf, pop1, offset, cIS); \ JU_DELETECOPY(Pjvnew, Pjv, pop1, offset, cIS); \ DBGCODE(JudyCheckSorted((Pjll_t) (Pjp->jp_LIndex), pop1-1, cIS);) \ FreeLeaf(PjllRaw, pop1, Pjpm); \ Pjp->jp_Addr = (Word_t) PjvnewRaw; \ Pjp->jp_Type = (BaseJPType) - 2 + (MaxPop1); \ return(1); \ } // A complicating factor for JudyL & 32-bit is that Leaf2..3, and for JudyL & // 64-bit Leaf 4..7, go directly to an Immed*_01, where the value is stored in // jp_Addr and not in a separate LeafV. For efficiency, use the following // macro in cases where it can apply; it is rigged to do the right thing. // Unfortunately, this requires the calling code to "know" the transition table // and call the right macro. // // This variant compresses a Leaf* with pop1 = 2 into a JPIMMED_*_01: #define JU_LEAF_TOIMMED_01(cIS,LeafType,MaxPop1,ignore,Immed01JPType, \ ToImmed,SearchLeaf,CopyPIndex, \ DeleteCopy,FreeLeaf) \ \ assert(pop1 > (MaxPop1)); \ \ if ((pop1 - 1) == (MaxPop1)) /* hysteresis = 0 */ \ { \ Pjll_t PjllRaw = (Pjll_t) (Pjp->jp_Addr); \ ToImmed(cIS, SearchLeaf, CopyPIndex); \ FreeLeaf(PjllRaw, pop1, Pjpm); \ Pjp->jp_Type = (Immed01JPType); \ return(1); \ } #endif // JUDYL // See comments above about these: // // Note: Here "23" means index size 2 or 3, and "47" means 4..7. #if (defined(JUDY1) || defined(JU_64BIT)) #define JU_LEAF_TOIMMED_23(cIS,LeafType,MaxPop1,BaseJPType,Immed01JPType, \ ToImmed,SearchLeaf,CopyPIndex, \ DeleteCopy,FreeLeaf) \ JU_LEAF_TOIMMED( cIS,LeafType,MaxPop1,BaseJPType,ignore1, \ ignore2,ignore3,ignore4, \ DeleteCopy,FreeLeaf) #else // JUDYL && 32-bit #define JU_LEAF_TOIMMED_23(cIS,LeafType,MaxPop1,BaseJPType,Immed01JPType, \ ToImmed,SearchLeaf,CopyPIndex, \ DeleteCopy,FreeLeaf) \ JU_LEAF_TOIMMED_01(cIS,LeafType,MaxPop1,ignore,Immed01JPType, \ ToImmed,SearchLeaf,CopyPIndex, \ DeleteCopy,FreeLeaf) #endif #ifdef JU_64BIT #ifdef JUDY1 #define JU_LEAF_TOIMMED_47(cIS,LeafType,MaxPop1,BaseJPType,Immed01JPType, \ ToImmed,SearchLeaf,CopyPIndex, \ DeleteCopy,FreeLeaf) \ JU_LEAF_TOIMMED( cIS,LeafType,MaxPop1,BaseJPType,ignore1, \ ignore2,ignore3,ignore4, \ DeleteCopy,FreeLeaf) #else // JUDYL && 64-bit #define JU_LEAF_TOIMMED_47(cIS,LeafType,MaxPop1,BaseJPType,Immed01JPType, \ ToImmed,SearchLeaf,CopyPIndex, \ DeleteCopy,FreeLeaf) \ JU_LEAF_TOIMMED_01(cIS,LeafType,MaxPop1,ignore,Immed01JPType, \ ToImmed,SearchLeaf,CopyPIndex, \ DeleteCopy,FreeLeaf) #endif // JUDYL #endif // JU_64BIT // Compress a Leaf* in place: // // Here hysteresis = 0 (no memory is wasted). Variables pop1, Pleaf, and // offset, and for JudyL, Pjv, are in the context. #ifdef JUDY1 #define JU_LEAF_INPLACE(cIS,GrowInPlace,DeleteInPlace) \ if (GrowInPlace(pop1 - 1)) /* hysteresis = 0 */ \ { \ DeleteInPlace(Pleaf, pop1, offset, cIS); \ DBGCODE(JudyCheckSorted(Pleaf, pop1 - 1, cIS);) \ return(1); \ } #else #define JU_LEAF_INPLACE(cIS,GrowInPlace,DeleteInPlace) \ if (GrowInPlace(pop1 - 1)) /* hysteresis = 0 */ \ { \ DeleteInPlace(Pleaf, pop1, offset, cIS); \ /**/ JU_DELETEINPLACE(Pjv, pop1, offset, ignore); \ DBGCODE(JudyCheckSorted(Pleaf, pop1 - 1, cIS);) \ return(1); \ } #endif // Compress a Leaf* into a smaller memory object of the same JP type: // // Variables PjllnewRaw, Pjllnew, Pleafpop1, Pjpm, PleafRaw, Pleaf, and offset // are in the context. #ifdef JUDY1 #define JU_LEAF_SHRINK(cIS,LeafType,DeleteCopy,Alloc,FreeLeaf,ValueArea) \ if ((PjllnewRaw = Alloc(pop1 - 1, Pjpm)) == 0) return(-1); \ Pjllnew = P_JLL(PjllnewRaw); \ DeleteCopy((LeafType) Pjllnew, Pleaf, pop1, offset, cIS); \ DBGCODE(JudyCheckSorted(Pjllnew, pop1 - 1, cIS);) \ FreeLeaf(PleafRaw, pop1, Pjpm); \ Pjp->jp_Addr = (Word_t) PjllnewRaw; \ return(1) #else // JUDYL #define JU_LEAF_SHRINK(cIS,LeafType,DeleteCopy,Alloc,FreeLeaf,ValueArea) \ { \ /**/ Pjv_t Pjvnew; \ \ if ((PjllnewRaw = Alloc(pop1 - 1, Pjpm)) == 0) return(-1); \ Pjllnew = P_JLL(PjllnewRaw); \ /**/ Pjvnew = ValueArea(Pjllnew, pop1 - 1); \ DeleteCopy((LeafType) Pjllnew, Pleaf, pop1, offset, cIS); \ /**/ JU_DELETECOPY(Pjvnew, Pjv, pop1, offset, cIS); \ DBGCODE(JudyCheckSorted(Pjllnew, pop1 - 1, cIS);) \ FreeLeaf(PleafRaw, pop1, Pjpm); \ Pjp->jp_Addr = (Word_t) PjllnewRaw; \ return(1); \ } #endif // JUDYL // Overall common code for Leaf* deletion handling: // // See if the leaf can be: // - (de)compressed to one a level higher (JU_LEAF_UPLEVEL()), or if not, // - compressed to an Immediate JP (JU_LEAF_TOIMMED()), or if not, // - shrunk in place (JU_LEAF_INPLACE()), or if none of those, then // - shrink the leaf to a smaller chunk of memory (JU_LEAF_SHRINK()). // // Variables Pjp, pop1, Index, and offset are in the context. // The *Up parameters refer to a leaf one level up, if there is any. #define JU_LEAF(cIS, \ UpLevel, \ LeafTypeUp,MaxPop1Up,LeafJPTypeUp,LeafToLeaf, \ AllocUp,ValueAreaUp, \ LeafToImmed,ToImmed,CopyPIndex, \ LeafType,ImmedMaxPop1,ImmedBaseJPType,Immed01JPType, \ SearchLeaf,GrowInPlace,DeleteInPlace,DeleteCopy, \ Alloc,FreeLeaf,ValueArea) \ { \ Pjll_t PleafRaw; \ LeafType Pleaf; \ \ assert(! JU_DCDNOTMATCHINDEX(Index, Pjp, cIS)); \ assert(ParentLevel > (cIS)); \ \ PleafRaw = (Pjll_t) (Pjp->jp_Addr); \ Pleaf = (LeafType) P_JLL(PleafRaw); \ pop1 = JU_JPLEAF_POP0(Pjp) + 1; \ \ UpLevel(cIS, LeafTypeUp, MaxPop1Up, LeafJPTypeUp, \ LeafToLeaf, AllocUp, ValueAreaUp); \ \ offset = SearchLeaf(Pleaf, pop1, Index); \ assert(offset >= 0); /* Index must be valid */ \ JUDYLCODE(Pjv = ValueArea(Pleaf, pop1);) \ \ LeafToImmed(cIS, LeafType, ImmedMaxPop1, \ ImmedBaseJPType, Immed01JPType, \ ToImmed, SearchLeaf, CopyPIndex, \ DeleteCopy, FreeLeaf); \ \ JU_LEAF_INPLACE(cIS, GrowInPlace, DeleteInPlace); \ \ JU_LEAF_SHRINK(cIS, LeafType, DeleteCopy, Alloc, FreeLeaf, \ ValueArea); \ } // END OF MACROS, START OF CASES: // // (*) Leaf1 [[ => 1_15..08 ] => 1_07 => ... => 1_04 ] => 1_03 => 1_02 => 1_01 #if (defined(JUDYL) || (! defined(JU_64BIT))) case cJU_JPLEAF1: JU_LEAF(1, JU_LEAF_UPLEVEL, uint16_t *, cJU_LEAF2_MAXPOP1, cJU_JPLEAF2, j__udyLeaf1ToLeaf2, j__udyAllocJLL2, JL_LEAF2VALUEAREA, JU_LEAF_TOIMMED, ignore, ignore, uint8_t *, cJU_IMMED1_MAXPOP1, cJU_JPIMMED_1_02, cJU_JPIMMED_1_01, j__udySearchLeaf1, JU_LEAF1GROWINPLACE, JU_DELETEINPLACE, JU_DELETECOPY, j__udyAllocJLL1, j__udyFreeJLL1, JL_LEAF1VALUEAREA); #endif // A complicating factor is that for JudyL & 32-bit, a Leaf2 must go directly // to an Immed 2_01 and a Leaf3 must go directly to an Immed 3_01: // // Leaf2 [[ => 2_07..04 ] => 2_03 => 2_02 ] => 2_01 // Leaf3 [[ => 3_05..03 ] => 3_02 ] => 3_01 // // Hence use JU_LEAF_TOIMMED_23 instead of JU_LEAF_TOIMMED in the cases below, // and also the parameters ToImmed and, for odd index sizes, CopyPIndex, are // required. case cJU_JPLEAF2: JU_LEAF(2, JU_LEAF_UPLEVEL, uint8_t *, cJU_LEAF3_MAXPOP1, cJU_JPLEAF3, j__udyLeaf2ToLeaf3, j__udyAllocJLL3, JL_LEAF3VALUEAREA, JU_LEAF_TOIMMED_23, JU_TOIMMED_01_EVEN, ignore, uint16_t *, cJU_IMMED2_MAXPOP1, cJU_JPIMMED_2_02, cJU_JPIMMED_2_01, j__udySearchLeaf2, JU_LEAF2GROWINPLACE, JU_DELETEINPLACE, JU_DELETECOPY, j__udyAllocJLL2, j__udyFreeJLL2, JL_LEAF2VALUEAREA); // On 32-bit there is no transition to "uplevel" for a Leaf3, so use // JU_LEAF_UPLEVEL64 instead of JU_LEAF_UPLEVEL: case cJU_JPLEAF3: JU_LEAF(3, JU_LEAF_UPLEVEL64, uint32_t *, cJU_LEAF4_MAXPOP1, cJU_JPLEAF4, j__udyLeaf3ToLeaf4, j__udyAllocJLL4, JL_LEAF4VALUEAREA, JU_LEAF_TOIMMED_23, JU_TOIMMED_01_ODD, JU_COPY3_PINDEX_TO_LONG, uint8_t *, cJU_IMMED3_MAXPOP1, cJU_JPIMMED_3_02, cJU_JPIMMED_3_01, j__udySearchLeaf3, JU_LEAF3GROWINPLACE, JU_DELETEINPLACE_ODD, JU_DELETECOPY_ODD, j__udyAllocJLL3, j__udyFreeJLL3, JL_LEAF3VALUEAREA); #ifdef JU_64BIT // A complicating factor is that for JudyL & 64-bit, a Leaf[4-7] must go // directly to an Immed [4-7]_01: // // Leaf4 [[ => 4_03..02 ]] => 4_01 // Leaf5 [[ => 5_03..02 ]] => 5_01 // Leaf6 [[ => 6_02 ]] => 6_01 // Leaf7 [[ => 7_02 ]] => 7_01 // // Hence use JU_LEAF_TOIMMED_47 instead of JU_LEAF_TOIMMED in the cases below. case cJU_JPLEAF4: JU_LEAF(4, JU_LEAF_UPLEVEL, uint8_t *, cJU_LEAF5_MAXPOP1, cJU_JPLEAF5, j__udyLeaf4ToLeaf5, j__udyAllocJLL5, JL_LEAF5VALUEAREA, JU_LEAF_TOIMMED_47, JU_TOIMMED_01_EVEN, ignore, uint32_t *, cJU_IMMED4_MAXPOP1, cJ1_JPIMMED_4_02, cJU_JPIMMED_4_01, j__udySearchLeaf4, JU_LEAF4GROWINPLACE, JU_DELETEINPLACE, JU_DELETECOPY, j__udyAllocJLL4, j__udyFreeJLL4, JL_LEAF4VALUEAREA); case cJU_JPLEAF5: JU_LEAF(5, JU_LEAF_UPLEVEL, uint8_t *, cJU_LEAF6_MAXPOP1, cJU_JPLEAF6, j__udyLeaf5ToLeaf6, j__udyAllocJLL6, JL_LEAF6VALUEAREA, JU_LEAF_TOIMMED_47, JU_TOIMMED_01_ODD, JU_COPY5_PINDEX_TO_LONG, uint8_t *, cJU_IMMED5_MAXPOP1, cJ1_JPIMMED_5_02, cJU_JPIMMED_5_01, j__udySearchLeaf5, JU_LEAF5GROWINPLACE, JU_DELETEINPLACE_ODD, JU_DELETECOPY_ODD, j__udyAllocJLL5, j__udyFreeJLL5, JL_LEAF5VALUEAREA); case cJU_JPLEAF6: JU_LEAF(6, JU_LEAF_UPLEVEL, uint8_t *, cJU_LEAF7_MAXPOP1, cJU_JPLEAF7, j__udyLeaf6ToLeaf7, j__udyAllocJLL7, JL_LEAF7VALUEAREA, JU_LEAF_TOIMMED_47, JU_TOIMMED_01_ODD, JU_COPY6_PINDEX_TO_LONG, uint8_t *, cJU_IMMED6_MAXPOP1, cJ1_JPIMMED_6_02, cJU_JPIMMED_6_01, j__udySearchLeaf6, JU_LEAF6GROWINPLACE, JU_DELETEINPLACE_ODD, JU_DELETECOPY_ODD, j__udyAllocJLL6, j__udyFreeJLL6, JL_LEAF6VALUEAREA); // There is no transition to "uplevel" for a Leaf7, so use JU_LEAF_UPLEVEL_NONE // instead of JU_LEAF_UPLEVEL, and ignore all of the parameters to that macro: case cJU_JPLEAF7: JU_LEAF(7, JU_LEAF_UPLEVEL_NONE, ignore1, ignore2, ignore3, ignore4, ignore5, ignore6, JU_LEAF_TOIMMED_47, JU_TOIMMED_01_ODD, JU_COPY7_PINDEX_TO_LONG, uint8_t *, cJU_IMMED7_MAXPOP1, cJ1_JPIMMED_7_02, cJU_JPIMMED_7_01, j__udySearchLeaf7, JU_LEAF7GROWINPLACE, JU_DELETEINPLACE_ODD, JU_DELETECOPY_ODD, j__udyAllocJLL7, j__udyFreeJLL7, JL_LEAF7VALUEAREA); #endif // JU_64BIT // **************************************************************************** // BITMAP LEAF: case cJU_JPLEAF_B1: { #ifdef JUDYL Pjv_t PjvnewRaw; // new value area. Pjv_t Pjvnew; Word_t subexp; // 1 of 8 subexpanses in bitmap. Pjlb_t Pjlb; // pointer to bitmap part of the leaf. BITMAPL_t bitmap; // for one subexpanse. BITMAPL_t bitmask; // bit set for Indexs digit. #endif assert(! JU_DCDNOTMATCHINDEX(Index, Pjp, 1)); assert(ParentLevel > 1); // valid Index: assert(JU_BITMAPTESTL(P_JLB(Pjp->jp_Addr), Index)); pop1 = JU_JPLEAF_POP0(Pjp) + 1; // Like a Leaf1, see if its under a narrow pointer and can become a Leaf2 // (hysteresis = 1): JU_LEAF_UPLEVEL(1, uint16_t *, cJU_LEAF2_MAXPOP1, cJU_JPLEAF2, j__udyLeaf1ToLeaf2, j__udyAllocJLL2, JL_LEAF2VALUEAREA); #if (defined(JUDY1) && defined(JU_64BIT)) // Handle the unusual special case, on Judy1 64-bit only, where a LeafB1 goes // directly to a JPIMMED_1_15; as described in comments in Judy1.h and // JudyIns.c. Copy 1-byte indexes from old LeafB1 to the Immed: if ((pop1 - 1) == cJU_IMMED1_MAXPOP1) // hysteresis = 0. { Pjlb_t PjlbRaw; // bitmap in old leaf. Pjlb_t Pjlb; uint8_t * Pleafnew; // JPIMMED as a pointer. Word_t ldigit; // larger than uint8_t. PjlbRaw = (Pjlb_t) (Pjp->jp_Addr); Pjlb = P_JLB(PjlbRaw); Pleafnew = Pjp->jp_1Index; JU_BITMAPCLEARL(Pjlb, Index); // unset Indexs bit. // TBD: This is very slow, there must be a better way: for (ldigit = 0; ldigit < cJU_BRANCHUNUMJPS; ++ldigit) { if (JU_BITMAPTESTL(Pjlb, ldigit)) { *Pleafnew++ = ldigit; assert(Pleafnew - (Pjp->jp_1Index) <= cJU_IMMED1_MAXPOP1); } } DBGCODE(JudyCheckSorted((Pjll_t) (Pjp->jp_1Index), cJU_IMMED1_MAXPOP1, 1);) j__udyFreeJLB1(PjlbRaw, Pjpm); Pjp->jp_Type = cJ1_JPIMMED_1_15; return(1); } #else // (JUDYL || (! JU_64BIT)) // Compress LeafB1 to a Leaf1: // // Note: 4.37 of this file contained alternate code for Judy1 only that simply // cleared the bit and allowed the LeafB1 to go below cJU_LEAF1_MAXPOP1. This // was the ONLY case where a malloc failure was not fatal; however, it violated // the critical assumption that the tree is always kept in least-compressed // form. if (pop1 == cJU_LEAF1_MAXPOP1) // hysteresis = 1. { if (j__udyLeafB1ToLeaf1(Pjp, Pjpm) == -1) return(-1); goto ContinueDelWalk; // delete Index in new Leaf1. } #endif // (JUDYL || (! JU_64BIT)) #ifdef JUDY1 // unset Indexs bit: JU_BITMAPCLEARL(P_JLB(Pjp->jp_Addr), Index); #else // JUDYL // This is very different from Judy1 because of the need to manage the value // area: // // Get last byte to decode from Index, and pointer to bitmap leaf: digit = JU_DIGITATSTATE(Index, 1); Pjlb = P_JLB(Pjp->jp_Addr); // Prepare additional values: subexp = digit / cJU_BITSPERSUBEXPL; // which subexpanse. bitmap = JU_JLB_BITMAP(Pjlb, subexp); // subexps 32-bit map. PjvRaw = JL_JLB_PVALUE(Pjlb, subexp); // corresponding values. Pjv = P_JV(PjvRaw); bitmask = JU_BITPOSMASKL(digit); // mask for Index. assert(bitmap & bitmask); // Index must be valid. if (bitmap == cJU_FULLBITMAPL) // full bitmap, take shortcut: { pop1 = cJU_BITSPERSUBEXPL; offset = digit % cJU_BITSPERSUBEXPL; } else // compute subexpanse pop1 and value area offset: { pop1 = j__udyCountBitsL(bitmap); offset = j__udyCountBitsL(bitmap & (bitmask - 1)); } // Handle solitary Index remaining in subexpanse: if (pop1 == 1) { j__udyLFreeJV(PjvRaw, 1, Pjpm); JL_JLB_PVALUE(Pjlb, subexp) = (Pjv_t) NULL; JU_JLB_BITMAP(Pjlb, subexp) = 0; return(1); } // Shrink value area in place or move to a smaller value area: if (JL_LEAFVGROWINPLACE(pop1 - 1)) // hysteresis = 0. { JU_DELETEINPLACE(Pjv, pop1, offset, ignore); } else { if ((PjvnewRaw = j__udyLAllocJV(pop1 - 1, Pjpm)) == (Pjv_t) NULL) return(-1); Pjvnew = P_JV(PjvnewRaw); JU_DELETECOPY(Pjvnew, Pjv, pop1, offset, ignore); j__udyLFreeJV(PjvRaw, pop1, Pjpm); JL_JLB_PVALUE(Pjlb, subexp) = (Pjv_t) PjvnewRaw; } JU_JLB_BITMAP(Pjlb, subexp) ^= bitmask; // clear Indexs bit. #endif // JUDYL return(1); } // case. #ifdef JUDY1 // **************************************************************************** // FULL POPULATION LEAF: // // Convert to a LeafB1 and delete the index. Hysteresis = 0; none is possible. // // Note: Earlier the second assertion below said, "== 2", but in fact the // parent could be at a higher level if a fullpop is under a narrow pointer. case cJ1_JPFULLPOPU1: { Pjlb_t PjlbRaw; Pjlb_t Pjlb; Word_t subexp; assert(! JU_DCDNOTMATCHINDEX(Index, Pjp, 2)); assert(ParentLevel > 1); // see above. if ((PjlbRaw = j__udyAllocJLB1(Pjpm)) == (Pjlb_t) NULL) return(-1); Pjlb = P_JLB(PjlbRaw); // Fully populate the leaf, then unset Indexs bit: for (subexp = 0; subexp < cJU_NUMSUBEXPL; ++subexp) JU_JLB_BITMAP(Pjlb, subexp) = cJU_FULLBITMAPL; JU_BITMAPCLEARL(Pjlb, Index); Pjp->jp_Addr = (Word_t) PjlbRaw; Pjp->jp_Type = cJU_JPLEAF_B1; return(1); } #endif // JUDY1 // **************************************************************************** // IMMEDIATE JP: // // If theres just the one Index in the Immed, convert the JP to a JPNULL* // (should only happen in a BranchU); otherwise delete the Index from the // Immed. See the state transitions table elsewhere in this file for a summary // of which Immed types must be handled. Hysteresis = 0; none is possible with // Immeds. // // MACROS FOR COMMON CODE: // // Single Index remains in cJU_JPIMMED_*_01; convert JP to null: // // Variables Pjp and parentJPtype are in the context. // // Note: cJU_JPIMMED_*_01 should only be encountered in BranchUs, not in // BranchLs or BranchBs (where its improper to merely modify the JP to be a // null JP); that is, BranchL and BranchB code should have already handled // any cJU_JPIMMED_*_01 by different means. #define JU_IMMED_01(NewJPType,ParentJPType) \ \ assert(parentJPtype == (ParentJPType)); \ assert(JU_JPDCDPOP0(Pjp) == JU_TRIMTODCDSIZE(Index)); \ JU_JPSETADT(Pjp, 0, 0, NewJPType); \ return(1) // Convert cJ*_JPIMMED_*_02 to cJU_JPIMMED_*_01: // // Move the undeleted Index, whichever does not match the least bytes of Index, // from undecoded-bytes-only (in jp_1Index or jp_LIndex as appropriate) to // jp_DcdPopO (full-field). Pjp, Index, and offset are in the context. #define JU_IMMED_02(cIS,LeafType,NewJPType) \ { \ LeafType Pleaf; \ \ assert((ParentLevel - 1) == (cIS)); \ JUDY1CODE(Pleaf = (LeafType) (Pjp->jp_1Index);) \ JUDYLCODE(Pleaf = (LeafType) (Pjp->jp_LIndex);) \ JUDYLCODE(PjvRaw = (Pjv_t) (Pjp->jp_Addr);) \ JUDYLCODE(Pjv = P_JV(PjvRaw);) \ JU_TOIMMED_01_EVEN(cIS, ignore, ignore); \ JUDYLCODE(j__udyLFreeJV(PjvRaw, 2, Pjpm);) \ Pjp->jp_Type = (NewJPType); \ return(1); \ } #if (defined(JUDY1) || defined(JU_64BIT)) // Variation for "odd" cJ*_JPIMMED_*_02 JP types, which are very different from // "even" types because they use leaf search code and odd-copy macros: // // Note: JudyL 32-bit has no "odd" JPIMMED_*_02 types. #define JU_IMMED_02_ODD(cIS,NewJPType,SearchLeaf,CopyPIndex) \ { \ uint8_t * Pleaf; \ \ assert((ParentLevel - 1) == (cIS)); \ JUDY1CODE(Pleaf = (uint8_t *) (Pjp->jp_1Index);) \ JUDYLCODE(Pleaf = (uint8_t *) (Pjp->jp_LIndex);) \ JUDYLCODE(PjvRaw = (Pjv_t) (Pjp->jp_Addr);) \ JUDYLCODE(Pjv = P_JV(PjvRaw);) \ JU_TOIMMED_01_ODD(cIS, SearchLeaf, CopyPIndex); \ JUDYLCODE(j__udyLFreeJV(PjvRaw, 2, Pjpm);) \ Pjp->jp_Type = (NewJPType); \ return(1); \ } #endif // (JUDY1 || JU_64BIT) // Core code for deleting one Index (and for JudyL, its value area) from a // larger Immed: // // Variables Pleaf, pop1, and offset are in the context. #ifdef JUDY1 #define JU_IMMED_DEL(cIS,DeleteInPlace) \ DeleteInPlace(Pleaf, pop1, offset, cIS); \ DBGCODE(JudyCheckSorted(Pleaf, pop1 - 1, cIS);) #else // JUDYL // For JudyL the value area might need to be shrunk: #define JU_IMMED_DEL(cIS,DeleteInPlace) \ \ if (JL_LEAFVGROWINPLACE(pop1 - 1)) /* hysteresis = 0 */ \ { \ DeleteInPlace( Pleaf, pop1, offset, cIS); \ JU_DELETEINPLACE(Pjv, pop1, offset, ignore); \ DBGCODE(JudyCheckSorted(Pleaf, pop1 - 1, cIS);) \ } \ else \ { \ Pjv_t PjvnewRaw; \ Pjv_t Pjvnew; \ \ if ((PjvnewRaw = j__udyLAllocJV(pop1 - 1, Pjpm)) \ == (Pjv_t) NULL) return(-1); \ Pjvnew = P_JV(PjvnewRaw); \ \ DeleteInPlace(Pleaf, pop1, offset, cIS); \ JU_DELETECOPY(Pjvnew, Pjv, pop1, offset, ignore); \ DBGCODE(JudyCheckSorted(Pleaf, pop1 - 1, cIS);) \ j__udyLFreeJV(PjvRaw, pop1, Pjpm); \ \ (Pjp->jp_Addr) = (Word_t) PjvnewRaw; \ } #endif // JUDYL // Delete one Index from a larger Immed where no restructuring is required: // // Variables pop1, Pjp, offset, and Index are in the context. #define JU_IMMED(cIS,LeafType,BaseJPType,SearchLeaf,DeleteInPlace) \ { \ LeafType Pleaf; \ \ assert((ParentLevel - 1) == (cIS)); \ JUDY1CODE(Pleaf = (LeafType) (Pjp->jp_1Index);) \ JUDYLCODE(Pleaf = (LeafType) (Pjp->jp_LIndex);) \ JUDYLCODE(PjvRaw = (Pjv_t) (Pjp->jp_Addr);) \ JUDYLCODE(Pjv = P_JV(PjvRaw);) \ pop1 = (JU_JPTYPE(Pjp)) - (BaseJPType) + 2; \ offset = SearchLeaf(Pleaf, pop1, Index); \ assert(offset >= 0); /* Index must be valid */ \ \ JU_IMMED_DEL(cIS, DeleteInPlace); \ --(Pjp->jp_Type); \ return(1); \ } // END OF MACROS, START OF CASES: // Single Index remains in Immed; convert JP to null: case cJU_JPIMMED_1_01: JU_IMMED_01(cJU_JPNULL1, cJU_JPBRANCH_U2); case cJU_JPIMMED_2_01: JU_IMMED_01(cJU_JPNULL2, cJU_JPBRANCH_U3); #ifndef JU_64BIT case cJU_JPIMMED_3_01: JU_IMMED_01(cJU_JPNULL3, cJU_JPBRANCH_U); #else case cJU_JPIMMED_3_01: JU_IMMED_01(cJU_JPNULL3, cJU_JPBRANCH_U4); case cJU_JPIMMED_4_01: JU_IMMED_01(cJU_JPNULL4, cJU_JPBRANCH_U5); case cJU_JPIMMED_5_01: JU_IMMED_01(cJU_JPNULL5, cJU_JPBRANCH_U6); case cJU_JPIMMED_6_01: JU_IMMED_01(cJU_JPNULL6, cJU_JPBRANCH_U7); case cJU_JPIMMED_7_01: JU_IMMED_01(cJU_JPNULL7, cJU_JPBRANCH_U); #endif // Multiple Indexes remain in the Immed JP; delete the specified Index: case cJU_JPIMMED_1_02: JU_IMMED_02(1, uint8_t *, cJU_JPIMMED_1_01); case cJU_JPIMMED_1_03: #if (defined(JUDY1) || defined(JU_64BIT)) case cJU_JPIMMED_1_04: case cJU_JPIMMED_1_05: case cJU_JPIMMED_1_06: case cJU_JPIMMED_1_07: #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_1_08: case cJ1_JPIMMED_1_09: case cJ1_JPIMMED_1_10: case cJ1_JPIMMED_1_11: case cJ1_JPIMMED_1_12: case cJ1_JPIMMED_1_13: case cJ1_JPIMMED_1_14: case cJ1_JPIMMED_1_15: #endif JU_IMMED(1, uint8_t *, cJU_JPIMMED_1_02, j__udySearchLeaf1, JU_DELETEINPLACE); #if (defined(JUDY1) || defined(JU_64BIT)) case cJU_JPIMMED_2_02: JU_IMMED_02(2, uint16_t *, cJU_JPIMMED_2_01); case cJU_JPIMMED_2_03: #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_2_04: case cJ1_JPIMMED_2_05: case cJ1_JPIMMED_2_06: case cJ1_JPIMMED_2_07: #endif #if (defined(JUDY1) || defined(JU_64BIT)) JU_IMMED(2, uint16_t *, cJU_JPIMMED_2_02, j__udySearchLeaf2, JU_DELETEINPLACE); case cJU_JPIMMED_3_02: JU_IMMED_02_ODD(3, cJU_JPIMMED_3_01, j__udySearchLeaf3, JU_COPY3_PINDEX_TO_LONG); #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_3_03: case cJ1_JPIMMED_3_04: case cJ1_JPIMMED_3_05: JU_IMMED(3, uint8_t *, cJU_JPIMMED_3_02, j__udySearchLeaf3, JU_DELETEINPLACE_ODD); case cJ1_JPIMMED_4_02: JU_IMMED_02(4, uint32_t *, cJU_JPIMMED_4_01); case cJ1_JPIMMED_4_03: JU_IMMED(4, uint32_t *, cJ1_JPIMMED_4_02, j__udySearchLeaf4, JU_DELETEINPLACE); case cJ1_JPIMMED_5_02: JU_IMMED_02_ODD(5, cJU_JPIMMED_5_01, j__udySearchLeaf5, JU_COPY5_PINDEX_TO_LONG); case cJ1_JPIMMED_5_03: JU_IMMED(5, uint8_t *, cJ1_JPIMMED_5_02, j__udySearchLeaf5, JU_DELETEINPLACE_ODD); case cJ1_JPIMMED_6_02: JU_IMMED_02_ODD(6, cJU_JPIMMED_6_01, j__udySearchLeaf6, JU_COPY6_PINDEX_TO_LONG); case cJ1_JPIMMED_7_02: JU_IMMED_02_ODD(7, cJU_JPIMMED_7_01, j__udySearchLeaf7, JU_COPY7_PINDEX_TO_LONG); #endif // (JUDY1 && JU_64BIT) // **************************************************************************** // INVALID JP TYPE: default: JU_SET_ERRNO_NONNULL(Pjpm, JU_ERRNO_CORRUPT); return(-1); } // switch // PROCESS JP -- RECURSIVELY: // // For non-Immed JP types, if successful, post-decrement the population count // at this level, or collapse a BranchL if necessary by copying the remaining // JP in the BranchL to the parent (hysteresis = 0), which implicitly creates a // narrow pointer if there was not already one in the hierarchy. assert(level); retcode = j__udyDelWalk(Pjp, Index, level, Pjpm); assert(retcode != 0); // should never happen. if ((JU_JPTYPE(Pjp)) < cJU_JPIMMED_1_01) // not an Immed. { switch (retcode) { case 1: { jp_t JP = *Pjp; Word_t DcdP0; DcdP0 = JU_JPDCDPOP0(Pjp) - 1; // decrement count. JU_JPSETADT(Pjp, JP.jp_Addr, DcdP0, JU_JPTYPE(&JP)); break; } case 2: // collapse BranchL to single JP; see above: { Pjbl_t PjblRaw = (Pjbl_t) (Pjp->jp_Addr); Pjbl_t Pjbl = P_JBL(PjblRaw); *Pjp = Pjbl->jbl_jp[0]; j__udyFreeJBL(PjblRaw, Pjpm); retcode = 1; } } } return(retcode); } // j__udyDelWalk() // **************************************************************************** // J U D Y 1 U N S E T // J U D Y L D E L // // Main entry point. See the manual entry for details. #ifdef JUDY1 FUNCTION int Judy1Unset #else FUNCTION int JudyLDel #endif ( PPvoid_t PPArray, // in which to delete. Word_t Index, // to delete. PJError_t PJError // optional, for returning error info. ) { Word_t pop1; // population of leaf. int offset; // at which to delete Index. JUDY1CODE(int retcode;) // return code from Judy1Test(). JUDYLCODE(PPvoid_t PPvalue;) // pointer from JudyLGet(). // CHECK FOR NULL ARRAY POINTER (error by caller): if (PPArray == (PPvoid_t) NULL) { JU_SET_ERRNO(PJError, JU_ERRNO_NULLPPARRAY); return(JERRI); } // CHECK IF INDEX IS INVALID: // // If so, theres nothing to do. This saves a lot of time. Pass through // PJError, if any, from the "get" function. #ifdef JUDY1 if ((retcode = Judy1Test(*PPArray, Index, PJError)) == JERRI) return (JERRI); if (retcode == 0) return(0); #else if ((PPvalue = JudyLGet(*PPArray, Index, PJError)) == PPJERR) return (JERRI); if (PPvalue == (PPvoid_t) NULL) return(0); #endif // **************************************************************************** // PROCESS TOP LEVEL (LEAFW) BRANCHES AND LEAVES: // **************************************************************************** // LEAFW LEAF, OTHER SIZE: // // Shrink or convert the leaf as necessary. Hysteresis = 0; none is possible. if (JU_LEAFW_POP0(*PPArray) < cJU_LEAFW_MAXPOP1) // must be a LEAFW { JUDYLCODE(Pjv_t Pjv;) // current value area. JUDYLCODE(Pjv_t Pjvnew;) // value area in new leaf. Pjlw_t Pjlw = P_JLW(*PPArray); // first word of leaf. Pjlw_t Pjlwnew; // replacement leaf. pop1 = Pjlw[0] + 1; // first word of leaf is pop0. // Delete single (last) Index from array: if (pop1 == 1) { j__udyFreeJLW(Pjlw, /* pop1 = */ 1, (Pjpm_t) NULL); *PPArray = (Pvoid_t) NULL; return(1); } // Locate Index in compressible leaf: offset = j__udySearchLeafW(Pjlw + 1, pop1, Index); assert(offset >= 0); // Index must be valid. JUDYLCODE(Pjv = JL_LEAFWVALUEAREA(Pjlw, pop1);) // Delete Index in-place: // // Note: "Grow in place from pop1 - 1" is the logical inverse of, "shrink in // place from pop1." Also, Pjlw points to the count word, so skip that for // doing the deletion. if (JU_LEAFWGROWINPLACE(pop1 - 1)) { JU_DELETEINPLACE(Pjlw + 1, pop1, offset, ignore); #ifdef JUDYL // also delete from value area: JU_DELETEINPLACE(Pjv, pop1, offset, ignore); #endif DBGCODE(JudyCheckSorted((Pjll_t) (Pjlw + 1), pop1 - 1, cJU_ROOTSTATE);) --(Pjlw[0]); // decrement population. DBGCODE(JudyCheckPop(*PPArray);) return(1); } // Allocate new leaf for use in either case below: Pjlwnew = j__udyAllocJLW(pop1 - 1); JU_CHECKALLOC(Pjlw_t, Pjlwnew, JERRI); // Shrink to smaller LEAFW: // // Note: Skip the first word = pop0 in each leaf. Pjlwnew[0] = (pop1 - 1) - 1; JU_DELETECOPY(Pjlwnew + 1, Pjlw + 1, pop1, offset, ignore); #ifdef JUDYL // also delete from value area: Pjvnew = JL_LEAFWVALUEAREA(Pjlwnew, pop1 - 1); JU_DELETECOPY(Pjvnew, Pjv, pop1, offset, ignore); #endif DBGCODE(JudyCheckSorted(Pjlwnew + 1, pop1 - 1, cJU_ROOTSTATE);) j__udyFreeJLW(Pjlw, pop1, (Pjpm_t) NULL); //// *PPArray = (Pvoid_t) Pjlwnew | cJU_LEAFW); *PPArray = (Pvoid_t) Pjlwnew; DBGCODE(JudyCheckPop(*PPArray);) return(1); } else // **************************************************************************** // JRP BRANCH: // // Traverse through the JPM to do the deletion unless the population is small // enough to convert immediately to a LEAFW. { Pjpm_t Pjpm; Pjp_t Pjp; // top-level JP to process. Word_t digit; // in a branch. JUDYLCODE(Pjv_t Pjv;) // to value area. Pjlw_t Pjlwnew; // replacement leaf. DBGCODE(Pjlw_t Pjlwnew_orig;) Pjpm = P_JPM(*PPArray); // top object in array (tree). Pjp = &(Pjpm->jpm_JP); // next object (first branch or leaf). assert(((Pjpm->jpm_JP.jp_Type) == cJU_JPBRANCH_L) || ((Pjpm->jpm_JP.jp_Type) == cJU_JPBRANCH_B) || ((Pjpm->jpm_JP.jp_Type) == cJU_JPBRANCH_U)); // WALK THE TREE // // Note: Recursive code in j__udyDelWalk() knows how to collapse a lower-level // BranchL containing a single JP into the parent JP as a narrow pointer, but // the code here cant do that for a top-level BranchL. The result can be // PArray -> JPM -> BranchL containing a single JP. This situation is // unavoidable because a JPM cannot contain a narrow pointer; the BranchL is // required in order to hold the top digit decoded, and it does not collapse to // a LEAFW until the population is low enough. // // TBD: Should we add a topdigit field to JPMs so they can hold narrow // pointers? if (j__udyDelWalk(Pjp, Index, cJU_ROOTSTATE, Pjpm) == -1) { JU_COPY_ERRNO(PJError, Pjpm); return(JERRI); } --(Pjpm->jpm_Pop0); // success; decrement total population. if ((Pjpm->jpm_Pop0 + 1) != cJU_LEAFW_MAXPOP1) { DBGCODE(JudyCheckPop(*PPArray);) return(1); } // COMPRESS A BRANCH[LBU] TO A LEAFW: // Pjlwnew = j__udyAllocJLW(cJU_LEAFW_MAXPOP1); JU_CHECKALLOC(Pjlw_t, Pjlwnew, JERRI); // Plug leaf into root pointer and set population count: //// *PPArray = (Pvoid_t) ((Word_t) Pjlwnew | cJU_LEAFW); *PPArray = (Pvoid_t) Pjlwnew; #ifdef JUDYL // prepare value area: Pjv = JL_LEAFWVALUEAREA(Pjlwnew, cJU_LEAFW_MAXPOP1); #endif *Pjlwnew++ = cJU_LEAFW_MAXPOP1 - 1; // set pop0. DBGCODE(Pjlwnew_orig = Pjlwnew;) switch (JU_JPTYPE(Pjp)) { // JPBRANCH_L: Copy each JPs indexes to the new LEAFW and free the old // branch: case cJU_JPBRANCH_L: { Pjbl_t PjblRaw = (Pjbl_t) (Pjp->jp_Addr); Pjbl_t Pjbl = P_JBL(PjblRaw); for (offset = 0; offset < Pjbl->jbl_NumJPs; ++offset) { pop1 = j__udyLeafM1ToLeafW(Pjlwnew, JU_PVALUEPASS (Pjbl->jbl_jp) + offset, JU_DIGITTOSTATE(Pjbl->jbl_Expanse[offset], cJU_BYTESPERWORD), (Pvoid_t) Pjpm); Pjlwnew += pop1; // advance through indexes. JUDYLCODE(Pjv += pop1;) // advance through values. } j__udyFreeJBL(PjblRaw, Pjpm); assert(Pjlwnew == Pjlwnew_orig + cJU_LEAFW_MAXPOP1); break; // delete Index from new LEAFW. } // JPBRANCH_B: Copy each JPs indexes to the new LEAFW and free the old // branch, including each JP subarray: case cJU_JPBRANCH_B: { Pjbb_t PjbbRaw = (Pjbb_t) (Pjp->jp_Addr); Pjbb_t Pjbb = P_JBB(PjbbRaw); Word_t subexp; // current subexpanse number. BITMAPB_t bitmap; // portion for this subexpanse. Pjp_t Pjp2Raw; // one subexpanses subarray. Pjp_t Pjp2; for (subexp = 0; subexp < cJU_NUMSUBEXPB; ++subexp) { if ((bitmap = JU_JBB_BITMAP(Pjbb, subexp)) == 0) continue; // skip empty subexpanse. digit = subexp * cJU_BITSPERSUBEXPB; Pjp2Raw = JU_JBB_PJP(Pjbb, subexp); Pjp2 = P_JP(Pjp2Raw); assert(Pjp2 != (Pjp_t) NULL); // Walk through bits for all possible sub-subexpanses (digits); increment // offset for each populated subexpanse; until no more set bits: for (offset = 0; bitmap != 0; bitmap >>= 1, ++digit) { if (! (bitmap & 1)) // skip empty sub-subexpanse. continue; pop1 = j__udyLeafM1ToLeafW(Pjlwnew, JU_PVALUEPASS Pjp2 + offset, JU_DIGITTOSTATE(digit, cJU_BYTESPERWORD), (Pvoid_t) Pjpm); Pjlwnew += pop1; // advance through indexes. JUDYLCODE(Pjv += pop1;) // advance through values. ++offset; } j__udyFreeJBBJP(Pjp2Raw, /* pop1 = */ offset, Pjpm); } j__udyFreeJBB(PjbbRaw, Pjpm); assert(Pjlwnew == Pjlwnew_orig + cJU_LEAFW_MAXPOP1); break; // delete Index from new LEAFW. } // case cJU_JPBRANCH_B. // JPBRANCH_U: Copy each JPs indexes to the new LEAFW and free the old // branch: case cJU_JPBRANCH_U: { Pjbu_t PjbuRaw = (Pjbu_t) (Pjp->jp_Addr); Pjbu_t Pjbu = P_JBU(PjbuRaw); Word_t ldigit; // larger than uint8_t. for (Pjp = Pjbu->jbu_jp, ldigit = 0; ldigit < cJU_BRANCHUNUMJPS; ++Pjp, ++ldigit) { // Shortcuts, to save a little time for possibly big branches: if ((JU_JPTYPE(Pjp)) == cJU_JPNULLMAX) // skip null JP. continue; // TBD: Should the following shortcut also be used in BranchL and BranchB // code? #ifndef JU_64BIT if ((JU_JPTYPE(Pjp)) == cJU_JPIMMED_3_01) #else if ((JU_JPTYPE(Pjp)) == cJU_JPIMMED_7_01) #endif { // single Immed: *Pjlwnew++ = JU_DIGITTOSTATE(ldigit, cJU_BYTESPERWORD) | JU_JPDCDPOP0(Pjp); // rebuild Index. #ifdef JUDYL *Pjv++ = Pjp->jp_Addr; // copy value area. #endif continue; } pop1 = j__udyLeafM1ToLeafW(Pjlwnew, JU_PVALUEPASS Pjp, JU_DIGITTOSTATE(ldigit, cJU_BYTESPERWORD), (Pvoid_t) Pjpm); Pjlwnew += pop1; // advance through indexes. JUDYLCODE(Pjv += pop1;) // advance through values. } j__udyFreeJBU(PjbuRaw, Pjpm); assert(Pjlwnew == Pjlwnew_orig + cJU_LEAFW_MAXPOP1); break; // delete Index from new LEAFW. } // case cJU_JPBRANCH_U. // INVALID JP TYPE in jpm_t struct default: JU_SET_ERRNO_NONNULL(Pjpm, JU_ERRNO_CORRUPT); return(JERRI); } // end switch on sub-JP type. DBGCODE(JudyCheckSorted((Pjll_t) Pjlwnew_orig, cJU_LEAFW_MAXPOP1, cJU_ROOTSTATE);) // FREE JPM (no longer needed): j__udyFreeJPM(Pjpm, (Pjpm_t) NULL); DBGCODE(JudyCheckPop(*PPArray);) return(1); } /*NOTREACHED*/ } // Judy1Unset() / JudyLDel() judy-1.0.5/src/JudyCommon/JudyMalloc.c0000644000175000017500000000515110204462077020002 0ustar troyhebetroyhebe// Copyright (C) 2000 - 2002 Hewlett-Packard Company // // This program is free software; you can redistribute it and/or modify it // under the term of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License // for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program; if not, write to the Free Software Foundation, // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // _________________ // @(#) $Revision: 4.33 $ $Source: /judy/src/JudyCommon/JudyMalloc.c $ // ************************************************************************ // // JUDY - Memory Allocater // // -by- // // Douglas L. Baskins // // Hewlett Packard // // Fort Collins, Co // // (970) 229-2027 // // // // ************************************************************************ // // JUDY INCLUDE FILES #include "Judy.h" // **************************************************************************** // J U D Y M A L L O C // // Allocate RAM. This is the single location in Judy code that calls // malloc(3C). Note: JPM accounting occurs at a higher level. Word_t JudyMalloc( Word_t Words) { Word_t Addr; Addr = (Word_t) malloc(Words * sizeof(Word_t)); return(Addr); } // JudyMalloc() // **************************************************************************** // J U D Y F R E E void JudyFree( void * PWord, Word_t Words) { (void) Words; free(PWord); } // JudyFree() // **************************************************************************** // J U D Y M A L L O C // // Higher-level "wrapper" for allocating objects that need not be in RAM, // although at this time they are in fact only in RAM. Later we hope that some // entire subtrees (at a JPM or branch) can be "virtual", so their allocations // and frees should go through this level. Word_t JudyMallocVirtual( Word_t Words) { return(JudyMalloc(Words)); } // JudyMallocVirtual() // **************************************************************************** // J U D Y F R E E void JudyFreeVirtual( void * PWord, Word_t Words) { JudyFree(PWord, Words); } // JudyFreeVirtual() judy-1.0.5/src/JudyCommon/JudyPrevNext.c0000644000175000017500000016565510204462077020366 0ustar troyhebetroyhebe// Copyright (C) 2000 - 2002 Hewlett-Packard Company // // This program is free software; you can redistribute it and/or modify it // under the term of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License // for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program; if not, write to the Free Software Foundation, // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // _________________ // @(#) $Revision: 4.54 $ $Source: /judy/src/JudyCommon/JudyPrevNext.c $ // // Judy*Prev() and Judy*Next() functions for Judy1 and JudyL. // Compile with one of -DJUDY1 or -DJUDYL. // // Compile with -DJUDYNEXT for the Judy*Next() function; otherwise defaults to // Judy*Prev(). #if (! (defined(JUDY1) || defined(JUDYL))) #error: One of -DJUDY1 or -DJUDYL must be specified. #endif #ifndef JUDYNEXT #ifndef JUDYPREV #define JUDYPREV 1 // neither set => use default. #endif #endif #ifdef JUDY1 #include "Judy1.h" #else #include "JudyL.h" #endif #include "JudyPrivate1L.h" // **************************************************************************** // J U D Y 1 P R E V // J U D Y 1 N E X T // J U D Y L P R E V // J U D Y L N E X T // // See the manual entry for the API. // // OVERVIEW OF Judy*Prev(): // // Use a reentrant switch statement (state machine, SM1 = "get") to decode the // callers *PIndex-1, starting with the (PArray), through branches, if // any, down to an immediate or a leaf. Look for *PIndex-1 in that leaf, and // if found, return it. // // A dead end is either a branch that does not contain a JP for the appropriate // digit in *PIndex-1, or a leaf that does not contain the undecoded digits of // *PIndex-1. Upon reaching a dead end, backtrack through the leaf/branches // that were just traversed, using a list (history) of parent JPs that is built // while going forward in SM1Get. Start with the current leaf or branch. In a // backtracked leaf, look for an Index less than *PIndex-1. In each // backtracked branch, look "sideways" for the next JP, if any, lower than the // one for the digit (from *PIndex-1) that was previously decoded. While // backtracking, if a leaf has no previous Index or a branch has no lower JP, // go to its parent branch in turn. Upon reaching the JRP, return failure, "no // previous Index". The backtrack process is sufficiently different from // SM1Get to merit its own separate reentrant switch statement (SM2 = // "backtrack"). // // While backtracking, upon finding a lower JP in a branch, there is certain to // be a "prev" Index under that JP (unless the Judy array is corrupt). // Traverse forward again, this time taking the last (highest, right-most) JP // in each branch, and the last (highest) Index upon reaching an immediate or a // leaf. This traversal is sufficiently different from SM1Get and SM2Backtrack // to merit its own separate reentrant switch statement (SM3 = "findlimit"). // // "Decode" bytes in JPs complicate this process a little. In SM1Get, when a // JP is a narrow pointer, that is, when states are skipped (so the skipped // digits are stored in jp_DcdPopO), compare the relevant digits to the same // digits in *PIndex-1. If they are EQUAL, proceed in SM1Get as before. If // jp_DcdPopOs digits are GREATER, treat the JP as a dead end and proceed in // SM2Backtrack. If jp_DcdPopOs digits are LESS, treat the JP as if it had // just been found during a backtrack and proceed directly in SM3Findlimit. // // Note that Decode bytes can be ignored in SM3Findlimit; they dont matter. // Also note that in practice the Decode bytes are routinely compared with // *PIndex-1 because thats simpler and no slower than first testing for // narrowness. // // Decode bytes also make it unnecessary to construct the Index to return (the // revised *PIndex) during the search. This step is deferred until finding an // Index during backtrack or findlimit, before returning it. The first digit // of *PIndex is derived (saved) based on which JP is used in a JRP branch. // The remaining digits are obtained from the jp_DcdPopO field in the JP (if // any) above the immediate or leaf containing the found (prev) Index, plus the // remaining digit(s) in the immediate or leaf itself. In the case of a LEAFW, // the Index to return is found directly in the leaf. // // Note: Theoretically, as described above, upon reaching a dead end, SM1Get // passes control to SM2Backtrack to look sideways, even in a leaf. Actually // its a little more efficient for the SM1Get leaf cases to shortcut this and // take care of the sideways searches themselves. Hence the history list only // contains branch JPs, and SM2Backtrack only handles branches. In fact, even // the branch handling cases in SM1Get do some shortcutting (sideways // searching) to avoid pushing history and calling SM2Backtrack unnecessarily. // // Upon reaching an Index to return after backtracking, *PIndex must be // modified to the found Index. In principle this could be done by building // the Index from a saved rootdigit (in the top branch) plus the Dcd bytes from // the parent JP plus the appropriate Index bytes from the leaf. However, // Immediates are difficult because their parent JPs lack one (last) digit. So // instead just build the *PIndex to return "top down" while backtracking and // findlimiting. // // This function is written iteratively for speed, rather than recursively. // // CAVEATS: // // Why use a backtrack list (history stack), since it has finite size? The // size is small for Judy on both 32-bit and 64-bit systems, and a list (really // just an array) is fast to maintain and use. Other alternatives include // doing a lookahead (lookaside) in each branch while traversing forward // (decoding), and restarting from the top upon a dead end. // // A lookahead means noting the last branch traversed which contained a // non-null JP lower than the one specified by a digit in *PIndex-1, and // returning to that point for SM3Findlimit. This seems like a good idea, and // should be pretty cheap for linear and bitmap branches, but it could result // in up to 31 unnecessary additional cache line fills (in extreme cases) for // every uncompressed branch traversed. We have considered means of attaching // to or hiding within an uncompressed branch (in null JPs) a "cache line map" // or other structure, such as an offset to the next non-null JP, that would // speed this up, but it seems unnecessary merely to avoid having a // finite-length list (array). (If JudySL is ever made "native", the finite // list length will be an issue.) // // Restarting at the top of the Judy array after a dead end requires a careful // modification of *PIndex-1 to decrement the digit for the parent branch and // set the remaining lower digits to all 1s. This must be repeated each time a // parent branch contains another dead end, so even though it should all happen // in cache, the CPU time can be excessive. (For JudySL or an equivalent // "infinitely deep" Judy array, consider a hybrid of a large, finite, // "circular" list and a restart-at-top when the list is backtracked to // exhaustion.) // // Why search for *PIndex-1 instead of *PIndex during SM1Get? In rare // instances this prevents an unnecessary decode down the wrong path followed // by a backtrack; its pretty cheap to set up initially; and it means the // SM1Get machine can simply return if/when it finds that Index. // // TBD: Wed like to enhance this function to make successive searches faster. // This would require saving some previous state, including the previous Index // returned, and in which leaf it was found. If the next call is for the same // Index and the array has not been modified, start at the same leaf. This // should be much easier to implement since this is iterative rather than // recursive code. // // VARIATIONS FOR Judy*Next(): // // The Judy*Next() code is nearly a perfect mirror of the Judy*Prev() code. // See the Judy*Prev() overview comments, and mentally switch the following: // // - "*PIndex-1" => "*PIndex+1" // - "less than" => "greater than" // - "lower" => "higher" // - "lowest" => "highest" // - "next-left" => "next-right" // - "right-most" => "left-most" // // Note: SM3Findlimit could be called SM3Findmax/SM3Findmin, but a common name // for both Prev and Next means many fewer ifdefs in this code. // // TBD: Currently this code traverses a JP whether its expanse is partially or // completely full (populated). For Judy1 (only), since there is no value area // needed, consider shortcutting to a "success" return upon encountering a full // JP in SM1Get (or even SM3Findlimit?) A full JP looks like this: // // (((JU_JPDCDPOP0(Pjp) ^ cJU_ALLONES) & cJU_POP0MASK(cLevel)) == 0) #ifdef JUDY1 #ifdef JUDYPREV FUNCTION int Judy1Prev #else FUNCTION int Judy1Next #endif #else #ifdef JUDYPREV FUNCTION PPvoid_t JudyLPrev #else FUNCTION PPvoid_t JudyLNext #endif #endif ( Pcvoid_t PArray, // Judy array to search. Word_t * PIndex, // starting point and result. PJError_t PJError // optional, for returning error info. ) { Pjp_t Pjp, Pjp2; // current JPs. Pjbl_t Pjbl; // Pjp->jp_Addr masked and cast to types: Pjbb_t Pjbb; Pjbu_t Pjbu; // Note: The following initialization is not strictly required but it makes // gcc -Wall happy because there is an "impossible" path from Immed handling to // SM1LeafLImm code that looks like Pjll might be used before set: Pjll_t Pjll = (Pjll_t) NULL; Word_t state; // current state in SM. Word_t digit; // next digit to decode from Index. // Note: The following initialization is not strictly required but it makes // gcc -Wall happy because there is an "impossible" path from Immed handling to // SM1LeafLImm code (for JudyL & JudyPrev only) that looks like pop1 might be // used before set: #if (defined(JUDYL) && defined(JUDYPREV)) Word_t pop1 = 0; // in a leaf. #else Word_t pop1; // in a leaf. #endif int offset; // linear branch/leaf, from j__udySearchLeaf*(). int subexp; // subexpanse in a bitmap branch. Word_t bitposmask; // bit in bitmap for Index. // History for SM2Backtrack: // // For a given histnum, APjphist[histnum] is a parent JP that points to a // branch, and Aoffhist[histnum] is the offset of the NEXT JP in the branch to // which the parent JP points. The meaning of Aoffhist[histnum] depends on the // type of branch to which the parent JP points: // // Linear: Offset of the next JP in the JP list. // // Bitmap: Which subexpanse, plus the offset of the next JP in the // subexpanses JP list (to avoid bit-counting again), plus for Judy*Next(), // hidden one byte to the left, which digit, because Judy*Next() also needs // this. // // Uncompressed: Digit, which is actually the offset of the JP in the branch. // // Note: Only branch JPs are stored in APjphist[] because, as explained // earlier, SM1Get shortcuts sideways searches in leaves (and even in branches // in some cases), so SM2Backtrack only handles branches. #define HISTNUMMAX cJU_ROOTSTATE // maximum branches traversable. Pjp_t APjphist[HISTNUMMAX]; // list of branch JPs traversed. int Aoffhist[HISTNUMMAX]; // list of next JP offsets; see above. int histnum = 0; // number of JPs now in list. // ---------------------------------------------------------------------------- // M A C R O S // // These are intended to make the code a bit more readable and less redundant. // "PUSH" AND "POP" Pjp AND offset ON HISTORY STACKS: // // Note: Ensure a corrupt Judy array does not overflow *hist[]. Meanwhile, // underflowing *hist[] simply means theres no more room to backtrack => // "no previous/next Index". #define HISTPUSH(Pjp,Offset) \ APjphist[histnum] = (Pjp); \ Aoffhist[histnum] = (Offset); \ \ if (++histnum >= HISTNUMMAX) \ { \ JU_SET_ERRNO(PJError, JU_ERRNO_CORRUPT) \ JUDY1CODE(return(JERRI );) \ JUDYLCODE(return(PPJERR);) \ } #define HISTPOP(Pjp,Offset) \ if ((histnum--) < 1) JU_RET_NOTFOUND; \ (Pjp) = APjphist[histnum]; \ (Offset) = Aoffhist[histnum] // How to pack/unpack Aoffhist[] values for bitmap branches: #ifdef JUDYPREV #define HISTPUSHBOFF(Subexp,Offset,Digit) \ (((Subexp) * cJU_BITSPERSUBEXPB) | (Offset)) #define HISTPOPBOFF(Subexp,Offset,Digit) \ (Subexp) = (Offset) / cJU_BITSPERSUBEXPB; \ (Offset) %= cJU_BITSPERSUBEXPB #else #define HISTPUSHBOFF(Subexp,Offset,Digit) \ (((Digit) << cJU_BITSPERBYTE) \ | ((Subexp) * cJU_BITSPERSUBEXPB) | (Offset)) #define HISTPOPBOFF(Subexp,Offset,Digit) \ (Digit) = (Offset) >> cJU_BITSPERBYTE; \ (Subexp) = ((Offset) & JU_LEASTBYTESMASK(1)) / cJU_BITSPERSUBEXPB; \ (Offset) %= cJU_BITSPERSUBEXPB #endif // CHECK FOR NULL JP: #define JPNULL(Type) (((Type) >= cJU_JPNULL1) && ((Type) <= cJU_JPNULLMAX)) // SEARCH A BITMAP: // // This is a weak analog of j__udySearchLeaf*() for bitmaps. Return the actual // or next-left position, base 0, of Digit in the single uint32_t bitmap, also // given a Bitposmask for Digit. // // Unlike j__udySearchLeaf*(), the offset is not returned bit-complemented if // Digits bit is unset, because the caller can check the bitmap themselves to // determine that. Also, if Digits bit is unset, the returned offset is to // the next-left JP (including -1), not to the "ideal" position for the Index = // next-right JP. // // Shortcut and skip calling j__udyCountBits*() if the bitmap is full, in which // case (Digit % cJU_BITSPERSUBEXP*) itself is the base-0 offset. // // TBD for Judy*Next(): Should this return next-right instead of next-left? // That is, +1 from current value? Maybe not, if Digits bit IS set, +1 would // be wrong. #define SEARCHBITMAPB(Bitmap,Digit,Bitposmask) \ (((Bitmap) == cJU_FULLBITMAPB) ? (Digit % cJU_BITSPERSUBEXPB) : \ j__udyCountBitsB((Bitmap) & JU_MASKLOWERINC(Bitposmask)) - 1) #define SEARCHBITMAPL(Bitmap,Digit,Bitposmask) \ (((Bitmap) == cJU_FULLBITMAPL) ? (Digit % cJU_BITSPERSUBEXPL) : \ j__udyCountBitsL((Bitmap) & JU_MASKLOWERINC(Bitposmask)) - 1) #ifdef JUDYPREV // Equivalent to search for the highest offset in Bitmap: #define SEARCHBITMAPMAXB(Bitmap) \ (((Bitmap) == cJU_FULLBITMAPB) ? cJU_BITSPERSUBEXPB - 1 : \ j__udyCountBitsB(Bitmap) - 1) #define SEARCHBITMAPMAXL(Bitmap) \ (((Bitmap) == cJU_FULLBITMAPL) ? cJU_BITSPERSUBEXPL - 1 : \ j__udyCountBitsL(Bitmap) - 1) #endif // CHECK DECODE BYTES: // // Check Decode bytes in a JP against the equivalent portion of *PIndex. If // *PIndex is lower (for Judy*Prev()) or higher (for Judy*Next()), this JP is a // dead end (the same as if it had been absent in a linear or bitmap branch or // null in an uncompressed branch), enter SM2Backtrack; otherwise enter // SM3Findlimit to find the highest/lowest Index under this JP, as if the code // had already backtracked to this JP. #ifdef JUDYPREV #define CDcmp__ < #else #define CDcmp__ > #endif #define CHECKDCD(cState) \ if (JU_DCDNOTMATCHINDEX(*PIndex, Pjp, cState)) \ { \ if ((*PIndex & cJU_DCDMASK(cState)) \ CDcmp__(JU_JPDCDPOP0(Pjp) & cJU_DCDMASK(cState))) \ { \ goto SM2Backtrack; \ } \ goto SM3Findlimit; \ } // PREPARE TO HANDLE A LEAFW OR JRP BRANCH IN SM1: // // Extract a state-dependent digit from Index in a "constant" way, then jump to // common code for multiple cases. #define SM1PREPB(cState,Next) \ state = (cState); \ digit = JU_DIGITATSTATE(*PIndex, cState); \ goto Next // PREPARE TO HANDLE A LEAFW OR JRP BRANCH IN SM3: // // Optionally save Dcd bytes into *PIndex, then save state and jump to common // code for multiple cases. #define SM3PREPB_DCD(cState,Next) \ JU_SETDCD(*PIndex, Pjp, cState); \ SM3PREPB(cState,Next) #define SM3PREPB(cState,Next) state = (cState); goto Next // ---------------------------------------------------------------------------- // CHECK FOR SHORTCUTS: // // Error out if PIndex is null. Execute JU_RET_NOTFOUND if the Judy array is // empty or *PIndex is already the minimum/maximum Index possible. // // Note: As documented, in case of failure *PIndex may be modified. if (PIndex == (PWord_t) NULL) { JU_SET_ERRNO(PJError, JU_ERRNO_NULLPINDEX); JUDY1CODE(return(JERRI );) JUDYLCODE(return(PPJERR);) } #ifdef JUDYPREV if ((PArray == (Pvoid_t) NULL) || ((*PIndex)-- == 0)) #else if ((PArray == (Pvoid_t) NULL) || ((*PIndex)++ == cJU_ALLONES)) #endif JU_RET_NOTFOUND; // HANDLE JRP: // // Before even entering SM1Get, check the JRP type. For JRP branches, traverse // the JPM; handle LEAFW leaves directly; but look for the most common cases // first. // ROOT-STATE LEAF that starts with a Pop0 word; just look within the leaf: // // If *PIndex is in the leaf, return it; otherwise return the Index, if any, // below where it would belong. if (JU_LEAFW_POP0(PArray) < cJU_LEAFW_MAXPOP1) // must be a LEAFW { Pjlw_t Pjlw = P_JLW(PArray); // first word of leaf. pop1 = Pjlw[0] + 1; if ((offset = j__udySearchLeafW(Pjlw + 1, pop1, *PIndex)) >= 0) // Index is present. { assert(offset < pop1); // in expected range. JU_RET_FOUND_LEAFW(Pjlw, pop1, offset); // *PIndex is set. } #ifdef JUDYPREV if ((offset = ~offset) == 0) // no next-left Index. #else if ((offset = ~offset) >= pop1) // no next-right Index. #endif JU_RET_NOTFOUND; assert(offset <= pop1); // valid result. #ifdef JUDYPREV *PIndex = Pjlw[offset--]; // next-left Index, base 1. #else *PIndex = Pjlw[offset + 1]; // next-right Index, base 1. #endif JU_RET_FOUND_LEAFW(Pjlw, pop1, offset); // base 0. } else // JRP BRANCH { Pjpm_t Pjpm = P_JPM(PArray); Pjp = &(Pjpm->jpm_JP); // goto SM1Get; } // ============================================================================ // STATE MACHINE 1 -- GET INDEX: // // Search for *PIndex (already decremented/incremented so as to be inclusive). // If found, return it. Otherwise in theory hand off to SM2Backtrack or // SM3Findlimit, but in practice "shortcut" by first sideways searching the // current branch or leaf upon hitting a dead end. During sideways search, // modify *PIndex to a new path taken. // // ENTRY: Pjp points to next JP to interpret, whose Decode bytes have not yet // been checked. This JP is not yet listed in history. // // Note: Check Decode bytes at the start of each loop, not after looking up a // new JP, so its easy to do constant shifts/masks, although this requires // cautious handling of Pjp, offset, and *hist[] for correct entry to // SM2Backtrack. // // EXIT: Return, or branch to SM2Backtrack or SM3Findlimit with correct // interface, as described elsewhere. // // WARNING: For run-time efficiency the following cases replicate code with // varying constants, rather than using common code with variable values! SM1Get: // return here for next branch/leaf. switch (JU_JPTYPE(Pjp)) { // ---------------------------------------------------------------------------- // LINEAR BRANCH: // // Check Decode bytes, if any, in the current JP, then search for a JP for the // next digit in *PIndex. case cJU_JPBRANCH_L2: CHECKDCD(2); SM1PREPB(2, SM1BranchL); case cJU_JPBRANCH_L3: CHECKDCD(3); SM1PREPB(3, SM1BranchL); #ifdef JU_64BIT case cJU_JPBRANCH_L4: CHECKDCD(4); SM1PREPB(4, SM1BranchL); case cJU_JPBRANCH_L5: CHECKDCD(5); SM1PREPB(5, SM1BranchL); case cJU_JPBRANCH_L6: CHECKDCD(6); SM1PREPB(6, SM1BranchL); case cJU_JPBRANCH_L7: CHECKDCD(7); SM1PREPB(7, SM1BranchL); #endif case cJU_JPBRANCH_L: SM1PREPB(cJU_ROOTSTATE, SM1BranchL); // Common code (state-independent) for all cases of linear branches: SM1BranchL: Pjbl = P_JBL(Pjp->jp_Addr); // Found JP matching current digit in *PIndex; record parent JP and the next // JPs offset, and iterate to the next JP: if ((offset = j__udySearchLeaf1((Pjll_t) (Pjbl->jbl_Expanse), Pjbl->jbl_NumJPs, digit)) >= 0) { HISTPUSH(Pjp, offset); Pjp = (Pjbl->jbl_jp) + offset; goto SM1Get; } // Dead end, no JP in BranchL for next digit in *PIndex: // // Get the ideal location of digits JP, and if theres no next-left/right JP // in the BranchL, shortcut and start backtracking one level up; ignore the // current Pjp because it points to a BranchL with no next-left/right JP. #ifdef JUDYPREV if ((offset = (~offset) - 1) < 0) // no next-left JP in BranchL. #else if ((offset = (~offset)) >= Pjbl->jbl_NumJPs) // no next-right. #endif goto SM2Backtrack; // Theres a next-left/right JP in the current BranchL; save its digit in // *PIndex and shortcut to SM3Findlimit: JU_SETDIGIT(*PIndex, Pjbl->jbl_Expanse[offset], state); Pjp = (Pjbl->jbl_jp) + offset; goto SM3Findlimit; // ---------------------------------------------------------------------------- // BITMAP BRANCH: // // Check Decode bytes, if any, in the current JP, then look for a JP for the // next digit in *PIndex. case cJU_JPBRANCH_B2: CHECKDCD(2); SM1PREPB(2, SM1BranchB); case cJU_JPBRANCH_B3: CHECKDCD(3); SM1PREPB(3, SM1BranchB); #ifdef JU_64BIT case cJU_JPBRANCH_B4: CHECKDCD(4); SM1PREPB(4, SM1BranchB); case cJU_JPBRANCH_B5: CHECKDCD(5); SM1PREPB(5, SM1BranchB); case cJU_JPBRANCH_B6: CHECKDCD(6); SM1PREPB(6, SM1BranchB); case cJU_JPBRANCH_B7: CHECKDCD(7); SM1PREPB(7, SM1BranchB); #endif case cJU_JPBRANCH_B: SM1PREPB(cJU_ROOTSTATE, SM1BranchB); // Common code (state-independent) for all cases of bitmap branches: SM1BranchB: Pjbb = P_JBB(Pjp->jp_Addr); // Locate the digits JP in the subexpanse list, if present, otherwise the // offset of the next-left JP, if any: subexp = digit / cJU_BITSPERSUBEXPB; assert(subexp < cJU_NUMSUBEXPB); // falls in expected range. bitposmask = JU_BITPOSMASKB(digit); offset = SEARCHBITMAPB(JU_JBB_BITMAP(Pjbb, subexp), digit, bitposmask); // right range: assert((offset >= -1) && (offset < (int) cJU_BITSPERSUBEXPB)); // Found JP matching current digit in *PIndex: // // Record the parent JP and the next JPs offset; and iterate to the next JP. // if (JU_BITMAPTESTB(Pjbb, digit)) // slower. if (JU_JBB_BITMAP(Pjbb, subexp) & bitposmask) // faster. { // not negative since at least one bit is set: assert(offset >= 0); HISTPUSH(Pjp, HISTPUSHBOFF(subexp, offset, digit)); if ((Pjp = P_JP(JU_JBB_PJP(Pjbb, subexp))) == (Pjp_t) NULL) { JU_SET_ERRNO(PJError, JU_ERRNO_CORRUPT); JUDY1CODE(return(JERRI );) JUDYLCODE(return(PPJERR);) } Pjp += offset; goto SM1Get; // iterate to next JP. } // Dead end, no JP in BranchB for next digit in *PIndex: // // If theres a next-left/right JP in the current BranchB, shortcut to // SM3Findlimit. Note: offset is already set to the correct value for the // next-left/right JP. #ifdef JUDYPREV if (offset >= 0) // next-left JP is in this subexpanse. goto SM1BranchBFindlimit; while (--subexp >= 0) // search next-left subexpanses. #else if (JU_JBB_BITMAP(Pjbb, subexp) & JU_MASKHIGHEREXC(bitposmask)) { ++offset; // next-left => next-right. goto SM1BranchBFindlimit; } while (++subexp < cJU_NUMSUBEXPB) // search next-right subexps. #endif { if (! JU_JBB_PJP(Pjbb, subexp)) continue; // empty subexpanse. #ifdef JUDYPREV offset = SEARCHBITMAPMAXB(JU_JBB_BITMAP(Pjbb, subexp)); // expected range: assert((offset >= 0) && (offset < cJU_BITSPERSUBEXPB)); #else offset = 0; #endif // Save the next-left/right JPs digit in *PIndex: SM1BranchBFindlimit: JU_BITMAPDIGITB(digit, subexp, JU_JBB_BITMAP(Pjbb, subexp), offset); JU_SETDIGIT(*PIndex, digit, state); if ((Pjp = P_JP(JU_JBB_PJP(Pjbb, subexp))) == (Pjp_t) NULL) { JU_SET_ERRNO(PJError, JU_ERRNO_CORRUPT); JUDY1CODE(return(JERRI );) JUDYLCODE(return(PPJERR);) } Pjp += offset; goto SM3Findlimit; } // Theres no next-left/right JP in the BranchB: // // Shortcut and start backtracking one level up; ignore the current Pjp because // it points to a BranchB with no next-left/right JP. goto SM2Backtrack; // ---------------------------------------------------------------------------- // UNCOMPRESSED BRANCH: // // Check Decode bytes, if any, in the current JP, then look for a JP for the // next digit in *PIndex. case cJU_JPBRANCH_U2: CHECKDCD(2); SM1PREPB(2, SM1BranchU); case cJU_JPBRANCH_U3: CHECKDCD(3); SM1PREPB(3, SM1BranchU); #ifdef JU_64BIT case cJU_JPBRANCH_U4: CHECKDCD(4); SM1PREPB(4, SM1BranchU); case cJU_JPBRANCH_U5: CHECKDCD(5); SM1PREPB(5, SM1BranchU); case cJU_JPBRANCH_U6: CHECKDCD(6); SM1PREPB(6, SM1BranchU); case cJU_JPBRANCH_U7: CHECKDCD(7); SM1PREPB(7, SM1BranchU); #endif case cJU_JPBRANCH_U: SM1PREPB(cJU_ROOTSTATE, SM1BranchU); // Common code (state-independent) for all cases of uncompressed branches: SM1BranchU: Pjbu = P_JBU(Pjp->jp_Addr); Pjp2 = (Pjbu->jbu_jp) + digit; // Found JP matching current digit in *PIndex: // // Record the parent JP and the next JPs digit, and iterate to the next JP. // // TBD: Instead of this, just goto SM1Get, and add cJU_JPNULL* cases to the // SM1Get state machine? Then backtrack? However, it means you cant detect // an inappropriate cJU_JPNULL*, when it occurs in other than a BranchU, and // return JU_RET_CORRUPT. if (! JPNULL(JU_JPTYPE(Pjp2))) // digit has a JP. { HISTPUSH(Pjp, digit); Pjp = Pjp2; goto SM1Get; } // Dead end, no JP in BranchU for next digit in *PIndex: // // Search for a next-left/right JP in the current BranchU, and if one is found, // save its digit in *PIndex and shortcut to SM3Findlimit: #ifdef JUDYPREV while (digit >= 1) { Pjp = (Pjbu->jbu_jp) + (--digit); #else while (digit < cJU_BRANCHUNUMJPS - 1) { Pjp = (Pjbu->jbu_jp) + (++digit); #endif if (JPNULL(JU_JPTYPE(Pjp))) continue; JU_SETDIGIT(*PIndex, digit, state); goto SM3Findlimit; } // Theres no next-left/right JP in the BranchU: // // Shortcut and start backtracking one level up; ignore the current Pjp because // it points to a BranchU with no next-left/right JP. goto SM2Backtrack; // ---------------------------------------------------------------------------- // LINEAR LEAF: // // Check Decode bytes, if any, in the current JP, then search the leaf for // *PIndex. #define SM1LEAFL(Func) \ Pjll = P_JLL(Pjp->jp_Addr); \ pop1 = JU_JPLEAF_POP0(Pjp) + 1; \ offset = Func(Pjll, pop1, *PIndex); \ goto SM1LeafLImm #if (defined(JUDYL) || (! defined(JU_64BIT))) case cJU_JPLEAF1: CHECKDCD(1); SM1LEAFL(j__udySearchLeaf1); #endif case cJU_JPLEAF2: CHECKDCD(2); SM1LEAFL(j__udySearchLeaf2); case cJU_JPLEAF3: CHECKDCD(3); SM1LEAFL(j__udySearchLeaf3); #ifdef JU_64BIT case cJU_JPLEAF4: CHECKDCD(4); SM1LEAFL(j__udySearchLeaf4); case cJU_JPLEAF5: CHECKDCD(5); SM1LEAFL(j__udySearchLeaf5); case cJU_JPLEAF6: CHECKDCD(6); SM1LEAFL(j__udySearchLeaf6); case cJU_JPLEAF7: CHECKDCD(7); SM1LEAFL(j__udySearchLeaf7); #endif // Common code (state-independent) for all cases of linear leaves and // immediates: SM1LeafLImm: if (offset >= 0) // *PIndex is in LeafL / Immed. #ifdef JUDY1 JU_RET_FOUND; #else { // JudyL is trickier... switch (JU_JPTYPE(Pjp)) { #if (defined(JUDYL) || (! defined(JU_64BIT))) case cJU_JPLEAF1: JU_RET_FOUND_LEAF1(Pjll, pop1, offset); #endif case cJU_JPLEAF2: JU_RET_FOUND_LEAF2(Pjll, pop1, offset); case cJU_JPLEAF3: JU_RET_FOUND_LEAF3(Pjll, pop1, offset); #ifdef JU_64BIT case cJU_JPLEAF4: JU_RET_FOUND_LEAF4(Pjll, pop1, offset); case cJU_JPLEAF5: JU_RET_FOUND_LEAF5(Pjll, pop1, offset); case cJU_JPLEAF6: JU_RET_FOUND_LEAF6(Pjll, pop1, offset); case cJU_JPLEAF7: JU_RET_FOUND_LEAF7(Pjll, pop1, offset); #endif case cJU_JPIMMED_1_01: case cJU_JPIMMED_2_01: case cJU_JPIMMED_3_01: #ifdef JU_64BIT case cJU_JPIMMED_4_01: case cJU_JPIMMED_5_01: case cJU_JPIMMED_6_01: case cJU_JPIMMED_7_01: #endif JU_RET_FOUND_IMM_01(Pjp); case cJU_JPIMMED_1_02: case cJU_JPIMMED_1_03: #ifdef JU_64BIT case cJU_JPIMMED_1_04: case cJU_JPIMMED_1_05: case cJU_JPIMMED_1_06: case cJU_JPIMMED_1_07: case cJU_JPIMMED_2_02: case cJU_JPIMMED_2_03: case cJU_JPIMMED_3_02: #endif JU_RET_FOUND_IMM(Pjp, offset); } JU_SET_ERRNO(PJError, JU_ERRNO_CORRUPT); // impossible? JUDY1CODE(return(JERRI );) JUDYLCODE(return(PPJERR);) } // found *PIndex #endif // JUDYL // Dead end, no Index in LeafL / Immed for remaining digit(s) in *PIndex: // // Get the ideal location of Index, and if theres no next-left/right Index in // the LeafL / Immed, shortcut and start backtracking one level up; ignore the // current Pjp because it points to a LeafL / Immed with no next-left/right // Index. #ifdef JUDYPREV if ((offset = (~offset) - 1) < 0) // no next-left Index. #else if ((offset = (~offset)) >= pop1) // no next-right Index. #endif goto SM2Backtrack; // Theres a next-left/right Index in the current LeafL / Immed; shortcut by // copying its digit(s) to *PIndex and returning it. // // Unfortunately this is pretty hairy, especially avoiding endian issues. // // The cJU_JPLEAF* cases are very similar to same-index-size cJU_JPIMMED* cases // for *_02 and above, but must return differently, at least for JudyL, so // spell them out separately here at the cost of a little redundant code for // Judy1. switch (JU_JPTYPE(Pjp)) { #if (defined(JUDYL) || (! defined(JU_64BIT))) case cJU_JPLEAF1: JU_SETDIGIT1(*PIndex, ((uint8_t *) Pjll)[offset]); JU_RET_FOUND_LEAF1(Pjll, pop1, offset); #endif case cJU_JPLEAF2: *PIndex = (*PIndex & (~JU_LEASTBYTESMASK(2))) | ((uint16_t *) Pjll)[offset]; JU_RET_FOUND_LEAF2(Pjll, pop1, offset); case cJU_JPLEAF3: { Word_t lsb; JU_COPY3_PINDEX_TO_LONG(lsb, ((uint8_t *) Pjll) + (3 * offset)); *PIndex = (*PIndex & (~JU_LEASTBYTESMASK(3))) | lsb; JU_RET_FOUND_LEAF3(Pjll, pop1, offset); } #ifdef JU_64BIT case cJU_JPLEAF4: *PIndex = (*PIndex & (~JU_LEASTBYTESMASK(4))) | ((uint32_t *) Pjll)[offset]; JU_RET_FOUND_LEAF4(Pjll, pop1, offset); case cJU_JPLEAF5: { Word_t lsb; JU_COPY5_PINDEX_TO_LONG(lsb, ((uint8_t *) Pjll) + (5 * offset)); *PIndex = (*PIndex & (~JU_LEASTBYTESMASK(5))) | lsb; JU_RET_FOUND_LEAF5(Pjll, pop1, offset); } case cJU_JPLEAF6: { Word_t lsb; JU_COPY6_PINDEX_TO_LONG(lsb, ((uint8_t *) Pjll) + (6 * offset)); *PIndex = (*PIndex & (~JU_LEASTBYTESMASK(6))) | lsb; JU_RET_FOUND_LEAF6(Pjll, pop1, offset); } case cJU_JPLEAF7: { Word_t lsb; JU_COPY7_PINDEX_TO_LONG(lsb, ((uint8_t *) Pjll) + (7 * offset)); *PIndex = (*PIndex & (~JU_LEASTBYTESMASK(7))) | lsb; JU_RET_FOUND_LEAF7(Pjll, pop1, offset); } #endif // JU_64BIT #define SET_01(cState) JU_SETDIGITS(*PIndex, JU_JPDCDPOP0(Pjp), cState) case cJU_JPIMMED_1_01: SET_01(1); goto SM1Imm_01; case cJU_JPIMMED_2_01: SET_01(2); goto SM1Imm_01; case cJU_JPIMMED_3_01: SET_01(3); goto SM1Imm_01; #ifdef JU_64BIT case cJU_JPIMMED_4_01: SET_01(4); goto SM1Imm_01; case cJU_JPIMMED_5_01: SET_01(5); goto SM1Imm_01; case cJU_JPIMMED_6_01: SET_01(6); goto SM1Imm_01; case cJU_JPIMMED_7_01: SET_01(7); goto SM1Imm_01; #endif SM1Imm_01: JU_RET_FOUND_IMM_01(Pjp); // Shorthand for where to find start of Index bytes array: #ifdef JUDY1 #define PJI (Pjp->jp_1Index) #else #define PJI (Pjp->jp_LIndex) #endif case cJU_JPIMMED_1_02: case cJU_JPIMMED_1_03: #if (defined(JUDY1) || defined(JU_64BIT)) case cJU_JPIMMED_1_04: case cJU_JPIMMED_1_05: case cJU_JPIMMED_1_06: case cJU_JPIMMED_1_07: #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_1_08: case cJ1_JPIMMED_1_09: case cJ1_JPIMMED_1_10: case cJ1_JPIMMED_1_11: case cJ1_JPIMMED_1_12: case cJ1_JPIMMED_1_13: case cJ1_JPIMMED_1_14: case cJ1_JPIMMED_1_15: #endif JU_SETDIGIT1(*PIndex, ((uint8_t *) PJI)[offset]); JU_RET_FOUND_IMM(Pjp, offset); #if (defined(JUDY1) || defined(JU_64BIT)) case cJU_JPIMMED_2_02: case cJU_JPIMMED_2_03: #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_2_04: case cJ1_JPIMMED_2_05: case cJ1_JPIMMED_2_06: case cJ1_JPIMMED_2_07: #endif #if (defined(JUDY1) || defined(JU_64BIT)) *PIndex = (*PIndex & (~JU_LEASTBYTESMASK(2))) | ((uint16_t *) PJI)[offset]; JU_RET_FOUND_IMM(Pjp, offset); #endif #if (defined(JUDY1) || defined(JU_64BIT)) case cJU_JPIMMED_3_02: #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_3_03: case cJ1_JPIMMED_3_04: case cJ1_JPIMMED_3_05: #endif #if (defined(JUDY1) || defined(JU_64BIT)) { Word_t lsb; JU_COPY3_PINDEX_TO_LONG(lsb, ((uint8_t *) PJI) + (3 * offset)); *PIndex = (*PIndex & (~JU_LEASTBYTESMASK(3))) | lsb; JU_RET_FOUND_IMM(Pjp, offset); } #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_4_02: case cJ1_JPIMMED_4_03: *PIndex = (*PIndex & (~JU_LEASTBYTESMASK(4))) | ((uint32_t *) PJI)[offset]; JU_RET_FOUND_IMM(Pjp, offset); case cJ1_JPIMMED_5_02: case cJ1_JPIMMED_5_03: { Word_t lsb; JU_COPY5_PINDEX_TO_LONG(lsb, ((uint8_t *) PJI) + (5 * offset)); *PIndex = (*PIndex & (~JU_LEASTBYTESMASK(5))) | lsb; JU_RET_FOUND_IMM(Pjp, offset); } case cJ1_JPIMMED_6_02: { Word_t lsb; JU_COPY6_PINDEX_TO_LONG(lsb, ((uint8_t *) PJI) + (6 * offset)); *PIndex = (*PIndex & (~JU_LEASTBYTESMASK(6))) | lsb; JU_RET_FOUND_IMM(Pjp, offset); } case cJ1_JPIMMED_7_02: { Word_t lsb; JU_COPY7_PINDEX_TO_LONG(lsb, ((uint8_t *) PJI) + (7 * offset)); *PIndex = (*PIndex & (~JU_LEASTBYTESMASK(7))) | lsb; JU_RET_FOUND_IMM(Pjp, offset); } #endif // (JUDY1 && JU_64BIT) } // switch for not-found *PIndex JU_SET_ERRNO(PJError, JU_ERRNO_CORRUPT); // impossible? JUDY1CODE(return(JERRI );) JUDYLCODE(return(PPJERR);) // ---------------------------------------------------------------------------- // BITMAP LEAF: // // Check Decode bytes, if any, in the current JP, then look in the leaf for // *PIndex. case cJU_JPLEAF_B1: { Pjlb_t Pjlb; CHECKDCD(1); Pjlb = P_JLB(Pjp->jp_Addr); digit = JU_DIGITATSTATE(*PIndex, 1); subexp = JU_SUBEXPL(digit); bitposmask = JU_BITPOSMASKL(digit); assert(subexp < cJU_NUMSUBEXPL); // falls in expected range. // *PIndex exists in LeafB1: // if (JU_BITMAPTESTL(Pjlb, digit)) // slower. if (JU_JLB_BITMAP(Pjlb, subexp) & bitposmask) // faster. { #ifdef JUDYL // needs offset at this point: offset = SEARCHBITMAPL(JU_JLB_BITMAP(Pjlb, subexp), digit, bitposmask); #endif JU_RET_FOUND_LEAF_B1(Pjlb, subexp, offset); // == return((PPvoid_t) (P_JV(JL_JLB_PVALUE(Pjlb, subexp)) + (offset))); } // Dead end, no Index in LeafB1 for remaining digit in *PIndex: // // If theres a next-left/right Index in the current LeafB1, which for // Judy*Next() is true if any bits are set for higher Indexes, shortcut by // returning it. Note: For Judy*Prev(), offset is set here to the correct // value for the next-left JP. offset = SEARCHBITMAPL(JU_JLB_BITMAP(Pjlb, subexp), digit, bitposmask); // right range: assert((offset >= -1) && (offset < (int) cJU_BITSPERSUBEXPL)); #ifdef JUDYPREV if (offset >= 0) // next-left JP is in this subexpanse. goto SM1LeafB1Findlimit; while (--subexp >= 0) // search next-left subexpanses. #else if (JU_JLB_BITMAP(Pjlb, subexp) & JU_MASKHIGHEREXC(bitposmask)) { ++offset; // next-left => next-right. goto SM1LeafB1Findlimit; } while (++subexp < cJU_NUMSUBEXPL) // search next-right subexps. #endif { if (! JU_JLB_BITMAP(Pjlb, subexp)) continue; // empty subexp. #ifdef JUDYPREV offset = SEARCHBITMAPMAXL(JU_JLB_BITMAP(Pjlb, subexp)); // expected range: assert((offset >= 0) && (offset < (int) cJU_BITSPERSUBEXPL)); #else offset = 0; #endif // Save the next-left/right Indexess digit in *PIndex: SM1LeafB1Findlimit: JU_BITMAPDIGITL(digit, subexp, JU_JLB_BITMAP(Pjlb, subexp), offset); JU_SETDIGIT1(*PIndex, digit); JU_RET_FOUND_LEAF_B1(Pjlb, subexp, offset); // == return((PPvoid_t) (P_JV(JL_JLB_PVALUE(Pjlb, subexp)) + (offset))); } // Theres no next-left/right Index in the LeafB1: // // Shortcut and start backtracking one level up; ignore the current Pjp because // it points to a LeafB1 with no next-left/right Index. goto SM2Backtrack; } // case cJU_JPLEAF_B1 #ifdef JUDY1 // ---------------------------------------------------------------------------- // FULL POPULATION: // // If the Decode bytes match, *PIndex is found (without modification). case cJ1_JPFULLPOPU1: CHECKDCD(1); JU_RET_FOUND_FULLPOPU1; #endif // ---------------------------------------------------------------------------- // IMMEDIATE: #ifdef JUDYPREV #define SM1IMM_SETPOP1(cPop1) #else #define SM1IMM_SETPOP1(cPop1) pop1 = (cPop1) #endif #define SM1IMM(Func,cPop1) \ SM1IMM_SETPOP1(cPop1); \ offset = Func((Pjll_t) (PJI), cPop1, *PIndex); \ goto SM1LeafLImm // Special case for Pop1 = 1 Immediate JPs: // // If *PIndex is in the immediate, offset is 0, otherwise the binary NOT of the // offset where it belongs, 0 or 1, same as from the search functions. #ifdef JUDYPREV #define SM1IMM_01_SETPOP1 #else #define SM1IMM_01_SETPOP1 pop1 = 1 #endif #define SM1IMM_01 \ SM1IMM_01_SETPOP1; \ offset = ((JU_JPDCDPOP0(Pjp) < JU_TRIMTODCDSIZE(*PIndex)) ? ~1 : \ (JU_JPDCDPOP0(Pjp) == JU_TRIMTODCDSIZE(*PIndex)) ? 0 : \ ~0); \ goto SM1LeafLImm case cJU_JPIMMED_1_01: case cJU_JPIMMED_2_01: case cJU_JPIMMED_3_01: #ifdef JU_64BIT case cJU_JPIMMED_4_01: case cJU_JPIMMED_5_01: case cJU_JPIMMED_6_01: case cJU_JPIMMED_7_01: #endif SM1IMM_01; // TBD: Doug says it would be OK to have fewer calls and calculate arg 2, here // and in Judy*Count() also. case cJU_JPIMMED_1_02: SM1IMM(j__udySearchLeaf1, 2); case cJU_JPIMMED_1_03: SM1IMM(j__udySearchLeaf1, 3); #if (defined(JUDY1) || defined(JU_64BIT)) case cJU_JPIMMED_1_04: SM1IMM(j__udySearchLeaf1, 4); case cJU_JPIMMED_1_05: SM1IMM(j__udySearchLeaf1, 5); case cJU_JPIMMED_1_06: SM1IMM(j__udySearchLeaf1, 6); case cJU_JPIMMED_1_07: SM1IMM(j__udySearchLeaf1, 7); #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_1_08: SM1IMM(j__udySearchLeaf1, 8); case cJ1_JPIMMED_1_09: SM1IMM(j__udySearchLeaf1, 9); case cJ1_JPIMMED_1_10: SM1IMM(j__udySearchLeaf1, 10); case cJ1_JPIMMED_1_11: SM1IMM(j__udySearchLeaf1, 11); case cJ1_JPIMMED_1_12: SM1IMM(j__udySearchLeaf1, 12); case cJ1_JPIMMED_1_13: SM1IMM(j__udySearchLeaf1, 13); case cJ1_JPIMMED_1_14: SM1IMM(j__udySearchLeaf1, 14); case cJ1_JPIMMED_1_15: SM1IMM(j__udySearchLeaf1, 15); #endif #if (defined(JUDY1) || defined(JU_64BIT)) case cJU_JPIMMED_2_02: SM1IMM(j__udySearchLeaf2, 2); case cJU_JPIMMED_2_03: SM1IMM(j__udySearchLeaf2, 3); #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_2_04: SM1IMM(j__udySearchLeaf2, 4); case cJ1_JPIMMED_2_05: SM1IMM(j__udySearchLeaf2, 5); case cJ1_JPIMMED_2_06: SM1IMM(j__udySearchLeaf2, 6); case cJ1_JPIMMED_2_07: SM1IMM(j__udySearchLeaf2, 7); #endif #if (defined(JUDY1) || defined(JU_64BIT)) case cJU_JPIMMED_3_02: SM1IMM(j__udySearchLeaf3, 2); #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_3_03: SM1IMM(j__udySearchLeaf3, 3); case cJ1_JPIMMED_3_04: SM1IMM(j__udySearchLeaf3, 4); case cJ1_JPIMMED_3_05: SM1IMM(j__udySearchLeaf3, 5); case cJ1_JPIMMED_4_02: SM1IMM(j__udySearchLeaf4, 2); case cJ1_JPIMMED_4_03: SM1IMM(j__udySearchLeaf4, 3); case cJ1_JPIMMED_5_02: SM1IMM(j__udySearchLeaf5, 2); case cJ1_JPIMMED_5_03: SM1IMM(j__udySearchLeaf5, 3); case cJ1_JPIMMED_6_02: SM1IMM(j__udySearchLeaf6, 2); case cJ1_JPIMMED_7_02: SM1IMM(j__udySearchLeaf7, 2); #endif // ---------------------------------------------------------------------------- // INVALID JP TYPE: default: JU_SET_ERRNO(PJError, JU_ERRNO_CORRUPT); JUDY1CODE(return(JERRI );) JUDYLCODE(return(PPJERR);) } // SM1Get switch. /*NOTREACHED*/ // ============================================================================ // STATE MACHINE 2 -- BACKTRACK BRANCH TO PREVIOUS JP: // // Look for the next-left/right JP in a branch, backing up the history list as // necessary. Upon finding a next-left/right JP, modify the corresponding // digit in *PIndex before passing control to SM3Findlimit. // // Note: As described earlier, only branch JPs are expected here; other types // fall into the default case. // // Note: If a found JP contains needed Dcd bytes, thats OK, theyre copied to // *PIndex in SM3Findlimit. // // TBD: This code has a lot in common with similar code in the shortcut cases // in SM1Get. Can combine this code somehow? // // ENTRY: List, possibly empty, of JPs and offsets in APjphist[] and // Aoffhist[]; see earlier comments. // // EXIT: Execute JU_RET_NOTFOUND if no previous/next JP; otherwise jump to // SM3Findlimit to resume a new but different downward search. SM2Backtrack: // come or return here for first/next sideways search. HISTPOP(Pjp, offset); switch (JU_JPTYPE(Pjp)) { // ---------------------------------------------------------------------------- // LINEAR BRANCH: case cJU_JPBRANCH_L2: state = 2; goto SM2BranchL; case cJU_JPBRANCH_L3: state = 3; goto SM2BranchL; #ifdef JU_64BIT case cJU_JPBRANCH_L4: state = 4; goto SM2BranchL; case cJU_JPBRANCH_L5: state = 5; goto SM2BranchL; case cJU_JPBRANCH_L6: state = 6; goto SM2BranchL; case cJU_JPBRANCH_L7: state = 7; goto SM2BranchL; #endif case cJU_JPBRANCH_L: state = cJU_ROOTSTATE; goto SM2BranchL; SM2BranchL: #ifdef JUDYPREV if (--offset < 0) goto SM2Backtrack; // no next-left JP in BranchL. #endif Pjbl = P_JBL(Pjp->jp_Addr); #ifdef JUDYNEXT if (++offset >= (Pjbl->jbl_NumJPs)) goto SM2Backtrack; // no next-right JP in BranchL. #endif // Theres a next-left/right JP in the current BranchL; save its digit in // *PIndex and continue with SM3Findlimit: JU_SETDIGIT(*PIndex, Pjbl->jbl_Expanse[offset], state); Pjp = (Pjbl->jbl_jp) + offset; goto SM3Findlimit; // ---------------------------------------------------------------------------- // BITMAP BRANCH: case cJU_JPBRANCH_B2: state = 2; goto SM2BranchB; case cJU_JPBRANCH_B3: state = 3; goto SM2BranchB; #ifdef JU_64BIT case cJU_JPBRANCH_B4: state = 4; goto SM2BranchB; case cJU_JPBRANCH_B5: state = 5; goto SM2BranchB; case cJU_JPBRANCH_B6: state = 6; goto SM2BranchB; case cJU_JPBRANCH_B7: state = 7; goto SM2BranchB; #endif case cJU_JPBRANCH_B: state = cJU_ROOTSTATE; goto SM2BranchB; SM2BranchB: Pjbb = P_JBB(Pjp->jp_Addr); HISTPOPBOFF(subexp, offset, digit); // unpack values. // If theres a next-left/right JP in the current BranchB, which for // Judy*Next() is true if any bits are set for higher Indexes, continue to // SM3Findlimit: // // Note: offset is set to the JP previously traversed; go one to the // left/right. #ifdef JUDYPREV if (offset > 0) // next-left JP is in this subexpanse. { --offset; goto SM2BranchBFindlimit; } while (--subexp >= 0) // search next-left subexpanses. #else if (JU_JBB_BITMAP(Pjbb, subexp) & JU_MASKHIGHEREXC(JU_BITPOSMASKB(digit))) { ++offset; // next-left => next-right. goto SM2BranchBFindlimit; } while (++subexp < cJU_NUMSUBEXPB) // search next-right subexps. #endif { if (! JU_JBB_PJP(Pjbb, subexp)) continue; // empty subexpanse. #ifdef JUDYPREV offset = SEARCHBITMAPMAXB(JU_JBB_BITMAP(Pjbb, subexp)); // expected range: assert((offset >= 0) && (offset < cJU_BITSPERSUBEXPB)); #else offset = 0; #endif // Save the next-left/right JPs digit in *PIndex: SM2BranchBFindlimit: JU_BITMAPDIGITB(digit, subexp, JU_JBB_BITMAP(Pjbb, subexp), offset); JU_SETDIGIT(*PIndex, digit, state); if ((Pjp = P_JP(JU_JBB_PJP(Pjbb, subexp))) == (Pjp_t) NULL) { JU_SET_ERRNO(PJError, JU_ERRNO_CORRUPT); JUDY1CODE(return(JERRI );) JUDYLCODE(return(PPJERR);) } Pjp += offset; goto SM3Findlimit; } // Theres no next-left/right JP in the BranchB: goto SM2Backtrack; // ---------------------------------------------------------------------------- // UNCOMPRESSED BRANCH: case cJU_JPBRANCH_U2: state = 2; goto SM2BranchU; case cJU_JPBRANCH_U3: state = 3; goto SM2BranchU; #ifdef JU_64BIT case cJU_JPBRANCH_U4: state = 4; goto SM2BranchU; case cJU_JPBRANCH_U5: state = 5; goto SM2BranchU; case cJU_JPBRANCH_U6: state = 6; goto SM2BranchU; case cJU_JPBRANCH_U7: state = 7; goto SM2BranchU; #endif case cJU_JPBRANCH_U: state = cJU_ROOTSTATE; goto SM2BranchU; SM2BranchU: // Search for a next-left/right JP in the current BranchU, and if one is found, // save its digit in *PIndex and continue to SM3Findlimit: Pjbu = P_JBU(Pjp->jp_Addr); digit = offset; #ifdef JUDYPREV while (digit >= 1) { Pjp = (Pjbu->jbu_jp) + (--digit); #else while (digit < cJU_BRANCHUNUMJPS - 1) { Pjp = (Pjbu->jbu_jp) + (++digit); #endif if (JPNULL(JU_JPTYPE(Pjp))) continue; JU_SETDIGIT(*PIndex, digit, state); goto SM3Findlimit; } // Theres no next-left/right JP in the BranchU: goto SM2Backtrack; // ---------------------------------------------------------------------------- // INVALID JP TYPE: default: JU_SET_ERRNO(PJError, JU_ERRNO_CORRUPT); JUDY1CODE(return(JERRI );) JUDYLCODE(return(PPJERR);) } // SM2Backtrack switch. /*NOTREACHED*/ // ============================================================================ // STATE MACHINE 3 -- FIND LIMIT JP/INDEX: // // Look for the highest/lowest (right/left-most) JP in each branch and the // highest/lowest Index in a leaf or immediate, and return it. While // traversing, modify appropriate digit(s) in *PIndex to reflect the path // taken, including Dcd bytes in each JP (which could hold critical missing // digits for skipped branches). // // ENTRY: Pjp set to a JP under which to find max/min JPs (if a branch JP) or // a max/min Index and return (if a leaf or immediate JP). // // EXIT: Execute JU_RET_FOUND* upon reaching a leaf or immediate. Should be // impossible to fail, unless the Judy array is corrupt. SM3Findlimit: // come or return here for first/next branch/leaf. switch (JU_JPTYPE(Pjp)) { // ---------------------------------------------------------------------------- // LINEAR BRANCH: // // Simply use the highest/lowest (right/left-most) JP in the BranchL, but first // copy the Dcd bytes to *PIndex if there are any (only if state < // cJU_ROOTSTATE - 1). case cJU_JPBRANCH_L2: SM3PREPB_DCD(2, SM3BranchL); #ifndef JU_64BIT case cJU_JPBRANCH_L3: SM3PREPB( 3, SM3BranchL); #else case cJU_JPBRANCH_L3: SM3PREPB_DCD(3, SM3BranchL); case cJU_JPBRANCH_L4: SM3PREPB_DCD(4, SM3BranchL); case cJU_JPBRANCH_L5: SM3PREPB_DCD(5, SM3BranchL); case cJU_JPBRANCH_L6: SM3PREPB_DCD(6, SM3BranchL); case cJU_JPBRANCH_L7: SM3PREPB( 7, SM3BranchL); #endif case cJU_JPBRANCH_L: SM3PREPB( cJU_ROOTSTATE, SM3BranchL); SM3BranchL: Pjbl = P_JBL(Pjp->jp_Addr); #ifdef JUDYPREV if ((offset = (Pjbl->jbl_NumJPs) - 1) < 0) #else offset = 0; if ((Pjbl->jbl_NumJPs) == 0) #endif { JU_SET_ERRNO(PJError, JU_ERRNO_CORRUPT); JUDY1CODE(return(JERRI );) JUDYLCODE(return(PPJERR);) } JU_SETDIGIT(*PIndex, Pjbl->jbl_Expanse[offset], state); Pjp = (Pjbl->jbl_jp) + offset; goto SM3Findlimit; // ---------------------------------------------------------------------------- // BITMAP BRANCH: // // Look for the highest/lowest (right/left-most) non-null subexpanse, then use // the highest/lowest JP in that subexpanse, but first copy Dcd bytes, if there // are any (only if state < cJU_ROOTSTATE - 1), to *PIndex. case cJU_JPBRANCH_B2: SM3PREPB_DCD(2, SM3BranchB); #ifndef JU_64BIT case cJU_JPBRANCH_B3: SM3PREPB( 3, SM3BranchB); #else case cJU_JPBRANCH_B3: SM3PREPB_DCD(3, SM3BranchB); case cJU_JPBRANCH_B4: SM3PREPB_DCD(4, SM3BranchB); case cJU_JPBRANCH_B5: SM3PREPB_DCD(5, SM3BranchB); case cJU_JPBRANCH_B6: SM3PREPB_DCD(6, SM3BranchB); case cJU_JPBRANCH_B7: SM3PREPB( 7, SM3BranchB); #endif case cJU_JPBRANCH_B: SM3PREPB( cJU_ROOTSTATE, SM3BranchB); SM3BranchB: Pjbb = P_JBB(Pjp->jp_Addr); #ifdef JUDYPREV subexp = cJU_NUMSUBEXPB; while (! (JU_JBB_BITMAP(Pjbb, --subexp))) // find non-empty subexp. { if (subexp <= 0) // wholly empty bitmap. { JU_SET_ERRNO(PJError, JU_ERRNO_CORRUPT); JUDY1CODE(return(JERRI );) JUDYLCODE(return(PPJERR);) } } offset = SEARCHBITMAPMAXB(JU_JBB_BITMAP(Pjbb, subexp)); // expected range: assert((offset >= 0) && (offset < cJU_BITSPERSUBEXPB)); #else subexp = -1; while (! (JU_JBB_BITMAP(Pjbb, ++subexp))) // find non-empty subexp. { if (subexp >= cJU_NUMSUBEXPB - 1) // didnt find one. { JU_SET_ERRNO(PJError, JU_ERRNO_CORRUPT); JUDY1CODE(return(JERRI );) JUDYLCODE(return(PPJERR);) } } offset = 0; #endif JU_BITMAPDIGITB(digit, subexp, JU_JBB_BITMAP(Pjbb, subexp), offset); JU_SETDIGIT(*PIndex, digit, state); if ((Pjp = P_JP(JU_JBB_PJP(Pjbb, subexp))) == (Pjp_t) NULL) { JU_SET_ERRNO(PJError, JU_ERRNO_CORRUPT); JUDY1CODE(return(JERRI );) JUDYLCODE(return(PPJERR);) } Pjp += offset; goto SM3Findlimit; // ---------------------------------------------------------------------------- // UNCOMPRESSED BRANCH: // // Look for the highest/lowest (right/left-most) non-null JP, and use it, but // first copy Dcd bytes to *PIndex if there are any (only if state < // cJU_ROOTSTATE - 1). case cJU_JPBRANCH_U2: SM3PREPB_DCD(2, SM3BranchU); #ifndef JU_64BIT case cJU_JPBRANCH_U3: SM3PREPB( 3, SM3BranchU); #else case cJU_JPBRANCH_U3: SM3PREPB_DCD(3, SM3BranchU); case cJU_JPBRANCH_U4: SM3PREPB_DCD(4, SM3BranchU); case cJU_JPBRANCH_U5: SM3PREPB_DCD(5, SM3BranchU); case cJU_JPBRANCH_U6: SM3PREPB_DCD(6, SM3BranchU); case cJU_JPBRANCH_U7: SM3PREPB( 7, SM3BranchU); #endif case cJU_JPBRANCH_U: SM3PREPB( cJU_ROOTSTATE, SM3BranchU); SM3BranchU: Pjbu = P_JBU(Pjp->jp_Addr); #ifdef JUDYPREV digit = cJU_BRANCHUNUMJPS; while (digit >= 1) { Pjp = (Pjbu->jbu_jp) + (--digit); #else for (digit = 0; digit < cJU_BRANCHUNUMJPS; ++digit) { Pjp = (Pjbu->jbu_jp) + digit; #endif if (JPNULL(JU_JPTYPE(Pjp))) continue; JU_SETDIGIT(*PIndex, digit, state); goto SM3Findlimit; } // No non-null JPs in BranchU: JU_SET_ERRNO(PJError, JU_ERRNO_CORRUPT); JUDY1CODE(return(JERRI );) JUDYLCODE(return(PPJERR);) // ---------------------------------------------------------------------------- // LINEAR LEAF: // // Simply use the highest/lowest (right/left-most) Index in the LeafL, but the // details vary depending on leaf Index Size. First copy Dcd bytes, if there // are any (only if state < cJU_ROOTSTATE - 1), to *PIndex. #define SM3LEAFLDCD(cState) \ JU_SETDCD(*PIndex, Pjp, cState); \ SM3LEAFLNODCD #ifdef JUDY1 #define SM3LEAFL_SETPOP1 // not needed in any cases. #else #define SM3LEAFL_SETPOP1 pop1 = JU_JPLEAF_POP0(Pjp) + 1 #endif #ifdef JUDYPREV #define SM3LEAFLNODCD \ Pjll = P_JLL(Pjp->jp_Addr); \ SM3LEAFL_SETPOP1; \ offset = JU_JPLEAF_POP0(Pjp); assert(offset >= 0) #else #define SM3LEAFLNODCD \ Pjll = P_JLL(Pjp->jp_Addr); \ SM3LEAFL_SETPOP1; \ offset = 0; assert(JU_JPLEAF_POP0(Pjp) >= 0); #endif #if (defined(JUDYL) || (! defined(JU_64BIT))) case cJU_JPLEAF1: SM3LEAFLDCD(1); JU_SETDIGIT1(*PIndex, ((uint8_t *) Pjll)[offset]); JU_RET_FOUND_LEAF1(Pjll, pop1, offset); #endif case cJU_JPLEAF2: SM3LEAFLDCD(2); *PIndex = (*PIndex & (~JU_LEASTBYTESMASK(2))) | ((uint16_t *) Pjll)[offset]; JU_RET_FOUND_LEAF2(Pjll, pop1, offset); #ifndef JU_64BIT case cJU_JPLEAF3: { Word_t lsb; SM3LEAFLNODCD; JU_COPY3_PINDEX_TO_LONG(lsb, ((uint8_t *) Pjll) + (3 * offset)); *PIndex = (*PIndex & (~JU_LEASTBYTESMASK(3))) | lsb; JU_RET_FOUND_LEAF3(Pjll, pop1, offset); } #else case cJU_JPLEAF3: { Word_t lsb; SM3LEAFLDCD(3); JU_COPY3_PINDEX_TO_LONG(lsb, ((uint8_t *) Pjll) + (3 * offset)); *PIndex = (*PIndex & (~JU_LEASTBYTESMASK(3))) | lsb; JU_RET_FOUND_LEAF3(Pjll, pop1, offset); } case cJU_JPLEAF4: SM3LEAFLDCD(4); *PIndex = (*PIndex & (~JU_LEASTBYTESMASK(4))) | ((uint32_t *) Pjll)[offset]; JU_RET_FOUND_LEAF4(Pjll, pop1, offset); case cJU_JPLEAF5: { Word_t lsb; SM3LEAFLDCD(5); JU_COPY5_PINDEX_TO_LONG(lsb, ((uint8_t *) Pjll) + (5 * offset)); *PIndex = (*PIndex & (~JU_LEASTBYTESMASK(5))) | lsb; JU_RET_FOUND_LEAF5(Pjll, pop1, offset); } case cJU_JPLEAF6: { Word_t lsb; SM3LEAFLDCD(6); JU_COPY6_PINDEX_TO_LONG(lsb, ((uint8_t *) Pjll) + (6 * offset)); *PIndex = (*PIndex & (~JU_LEASTBYTESMASK(6))) | lsb; JU_RET_FOUND_LEAF6(Pjll, pop1, offset); } case cJU_JPLEAF7: { Word_t lsb; SM3LEAFLNODCD; JU_COPY7_PINDEX_TO_LONG(lsb, ((uint8_t *) Pjll) + (7 * offset)); *PIndex = (*PIndex & (~JU_LEASTBYTESMASK(7))) | lsb; JU_RET_FOUND_LEAF7(Pjll, pop1, offset); } #endif // ---------------------------------------------------------------------------- // BITMAP LEAF: // // Look for the highest/lowest (right/left-most) non-null subexpanse, then use // the highest/lowest Index in that subexpanse, but first copy Dcd bytes // (always present since state 1 < cJU_ROOTSTATE) to *PIndex. case cJU_JPLEAF_B1: { Pjlb_t Pjlb; JU_SETDCD(*PIndex, Pjp, 1); Pjlb = P_JLB(Pjp->jp_Addr); #ifdef JUDYPREV subexp = cJU_NUMSUBEXPL; while (! JU_JLB_BITMAP(Pjlb, --subexp)) // find non-empty subexp. { if (subexp <= 0) // wholly empty bitmap. { JU_SET_ERRNO(PJError, JU_ERRNO_CORRUPT); JUDY1CODE(return(JERRI );) JUDYLCODE(return(PPJERR);) } } // TBD: Might it be faster to just use a variant of BITMAPDIGIT*() that yields // the digit for the right-most Index with a bit set? offset = SEARCHBITMAPMAXL(JU_JLB_BITMAP(Pjlb, subexp)); // expected range: assert((offset >= 0) && (offset < cJU_BITSPERSUBEXPL)); #else subexp = -1; while (! JU_JLB_BITMAP(Pjlb, ++subexp)) // find non-empty subexp. { if (subexp >= cJU_NUMSUBEXPL - 1) // didnt find one. { JU_SET_ERRNO(PJError, JU_ERRNO_CORRUPT); JUDY1CODE(return(JERRI );) JUDYLCODE(return(PPJERR);) } } offset = 0; #endif JU_BITMAPDIGITL(digit, subexp, JU_JLB_BITMAP(Pjlb, subexp), offset); JU_SETDIGIT1(*PIndex, digit); JU_RET_FOUND_LEAF_B1(Pjlb, subexp, offset); // == return((PPvoid_t) (P_JV(JL_JLB_PVALUE(Pjlb, subexp)) + (offset))); } // case cJU_JPLEAF_B1 #ifdef JUDY1 // ---------------------------------------------------------------------------- // FULL POPULATION: // // Copy Dcd bytes to *PIndex (always present since state 1 < cJU_ROOTSTATE), // then set the highest/lowest possible digit as the LSB in *PIndex. case cJ1_JPFULLPOPU1: JU_SETDCD( *PIndex, Pjp, 1); #ifdef JUDYPREV JU_SETDIGIT1(*PIndex, cJU_BITSPERBITMAP - 1); #else JU_SETDIGIT1(*PIndex, 0); #endif JU_RET_FOUND_FULLPOPU1; #endif // JUDY1 // ---------------------------------------------------------------------------- // IMMEDIATE: // // Simply use the highest/lowest (right/left-most) Index in the Imm, but the // details vary depending on leaf Index Size and pop1. Note: There are no Dcd // bytes in an Immediate JP, but in a cJU_JPIMMED_*_01 JP, the field holds the // least bytes of the immediate Index. case cJU_JPIMMED_1_01: SET_01(1); goto SM3Imm_01; case cJU_JPIMMED_2_01: SET_01(2); goto SM3Imm_01; case cJU_JPIMMED_3_01: SET_01(3); goto SM3Imm_01; #ifdef JU_64BIT case cJU_JPIMMED_4_01: SET_01(4); goto SM3Imm_01; case cJU_JPIMMED_5_01: SET_01(5); goto SM3Imm_01; case cJU_JPIMMED_6_01: SET_01(6); goto SM3Imm_01; case cJU_JPIMMED_7_01: SET_01(7); goto SM3Imm_01; #endif SM3Imm_01: JU_RET_FOUND_IMM_01(Pjp); #ifdef JUDYPREV #define SM3IMM_OFFSET(cPop1) (cPop1) - 1 // highest. #else #define SM3IMM_OFFSET(cPop1) 0 // lowest. #endif #define SM3IMM(cPop1,Next) \ offset = SM3IMM_OFFSET(cPop1); \ goto Next case cJU_JPIMMED_1_02: SM3IMM( 2, SM3Imm1); case cJU_JPIMMED_1_03: SM3IMM( 3, SM3Imm1); #if (defined(JUDY1) || defined(JU_64BIT)) case cJU_JPIMMED_1_04: SM3IMM( 4, SM3Imm1); case cJU_JPIMMED_1_05: SM3IMM( 5, SM3Imm1); case cJU_JPIMMED_1_06: SM3IMM( 6, SM3Imm1); case cJU_JPIMMED_1_07: SM3IMM( 7, SM3Imm1); #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_1_08: SM3IMM( 8, SM3Imm1); case cJ1_JPIMMED_1_09: SM3IMM( 9, SM3Imm1); case cJ1_JPIMMED_1_10: SM3IMM(10, SM3Imm1); case cJ1_JPIMMED_1_11: SM3IMM(11, SM3Imm1); case cJ1_JPIMMED_1_12: SM3IMM(12, SM3Imm1); case cJ1_JPIMMED_1_13: SM3IMM(13, SM3Imm1); case cJ1_JPIMMED_1_14: SM3IMM(14, SM3Imm1); case cJ1_JPIMMED_1_15: SM3IMM(15, SM3Imm1); #endif SM3Imm1: JU_SETDIGIT1(*PIndex, ((uint8_t *) PJI)[offset]); JU_RET_FOUND_IMM(Pjp, offset); #if (defined(JUDY1) || defined(JU_64BIT)) case cJU_JPIMMED_2_02: SM3IMM(2, SM3Imm2); case cJU_JPIMMED_2_03: SM3IMM(3, SM3Imm2); #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_2_04: SM3IMM(4, SM3Imm2); case cJ1_JPIMMED_2_05: SM3IMM(5, SM3Imm2); case cJ1_JPIMMED_2_06: SM3IMM(6, SM3Imm2); case cJ1_JPIMMED_2_07: SM3IMM(7, SM3Imm2); #endif #if (defined(JUDY1) || defined(JU_64BIT)) SM3Imm2: *PIndex = (*PIndex & (~JU_LEASTBYTESMASK(2))) | ((uint16_t *) PJI)[offset]; JU_RET_FOUND_IMM(Pjp, offset); #endif #if (defined(JUDY1) || defined(JU_64BIT)) case cJU_JPIMMED_3_02: SM3IMM(2, SM3Imm3); #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_3_03: SM3IMM(3, SM3Imm3); case cJ1_JPIMMED_3_04: SM3IMM(4, SM3Imm3); case cJ1_JPIMMED_3_05: SM3IMM(5, SM3Imm3); #endif #if (defined(JUDY1) || defined(JU_64BIT)) SM3Imm3: { Word_t lsb; JU_COPY3_PINDEX_TO_LONG(lsb, ((uint8_t *) PJI) + (3 * offset)); *PIndex = (*PIndex & (~JU_LEASTBYTESMASK(3))) | lsb; JU_RET_FOUND_IMM(Pjp, offset); } #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_4_02: SM3IMM(2, SM3Imm4); case cJ1_JPIMMED_4_03: SM3IMM(3, SM3Imm4); SM3Imm4: *PIndex = (*PIndex & (~JU_LEASTBYTESMASK(4))) | ((uint32_t *) PJI)[offset]; JU_RET_FOUND_IMM(Pjp, offset); case cJ1_JPIMMED_5_02: SM3IMM(2, SM3Imm5); case cJ1_JPIMMED_5_03: SM3IMM(3, SM3Imm5); SM3Imm5: { Word_t lsb; JU_COPY5_PINDEX_TO_LONG(lsb, ((uint8_t *) PJI) + (5 * offset)); *PIndex = (*PIndex & (~JU_LEASTBYTESMASK(5))) | lsb; JU_RET_FOUND_IMM(Pjp, offset); } case cJ1_JPIMMED_6_02: SM3IMM(2, SM3Imm6); SM3Imm6: { Word_t lsb; JU_COPY6_PINDEX_TO_LONG(lsb, ((uint8_t *) PJI) + (6 * offset)); *PIndex = (*PIndex & (~JU_LEASTBYTESMASK(6))) | lsb; JU_RET_FOUND_IMM(Pjp, offset); } case cJ1_JPIMMED_7_02: SM3IMM(2, SM3Imm7); SM3Imm7: { Word_t lsb; JU_COPY7_PINDEX_TO_LONG(lsb, ((uint8_t *) PJI) + (7 * offset)); *PIndex = (*PIndex & (~JU_LEASTBYTESMASK(7))) | lsb; JU_RET_FOUND_IMM(Pjp, offset); } #endif // (JUDY1 && JU_64BIT) // ---------------------------------------------------------------------------- // OTHER CASES: default: JU_SET_ERRNO(PJError, JU_ERRNO_CORRUPT); JUDY1CODE(return(JERRI );) JUDYLCODE(return(PPJERR);) } // SM3Findlimit switch. /*NOTREACHED*/ } // Judy1Prev() / Judy1Next() / JudyLPrev() / JudyLNext() judy-1.0.5/src/JudyCommon/JudyTables.c0000644000175000017500000002152710204462077020012 0ustar troyhebetroyhebe// Copyright (C) 2000 - 2002 Hewlett-Packard Company // // This program is free software; you can redistribute it and/or modify it // under the term of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License // for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program; if not, write to the Free Software Foundation, // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // _________________ // @(#) $Revision: 4.37 $ $Source: /judy/src/JudyCommon/JudyTables.c $ #ifndef JU_WIN #include // unavailable on win_*. #endif #include #include #if (! (defined(JUDY1) || defined(JUDYL))) #error: One of -DJUDY1 or -DJUDYL must be specified. #endif #define TERMINATOR 999 // terminator for Alloc tables #define BPW sizeof(Word_t) // define bytes per word #ifdef JUDY1 #include "Judy1.h" #else #include "JudyL.h" #endif FILE *fd; // Definitions come from header files Judy1.h and JudyL.h: int AllocSizes[] = ALLOCSIZES; #define ROUNDUP(BYTES,BPW,OFFSETW) \ ((((BYTES) + (BPW) - 1) / (BPW)) + (OFFSETW)) // **************************************************************************** // G E N T A B L E // // Note: "const" is required for newer compilers. FUNCTION void GenTable( const char * TableName, // name of table string const char * TableSize, // dimentioned size string int IndexBytes, // bytes per Index int LeafSize, // number elements in object int ValueBytes, // bytes per Value int OffsetWords) // 1 for LEAFW { int * PAllocSizes = AllocSizes; int OWord; int CurWord; int IWord; int ii; int BytesOfIndex; int BytesOfObject; int Index; int LastWords; int Words [1000] = { 0 }; int Offset[1000] = { 0 }; int MaxWords; MaxWords = ROUNDUP((IndexBytes + ValueBytes) * LeafSize, BPW, OffsetWords); Words[0] = 0; Offset[0] = 0; CurWord = TERMINATOR; // Walk through all number of Indexes in table: for (Index = 1; /* null */; ++Index) { // Calculate byte required for next size: BytesOfIndex = IndexBytes * Index; BytesOfObject = (IndexBytes + ValueBytes) * Index; // Round up and calculate words required for next size: OWord = ROUNDUP(BytesOfObject, BPW, OffsetWords); IWord = ROUNDUP(BytesOfIndex, BPW, OffsetWords); // Root-level leaves of population of 1 and 2 do not have the 1 word offset: // Save minimum value of offset: Offset[Index] = IWord; // Round up to next available size of words: while (OWord > *PAllocSizes) PAllocSizes++; if (Index == LeafSize) { CurWord = Words[Index] = OWord; break; } // end of available sizes ? if (*PAllocSizes == TERMINATOR) { fprintf(stderr, "BUG, in %sPopToWords, sizes not big enough for object\n", TableName); exit(1); } // Save words required and last word: if (*PAllocSizes < MaxWords) { CurWord = Words[Index] = *PAllocSizes; } else { CurWord = Words[Index] = MaxWords; } } // for each index LastWords = TERMINATOR; // Round up to largest size in each group of malloc sizes: for (ii = LeafSize; ii > 0; ii--) { if (LastWords > (Words[ii] - ii)) LastWords = Offset[ii]; else Offset[ii] = LastWords; } // Print the PopToWords[] table: fprintf(fd,"\n//\tobject uses %d words\n", CurWord); fprintf(fd,"//\t%s = %d\n", TableSize, LeafSize); fprintf(fd,"const uint8_t\n"); fprintf(fd,"%sPopToWords[%s + 1] =\n", TableName, TableSize); fprintf(fd,"{\n\t 0,"); for (ii = 1; ii <= LeafSize; ii++) { // 8 columns per line, starting with 1: if ((ii % 8) == 1) fprintf(fd,"\n\t"); fprintf(fd,"%2d", Words[ii]); // If not last number place comma: if (ii != LeafSize) fprintf(fd,", "); } fprintf(fd,"\n};\n"); // Print the Offset table if needed: if (! ValueBytes) return; fprintf(fd,"const uint8_t\n"); fprintf(fd,"%sOffset[%s + 1] =\n", TableName, TableSize); fprintf(fd,"{\n"); fprintf(fd,"\t 0,"); for (ii = 1; ii <= LeafSize; ii++) { if ((ii % 8) == 1) fprintf(fd,"\n\t"); fprintf(fd,"%2d", Offset[ii]); if (ii != LeafSize) fprintf(fd,", "); } fprintf(fd,"\n};\n"); } // GenTable() // **************************************************************************** // M A I N FUNCTION int main() { int ii; #ifdef JUDY1 char *fname = "Judy1Tables.c"; #else char *fname = "JudyLTables.c"; #endif if ((fd = fopen(fname, "w")) == NULL){ perror("FATAL ERROR: could not write to Judy[1L]Tables.c file\n"); return (-1); } fprintf(fd,"// @(#) From generation tool: $Revision: 4.37 $ $Source: /judy/src/JudyCommon/JudyTables.c $\n"); fprintf(fd,"//\n\n"); // ================================ Judy1 ================================= #ifdef JUDY1 fprintf(fd,"#include \"Judy1.h\"\n"); fprintf(fd,"// Leave the malloc() sizes readable in the binary (via " "strings(1)):\n"); fprintf(fd,"const char * Judy1MallocSizes = \"Judy1MallocSizes ="); for (ii = 0; AllocSizes[ii] != TERMINATOR; ii++) fprintf(fd," %d,", AllocSizes[ii]); #ifndef JU_64BIT fprintf(fd," Leaf1 = %d\";\n\n", cJ1_LEAF1_MAXPOP1); #else fprintf(fd,"\";\n\n"); // no Leaf1 in this case. #endif // ================================ 32 bit ================================ #ifndef JU_64BIT GenTable("j__1_BranchBJP","cJU_BITSPERSUBEXPB", 8, cJU_BITSPERSUBEXPB,0,0); GenTable("j__1_Leaf1", "cJ1_LEAF1_MAXPOP1", 1, cJ1_LEAF1_MAXPOP1, 0, 0); GenTable("j__1_Leaf2", "cJ1_LEAF2_MAXPOP1", 2, cJ1_LEAF2_MAXPOP1, 0, 0); GenTable("j__1_Leaf3", "cJ1_LEAF3_MAXPOP1", 3, cJ1_LEAF3_MAXPOP1, 0, 0); GenTable("j__1_LeafW", "cJ1_LEAFW_MAXPOP1", 4, cJ1_LEAFW_MAXPOP1, 0, 1); #endif // ================================ 64 bit ================================ #ifdef JU_64BIT GenTable("j__1_BranchBJP","cJU_BITSPERSUBEXPB",16, cJU_BITSPERSUBEXPB,0,0); GenTable("j__1_Leaf2", "cJ1_LEAF2_MAXPOP1", 2, cJ1_LEAF2_MAXPOP1, 0, 0); GenTable("j__1_Leaf3", "cJ1_LEAF3_MAXPOP1", 3, cJ1_LEAF3_MAXPOP1, 0, 0); GenTable("j__1_Leaf4", "cJ1_LEAF4_MAXPOP1", 4, cJ1_LEAF4_MAXPOP1, 0, 0); GenTable("j__1_Leaf5", "cJ1_LEAF5_MAXPOP1", 5, cJ1_LEAF5_MAXPOP1, 0, 0); GenTable("j__1_Leaf6", "cJ1_LEAF6_MAXPOP1", 6, cJ1_LEAF6_MAXPOP1, 0, 0); GenTable("j__1_Leaf7", "cJ1_LEAF7_MAXPOP1", 7, cJ1_LEAF7_MAXPOP1, 0, 0); GenTable("j__1_LeafW", "cJ1_LEAFW_MAXPOP1", 8, cJ1_LEAFW_MAXPOP1, 0, 1); #endif #endif // JUDY1 // ================================ JudyL ================================= #ifdef JUDYL fprintf(fd,"#include \"JudyL.h\"\n"); fprintf(fd,"// Leave the malloc() sizes readable in the binary (via " "strings(1)):\n"); fprintf(fd,"const char * JudyLMallocSizes = \"JudyLMallocSizes ="); for (ii = 0; AllocSizes[ii] != TERMINATOR; ii++) fprintf(fd," %d,", AllocSizes[ii]); fprintf(fd," Leaf1 = %ld\";\n\n", (Word_t)cJL_LEAF1_MAXPOP1); #ifndef JU_64BIT // ================================ 32 bit ================================ GenTable("j__L_BranchBJP","cJU_BITSPERSUBEXPB", 8, cJU_BITSPERSUBEXPB, 0,0); GenTable("j__L_Leaf1", "cJL_LEAF1_MAXPOP1", 1, cJL_LEAF1_MAXPOP1, BPW,0); GenTable("j__L_Leaf2", "cJL_LEAF2_MAXPOP1", 2, cJL_LEAF2_MAXPOP1, BPW,0); GenTable("j__L_Leaf3", "cJL_LEAF3_MAXPOP1", 3, cJL_LEAF3_MAXPOP1, BPW,0); GenTable("j__L_LeafW", "cJL_LEAFW_MAXPOP1", 4, cJL_LEAFW_MAXPOP1, BPW,1); GenTable("j__L_LeafV", "cJU_BITSPERSUBEXPL", 4, cJU_BITSPERSUBEXPL, 0,0); #endif // 32 BIT #ifdef JU_64BIT // ================================ 64 bit ================================ GenTable("j__L_BranchBJP","cJU_BITSPERSUBEXPB",16, cJU_BITSPERSUBEXPB, 0,0); GenTable("j__L_Leaf1", "cJL_LEAF1_MAXPOP1", 1, cJL_LEAF1_MAXPOP1, BPW,0); GenTable("j__L_Leaf2", "cJL_LEAF2_MAXPOP1", 2, cJL_LEAF2_MAXPOP1, BPW,0); GenTable("j__L_Leaf3", "cJL_LEAF3_MAXPOP1", 3, cJL_LEAF3_MAXPOP1, BPW,0); GenTable("j__L_Leaf4", "cJL_LEAF4_MAXPOP1", 4, cJL_LEAF4_MAXPOP1, BPW,0); GenTable("j__L_Leaf5", "cJL_LEAF5_MAXPOP1", 5, cJL_LEAF5_MAXPOP1, BPW,0); GenTable("j__L_Leaf6", "cJL_LEAF6_MAXPOP1", 6, cJL_LEAF6_MAXPOP1, BPW,0); GenTable("j__L_Leaf7", "cJL_LEAF7_MAXPOP1", 7, cJL_LEAF7_MAXPOP1, BPW,0); GenTable("j__L_LeafW", "cJL_LEAFW_MAXPOP1", 8, cJL_LEAFW_MAXPOP1, BPW,1); GenTable("j__L_LeafV", "cJU_BITSPERSUBEXPL", 8, cJU_BITSPERSUBEXPL, 0,0); #endif // 64 BIT #endif // JUDYL fclose(fd); return(0); } // main() judy-1.0.5/src/JudyCommon/JudyCreateBranch.c0000644000175000017500000002017010204462077021112 0ustar troyhebetroyhebe// Copyright (C) 2000 - 2002 Hewlett-Packard Company // // This program is free software; you can redistribute it and/or modify it // under the term of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License // for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program; if not, write to the Free Software Foundation, // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // _________________ // @(#) $Revision: 4.26 $ $Source: /judy/src/JudyCommon/JudyCreateBranch.c $ // Branch creation functions for Judy1 and JudyL. // Compile with one of -DJUDY1 or -DJUDYL. #if (! (defined(JUDY1) || defined(JUDYL))) #error: One of -DJUDY1 or -DJUDYL must be specified. #endif #ifdef JUDY1 #include "Judy1.h" #else #include "JudyL.h" #endif #include "JudyPrivate1L.h" // **************************************************************************** // J U D Y C R E A T E B R A N C H L // // Build a BranchL from an array of JPs and associated 1 byte digits // (expanses). Return with Pjp pointing to the BranchL. Caller must // deallocate passed arrays, if necessary. // // We have no idea what kind of BranchL it is, so caller must set the jp_Type. // // Return -1 if error (details in Pjpm), otherwise return 1. FUNCTION int j__udyCreateBranchL( Pjp_t Pjp, // Build JPs from this place Pjp_t PJPs, // Array of JPs to put into Bitmap branch uint8_t Exp[], // Array of expanses to put into bitmap Word_t ExpCnt, // Number of above JPs and Expanses Pvoid_t Pjpm) { Pjbl_t PjblRaw; // pointer to linear branch. Pjbl_t Pjbl; assert(ExpCnt <= cJU_BRANCHLMAXJPS); PjblRaw = j__udyAllocJBL(Pjpm); if (PjblRaw == (Pjbl_t) NULL) return(-1); Pjbl = P_JBL(PjblRaw); // Build a Linear Branch Pjbl->jbl_NumJPs = ExpCnt; // Copy from the Linear branch from splayed leaves JU_COPYMEM(Pjbl->jbl_Expanse, Exp, ExpCnt); JU_COPYMEM(Pjbl->jbl_jp, PJPs, ExpCnt); // Pass back new pointer to the Linear branch in JP Pjp->jp_Addr = (Word_t) PjblRaw; return(1); } // j__udyCreateBranchL() // **************************************************************************** // J U D Y C R E A T E B R A N C H B // // Build a BranchB from an array of JPs and associated 1 byte digits // (expanses). Return with Pjp pointing to the BranchB. Caller must // deallocate passed arrays, if necessary. // // We have no idea what kind of BranchB it is, so caller must set the jp_Type. // // Return -1 if error (details in Pjpm), otherwise return 1. FUNCTION int j__udyCreateBranchB( Pjp_t Pjp, // Build JPs from this place Pjp_t PJPs, // Array of JPs to put into Bitmap branch uint8_t Exp[], // Array of expanses to put into bitmap Word_t ExpCnt, // Number of above JPs and Expanses Pvoid_t Pjpm) { Pjbb_t PjbbRaw; // pointer to bitmap branch. Pjbb_t Pjbb; Word_t ii, jj; // Temps uint8_t CurrSubExp; // Current sub expanse for BM // This assertion says the number of populated subexpanses is not too large. // This function is only called when a BranchL overflows to a BranchB or when a // cascade occurs, meaning a leaf overflows. Either way ExpCnt cant be very // large, in fact a lot smaller than cJU_BRANCHBMAXJPS. (Otherwise a BranchU // would be used.) Popping this assertion means something (unspecified) has // gone very wrong, or else Judys design criteria have changed, although in // fact there should be no HARM in creating a BranchB with higher actual // fanout. assert(ExpCnt <= cJU_BRANCHBMAXJPS); // Get memory for a Bitmap branch PjbbRaw = j__udyAllocJBB(Pjpm); if (PjbbRaw == (Pjbb_t) NULL) return(-1); Pjbb = P_JBB(PjbbRaw); // Get 1st "sub" expanse (0..7) of bitmap branch CurrSubExp = Exp[0] / cJU_BITSPERSUBEXPB; // Index thru all 1 byte sized expanses: for (jj = ii = 0; ii <= ExpCnt; ii++) { Word_t SubExp; // Cannot be a uint8_t // Make sure we cover the last one if (ii == ExpCnt) { SubExp = cJU_ALLONES; // Force last one } else { // Calculate the "sub" expanse of the byte expanse SubExp = Exp[ii] / cJU_BITSPERSUBEXPB; // Bits 5..7. // Set the bit that represents the expanse in Exp[] JU_JBB_BITMAP(Pjbb, SubExp) |= JU_BITPOSMASKB(Exp[ii]); } // Check if a new "sub" expanse range needed if (SubExp != CurrSubExp) { // Get number of JPs in this sub expanse Word_t NumJP = ii - jj; Pjp_t PjpRaw; Pjp_t Pjp; PjpRaw = j__udyAllocJBBJP(NumJP, Pjpm); Pjp = P_JP(PjpRaw); if (PjpRaw == (Pjp_t) NULL) // out of memory. { // Free any previous allocations: while(CurrSubExp--) { NumJP = j__udyCountBitsB(JU_JBB_BITMAP(Pjbb, CurrSubExp)); if (NumJP) { j__udyFreeJBBJP(JU_JBB_PJP(Pjbb, CurrSubExp), NumJP, Pjpm); } } j__udyFreeJBB(PjbbRaw, Pjpm); return(-1); } // Place the array of JPs in bitmap branch: JU_JBB_PJP(Pjbb, CurrSubExp) = PjpRaw; // Copy the JPs to new leaf: JU_COPYMEM(Pjp, PJPs + jj, NumJP); // On to the next bitmap branch "sub" expanse: jj = ii; CurrSubExp = SubExp; } } // for each 1-byte expanse // Pass back some of the JP to the new Bitmap branch: Pjp->jp_Addr = (Word_t) PjbbRaw; return(1); } // j__udyCreateBranchB() // **************************************************************************** // J U D Y C R E A T E B R A N C H U // // Build a BranchU from a BranchB. Return with Pjp pointing to the BranchU. // Free the BranchB and its JP subarrays. // // Return -1 if error (details in Pjpm), otherwise return 1. FUNCTION int j__udyCreateBranchU( Pjp_t Pjp, Pvoid_t Pjpm) { jp_t JPNull; Pjbu_t PjbuRaw; Pjbu_t Pjbu; Pjbb_t PjbbRaw; Pjbb_t Pjbb; Word_t ii, jj; BITMAPB_t BitMap; Pjp_t PDstJP; #ifdef JU_STAGED_EXP jbu_t BranchU; // Staged uncompressed branch #else // Allocate memory for a BranchU: PjbuRaw = j__udyAllocJBU(Pjpm); if (PjbuRaw == (Pjbu_t) NULL) return(-1); Pjbu = P_JBU(PjbuRaw); #endif JU_JPSETADT(&JPNull, 0, 0, JU_JPTYPE(Pjp) - cJU_JPBRANCH_B2 + cJU_JPNULL1); // Get the pointer to the BranchB: PjbbRaw = (Pjbb_t) (Pjp->jp_Addr); Pjbb = P_JBB(PjbbRaw); // Set the pointer to the Uncompressed branch #ifdef JU_STAGED_EXP PDstJP = BranchU.jbu_jp; #else PDstJP = Pjbu->jbu_jp; #endif for (ii = 0; ii < cJU_NUMSUBEXPB; ii++) { Pjp_t PjpA; Pjp_t PjpB; PjpB = PjpA = P_JP(JU_JBB_PJP(Pjbb, ii)); // Get the bitmap for this subexpanse BitMap = JU_JBB_BITMAP(Pjbb, ii); // NULL empty subexpanses if (BitMap == 0) { // But, fill with NULLs for (jj = 0; jj < cJU_BITSPERSUBEXPB; jj++) { PDstJP[jj] = JPNull; } PDstJP += cJU_BITSPERSUBEXPB; continue; } // Check if Uncompressed subexpanse if (BitMap == cJU_FULLBITMAPB) { // Copy subexpanse to the Uncompressed branch intact JU_COPYMEM(PDstJP, PjpA, cJU_BITSPERSUBEXPB); // Bump to next subexpanse PDstJP += cJU_BITSPERSUBEXPB; // Set length of subexpanse jj = cJU_BITSPERSUBEXPB; } else { for (jj = 0; jj < cJU_BITSPERSUBEXPB; jj++) { // Copy JP or NULLJP depending on bit if (BitMap & 1) { *PDstJP = *PjpA++; } else { *PDstJP = JPNull; } PDstJP++; // advance to next JP BitMap >>= 1; } jj = PjpA - PjpB; } // Free the subexpanse: j__udyFreeJBBJP(JU_JBB_PJP(Pjbb, ii), jj, Pjpm); } // for each JP in BranchU #ifdef JU_STAGED_EXP // Allocate memory for a BranchU: PjbuRaw = j__udyAllocJBU(Pjpm); if (PjbuRaw == (Pjbu_t) NULL) return(-1); Pjbu = P_JBU(PjbuRaw); // Copy staged branch to newly allocated branch: // // TBD: I think this code is broken. *Pjbu = BranchU; #endif // JU_STAGED_EXP // Finally free the BranchB and put the BranchU in its place: j__udyFreeJBB(PjbbRaw, Pjpm); Pjp->jp_Addr = (Word_t) PjbuRaw; Pjp->jp_Type += cJU_JPBRANCH_U - cJU_JPBRANCH_B; return(1); } // j__udyCreateBranchU() judy-1.0.5/src/JudyCommon/JudyPrivate1L.h0000644000175000017500000004027010204462077020410 0ustar troyhebetroyhebe#ifndef _JUDYPRIVATE1L_INCLUDED #define _JUDYPRIVATE1L_INCLUDED // _________________ // // Copyright (C) 2000 - 2002 Hewlett-Packard Company // // This program is free software; you can redistribute it and/or modify it // under the term of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License // for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program; if not, write to the Free Software Foundation, // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // _________________ // @(#) $Revision: 4.31 $ $Source: /judy/src/JudyCommon/JudyPrivate1L.h $ // **************************************************************************** // Declare common cJU_* names for JP Types that occur in both Judy1 and JudyL, // for use by code that ifdefs JUDY1 and JUDYL. Only JP Types common to both // Judy1 and JudyL are #defined here with equivalent cJU_* names. JP Types // unique to only Judy1 or JudyL are listed in comments, so the type lists // match the Judy1.h and JudyL.h files. // // This file also defines cJU_* for other JP-related constants and functions // that some shared JUDY1/JUDYL code finds handy. // // At least in principle this file should be included AFTER Judy1.h or JudyL.h. // // WARNING: This file must be kept consistent with the enums in Judy1.h and // JudyL.h. // // TBD: You might think, why not define common cJU_* enums in, say, // JudyPrivate.h, and then inherit them into superset enums in Judy1.h and // JudyL.h? The problem is that the enum lists for each class (cJ1_* and // cJL_*) must be numerically "packed" into the correct order, for two reasons: // (1) allow the compiler to generate "tight" switch statements with no wasted // slots (although this is not very big), and (2) allow calculations using the // enum values, although this is also not an issue if the calculations are only // within each cJ*_JPIMMED_*_* class and the members are packed within the // class. #ifdef JUDY1 #define cJU_JRPNULL cJ1_JRPNULL #define cJU_JPNULL1 cJ1_JPNULL1 #define cJU_JPNULL2 cJ1_JPNULL2 #define cJU_JPNULL3 cJ1_JPNULL3 #ifdef JU_64BIT #define cJU_JPNULL4 cJ1_JPNULL4 #define cJU_JPNULL5 cJ1_JPNULL5 #define cJU_JPNULL6 cJ1_JPNULL6 #define cJU_JPNULL7 cJ1_JPNULL7 #endif #define cJU_JPNULLMAX cJ1_JPNULLMAX #define cJU_JPBRANCH_L2 cJ1_JPBRANCH_L2 #define cJU_JPBRANCH_L3 cJ1_JPBRANCH_L3 #ifdef JU_64BIT #define cJU_JPBRANCH_L4 cJ1_JPBRANCH_L4 #define cJU_JPBRANCH_L5 cJ1_JPBRANCH_L5 #define cJU_JPBRANCH_L6 cJ1_JPBRANCH_L6 #define cJU_JPBRANCH_L7 cJ1_JPBRANCH_L7 #endif #define cJU_JPBRANCH_L cJ1_JPBRANCH_L #define j__U_BranchBJPPopToWords j__1_BranchBJPPopToWords #define cJU_JPBRANCH_B2 cJ1_JPBRANCH_B2 #define cJU_JPBRANCH_B3 cJ1_JPBRANCH_B3 #ifdef JU_64BIT #define cJU_JPBRANCH_B4 cJ1_JPBRANCH_B4 #define cJU_JPBRANCH_B5 cJ1_JPBRANCH_B5 #define cJU_JPBRANCH_B6 cJ1_JPBRANCH_B6 #define cJU_JPBRANCH_B7 cJ1_JPBRANCH_B7 #endif #define cJU_JPBRANCH_B cJ1_JPBRANCH_B #define cJU_JPBRANCH_U2 cJ1_JPBRANCH_U2 #define cJU_JPBRANCH_U3 cJ1_JPBRANCH_U3 #ifdef JU_64BIT #define cJU_JPBRANCH_U4 cJ1_JPBRANCH_U4 #define cJU_JPBRANCH_U5 cJ1_JPBRANCH_U5 #define cJU_JPBRANCH_U6 cJ1_JPBRANCH_U6 #define cJU_JPBRANCH_U7 cJ1_JPBRANCH_U7 #endif #define cJU_JPBRANCH_U cJ1_JPBRANCH_U #ifndef JU_64BIT #define cJU_JPLEAF1 cJ1_JPLEAF1 #endif #define cJU_JPLEAF2 cJ1_JPLEAF2 #define cJU_JPLEAF3 cJ1_JPLEAF3 #ifdef JU_64BIT #define cJU_JPLEAF4 cJ1_JPLEAF4 #define cJU_JPLEAF5 cJ1_JPLEAF5 #define cJU_JPLEAF6 cJ1_JPLEAF6 #define cJU_JPLEAF7 cJ1_JPLEAF7 #endif #define cJU_JPLEAF_B1 cJ1_JPLEAF_B1 // cJ1_JPFULLPOPU1 #define cJU_JPIMMED_1_01 cJ1_JPIMMED_1_01 #define cJU_JPIMMED_2_01 cJ1_JPIMMED_2_01 #define cJU_JPIMMED_3_01 cJ1_JPIMMED_3_01 #ifdef JU_64BIT #define cJU_JPIMMED_4_01 cJ1_JPIMMED_4_01 #define cJU_JPIMMED_5_01 cJ1_JPIMMED_5_01 #define cJU_JPIMMED_6_01 cJ1_JPIMMED_6_01 #define cJU_JPIMMED_7_01 cJ1_JPIMMED_7_01 #endif #define cJU_JPIMMED_1_02 cJ1_JPIMMED_1_02 #define cJU_JPIMMED_1_03 cJ1_JPIMMED_1_03 #define cJU_JPIMMED_1_04 cJ1_JPIMMED_1_04 #define cJU_JPIMMED_1_05 cJ1_JPIMMED_1_05 #define cJU_JPIMMED_1_06 cJ1_JPIMMED_1_06 #define cJU_JPIMMED_1_07 cJ1_JPIMMED_1_07 #ifdef JU_64BIT // cJ1_JPIMMED_1_08 // cJ1_JPIMMED_1_09 // cJ1_JPIMMED_1_10 // cJ1_JPIMMED_1_11 // cJ1_JPIMMED_1_12 // cJ1_JPIMMED_1_13 // cJ1_JPIMMED_1_14 // cJ1_JPIMMED_1_15 #endif #define cJU_JPIMMED_2_02 cJ1_JPIMMED_2_02 #define cJU_JPIMMED_2_03 cJ1_JPIMMED_2_03 #ifdef JU_64BIT // cJ1_JPIMMED_2_04 // cJ1_JPIMMED_2_05 // cJ1_JPIMMED_2_06 // cJ1_JPIMMED_2_07 #endif #define cJU_JPIMMED_3_02 cJ1_JPIMMED_3_02 #ifdef JU_64BIT // cJ1_JPIMMED_3_03 // cJ1_JPIMMED_3_04 // cJ1_JPIMMED_3_05 // cJ1_JPIMMED_4_02 // cJ1_JPIMMED_4_03 // cJ1_JPIMMED_5_02 // cJ1_JPIMMED_5_03 // cJ1_JPIMMED_6_02 // cJ1_JPIMMED_7_02 #endif #define cJU_JPIMMED_CAP cJ1_JPIMMED_CAP #else // JUDYL **************************************************************** #define cJU_JRPNULL cJL_JRPNULL #define cJU_JPNULL1 cJL_JPNULL1 #define cJU_JPNULL2 cJL_JPNULL2 #define cJU_JPNULL3 cJL_JPNULL3 #ifdef JU_64BIT #define cJU_JPNULL4 cJL_JPNULL4 #define cJU_JPNULL5 cJL_JPNULL5 #define cJU_JPNULL6 cJL_JPNULL6 #define cJU_JPNULL7 cJL_JPNULL7 #endif #define cJU_JPNULLMAX cJL_JPNULLMAX #define cJU_JPBRANCH_L2 cJL_JPBRANCH_L2 #define cJU_JPBRANCH_L3 cJL_JPBRANCH_L3 #ifdef JU_64BIT #define cJU_JPBRANCH_L4 cJL_JPBRANCH_L4 #define cJU_JPBRANCH_L5 cJL_JPBRANCH_L5 #define cJU_JPBRANCH_L6 cJL_JPBRANCH_L6 #define cJU_JPBRANCH_L7 cJL_JPBRANCH_L7 #endif #define cJU_JPBRANCH_L cJL_JPBRANCH_L #define j__U_BranchBJPPopToWords j__L_BranchBJPPopToWords #define cJU_JPBRANCH_B2 cJL_JPBRANCH_B2 #define cJU_JPBRANCH_B3 cJL_JPBRANCH_B3 #ifdef JU_64BIT #define cJU_JPBRANCH_B4 cJL_JPBRANCH_B4 #define cJU_JPBRANCH_B5 cJL_JPBRANCH_B5 #define cJU_JPBRANCH_B6 cJL_JPBRANCH_B6 #define cJU_JPBRANCH_B7 cJL_JPBRANCH_B7 #endif #define cJU_JPBRANCH_B cJL_JPBRANCH_B #define cJU_JPBRANCH_U2 cJL_JPBRANCH_U2 #define cJU_JPBRANCH_U3 cJL_JPBRANCH_U3 #ifdef JU_64BIT #define cJU_JPBRANCH_U4 cJL_JPBRANCH_U4 #define cJU_JPBRANCH_U5 cJL_JPBRANCH_U5 #define cJU_JPBRANCH_U6 cJL_JPBRANCH_U6 #define cJU_JPBRANCH_U7 cJL_JPBRANCH_U7 #endif #define cJU_JPBRANCH_U cJL_JPBRANCH_U #define cJU_JPLEAF1 cJL_JPLEAF1 #define cJU_JPLEAF2 cJL_JPLEAF2 #define cJU_JPLEAF3 cJL_JPLEAF3 #ifdef JU_64BIT #define cJU_JPLEAF4 cJL_JPLEAF4 #define cJU_JPLEAF5 cJL_JPLEAF5 #define cJU_JPLEAF6 cJL_JPLEAF6 #define cJU_JPLEAF7 cJL_JPLEAF7 #endif #define cJU_JPLEAF_B1 cJL_JPLEAF_B1 #define cJU_JPIMMED_1_01 cJL_JPIMMED_1_01 #define cJU_JPIMMED_2_01 cJL_JPIMMED_2_01 #define cJU_JPIMMED_3_01 cJL_JPIMMED_3_01 #ifdef JU_64BIT #define cJU_JPIMMED_4_01 cJL_JPIMMED_4_01 #define cJU_JPIMMED_5_01 cJL_JPIMMED_5_01 #define cJU_JPIMMED_6_01 cJL_JPIMMED_6_01 #define cJU_JPIMMED_7_01 cJL_JPIMMED_7_01 #endif #define cJU_JPIMMED_1_02 cJL_JPIMMED_1_02 #define cJU_JPIMMED_1_03 cJL_JPIMMED_1_03 #ifdef JU_64BIT #define cJU_JPIMMED_1_04 cJL_JPIMMED_1_04 #define cJU_JPIMMED_1_05 cJL_JPIMMED_1_05 #define cJU_JPIMMED_1_06 cJL_JPIMMED_1_06 #define cJU_JPIMMED_1_07 cJL_JPIMMED_1_07 #define cJU_JPIMMED_2_02 cJL_JPIMMED_2_02 #define cJU_JPIMMED_2_03 cJL_JPIMMED_2_03 #define cJU_JPIMMED_3_02 cJL_JPIMMED_3_02 #endif #define cJU_JPIMMED_CAP cJL_JPIMMED_CAP #endif // JUDYL // **************************************************************************** // cJU*_ other than JP types: #ifdef JUDY1 #define cJU_LEAFW_MAXPOP1 cJ1_LEAFW_MAXPOP1 #ifndef JU_64BIT #define cJU_LEAF1_MAXPOP1 cJ1_LEAF1_MAXPOP1 #endif #define cJU_LEAF2_MAXPOP1 cJ1_LEAF2_MAXPOP1 #define cJU_LEAF3_MAXPOP1 cJ1_LEAF3_MAXPOP1 #ifdef JU_64BIT #define cJU_LEAF4_MAXPOP1 cJ1_LEAF4_MAXPOP1 #define cJU_LEAF5_MAXPOP1 cJ1_LEAF5_MAXPOP1 #define cJU_LEAF6_MAXPOP1 cJ1_LEAF6_MAXPOP1 #define cJU_LEAF7_MAXPOP1 cJ1_LEAF7_MAXPOP1 #endif #define cJU_IMMED1_MAXPOP1 cJ1_IMMED1_MAXPOP1 #define cJU_IMMED2_MAXPOP1 cJ1_IMMED2_MAXPOP1 #define cJU_IMMED3_MAXPOP1 cJ1_IMMED3_MAXPOP1 #ifdef JU_64BIT #define cJU_IMMED4_MAXPOP1 cJ1_IMMED4_MAXPOP1 #define cJU_IMMED5_MAXPOP1 cJ1_IMMED5_MAXPOP1 #define cJU_IMMED6_MAXPOP1 cJ1_IMMED6_MAXPOP1 #define cJU_IMMED7_MAXPOP1 cJ1_IMMED7_MAXPOP1 #endif #define JU_LEAF1POPTOWORDS(Pop1) J1_LEAF1POPTOWORDS(Pop1) #define JU_LEAF2POPTOWORDS(Pop1) J1_LEAF2POPTOWORDS(Pop1) #define JU_LEAF3POPTOWORDS(Pop1) J1_LEAF3POPTOWORDS(Pop1) #ifdef JU_64BIT #define JU_LEAF4POPTOWORDS(Pop1) J1_LEAF4POPTOWORDS(Pop1) #define JU_LEAF5POPTOWORDS(Pop1) J1_LEAF5POPTOWORDS(Pop1) #define JU_LEAF6POPTOWORDS(Pop1) J1_LEAF6POPTOWORDS(Pop1) #define JU_LEAF7POPTOWORDS(Pop1) J1_LEAF7POPTOWORDS(Pop1) #endif #define JU_LEAFWPOPTOWORDS(Pop1) J1_LEAFWPOPTOWORDS(Pop1) #ifndef JU_64BIT #define JU_LEAF1GROWINPLACE(Pop1) J1_LEAF1GROWINPLACE(Pop1) #endif #define JU_LEAF2GROWINPLACE(Pop1) J1_LEAF2GROWINPLACE(Pop1) #define JU_LEAF3GROWINPLACE(Pop1) J1_LEAF3GROWINPLACE(Pop1) #ifdef JU_64BIT #define JU_LEAF4GROWINPLACE(Pop1) J1_LEAF4GROWINPLACE(Pop1) #define JU_LEAF5GROWINPLACE(Pop1) J1_LEAF5GROWINPLACE(Pop1) #define JU_LEAF6GROWINPLACE(Pop1) J1_LEAF6GROWINPLACE(Pop1) #define JU_LEAF7GROWINPLACE(Pop1) J1_LEAF7GROWINPLACE(Pop1) #endif #define JU_LEAFWGROWINPLACE(Pop1) J1_LEAFWGROWINPLACE(Pop1) #define j__udyCreateBranchL j__udy1CreateBranchL #define j__udyCreateBranchB j__udy1CreateBranchB #define j__udyCreateBranchU j__udy1CreateBranchU #define j__udyCascade1 j__udy1Cascade1 #define j__udyCascade2 j__udy1Cascade2 #define j__udyCascade3 j__udy1Cascade3 #ifdef JU_64BIT #define j__udyCascade4 j__udy1Cascade4 #define j__udyCascade5 j__udy1Cascade5 #define j__udyCascade6 j__udy1Cascade6 #define j__udyCascade7 j__udy1Cascade7 #endif #define j__udyCascadeL j__udy1CascadeL #define j__udyInsertBranch j__udy1InsertBranch #define j__udyBranchBToBranchL j__udy1BranchBToBranchL #ifndef JU_64BIT #define j__udyLeafB1ToLeaf1 j__udy1LeafB1ToLeaf1 #endif #define j__udyLeaf1ToLeaf2 j__udy1Leaf1ToLeaf2 #define j__udyLeaf2ToLeaf3 j__udy1Leaf2ToLeaf3 #ifndef JU_64BIT #define j__udyLeaf3ToLeafW j__udy1Leaf3ToLeafW #else #define j__udyLeaf3ToLeaf4 j__udy1Leaf3ToLeaf4 #define j__udyLeaf4ToLeaf5 j__udy1Leaf4ToLeaf5 #define j__udyLeaf5ToLeaf6 j__udy1Leaf5ToLeaf6 #define j__udyLeaf6ToLeaf7 j__udy1Leaf6ToLeaf7 #define j__udyLeaf7ToLeafW j__udy1Leaf7ToLeafW #endif #define jpm_t j1pm_t #define Pjpm_t Pj1pm_t #define jlb_t j1lb_t #define Pjlb_t Pj1lb_t #define JU_JLB_BITMAP J1_JLB_BITMAP #define j__udyAllocJPM j__udy1AllocJ1PM #define j__udyAllocJBL j__udy1AllocJBL #define j__udyAllocJBB j__udy1AllocJBB #define j__udyAllocJBBJP j__udy1AllocJBBJP #define j__udyAllocJBU j__udy1AllocJBU #ifndef JU_64BIT #define j__udyAllocJLL1 j__udy1AllocJLL1 #endif #define j__udyAllocJLL2 j__udy1AllocJLL2 #define j__udyAllocJLL3 j__udy1AllocJLL3 #ifdef JU_64BIT #define j__udyAllocJLL4 j__udy1AllocJLL4 #define j__udyAllocJLL5 j__udy1AllocJLL5 #define j__udyAllocJLL6 j__udy1AllocJLL6 #define j__udyAllocJLL7 j__udy1AllocJLL7 #endif #define j__udyAllocJLW j__udy1AllocJLW #define j__udyAllocJLB1 j__udy1AllocJLB1 #define j__udyFreeJPM j__udy1FreeJ1PM #define j__udyFreeJBL j__udy1FreeJBL #define j__udyFreeJBB j__udy1FreeJBB #define j__udyFreeJBBJP j__udy1FreeJBBJP #define j__udyFreeJBU j__udy1FreeJBU #ifndef JU_64BIT #define j__udyFreeJLL1 j__udy1FreeJLL1 #endif #define j__udyFreeJLL2 j__udy1FreeJLL2 #define j__udyFreeJLL3 j__udy1FreeJLL3 #ifdef JU_64BIT #define j__udyFreeJLL4 j__udy1FreeJLL4 #define j__udyFreeJLL5 j__udy1FreeJLL5 #define j__udyFreeJLL6 j__udy1FreeJLL6 #define j__udyFreeJLL7 j__udy1FreeJLL7 #endif #define j__udyFreeJLW j__udy1FreeJLW #define j__udyFreeJLB1 j__udy1FreeJLB1 #define j__udyFreeSM j__udy1FreeSM #define j__uMaxWords j__u1MaxWords #ifdef DEBUG #define JudyCheckPop Judy1CheckPop #endif #else // JUDYL **************************************************************** #define cJU_LEAFW_MAXPOP1 cJL_LEAFW_MAXPOP1 #define cJU_LEAF1_MAXPOP1 cJL_LEAF1_MAXPOP1 #define cJU_LEAF2_MAXPOP1 cJL_LEAF2_MAXPOP1 #define cJU_LEAF3_MAXPOP1 cJL_LEAF3_MAXPOP1 #ifdef JU_64BIT #define cJU_LEAF4_MAXPOP1 cJL_LEAF4_MAXPOP1 #define cJU_LEAF5_MAXPOP1 cJL_LEAF5_MAXPOP1 #define cJU_LEAF6_MAXPOP1 cJL_LEAF6_MAXPOP1 #define cJU_LEAF7_MAXPOP1 cJL_LEAF7_MAXPOP1 #endif #define cJU_IMMED1_MAXPOP1 cJL_IMMED1_MAXPOP1 #define cJU_IMMED2_MAXPOP1 cJL_IMMED2_MAXPOP1 #define cJU_IMMED3_MAXPOP1 cJL_IMMED3_MAXPOP1 #ifdef JU_64BIT #define cJU_IMMED4_MAXPOP1 cJL_IMMED4_MAXPOP1 #define cJU_IMMED5_MAXPOP1 cJL_IMMED5_MAXPOP1 #define cJU_IMMED6_MAXPOP1 cJL_IMMED6_MAXPOP1 #define cJU_IMMED7_MAXPOP1 cJL_IMMED7_MAXPOP1 #endif #define JU_LEAF1POPTOWORDS(Pop1) JL_LEAF1POPTOWORDS(Pop1) #define JU_LEAF2POPTOWORDS(Pop1) JL_LEAF2POPTOWORDS(Pop1) #define JU_LEAF3POPTOWORDS(Pop1) JL_LEAF3POPTOWORDS(Pop1) #ifdef JU_64BIT #define JU_LEAF4POPTOWORDS(Pop1) JL_LEAF4POPTOWORDS(Pop1) #define JU_LEAF5POPTOWORDS(Pop1) JL_LEAF5POPTOWORDS(Pop1) #define JU_LEAF6POPTOWORDS(Pop1) JL_LEAF6POPTOWORDS(Pop1) #define JU_LEAF7POPTOWORDS(Pop1) JL_LEAF7POPTOWORDS(Pop1) #endif #define JU_LEAFWPOPTOWORDS(Pop1) JL_LEAFWPOPTOWORDS(Pop1) #define JU_LEAF1GROWINPLACE(Pop1) JL_LEAF1GROWINPLACE(Pop1) #define JU_LEAF2GROWINPLACE(Pop1) JL_LEAF2GROWINPLACE(Pop1) #define JU_LEAF3GROWINPLACE(Pop1) JL_LEAF3GROWINPLACE(Pop1) #ifdef JU_64BIT #define JU_LEAF4GROWINPLACE(Pop1) JL_LEAF4GROWINPLACE(Pop1) #define JU_LEAF5GROWINPLACE(Pop1) JL_LEAF5GROWINPLACE(Pop1) #define JU_LEAF6GROWINPLACE(Pop1) JL_LEAF6GROWINPLACE(Pop1) #define JU_LEAF7GROWINPLACE(Pop1) JL_LEAF7GROWINPLACE(Pop1) #endif #define JU_LEAFWGROWINPLACE(Pop1) JL_LEAFWGROWINPLACE(Pop1) #define j__udyCreateBranchL j__udyLCreateBranchL #define j__udyCreateBranchB j__udyLCreateBranchB #define j__udyCreateBranchU j__udyLCreateBranchU #define j__udyCascade1 j__udyLCascade1 #define j__udyCascade2 j__udyLCascade2 #define j__udyCascade3 j__udyLCascade3 #ifdef JU_64BIT #define j__udyCascade4 j__udyLCascade4 #define j__udyCascade5 j__udyLCascade5 #define j__udyCascade6 j__udyLCascade6 #define j__udyCascade7 j__udyLCascade7 #endif #define j__udyCascadeL j__udyLCascadeL #define j__udyInsertBranch j__udyLInsertBranch #define j__udyBranchBToBranchL j__udyLBranchBToBranchL #define j__udyLeafB1ToLeaf1 j__udyLLeafB1ToLeaf1 #define j__udyLeaf1ToLeaf2 j__udyLLeaf1ToLeaf2 #define j__udyLeaf2ToLeaf3 j__udyLLeaf2ToLeaf3 #ifndef JU_64BIT #define j__udyLeaf3ToLeafW j__udyLLeaf3ToLeafW #else #define j__udyLeaf3ToLeaf4 j__udyLLeaf3ToLeaf4 #define j__udyLeaf4ToLeaf5 j__udyLLeaf4ToLeaf5 #define j__udyLeaf5ToLeaf6 j__udyLLeaf5ToLeaf6 #define j__udyLeaf6ToLeaf7 j__udyLLeaf6ToLeaf7 #define j__udyLeaf7ToLeafW j__udyLLeaf7ToLeafW #endif #define jpm_t jLpm_t #define Pjpm_t PjLpm_t #define jlb_t jLlb_t #define Pjlb_t PjLlb_t #define JU_JLB_BITMAP JL_JLB_BITMAP #define j__udyAllocJPM j__udyLAllocJLPM #define j__udyAllocJBL j__udyLAllocJBL #define j__udyAllocJBB j__udyLAllocJBB #define j__udyAllocJBBJP j__udyLAllocJBBJP #define j__udyAllocJBU j__udyLAllocJBU #define j__udyAllocJLL1 j__udyLAllocJLL1 #define j__udyAllocJLL2 j__udyLAllocJLL2 #define j__udyAllocJLL3 j__udyLAllocJLL3 #ifdef JU_64BIT #define j__udyAllocJLL4 j__udyLAllocJLL4 #define j__udyAllocJLL5 j__udyLAllocJLL5 #define j__udyAllocJLL6 j__udyLAllocJLL6 #define j__udyAllocJLL7 j__udyLAllocJLL7 #endif #define j__udyAllocJLW j__udyLAllocJLW #define j__udyAllocJLB1 j__udyLAllocJLB1 // j__udyLAllocJV #define j__udyFreeJPM j__udyLFreeJLPM #define j__udyFreeJBL j__udyLFreeJBL #define j__udyFreeJBB j__udyLFreeJBB #define j__udyFreeJBBJP j__udyLFreeJBBJP #define j__udyFreeJBU j__udyLFreeJBU #define j__udyFreeJLL1 j__udyLFreeJLL1 #define j__udyFreeJLL2 j__udyLFreeJLL2 #define j__udyFreeJLL3 j__udyLFreeJLL3 #ifdef JU_64BIT #define j__udyFreeJLL4 j__udyLFreeJLL4 #define j__udyFreeJLL5 j__udyLFreeJLL5 #define j__udyFreeJLL6 j__udyLFreeJLL6 #define j__udyFreeJLL7 j__udyLFreeJLL7 #endif #define j__udyFreeJLW j__udyLFreeJLW #define j__udyFreeJLB1 j__udyLFreeJLB1 #define j__udyFreeSM j__udyLFreeSM // j__udyLFreeJV #define j__uMaxWords j__uLMaxWords #ifdef DEBUG #define JudyCheckPop JudyLCheckPop #endif #endif // JUDYL #endif // _JUDYPRIVATE1L_INCLUDED judy-1.0.5/src/JudyCommon/JudyGet.c0000644000175000017500000010563410204462077017321 0ustar troyhebetroyhebe// Copyright (C) 2000 - 2002 Hewlett-Packard Company // // This program is free software; you can redistribute it and/or modify it // under the term of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License // for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program; if not, write to the Free Software Foundation, // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // _________________ // @(#) $Revision: 4.43 $ $Source: /judy/src/JudyCommon/JudyGet.c $ // // Judy1Test() and JudyLGet() functions for Judy1 and JudyL. // Compile with one of -DJUDY1 or -DJUDYL. #if (! (defined(JUDY1) || defined(JUDYL))) #error: One of -DJUDY1 or -DJUDYL must be specified. #endif #ifdef JUDY1 #include "Judy1.h" #else #include "JudyL.h" #endif #include "JudyPrivate1L.h" #ifdef TRACEJPR // different macro name, for "retrieval" only. #include "JudyPrintJP.c" #endif // **************************************************************************** // J U D Y 1 T E S T // J U D Y L G E T // // See the manual entry for details. Note support for "shortcut" entries to // trees known to start with a JPM. #ifdef JUDY1 #ifdef JUDYGETINLINE FUNCTION int j__udy1Test #else FUNCTION int Judy1Test #endif #else // JUDYL #ifdef JUDYGETINLINE FUNCTION PPvoid_t j__udyLGet #else FUNCTION PPvoid_t JudyLGet #endif #endif // JUDYL ( #ifdef JUDYGETINLINE Pvoid_t PArray, // from which to retrieve. Word_t Index // to retrieve. #else Pcvoid_t PArray, // from which to retrieve. Word_t Index, // to retrieve. PJError_t PJError // optional, for returning error info. #endif ) { Pjp_t Pjp; // current JP while walking the tree. Pjpm_t Pjpm; // for global accounting. uint8_t Digit; // byte just decoded from Index. Word_t Pop1; // leaf population (number of indexes). Pjll_t Pjll; // pointer to LeafL. DBGCODE(uint8_t ParentJPType;) #ifndef JUDYGETINLINE if (PArray == (Pcvoid_t) NULL) // empty array. { JUDY1CODE(return(0);) JUDYLCODE(return((PPvoid_t) NULL);) } // **************************************************************************** // PROCESS TOP LEVEL BRANCHES AND LEAF: if (JU_LEAFW_POP0(PArray) < cJU_LEAFW_MAXPOP1) // must be a LEAFW { Pjlw_t Pjlw = P_JLW(PArray); // first word of leaf. int posidx; // signed offset in leaf. Pop1 = Pjlw[0] + 1; posidx = j__udySearchLeafW(Pjlw + 1, Pop1, Index); if (posidx >= 0) { JUDY1CODE(return(1);) JUDYLCODE(return((PPvoid_t) (JL_LEAFWVALUEAREA(Pjlw, Pop1) + posidx));) } JUDY1CODE(return(0);) JUDYLCODE(return((PPvoid_t) NULL);) } #endif // ! JUDYGETINLINE Pjpm = P_JPM(PArray); Pjp = &(Pjpm->jpm_JP); // top branch is below JPM. // **************************************************************************** // WALK THE JUDY TREE USING A STATE MACHINE: ContinueWalk: // for going down one level; come here with Pjp set. #ifdef TRACEJPR JudyPrintJP(Pjp, "g", __LINE__); #endif switch (JU_JPTYPE(Pjp)) { // Ensure the switch table starts at 0 for speed; otherwise more code is // executed: case 0: goto ReturnCorrupt; // save a little code. // **************************************************************************** // JPNULL*: // // Note: These are legitimate in a BranchU (only) and do not constitute a // fault. case cJU_JPNULL1: case cJU_JPNULL2: case cJU_JPNULL3: #ifdef JU_64BIT case cJU_JPNULL4: case cJU_JPNULL5: case cJU_JPNULL6: case cJU_JPNULL7: #endif assert(ParentJPType >= cJU_JPBRANCH_U2); assert(ParentJPType <= cJU_JPBRANCH_U); JUDY1CODE(return(0);) JUDYLCODE(return((PPvoid_t) NULL);) // **************************************************************************** // JPBRANCH_L*: // // Note: The use of JU_DCDNOTMATCHINDEX() in branches is not strictly // required,since this can be done at leaf level, but it costs nothing to do it // sooner, and it aborts an unnecessary traversal sooner. case cJU_JPBRANCH_L2: if (JU_DCDNOTMATCHINDEX(Index, Pjp, 2)) break; Digit = JU_DIGITATSTATE(Index, 2); goto JudyBranchL; case cJU_JPBRANCH_L3: #ifdef JU_64BIT // otherwise its a no-op: if (JU_DCDNOTMATCHINDEX(Index, Pjp, 3)) break; #endif Digit = JU_DIGITATSTATE(Index, 3); goto JudyBranchL; #ifdef JU_64BIT case cJU_JPBRANCH_L4: if (JU_DCDNOTMATCHINDEX(Index, Pjp, 4)) break; Digit = JU_DIGITATSTATE(Index, 4); goto JudyBranchL; case cJU_JPBRANCH_L5: if (JU_DCDNOTMATCHINDEX(Index, Pjp, 5)) break; Digit = JU_DIGITATSTATE(Index, 5); goto JudyBranchL; case cJU_JPBRANCH_L6: if (JU_DCDNOTMATCHINDEX(Index, Pjp, 6)) break; Digit = JU_DIGITATSTATE(Index, 6); goto JudyBranchL; case cJU_JPBRANCH_L7: // JU_DCDNOTMATCHINDEX() would be a no-op. Digit = JU_DIGITATSTATE(Index, 7); goto JudyBranchL; #endif // JU_64BIT case cJU_JPBRANCH_L: { Pjbl_t Pjbl; int posidx; Digit = JU_DIGITATSTATE(Index, cJU_ROOTSTATE); // Common code for all BranchLs; come here with Digit set: JudyBranchL: Pjbl = P_JBL(Pjp->jp_Addr); posidx = 0; do { if (Pjbl->jbl_Expanse[posidx] == Digit) { // found Digit; continue traversal: DBGCODE(ParentJPType = JU_JPTYPE(Pjp);) Pjp = Pjbl->jbl_jp + posidx; goto ContinueWalk; } } while (++posidx != Pjbl->jbl_NumJPs); break; } // **************************************************************************** // JPBRANCH_B*: case cJU_JPBRANCH_B2: if (JU_DCDNOTMATCHINDEX(Index, Pjp, 2)) break; Digit = JU_DIGITATSTATE(Index, 2); goto JudyBranchB; case cJU_JPBRANCH_B3: #ifdef JU_64BIT // otherwise its a no-op: if (JU_DCDNOTMATCHINDEX(Index, Pjp, 3)) break; #endif Digit = JU_DIGITATSTATE(Index, 3); goto JudyBranchB; #ifdef JU_64BIT case cJU_JPBRANCH_B4: if (JU_DCDNOTMATCHINDEX(Index, Pjp, 4)) break; Digit = JU_DIGITATSTATE(Index, 4); goto JudyBranchB; case cJU_JPBRANCH_B5: if (JU_DCDNOTMATCHINDEX(Index, Pjp, 5)) break; Digit = JU_DIGITATSTATE(Index, 5); goto JudyBranchB; case cJU_JPBRANCH_B6: if (JU_DCDNOTMATCHINDEX(Index, Pjp, 6)) break; Digit = JU_DIGITATSTATE(Index, 6); goto JudyBranchB; case cJU_JPBRANCH_B7: // JU_DCDNOTMATCHINDEX() would be a no-op. Digit = JU_DIGITATSTATE(Index, 7); goto JudyBranchB; #endif // JU_64BIT case cJU_JPBRANCH_B: { Pjbb_t Pjbb; Word_t subexp; // in bitmap, 0..7. BITMAPB_t BitMap; // for one subexpanse. BITMAPB_t BitMask; // bit in BitMap for Indexs Digit. Digit = JU_DIGITATSTATE(Index, cJU_ROOTSTATE); // Common code for all BranchBs; come here with Digit set: JudyBranchB: DBGCODE(ParentJPType = JU_JPTYPE(Pjp);) Pjbb = P_JBB(Pjp->jp_Addr); subexp = Digit / cJU_BITSPERSUBEXPB; BitMap = JU_JBB_BITMAP(Pjbb, subexp); Pjp = P_JP(JU_JBB_PJP(Pjbb, subexp)); BitMask = JU_BITPOSMASKB(Digit); // No JP in subexpanse for Index => Index not found: if (! (BitMap & BitMask)) break; // Count JPs in the subexpanse below the one for Index: Pjp += j__udyCountBitsB(BitMap & (BitMask - 1)); goto ContinueWalk; } // case cJU_JPBRANCH_B* // **************************************************************************** // JPBRANCH_U*: // // Notice the reverse order of the cases, and falling through to the next case, // for performance. case cJU_JPBRANCH_U: DBGCODE(ParentJPType = JU_JPTYPE(Pjp);) Pjp = JU_JBU_PJP(Pjp, Index, cJU_ROOTSTATE); // If not a BranchU, traverse; otherwise fall into the next case, which makes // this very fast code for a large Judy array (mainly BranchUs), especially // when branches are already in the cache, such as for prev/next: #ifndef JU_64BIT if (JU_JPTYPE(Pjp) != cJU_JPBRANCH_U3) goto ContinueWalk; #else if (JU_JPTYPE(Pjp) != cJU_JPBRANCH_U7) goto ContinueWalk; #endif #ifdef JU_64BIT case cJU_JPBRANCH_U7: // JU_DCDNOTMATCHINDEX() would be a no-op. DBGCODE(ParentJPType = JU_JPTYPE(Pjp);) Pjp = JU_JBU_PJP(Pjp, Index, 7); if (JU_JPTYPE(Pjp) != cJU_JPBRANCH_U6) goto ContinueWalk; // and fall through. case cJU_JPBRANCH_U6: if (JU_DCDNOTMATCHINDEX(Index, Pjp, 6)) break; DBGCODE(ParentJPType = JU_JPTYPE(Pjp);) Pjp = JU_JBU_PJP(Pjp, Index, 6); if (JU_JPTYPE(Pjp) != cJU_JPBRANCH_U5) goto ContinueWalk; // and fall through. case cJU_JPBRANCH_U5: if (JU_DCDNOTMATCHINDEX(Index, Pjp, 5)) break; DBGCODE(ParentJPType = JU_JPTYPE(Pjp);) Pjp = JU_JBU_PJP(Pjp, Index, 5); if (JU_JPTYPE(Pjp) != cJU_JPBRANCH_U4) goto ContinueWalk; // and fall through. case cJU_JPBRANCH_U4: if (JU_DCDNOTMATCHINDEX(Index, Pjp, 4)) break; DBGCODE(ParentJPType = JU_JPTYPE(Pjp);) Pjp = JU_JBU_PJP(Pjp, Index, 4); if (JU_JPTYPE(Pjp) != cJU_JPBRANCH_U3) goto ContinueWalk; // and fall through. #endif // JU_64BIT case cJU_JPBRANCH_U3: #ifdef JU_64BIT // otherwise its a no-op: if (JU_DCDNOTMATCHINDEX(Index, Pjp, 3)) break; #endif DBGCODE(ParentJPType = JU_JPTYPE(Pjp);) Pjp = JU_JBU_PJP(Pjp, Index, 3); if (JU_JPTYPE(Pjp) != cJU_JPBRANCH_U2) goto ContinueWalk; // and fall through. case cJU_JPBRANCH_U2: if (JU_DCDNOTMATCHINDEX(Index, Pjp, 2)) break; DBGCODE(ParentJPType = JU_JPTYPE(Pjp);) Pjp = JU_JBU_PJP(Pjp, Index, 2); // Note: BranchU2 is a special case that must continue traversal to a leaf, // immed, full, or null type: goto ContinueWalk; // **************************************************************************** // JPLEAF*: // // Note: Here the calls of JU_DCDNOTMATCHINDEX() are necessary and check // whether Index is out of the expanse of a narrow pointer. #if (defined(JUDYL) || (! defined(JU_64BIT))) case cJU_JPLEAF1: { int posidx; // signed offset in leaf. if (JU_DCDNOTMATCHINDEX(Index, Pjp, 1)) break; Pop1 = JU_JPLEAF_POP0(Pjp) + 1; Pjll = P_JLL(Pjp->jp_Addr); if ((posidx = j__udySearchLeaf1(Pjll, Pop1, Index)) < 0) break; JUDY1CODE(return(1);) JUDYLCODE(return((PPvoid_t) (JL_LEAF1VALUEAREA(Pjll, Pop1) + posidx));) } #endif // (JUDYL || (! JU_64BIT)) case cJU_JPLEAF2: { int posidx; // signed offset in leaf. if (JU_DCDNOTMATCHINDEX(Index, Pjp, 2)) break; Pop1 = JU_JPLEAF_POP0(Pjp) + 1; Pjll = P_JLL(Pjp->jp_Addr); if ((posidx = j__udySearchLeaf2(Pjll, Pop1, Index)) < 0) break; JUDY1CODE(return(1);) JUDYLCODE(return((PPvoid_t) (JL_LEAF2VALUEAREA(Pjll, Pop1) + posidx));) } case cJU_JPLEAF3: { int posidx; // signed offset in leaf. #ifdef JU_64BIT // otherwise its a no-op: if (JU_DCDNOTMATCHINDEX(Index, Pjp, 3)) break; #endif Pop1 = JU_JPLEAF_POP0(Pjp) + 1; Pjll = P_JLL(Pjp->jp_Addr); if ((posidx = j__udySearchLeaf3(Pjll, Pop1, Index)) < 0) break; JUDY1CODE(return(1);) JUDYLCODE(return((PPvoid_t) (JL_LEAF3VALUEAREA(Pjll, Pop1) + posidx));) } #ifdef JU_64BIT case cJU_JPLEAF4: { int posidx; // signed offset in leaf. if (JU_DCDNOTMATCHINDEX(Index, Pjp, 4)) break; Pop1 = JU_JPLEAF_POP0(Pjp) + 1; Pjll = P_JLL(Pjp->jp_Addr); if ((posidx = j__udySearchLeaf4(Pjll, Pop1, Index)) < 0) break; JUDY1CODE(return(1);) JUDYLCODE(return((PPvoid_t) (JL_LEAF4VALUEAREA(Pjll, Pop1) + posidx));) } case cJU_JPLEAF5: { int posidx; // signed offset in leaf. if (JU_DCDNOTMATCHINDEX(Index, Pjp, 5)) break; Pop1 = JU_JPLEAF_POP0(Pjp) + 1; Pjll = P_JLL(Pjp->jp_Addr); if ((posidx = j__udySearchLeaf5(Pjll, Pop1, Index)) < 0) break; JUDY1CODE(return(1);) JUDYLCODE(return((PPvoid_t) (JL_LEAF5VALUEAREA(Pjll, Pop1) + posidx));) } case cJU_JPLEAF6: { int posidx; // signed offset in leaf. if (JU_DCDNOTMATCHINDEX(Index, Pjp, 6)) break; Pop1 = JU_JPLEAF_POP0(Pjp) + 1; Pjll = P_JLL(Pjp->jp_Addr); if ((posidx = j__udySearchLeaf6(Pjll, Pop1, Index)) < 0) break; JUDY1CODE(return(1);) JUDYLCODE(return((PPvoid_t) (JL_LEAF6VALUEAREA(Pjll, Pop1) + posidx));) } case cJU_JPLEAF7: { int posidx; // signed offset in leaf. // JU_DCDNOTMATCHINDEX() would be a no-op. Pop1 = JU_JPLEAF_POP0(Pjp) + 1; Pjll = P_JLL(Pjp->jp_Addr); if ((posidx = j__udySearchLeaf7(Pjll, Pop1, Index)) < 0) break; JUDY1CODE(return(1);) JUDYLCODE(return((PPvoid_t) (JL_LEAF7VALUEAREA(Pjll, Pop1) + posidx));) } #endif // JU_64BIT // **************************************************************************** // JPLEAF_B1: case cJU_JPLEAF_B1: { Pjlb_t Pjlb; #ifdef JUDYL int posidx; Word_t subexp; // in bitmap, 0..7. BITMAPL_t BitMap; // for one subexpanse. BITMAPL_t BitMask; // bit in BitMap for Indexs Digit. Pjv_t Pjv; #endif if (JU_DCDNOTMATCHINDEX(Index, Pjp, 1)) break; Pjlb = P_JLB(Pjp->jp_Addr); #ifdef JUDY1 // Simply check if Indexs bit is set in the bitmap: if (JU_BITMAPTESTL(Pjlb, Index)) return(1); break; #else // JUDYL // JudyL is much more complicated because of value area subarrays: Digit = JU_DIGITATSTATE(Index, 1); subexp = Digit / cJU_BITSPERSUBEXPL; BitMap = JU_JLB_BITMAP(Pjlb, subexp); BitMask = JU_BITPOSMASKL(Digit); // No value in subexpanse for Index => Index not found: if (! (BitMap & BitMask)) break; // Count value areas in the subexpanse below the one for Index: Pjv = P_JV(JL_JLB_PVALUE(Pjlb, subexp)); assert(Pjv != (Pjv_t) NULL); posidx = j__udyCountBitsL(BitMap & (BitMask - 1)); return((PPvoid_t) (Pjv + posidx)); #endif // JUDYL } // case cJU_JPLEAF_B1 #ifdef JUDY1 // **************************************************************************** // JPFULLPOPU1: // // If the Index is in the expanse, it is necessarily valid (found). case cJ1_JPFULLPOPU1: if (JU_DCDNOTMATCHINDEX(Index, Pjp, 1)) break; return(1); #ifdef notdef // for future enhancements #ifdef JU_64BIT // Note: Need ? if (JU_DCDNOTMATCHINDEX(Index, Pjp, 1)) break; case cJ1_JPFULLPOPU1m15: if (Pjp->jp_1Index[14] == (uint8_t)Index) break; case cJ1_JPFULLPOPU1m14: if (Pjp->jp_1Index[13] == (uint8_t)Index) break; case cJ1_JPFULLPOPU1m13: if (Pjp->jp_1Index[12] == (uint8_t)Index) break; case cJ1_JPFULLPOPU1m12: if (Pjp->jp_1Index[11] == (uint8_t)Index) break; case cJ1_JPFULLPOPU1m11: if (Pjp->jp_1Index[10] == (uint8_t)Index) break; case cJ1_JPFULLPOPU1m10: if (Pjp->jp_1Index[9] == (uint8_t)Index) break; case cJ1_JPFULLPOPU1m9: if (Pjp->jp_1Index[8] == (uint8_t)Index) break; case cJ1_JPFULLPOPU1m8: if (Pjp->jp_1Index[7] == (uint8_t)Index) break; #endif case cJ1_JPFULLPOPU1m7: if (Pjp->jp_1Index[6] == (uint8_t)Index) break; case cJ1_JPFULLPOPU1m6: if (Pjp->jp_1Index[5] == (uint8_t)Index) break; case cJ1_JPFULLPOPU1m5: if (Pjp->jp_1Index[4] == (uint8_t)Index) break; case cJ1_JPFULLPOPU1m4: if (Pjp->jp_1Index[3] == (uint8_t)Index) break; case cJ1_JPFULLPOPU1m3: if (Pjp->jp_1Index[2] == (uint8_t)Index) break; case cJ1_JPFULLPOPU1m2: if (Pjp->jp_1Index[1] == (uint8_t)Index) break; case cJ1_JPFULLPOPU1m1: if (Pjp->jp_1Index[0] == (uint8_t)Index) break; return(1); // found, not in exclusion list #endif // JUDY1 #endif // notdef // **************************************************************************** // JPIMMED*: // // Note that the contents of jp_DcdPopO are different for cJU_JPIMMED_*_01: case cJU_JPIMMED_1_01: case cJU_JPIMMED_2_01: case cJU_JPIMMED_3_01: #ifdef JU_64BIT case cJU_JPIMMED_4_01: case cJU_JPIMMED_5_01: case cJU_JPIMMED_6_01: case cJU_JPIMMED_7_01: #endif if (JU_JPDCDPOP0(Pjp) != JU_TRIMTODCDSIZE(Index)) break; JUDY1CODE(return(1);) JUDYLCODE(return((PPvoid_t) &(Pjp->jp_Addr));) // immediate value area. // Macros to make code more readable and avoid dup errors #ifdef JUDY1 #define CHECKINDEXNATIVE(LEAF_T, PJP, IDX, INDEX) \ if (((LEAF_T *)((PJP)->jp_1Index))[(IDX) - 1] == (LEAF_T)(INDEX)) \ return(1) #define CHECKLEAFNONNAT(LFBTS, PJP, INDEX, IDX, COPY) \ { \ Word_t i_ndex; \ uint8_t *a_ddr; \ a_ddr = (PJP)->jp_1Index + (((IDX) - 1) * (LFBTS)); \ COPY(i_ndex, a_ddr); \ if (i_ndex == JU_LEASTBYTES((INDEX), (LFBTS))) \ return(1); \ } #endif #ifdef JUDYL #define CHECKINDEXNATIVE(LEAF_T, PJP, IDX, INDEX) \ if (((LEAF_T *)((PJP)->jp_LIndex))[(IDX) - 1] == (LEAF_T)(INDEX)) \ return((PPvoid_t)(P_JV((PJP)->jp_Addr) + (IDX) - 1)) #define CHECKLEAFNONNAT(LFBTS, PJP, INDEX, IDX, COPY) \ { \ Word_t i_ndex; \ uint8_t *a_ddr; \ a_ddr = (PJP)->jp_LIndex + (((IDX) - 1) * (LFBTS)); \ COPY(i_ndex, a_ddr); \ if (i_ndex == JU_LEASTBYTES((INDEX), (LFBTS))) \ return((PPvoid_t)(P_JV((PJP)->jp_Addr) + (IDX) - 1)); \ } #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_1_15: CHECKINDEXNATIVE(uint8_t, Pjp, 15, Index); case cJ1_JPIMMED_1_14: CHECKINDEXNATIVE(uint8_t, Pjp, 14, Index); case cJ1_JPIMMED_1_13: CHECKINDEXNATIVE(uint8_t, Pjp, 13, Index); case cJ1_JPIMMED_1_12: CHECKINDEXNATIVE(uint8_t, Pjp, 12, Index); case cJ1_JPIMMED_1_11: CHECKINDEXNATIVE(uint8_t, Pjp, 11, Index); case cJ1_JPIMMED_1_10: CHECKINDEXNATIVE(uint8_t, Pjp, 10, Index); case cJ1_JPIMMED_1_09: CHECKINDEXNATIVE(uint8_t, Pjp, 9, Index); case cJ1_JPIMMED_1_08: CHECKINDEXNATIVE(uint8_t, Pjp, 8, Index); #endif #if (defined(JUDY1) || defined(JU_64BIT)) case cJU_JPIMMED_1_07: CHECKINDEXNATIVE(uint8_t, Pjp, 7, Index); case cJU_JPIMMED_1_06: CHECKINDEXNATIVE(uint8_t, Pjp, 6, Index); case cJU_JPIMMED_1_05: CHECKINDEXNATIVE(uint8_t, Pjp, 5, Index); case cJU_JPIMMED_1_04: CHECKINDEXNATIVE(uint8_t, Pjp, 4, Index); #endif case cJU_JPIMMED_1_03: CHECKINDEXNATIVE(uint8_t, Pjp, 3, Index); case cJU_JPIMMED_1_02: CHECKINDEXNATIVE(uint8_t, Pjp, 2, Index); CHECKINDEXNATIVE(uint8_t, Pjp, 1, Index); break; #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_2_07: CHECKINDEXNATIVE(uint16_t, Pjp, 7, Index); case cJ1_JPIMMED_2_06: CHECKINDEXNATIVE(uint16_t, Pjp, 6, Index); case cJ1_JPIMMED_2_05: CHECKINDEXNATIVE(uint16_t, Pjp, 5, Index); case cJ1_JPIMMED_2_04: CHECKINDEXNATIVE(uint16_t, Pjp, 4, Index); #endif #if (defined(JUDY1) || defined(JU_64BIT)) case cJU_JPIMMED_2_03: CHECKINDEXNATIVE(uint16_t, Pjp, 3, Index); case cJU_JPIMMED_2_02: CHECKINDEXNATIVE(uint16_t, Pjp, 2, Index); CHECKINDEXNATIVE(uint16_t, Pjp, 1, Index); break; #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_3_05: CHECKLEAFNONNAT(3, Pjp, Index, 5, JU_COPY3_PINDEX_TO_LONG); case cJ1_JPIMMED_3_04: CHECKLEAFNONNAT(3, Pjp, Index, 4, JU_COPY3_PINDEX_TO_LONG); case cJ1_JPIMMED_3_03: CHECKLEAFNONNAT(3, Pjp, Index, 3, JU_COPY3_PINDEX_TO_LONG); #endif #if (defined(JUDY1) || defined(JU_64BIT)) case cJU_JPIMMED_3_02: CHECKLEAFNONNAT(3, Pjp, Index, 2, JU_COPY3_PINDEX_TO_LONG); CHECKLEAFNONNAT(3, Pjp, Index, 1, JU_COPY3_PINDEX_TO_LONG); break; #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_4_03: CHECKINDEXNATIVE(uint32_t, Pjp, 3, Index); case cJ1_JPIMMED_4_02: CHECKINDEXNATIVE(uint32_t, Pjp, 2, Index); CHECKINDEXNATIVE(uint32_t, Pjp, 1, Index); break; case cJ1_JPIMMED_5_03: CHECKLEAFNONNAT(5, Pjp, Index, 3, JU_COPY5_PINDEX_TO_LONG); case cJ1_JPIMMED_5_02: CHECKLEAFNONNAT(5, Pjp, Index, 2, JU_COPY5_PINDEX_TO_LONG); CHECKLEAFNONNAT(5, Pjp, Index, 1, JU_COPY5_PINDEX_TO_LONG); break; case cJ1_JPIMMED_6_02: CHECKLEAFNONNAT(6, Pjp, Index, 2, JU_COPY6_PINDEX_TO_LONG); CHECKLEAFNONNAT(6, Pjp, Index, 1, JU_COPY6_PINDEX_TO_LONG); break; case cJ1_JPIMMED_7_02: CHECKLEAFNONNAT(7, Pjp, Index, 2, JU_COPY7_PINDEX_TO_LONG); CHECKLEAFNONNAT(7, Pjp, Index, 1, JU_COPY7_PINDEX_TO_LONG); break; #endif // (JUDY1 && JU_64BIT) // **************************************************************************** // INVALID JP TYPE: default: ReturnCorrupt: #ifdef JUDYGETINLINE // Pjpm is known to be non-null: JU_SET_ERRNO_NONNULL(Pjpm, JU_ERRNO_CORRUPT); #else JU_SET_ERRNO(PJError, JU_ERRNO_CORRUPT); #endif JUDY1CODE(return(JERRI );) JUDYLCODE(return(PPJERR);) } // switch on JP type JUDY1CODE(return(0);) JUDYLCODE(return((PPvoid_t) NULL);) } // Judy1Test() / JudyLGet() #ifndef JUDYGETINLINE // only compile the following function once: #ifdef DEBUG // **************************************************************************** // J U D Y C H E C K P O P // // Given a pointer to a Judy array, traverse the entire array to ensure // population counts add up correctly. This can catch various coding errors. // // Since walking the entire tree is probably time-consuming, enable this // function by setting env parameter $CHECKPOP to first call at which to start // checking. Note: This function is called both from insert and delete code. // // Note: Even though this function does nothing useful for LEAFW leaves, its // good practice to call it anyway, and cheap too. // // TBD: This is a debug-only check function similar to JudyCheckSorted(), but // since it walks the tree it is Judy1/JudyL-specific and must live in a source // file that is built both ways. // // TBD: As feared, enabling this code for every insert/delete makes Judy // deathly slow, even for a small tree (10K indexes). Its not so bad if // present but disabled (<1% slowdown measured). Still, should it be ifdefd // other than DEBUG and/or called less often? // // TBD: Should this "population checker" be expanded to a comprehensive tree // checker? It currently detects invalid LEAFW/JP types as well as inconsistent // pop1s. Other possible checks, all based on essentially redundant data in // the Judy tree, include: // // - Zero LS bits in jp_Addr field. // // - Correct Dcd bits. // // - Consistent JP types (always descending down the tree). // // - Sorted linear lists in BranchLs and leaves (using JudyCheckSorted(), but // ideally that function is already called wherever appropriate after any // linear list is modified). // // - Any others possible? #include // for getenv() and atol(). static Word_t JudyCheckPopSM(Pjp_t Pjp, Word_t RootPop1); FUNCTION void JudyCheckPop( Pvoid_t PArray) { static bool_t checked = FALSE; // already checked env parameter. static bool_t enabled = FALSE; // env parameter set. static bool_t active = FALSE; // calls >= callsmin. static Word_t callsmin; // start point from $CHECKPOP. static Word_t calls = 0; // times called so far. // CHECK FOR EXTERNAL ENABLING: if (! checked) // only check once. { char * value; // for getenv(). checked = TRUE; if ((value = getenv("CHECKPOP")) == (char *) NULL) { #ifdef notdef // Take this out because nightly tests want to be flavor-independent; its not // OK to emit special non-error output from the debug flavor: (void) puts("JudyCheckPop() present but not enabled by " "$CHECKPOP env parameter; set it to the number of " "calls at which to begin checking"); #endif return; } callsmin = atol(value); // note: non-number evaluates to 0. enabled = TRUE; (void) printf("JudyCheckPop() present and enabled; callsmin = " "%lu\n", callsmin); } else if (! enabled) return; // Previously or just now enabled; check if non-active or newly active: if (! active) { if (++calls < callsmin) return; (void) printf("JudyCheckPop() activated at call %lu\n", calls); active = TRUE; } // IGNORE LEAFW AT TOP OF TREE: if (JU_LEAFW_POP0(PArray) < cJU_LEAFW_MAXPOP1) // must be a LEAFW return; // Check JPM pop0 against tree, recursively: // // Note: The traversal code in JudyCheckPopSM() is simplest when the case // statement for each JP type compares the pop1 for that JP to its subtree (if // any) after traversing the subtree (thats the hard part) and adding up // actual pop1s. A top branchs JP in the JPM does not have room for a // full-word pop1, so pass it in as a special case. { Pjpm_t Pjpm = P_JPM(PArray); (void) JudyCheckPopSM(&(Pjpm->jpm_JP), Pjpm->jpm_Pop0 + 1); return; } } // JudyCheckPop() // **************************************************************************** // J U D Y C H E C K P O P S M // // Recursive state machine (subroutine) for JudyCheckPop(): Given a Pjp (other // than JPNULL*; caller should shortcut) and the root population for top-level // branches, check the subtrees actual pop1 against its nominal value, and // return the total pop1 for the subtree. // // Note: Expect RootPop1 to be ignored at lower levels, so pass down 0, which // should pop an assertion if this expectation is violated. FUNCTION static Word_t JudyCheckPopSM( Pjp_t Pjp, // top of subtree. Word_t RootPop1) // whole array, for top-level branches only. { Word_t pop1_jp; // nominal population from the JP. Word_t pop1 = 0; // actual population at this level. Word_t offset; // in a branch. #define PREPBRANCH(cPopBytes,Next) \ pop1_jp = JU_JPBRANCH_POP0(Pjp, cPopBytes) + 1; goto Next assert((((Word_t) (Pjp->jp_Addr)) & 7) == 3); switch (JU_JPTYPE(Pjp)) { case cJU_JPBRANCH_L2: PREPBRANCH(2, BranchL); case cJU_JPBRANCH_L3: PREPBRANCH(3, BranchL); #ifdef JU_64BIT case cJU_JPBRANCH_L4: PREPBRANCH(4, BranchL); case cJU_JPBRANCH_L5: PREPBRANCH(5, BranchL); case cJU_JPBRANCH_L6: PREPBRANCH(6, BranchL); case cJU_JPBRANCH_L7: PREPBRANCH(7, BranchL); #endif case cJU_JPBRANCH_L: pop1_jp = RootPop1; { Pjbl_t Pjbl; BranchL: Pjbl = P_JBL(Pjp->jp_Addr); for (offset = 0; offset < (Pjbl->jbl_NumJPs); ++offset) pop1 += JudyCheckPopSM((Pjbl->jbl_jp) + offset, 0); assert(pop1_jp == pop1); return(pop1); } case cJU_JPBRANCH_B2: PREPBRANCH(2, BranchB); case cJU_JPBRANCH_B3: PREPBRANCH(3, BranchB); #ifdef JU_64BIT case cJU_JPBRANCH_B4: PREPBRANCH(4, BranchB); case cJU_JPBRANCH_B5: PREPBRANCH(5, BranchB); case cJU_JPBRANCH_B6: PREPBRANCH(6, BranchB); case cJU_JPBRANCH_B7: PREPBRANCH(7, BranchB); #endif case cJU_JPBRANCH_B: pop1_jp = RootPop1; { Word_t subexp; Word_t jpcount; Pjbb_t Pjbb; BranchB: Pjbb = P_JBB(Pjp->jp_Addr); for (subexp = 0; subexp < cJU_NUMSUBEXPB; ++subexp) { jpcount = j__udyCountBitsB(JU_JBB_BITMAP(Pjbb, subexp)); for (offset = 0; offset < jpcount; ++offset) { pop1 += JudyCheckPopSM(P_JP(JU_JBB_PJP(Pjbb, subexp)) + offset, 0); } } assert(pop1_jp == pop1); return(pop1); } case cJU_JPBRANCH_U2: PREPBRANCH(2, BranchU); case cJU_JPBRANCH_U3: PREPBRANCH(3, BranchU); #ifdef JU_64BIT case cJU_JPBRANCH_U4: PREPBRANCH(4, BranchU); case cJU_JPBRANCH_U5: PREPBRANCH(5, BranchU); case cJU_JPBRANCH_U6: PREPBRANCH(6, BranchU); case cJU_JPBRANCH_U7: PREPBRANCH(7, BranchU); #endif case cJU_JPBRANCH_U: pop1_jp = RootPop1; { Pjbu_t Pjbu; BranchU: Pjbu = P_JBU(Pjp->jp_Addr); for (offset = 0; offset < cJU_BRANCHUNUMJPS; ++offset) { if (((Pjbu->jbu_jp[offset].jp_Type) >= cJU_JPNULL1) && ((Pjbu->jbu_jp[offset].jp_Type) <= cJU_JPNULLMAX)) { continue; // skip null JP to save time. } pop1 += JudyCheckPopSM((Pjbu->jbu_jp) + offset, 0); } assert(pop1_jp == pop1); return(pop1); } // -- Cases below here terminate and do not recurse. -- // // For all of these cases except JPLEAF_B1, there is no way to check the JPs // pop1 against the object itself; just return the pop1; but for linear leaves, // a bounds check is possible. #define CHECKLEAF(MaxPop1) \ pop1 = JU_JPLEAF_POP0(Pjp) + 1; \ assert(pop1 >= 1); \ assert(pop1 <= (MaxPop1)); \ return(pop1) #if (defined(JUDYL) || (! defined(JU_64BIT))) case cJU_JPLEAF1: CHECKLEAF(cJU_LEAF1_MAXPOP1); #endif case cJU_JPLEAF2: CHECKLEAF(cJU_LEAF2_MAXPOP1); case cJU_JPLEAF3: CHECKLEAF(cJU_LEAF3_MAXPOP1); #ifdef JU_64BIT case cJU_JPLEAF4: CHECKLEAF(cJU_LEAF4_MAXPOP1); case cJU_JPLEAF5: CHECKLEAF(cJU_LEAF5_MAXPOP1); case cJU_JPLEAF6: CHECKLEAF(cJU_LEAF6_MAXPOP1); case cJU_JPLEAF7: CHECKLEAF(cJU_LEAF7_MAXPOP1); #endif case cJU_JPLEAF_B1: { Word_t subexp; Pjlb_t Pjlb; pop1_jp = JU_JPLEAF_POP0(Pjp) + 1; Pjlb = P_JLB(Pjp->jp_Addr); for (subexp = 0; subexp < cJU_NUMSUBEXPL; ++subexp) pop1 += j__udyCountBitsL(JU_JLB_BITMAP(Pjlb, subexp)); assert(pop1_jp == pop1); return(pop1); } JUDY1CODE(case cJ1_JPFULLPOPU1: return(cJU_JPFULLPOPU1_POP0);) case cJU_JPIMMED_1_01: return(1); case cJU_JPIMMED_2_01: return(1); case cJU_JPIMMED_3_01: return(1); #ifdef JU_64BIT case cJU_JPIMMED_4_01: return(1); case cJU_JPIMMED_5_01: return(1); case cJU_JPIMMED_6_01: return(1); case cJU_JPIMMED_7_01: return(1); #endif case cJU_JPIMMED_1_02: return(2); case cJU_JPIMMED_1_03: return(3); #if (defined(JUDY1) || defined(JU_64BIT)) case cJU_JPIMMED_1_04: return(4); case cJU_JPIMMED_1_05: return(5); case cJU_JPIMMED_1_06: return(6); case cJU_JPIMMED_1_07: return(7); #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_1_08: return(8); case cJ1_JPIMMED_1_09: return(9); case cJ1_JPIMMED_1_10: return(10); case cJ1_JPIMMED_1_11: return(11); case cJ1_JPIMMED_1_12: return(12); case cJ1_JPIMMED_1_13: return(13); case cJ1_JPIMMED_1_14: return(14); case cJ1_JPIMMED_1_15: return(15); #endif #if (defined(JUDY1) || defined(JU_64BIT)) case cJU_JPIMMED_2_02: return(2); case cJU_JPIMMED_2_03: return(3); #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_2_04: return(4); case cJ1_JPIMMED_2_05: return(5); case cJ1_JPIMMED_2_06: return(6); case cJ1_JPIMMED_2_07: return(7); #endif #if (defined(JUDY1) || defined(JU_64BIT)) case cJU_JPIMMED_3_02: return(2); #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_3_03: return(3); case cJ1_JPIMMED_3_04: return(4); case cJ1_JPIMMED_3_05: return(5); case cJ1_JPIMMED_4_02: return(2); case cJ1_JPIMMED_4_03: return(3); case cJ1_JPIMMED_5_02: return(2); case cJ1_JPIMMED_5_03: return(3); case cJ1_JPIMMED_6_02: return(2); case cJ1_JPIMMED_7_02: return(2); #endif } // switch (JU_JPTYPE(Pjp)) assert(FALSE); // unrecognized JP type => corruption. return(0); // to make some compilers happy. } // JudyCheckPopSM() #endif // DEBUG #endif // ! JUDYGETINLINE judy-1.0.5/src/JudyCommon/JudyPrivate.h0000644000175000017500000021030510204462077020211 0ustar troyhebetroyhebe#ifndef _JUDYPRIVATE_INCLUDED #define _JUDYPRIVATE_INCLUDED // _________________ // // Copyright (C) 2000 - 2002 Hewlett-Packard Company // // This program is free software; you can redistribute it and/or modify it // under the term of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License // for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program; if not, write to the Free Software Foundation, // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // _________________ // @(#) $Revision: 4.77 $ $Source: /judy/src/JudyCommon/JudyPrivate.h $ // // Header file for all Judy sources, for global but private (non-exported) // declarations. #include "Judy.h" // **************************************************************************** // A VERY BRIEF EXPLANATION OF A JUDY ARRAY // // A Judy array is, effectively, a digital tree (or Trie) with 256 element // branches (nodes), and with "compression tricks" applied to low-population // branches or leaves to save a lot of memory at the cost of relatively little // CPU time or cache fills. // // In the actual implementation, a Judy array is level-less, and traversing the // "tree" actually means following the states in a state machine (SM) as // directed by the Index. A Judy array is referred to here as an "SM", rather // than as a "tree"; having "states", rather than "levels". // // Each branch or leaf in the SM decodes a portion ("digit") of the original // Index; with 256-way branches there are 8 bits per digit. There are 3 kinds // of branches, called: Linear, Bitmap and Uncompressed, of which the first 2 // are compressed to contain no NULL entries. // // An Uncompressed branch has a 1.0 cache line fill cost to decode 8 bits of // (digit, part of an Index), but it might contain many NULL entries, and is // therefore inefficient with memory if lightly populated. // // A Linear branch has a ~1.75 cache line fill cost when at maximum population. // A Bitmap branch has ~2.0 cache line fills. Linear and Bitmap branches are // converted to Uncompressed branches when the additional memory can be // amortized with larger populations. Higher-state branches have higher // priority to be converted. // // Linear branches can hold 28 elements (based on detailed analysis) -- thus 28 // expanses. A Linear branch is converted to a Bitmap branch when the 29th // expanse is required. // // A Bitmap branch could hold 256 expanses, but is forced to convert to an // Uncompressed branch when 185 expanses are required. Hopefully, it is // converted before that because of population growth (again, based on detailed // analysis and heuristics in the code). // // A path through the SM terminates to a leaf when the Index (or key) // population in the expanse below a pointer will fit into 1 or 2 cache lines // (~31..255 Indexes). A maximum-population Leaf has ~1.5 cache line fill // cost. // // Leaves are sorted arrays of Indexes, where the Index Sizes (IS) are: 0, 1, // 8, 16, 24, 32, [40, 48, 56, 64] bits. The IS depends on the "density" // (population/expanse) of the values in the Leaf. Zero bits are possible if // population == expanse in the SM (that is, a full small expanse). // // Elements of a branches are called Judy Pointers (JPs). Each JP object // points to the next object in the SM, plus, a JP can decode an additional // 2[6] bytes of an Index, but at the cost of "narrowing" the expanse // represented by the next object in the SM. A "narrow" JP (one which has // decode bytes/digits) is a way of skipping states in the SM. // // Although counterintuitive, we think a Judy SM is optimal when the Leaves are // stored at MINIMUM compression (narrowing, or use of Decode bytes). If more // aggressive compression was used, decompression of a leaf be required to // insert an index. Additional compression would save a little memory but not // help performance significantly. #ifdef A_PICTURE_IS_WORTH_1000_WORDS ******************************************************************************* JUDY 32-BIT STATE MACHINE (SM) EXAMPLE, FOR INDEX = 0x02040103 The Index used in this example is purposely chosen to allow small, simple examples below; each 1-byte "digit" from the Index has a small numeric value that fits in one column. In the drawing below: JRP == Judy Root Pointer; C == 1 byte of a 1..3 byte Population (count of Indexes) below this pointer. Since this is shared with the Decode field, the combined sizes must be 3[7], that is, 1 word less 1 byte for the JP Type. The 1-byte field jp_Type is represented as: 1..3 == Number of bytes in the population (Pop0) word of the Branch or Leaf below the pointer (note: 1..7 on 64-bit); indicates: - number of bytes in Decode field == 3 - this number; - number of bytes remaining to decode. Note: The maximum is 3, not 4, because the 1st byte of the Index is always decoded digitally in the top branch. -B- == JP points to a Branch (there are many kinds of Branches). -L- == JP points to a Leaf (there are many kinds of Leaves). (2) == Digit of Index decoded by position offset in branch (really 0..0xff). 4* == Digit of Index necessary for decoding a "narrow" pointer, in a Decode field; replaces 1 missing branch (really 0..0xff). 4+ == Digit of Index NOT necessary for decoding a "narrow" pointer, but used for fast traversal of the SM by Judy1Test() and JudyLGet() (see the code) (really 0..0xff). 0 == Byte in a JPs Pop0 field that is always ignored, because a leaf can never contain more than 256 Indexes (Pop0 <= 255). +----- == A Branch or Leaf; drawn open-ended to remind you that it could | have up to 256 columns. +----- | | == Pointer to next Branch or Leaf. V | O == A state is skipped by using a "narrow" pointer. | < 1 > == Digit (Index) shown as an example is not necessarily in the position shown; is sorted in order with neighbor Indexes. (Really 0..0xff.) Note that this example shows every possibly topology to reach a leaf in a 32-bit Judy SM, although this is a very subtle point! STATE or` LEVEL +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ |RJP| |RJP| |RJP| |RJP| |RJP| |RJP| |RJP| |RJP| L---+ B---+ B---+ B---+ B---+ B---+ B---+ B---+ | | | | | | | | | | | | | | | | V V (2) V (2) V (2) V (2) V (2) V (2) V (2) +------ +------ +------ +------ +------ +------ +------ +------ Four |< 2 > | 0 | 4* | C | 4* | 4* | C | C byte |< 4 > | 0 | 0 | C | 1* | C | C | C 4 Index|< 1 > | C | C | C | C | C | C | C Leaf |< 3 > | 3 | 2 | 3 | 1 | 2 | 3 | 3 +------ +--L--- +--L--- +--B--- +--L--- +--B--- +--B--- +--B--- | | | | | | | / | / | | / / / | / | | / / | | | | | | | V | V (4) | | V (4) V (4) +------ | +------ | | +------ +------ Three |< 4 > | | 4+ | | | 4+ | 4+ byte Index|< 1 > O | 0 O O | 1* | C 3 Leaf |< 3 > | | C | | | C | C +------ | | 2 | | | 1 | 2 / +----L- | | +----L- +----B- / | | | | | | / | / / / | / | / / / | / | | / / | / | | / / | | | | | | V V | V(1) | V(1) +------ +------ | +------ | +------ Two byte |< 1 > |< 1 > | | 4+ | | 4+ Index Leaf |< 3 > |< 3 > O | 1+ O | 1+ 2 +------ +------ / | C | | C / | 1 | | 1 | +-L---- | +-L---- | | | | | / | / | | | | V V V V +------ +------ +------ +------ One byte Index Leaf |< 3 > |< 3 > |< 3 > |< 3 > 1 +------ +------ +------ +------ #endif // A_PICTURE_IS_WORTH_1000_WORDS // **************************************************************************** // MISCELLANEOUS GLOBALS: // // PLATFORM-SPECIFIC CONVENIENCE MACROS: // // These are derived from context (set by cc or in system header files) or // based on JU_ macros from make_includes/platform.*.mk. We decided // on 011018 that any macro reliably derivable from context (cc or headers) for // ALL platforms supported by Judy is based on that derivation, but ANY // exception means to stop using the external macro completely and derive from // JU_ instead. // Other miscellaneous stuff: #ifndef _BOOL_T #define _BOOL_T typedef int bool_t; #endif #define FUNCTION // null; easy to find functions. #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif #ifdef TRACE // turn on all other tracing in the code: #define TRACEJP 1 // JP traversals in JudyIns.c and JudyDel.c. #define TRACEJPR 1 // JP traversals in retrieval code, JudyGet.c. #define TRACECF 1 // cache fills in JudyGet.c. #define TRACEMI 1 // malloc calls in JudyMallocIF.c. #define TRACEMF 1 // malloc calls at a lower level in JudyMalloc.c. #endif // SUPPORT FOR DEBUG-ONLY CODE: // // By convention, use -DDEBUG to enable both debug-only code AND assertions in // the Judy sources. // // Invert the sense of assertions, so they are off unless explicitly requested, // in a uniform way. // // Note: It is NOT appropriate to put this in Judy.h; it would mess up // application code. #ifndef DEBUG #define NDEBUG 1 // must be 1 for "#if". #endif // Shorthand notations to avoid #ifdefs for single-line conditional statements: // // Warning: These cannot be used around compiler directives, such as // "#include", nor in the case where Code contains a comma other than nested // within parentheses or quotes. #ifndef DEBUG #define DBGCODE(Code) // null. #else #define DBGCODE(Code) Code #endif #ifdef JUDY1 #define JUDY1CODE(Code) Code #define JUDYLCODE(Code) // null. #endif #ifdef JUDYL #define JUDYLCODE(Code) Code #define JUDY1CODE(Code) // null. #endif #include // **************************************************************************** // FUNDAMENTAL CONSTANTS FOR MACHINE // **************************************************************************** // Machine (CPU) cache line size: // // NOTE: A leaf size of 2 cache lines maximum is the target (optimal) for // Judy. Its hard to obtain a machines cache line size at compile time, but // if the machine has an unexpected cache line size, its not devastating if // the following constants end up causing leaves that are 1 cache line in size, // or even 4 cache lines in size. The assumed 32-bit system has 16-word = // 64-byte cache lines, and the assumed 64-bit system has 16-word = 128-byte // cache lines. #ifdef JU_64BIT #define cJU_BYTESPERCL 128 // cache line size in bytes. #else #define cJU_BYTESPERCL 64 // cache line size in bytes. #endif // Bits Per Byte: #define cJU_BITSPERBYTE 0x8 // Bytes Per Word and Bits Per Word, latter assuming sizeof(byte) is 8 bits: // // Expect 32 [64] bits per word. #define cJU_BYTESPERWORD (sizeof(Word_t)) #define cJU_BITSPERWORD (sizeof(Word_t) * cJU_BITSPERBYTE) #define JU_BYTESTOWORDS(BYTES) \ (((BYTES) + cJU_BYTESPERWORD - 1) / cJU_BYTESPERWORD) // A word that is all-ones, normally equal to -1UL, but safer with ~0: #define cJU_ALLONES (~0UL) // Note, these are forward references, but thats OK: #define cJU_FULLBITMAPB ((BITMAPB_t) cJU_ALLONES) #define cJU_FULLBITMAPL ((BITMAPL_t) cJU_ALLONES) // **************************************************************************** // MISCELLANEOUS JUDY-SPECIFIC DECLARATIONS // **************************************************************************** // ROOT STATE: // // State at the start of the Judy SM, based on 1 byte decoded per state; equal // to the number of bytes per Index to decode. #define cJU_ROOTSTATE (sizeof(Word_t)) // SUBEXPANSES PER STATE: // // Number of subexpanses per state traversed, which is the number of JPs in a // branch (actual or theoretical) and the number of bits in a bitmap. #define cJU_SUBEXPPERSTATE 256 // LEAF AND VALUE POINTERS: // // Some other basic object types are in declared in JudyPrivateBranch.h // (Pjbl_t, Pjbb_t, Pjbu_t, Pjp_t) or are Judy1/L-specific (Pjlb_t). The // few remaining types are declared below. // // Note: Leaf pointers are cast to different-sized objects depending on the // leafs level, but are at least addresses (not just numbers), so use void * // (Pvoid_t), not PWord_t or Word_t for them, except use Pjlw_t for whole-word // (top-level, root-level) leaves. Value areas, however, are always whole // words. // // Furthermore, use Pjll_t only for generic leaf pointers (for various size // LeafLs). Use Pjlw_t for LeafWs. Use Pleaf (with type uint8_t *, uint16_t // *, etc) when the leaf index size is known. typedef PWord_t Pjlw_t; // pointer to root-level leaf (whole-word indexes). typedef Pvoid_t Pjll_t; // pointer to lower-level linear leaf. #ifdef JUDYL typedef PWord_t Pjv_t; // pointer to JudyL value area. #endif // POINTER PREPARATION MACROS: // // These macros are used to strip malloc-namespace-type bits from a pointer + // malloc-type word (which references any Judy mallocd object that might be // obtained from other than a direct call of malloc()), prior to dereferencing // the pointer as an address. The malloc-type bits allow Judy mallocd objects // to come from different "malloc() namespaces". // // (root pointer) (JRP, see above) // jp.jp_Addr generic pointer to next-level node, except when used // as a JudyL Immed01 value area // JU_JBB_PJP macro hides jbbs_Pjp (pointer to JP subarray) // JL_JLB_PVALUE macro hides jLlbs_PValue (pointer to value subarray) // // When setting one of these fields or passing an address to j__udyFree*(), the // "raw" memory address is used; otherwise the memory address must be passed // through one of the macros below before its dereferenced. // // Note: After much study, the typecasts below appear in the macros rather // than at the point of use, which is both simpler and allows the compiler to // do type-checking. #define P_JLW( ADDR) ((Pjlw_t) (ADDR)) // root leaf. #define P_JPM( ADDR) ((Pjpm_t) (ADDR)) // root JPM. #define P_JBL( ADDR) ((Pjbl_t) (ADDR)) // BranchL. #define P_JBB( ADDR) ((Pjbb_t) (ADDR)) // BranchB. #define P_JBU( ADDR) ((Pjbu_t) (ADDR)) // BranchU. #define P_JLL( ADDR) ((Pjll_t) (ADDR)) // LeafL. #define P_JLB( ADDR) ((Pjlb_t) (ADDR)) // LeafB1. #define P_JP( ADDR) ((Pjp_t) (ADDR)) // JP. #ifdef JUDYL #define P_JV( ADDR) ((Pjv_t) (ADDR)) // &value. #endif // LEAST BYTES: // // Mask for least bytes of a word, and a macro to perform this mask on an // Index. // // Note: This macro has been problematic in the past to get right and to make // portable. Its not OK on all systems to shift by the full word size. This // macro should allow shifting by 1..N bytes, where N is the word size, but // should produce a compiler warning if the macro is called with Bytes == 0. // // Warning: JU_LEASTBYTESMASK() is not a constant macro unless Bytes is a // constant; otherwise it is a variable shift, which is expensive on some // processors. #define JU_LEASTBYTESMASK(BYTES) \ ((0x100UL << (cJU_BITSPERBYTE * ((BYTES) - 1))) - 1) #define JU_LEASTBYTES(INDEX,BYTES) ((INDEX) & JU_LEASTBYTESMASK(BYTES)) // BITS IN EACH BITMAP SUBEXPANSE FOR BITMAP BRANCH AND LEAF: // // The bits per bitmap subexpanse times the number of subexpanses equals a // constant (cJU_SUBEXPPERSTATE). You can also think of this as a compile-time // choice of "aspect ratio" for bitmap branches and leaves (which can be set // independently for each). // // A default aspect ratio is hardwired here if not overridden at compile time, // such as by "EXTCCOPTS=-DBITMAP_BRANCH16x16 make". #if (! (defined(BITMAP_BRANCH8x32) || defined(BITMAP_BRANCH16x16) || defined(BITMAP_BRANCH32x8))) #define BITMAP_BRANCH32x8 1 // 32 bits per subexpanse, 8 subexpanses. #endif #ifdef BITMAP_BRANCH8x32 #define BITMAPB_t uint8_t #endif #ifdef BITMAP_BRANCH16x16 #define BITMAPB_t uint16_t #endif #ifdef BITMAP_BRANCH32x8 #define BITMAPB_t uint32_t #endif // Note: For bitmap leaves, BITMAP_LEAF64x4 is only valid for 64 bit: // // Note: Choice of aspect ratio mostly matters for JudyL bitmap leaves. For // Judy1 the choice doesnt matter much -- the code generated for different // BITMAP_LEAF* values choices varies, but correctness and performance are the // same. #ifndef JU_64BIT #if (! (defined(BITMAP_LEAF8x32) || defined(BITMAP_LEAF16x16) || defined(BITMAP_LEAF32x8))) #define BITMAP_LEAF32x8 // 32 bits per subexpanse, 8 subexpanses. #endif #else // 32BIT #if (! (defined(BITMAP_LEAF8x32) || defined(BITMAP_LEAF16x16) || defined(BITMAP_LEAF32x8) || defined(BITMAP_LEAF64x4))) #define BITMAP_LEAF64x4 // 64 bits per subexpanse, 4 subexpanses. #endif #endif // JU_64BIT #ifdef BITMAP_LEAF8x32 #define BITMAPL_t uint8_t #endif #ifdef BITMAP_LEAF16x16 #define BITMAPL_t uint16_t #endif #ifdef BITMAP_LEAF32x8 #define BITMAPL_t uint32_t #endif #ifdef BITMAP_LEAF64x4 #define BITMAPL_t uint64_t #endif // EXPORTED DATA AND FUNCTIONS: #ifdef JUDY1 extern const uint8_t j__1_BranchBJPPopToWords[]; #endif #ifdef JUDYL extern const uint8_t j__L_BranchBJPPopToWords[]; #endif // Fast LeafL search routine used for inlined code: #if (! defined(SEARCH_BINARY)) || (! defined(SEARCH_LINEAR)) // default a binary search leaf method #define SEARCH_BINARY 1 //#define SEARCH_LINEAR 1 #endif #ifdef SEARCH_LINEAR #define SEARCHLEAFNATIVE(LEAFTYPE,ADDR,POP1,INDEX) \ LEAFTYPE *P_leaf = (LEAFTYPE *)(ADDR); \ LEAFTYPE I_ndex = (INDEX); /* with masking */ \ if (I_ndex > P_leaf[(POP1) - 1]) return(~(POP1)); \ while(I_ndex > *P_leaf) P_leaf++; \ if (I_ndex == *P_leaf) return(P_leaf - (LEAFTYPE *)(ADDR)); \ return(~(P_leaf - (LEAFTYPE *)(ADDR))); #define SEARCHLEAFNONNAT(ADDR,POP1,INDEX,LFBTS,COPYINDEX) \ { \ uint8_t *P_leaf, *P_leafEnd; \ Word_t i_ndex; \ Word_t I_ndex = JU_LEASTBYTES((INDEX), (LFBTS)); \ Word_t p_op1; \ \ P_leaf = (uint8_t *)(ADDR); \ P_leafEnd = P_leaf + ((POP1) * (LFBTS)); \ \ do { \ JU_COPY3_PINDEX_TO_LONG(i_ndex, P_leaf); \ if (I_ndex <= i_ndex) break; \ P_leaf += (LFBTS); \ } while (P_leaf < P_leafEnd); \ \ p_op1 = (P_leaf - (uint8_t *) (ADDR)) / (LFBTS); \ if (I_ndex == i_ndex) return(p_op1); \ return(~p_op1); \ } #endif // SEARCH_LINEAR #ifdef SEARCH_BINARY #define SEARCHLEAFNATIVE(LEAFTYPE,ADDR,POP1,INDEX) \ LEAFTYPE *P_leaf = (LEAFTYPE *)(ADDR); \ LEAFTYPE I_ndex = (LEAFTYPE)INDEX; /* truncate hi bits */ \ Word_t l_ow = cJU_ALLONES; \ Word_t m_id; \ Word_t h_igh = POP1; \ \ while ((h_igh - l_ow) > 1UL) \ { \ m_id = (h_igh + l_ow) / 2; \ if (P_leaf[m_id] > I_ndex) \ h_igh = m_id; \ else \ l_ow = m_id; \ } \ if (l_ow == cJU_ALLONES || P_leaf[l_ow] != I_ndex) \ return(~h_igh); \ return(l_ow) #define SEARCHLEAFNONNAT(ADDR,POP1,INDEX,LFBTS,COPYINDEX) \ uint8_t *P_leaf = (uint8_t *)(ADDR); \ Word_t l_ow = cJU_ALLONES; \ Word_t m_id; \ Word_t h_igh = POP1; \ Word_t I_ndex = JU_LEASTBYTES((INDEX), (LFBTS)); \ Word_t i_ndex; \ \ I_ndex = JU_LEASTBYTES((INDEX), (LFBTS)); \ \ while ((h_igh - l_ow) > 1UL) \ { \ m_id = (h_igh + l_ow) / 2; \ COPYINDEX(i_ndex, &P_leaf[m_id * (LFBTS)]); \ if (i_ndex > I_ndex) \ h_igh = m_id; \ else \ l_ow = m_id; \ } \ if (l_ow == cJU_ALLONES) return(~h_igh); \ \ COPYINDEX(i_ndex, &P_leaf[l_ow * (LFBTS)]); \ if (i_ndex != I_ndex) return(~h_igh); \ return(l_ow) #endif // SEARCH_BINARY // Fast way to count bits set in 8..32[64]-bit int: // // For performance, j__udyCountBits*() are written to take advantage of // platform-specific features where available. // #ifdef JU_NOINLINE extern BITMAPB_t j__udyCountBitsB(BITMAPB_t word); extern BITMAPL_t j__udyCountBitsL(BITMAPL_t word); // Compiler supports inline #elif defined(JU_HPUX_IPF) #define j__udyCountBitsB(WORD) _Asm_popcnt(WORD) #define j__udyCountBitsL(WORD) _Asm_popcnt(WORD) #elif defined(JU_LINUX_IPF) static inline BITMAPB_t j__udyCountBitsB(BITMAPB_t word) { BITMAPB_t result; __asm__ ("popcnt %0=%1" : "=r" (result) : "r" (word)); return(result); } static inline BITMAPL_t j__udyCountBitsL(BITMAPL_t word) { BITMAPL_t result; __asm__ ("popcnt %0=%1" : "=r" (result) : "r" (word)); return(result); } #else // No instructions available, use inline code // **************************************************************************** // __ J U D Y C O U N T B I T S B // // Return the number of bits set in "Word", for a bitmap branch. // // Note: Bitmap branches have maximum bitmap size = 32 bits. #ifdef JU_WIN static __inline BITMAPB_t j__udyCountBitsB(BITMAPB_t word) #else static inline BITMAPB_t j__udyCountBitsB(BITMAPB_t word) #endif { word = (word & 0x55555555) + ((word & 0xAAAAAAAA) >> 1); word = (word & 0x33333333) + ((word & 0xCCCCCCCC) >> 2); word = (word & 0x0F0F0F0F) + ((word & 0xF0F0F0F0) >> 4); // >= 8 bits. #if defined(BITMAP_BRANCH16x16) || defined(BITMAP_BRANCH32x8) word = (word & 0x00FF00FF) + ((word & 0xFF00FF00) >> 8); // >= 16 bits. #endif #ifdef BITMAP_BRANCH32x8 word = (word & 0x0000FFFF) + ((word & 0xFFFF0000) >> 16); // >= 32 bits. #endif return(word); } // j__udyCountBitsB() // **************************************************************************** // __ J U D Y C O U N T B I T S L // // Return the number of bits set in "Word", for a bitmap leaf. // // Note: Bitmap branches have maximum bitmap size = 32 bits. // Note: Need both 32-bit and 64-bit versions of j__udyCountBitsL() because // bitmap leaves can have 64-bit bitmaps. #ifdef JU_WIN static __inline BITMAPL_t j__udyCountBitsL(BITMAPL_t word) #else static inline BITMAPL_t j__udyCountBitsL(BITMAPL_t word) #endif { #ifndef JU_64BIT word = (word & 0x55555555) + ((word & 0xAAAAAAAA) >> 1); word = (word & 0x33333333) + ((word & 0xCCCCCCCC) >> 2); word = (word & 0x0F0F0F0F) + ((word & 0xF0F0F0F0) >> 4); // >= 8 bits. #if defined(BITMAP_LEAF16x16) || defined(BITMAP_LEAF32x8) word = (word & 0x00FF00FF) + ((word & 0xFF00FF00) >> 8); // >= 16 bits. #endif #ifdef BITMAP_LEAF32x8 word = (word & 0x0000FFFF) + ((word & 0xFFFF0000) >> 16); // >= 32 bits. #endif #else // JU_64BIT word = (word & 0x5555555555555555) + ((word & 0xAAAAAAAAAAAAAAAA) >> 1); word = (word & 0x3333333333333333) + ((word & 0xCCCCCCCCCCCCCCCC) >> 2); word = (word & 0x0F0F0F0F0F0F0F0F) + ((word & 0xF0F0F0F0F0F0F0F0) >> 4); #if defined(BITMAP_LEAF16x16) || defined(BITMAP_LEAF32x8) || defined(BITMAP_LEAF64x4) word = (word & 0x00FF00FF00FF00FF) + ((word & 0xFF00FF00FF00FF00) >> 8); #endif #if defined(BITMAP_LEAF32x8) || defined(BITMAP_LEAF64x4) word = (word & 0x0000FFFF0000FFFF) + ((word & 0xFFFF0000FFFF0000) >>16); #endif #ifdef BITMAP_LEAF64x4 word = (word & 0x00000000FFFFFFFF) + ((word & 0xFFFFFFFF00000000) >>32); #endif #endif // JU_64BIT return(word); } // j__udyCountBitsL() #endif // Compiler supports inline // GET POP0: // // Get from jp_DcdPopO the Pop0 for various JP Types. // // Notes: // // - Different macros require different parameters... // // - There are no simple macros for cJU_BRANCH* Types because their // populations must be added up and dont reside in an already-calculated // place. (TBD: This is no longer true, now its in the JPM.) // // - cJU_JPIMM_POP0() is not defined because it would be redundant because the // Pop1 is already encoded in each enum name. // // - A linear or bitmap leaf Pop0 cannot exceed cJU_SUBEXPPERSTATE - 1 (Pop0 = // 0..255), so use a simpler, faster macro for it than for other JP Types. // // - Avoid any complex calculations that would slow down the compiled code. // Assume these macros are only called for the appropriate JP Types. // Unfortunately theres no way to trigger an assertion here if the JP type // is incorrect for the macro, because these are merely expressions, not // statements. #define JU_LEAFW_POP0(JRP) (*P_JLW(JRP)) #define cJU_JPFULLPOPU1_POP0 (cJU_SUBEXPPERSTATE - 1) // GET JP Type: // Since bit fields greater than 32 bits are not supported in some compilers // the jp_DcdPopO field is expanded to include the jp_Type in the high 8 bits // of the Word_t. // First the read macro: #define JU_JPTYPE(PJP) ((PJP)->jp_Type) #define JU_JPLEAF_POP0(PJP) ((PJP)->jp_DcdP0[sizeof(Word_t) - 2]) #ifdef JU_64BIT #define JU_JPDCDPOP0(PJP) \ ((Word_t)(PJP)->jp_DcdP0[0] << 48 | \ (Word_t)(PJP)->jp_DcdP0[1] << 40 | \ (Word_t)(PJP)->jp_DcdP0[2] << 32 | \ (Word_t)(PJP)->jp_DcdP0[3] << 24 | \ (Word_t)(PJP)->jp_DcdP0[4] << 16 | \ (Word_t)(PJP)->jp_DcdP0[5] << 8 | \ (Word_t)(PJP)->jp_DcdP0[6]) #define JU_JPSETADT(PJP,ADDR,DCDPOP0,TYPE) \ { \ (PJP)->jp_Addr = (ADDR); \ (PJP)->jp_DcdP0[0] = (uint8_t)((Word_t)(DCDPOP0) >> 48); \ (PJP)->jp_DcdP0[1] = (uint8_t)((Word_t)(DCDPOP0) >> 40); \ (PJP)->jp_DcdP0[2] = (uint8_t)((Word_t)(DCDPOP0) >> 32); \ (PJP)->jp_DcdP0[3] = (uint8_t)((Word_t)(DCDPOP0) >> 24); \ (PJP)->jp_DcdP0[4] = (uint8_t)((Word_t)(DCDPOP0) >> 16); \ (PJP)->jp_DcdP0[5] = (uint8_t)((Word_t)(DCDPOP0) >> 8); \ (PJP)->jp_DcdP0[6] = (uint8_t)((Word_t)(DCDPOP0)); \ (PJP)->jp_Type = (TYPE); \ } #else // 32 Bit #define JU_JPDCDPOP0(PJP) \ ((Word_t)(PJP)->jp_DcdP0[0] << 16 | \ (Word_t)(PJP)->jp_DcdP0[1] << 8 | \ (Word_t)(PJP)->jp_DcdP0[2]) #define JU_JPSETADT(PJP,ADDR,DCDPOP0,TYPE) \ { \ (PJP)->jp_Addr = (ADDR); \ (PJP)->jp_DcdP0[0] = (uint8_t)((Word_t)(DCDPOP0) >> 16); \ (PJP)->jp_DcdP0[1] = (uint8_t)((Word_t)(DCDPOP0) >> 8); \ (PJP)->jp_DcdP0[2] = (uint8_t)((Word_t)(DCDPOP0)); \ (PJP)->jp_Type = (TYPE); \ } #endif // 32 Bit // NUMBER OF BITS IN A BRANCH OR LEAF BITMAP AND SUBEXPANSE: // // Note: cJU_BITSPERBITMAP must be the same as the number of JPs in a branch. #define cJU_BITSPERBITMAP cJU_SUBEXPPERSTATE // Bitmaps are accessed in units of "subexpanses": #define cJU_BITSPERSUBEXPB (sizeof(BITMAPB_t) * cJU_BITSPERBYTE) #define cJU_NUMSUBEXPB (cJU_BITSPERBITMAP / cJU_BITSPERSUBEXPB) #define cJU_BITSPERSUBEXPL (sizeof(BITMAPL_t) * cJU_BITSPERBYTE) #define cJU_NUMSUBEXPL (cJU_BITSPERBITMAP / cJU_BITSPERSUBEXPL) // MASK FOR A SPECIFIED BIT IN A BITMAP: // // Warning: If BitNum is a variable, this results in a variable shift that is // expensive, at least on some processors. Use with caution. // // Warning: BitNum must be less than cJU_BITSPERWORD, that is, 0 .. // cJU_BITSPERWORD - 1, to avoid a truncated shift on some machines. // // TBD: Perhaps use an array[32] of masks instead of calculating them. #define JU_BITPOSMASKB(BITNUM) (1L << ((BITNUM) % cJU_BITSPERSUBEXPB)) #define JU_BITPOSMASKL(BITNUM) (1L << ((BITNUM) % cJU_BITSPERSUBEXPL)) // TEST/SET/CLEAR A BIT IN A BITMAP LEAF: // // Test if a byte-sized Digit (portion of Index) has a corresponding bit set in // a bitmap, or set a byte-sized Digits bit into a bitmap, by looking up the // correct subexpanse and then checking/setting the correct bit. // // Note: Mask higher bits, if any, for the convenience of the user of this // macro, in case they pass a full Index, not just a digit. If the caller has // a true 8-bit digit, make it of type uint8_t and the compiler should skip the // unnecessary mask step. #define JU_SUBEXPL(DIGIT) (((DIGIT) / cJU_BITSPERSUBEXPL) & (cJU_NUMSUBEXPL-1)) #define JU_BITMAPTESTL(PJLB, INDEX) \ (JU_JLB_BITMAP(PJLB, JU_SUBEXPL(INDEX)) & JU_BITPOSMASKL(INDEX)) #define JU_BITMAPSETL(PJLB, INDEX) \ (JU_JLB_BITMAP(PJLB, JU_SUBEXPL(INDEX)) |= JU_BITPOSMASKL(INDEX)) #define JU_BITMAPCLEARL(PJLB, INDEX) \ (JU_JLB_BITMAP(PJLB, JU_SUBEXPL(INDEX)) ^= JU_BITPOSMASKL(INDEX)) // MAP BITMAP BIT OFFSET TO DIGIT: // // Given a digit variable to set, a bitmap branch or leaf subexpanse (base 0), // the bitmap (BITMAP*_t) for that subexpanse, and an offset (Nth set bit in // the bitmap, base 0), compute the digit (also base 0) corresponding to the // subexpanse and offset by counting all bits in the bitmap until offset+1 set // bits are seen. Avoid expensive variable shifts. Offset should be less than // the number of set bits in the bitmap; assert this. // // If theres a better way to do this, I dont know what it is. #define JU_BITMAPDIGITB(DIGIT,SUBEXP,BITMAP,OFFSET) \ { \ BITMAPB_t bitmap = (BITMAP); int remain = (OFFSET); \ (DIGIT) = (SUBEXP) * cJU_BITSPERSUBEXPB; \ \ while ((remain -= (bitmap & 1)) >= 0) \ { \ bitmap >>= 1; ++(DIGIT); \ assert((DIGIT) < ((SUBEXP) + 1) * cJU_BITSPERSUBEXPB); \ } \ } #define JU_BITMAPDIGITL(DIGIT,SUBEXP,BITMAP,OFFSET) \ { \ BITMAPL_t bitmap = (BITMAP); int remain = (OFFSET); \ (DIGIT) = (SUBEXP) * cJU_BITSPERSUBEXPL; \ \ while ((remain -= (bitmap & 1)) >= 0) \ { \ bitmap >>= 1; ++(DIGIT); \ assert((DIGIT) < ((SUBEXP) + 1) * cJU_BITSPERSUBEXPL); \ } \ } // MASKS FOR PORTIONS OF 32-BIT WORDS: // // These are useful for bitmap subexpanses. // // "LOWER"/"HIGHER" means bits representing lower/higher-valued Indexes. The // exact order of bits in the word is explicit here but is hidden from the // caller. // // "EXC" means exclusive of the specified bit; "INC" means inclusive. // // In each case, BitPos is either "JU_BITPOSMASK*(BitNum)", or a variable saved // from an earlier call of that macro; either way, it must be a 32-bit word // with a single bit set. In the first case, assume the compiler is smart // enough to optimize out common subexpressions. // // The expressions depend on unsigned decimal math that should be universal. #define JU_MASKLOWEREXC( BITPOS) ((BITPOS) - 1) #define JU_MASKLOWERINC( BITPOS) (JU_MASKLOWEREXC(BITPOS) | (BITPOS)) #define JU_MASKHIGHERINC(BITPOS) (-(BITPOS)) #define JU_MASKHIGHEREXC(BITPOS) (JU_MASKHIGHERINC(BITPOS) ^ (BITPOS)) // **************************************************************************** // SUPPORT FOR NATIVE INDEX SIZES // **************************************************************************** // // Copy a series of generic objects (uint8_t, uint16_t, uint32_t, Word_t) from // one place to another. #define JU_COPYMEM(PDST,PSRC,POP1) \ { \ Word_t i_ndex = 0; \ assert((POP1) > 0); \ do { (PDST)[i_ndex] = (PSRC)[i_ndex]; } \ while (++i_ndex < (POP1)); \ } // **************************************************************************** // SUPPORT FOR NON-NATIVE INDEX SIZES // **************************************************************************** // // Copy a 3-byte Index pointed by a uint8_t * to a Word_t: // #define JU_COPY3_PINDEX_TO_LONG(DESTLONG,PINDEX) \ DESTLONG = (Word_t)(PINDEX)[0] << 16; \ DESTLONG += (Word_t)(PINDEX)[1] << 8; \ DESTLONG += (Word_t)(PINDEX)[2] // Copy a Word_t to a 3-byte Index pointed at by a uint8_t *: #define JU_COPY3_LONG_TO_PINDEX(PINDEX,SOURCELONG) \ (PINDEX)[0] = (uint8_t)((SOURCELONG) >> 16); \ (PINDEX)[1] = (uint8_t)((SOURCELONG) >> 8); \ (PINDEX)[2] = (uint8_t)((SOURCELONG)) #ifdef JU_64BIT // Copy a 5-byte Index pointed by a uint8_t * to a Word_t: // #define JU_COPY5_PINDEX_TO_LONG(DESTLONG,PINDEX) \ DESTLONG = (Word_t)(PINDEX)[0] << 32; \ DESTLONG += (Word_t)(PINDEX)[1] << 24; \ DESTLONG += (Word_t)(PINDEX)[2] << 16; \ DESTLONG += (Word_t)(PINDEX)[3] << 8; \ DESTLONG += (Word_t)(PINDEX)[4] // Copy a Word_t to a 5-byte Index pointed at by a uint8_t *: #define JU_COPY5_LONG_TO_PINDEX(PINDEX,SOURCELONG) \ (PINDEX)[0] = (uint8_t)((SOURCELONG) >> 32); \ (PINDEX)[1] = (uint8_t)((SOURCELONG) >> 24); \ (PINDEX)[2] = (uint8_t)((SOURCELONG) >> 16); \ (PINDEX)[3] = (uint8_t)((SOURCELONG) >> 8); \ (PINDEX)[4] = (uint8_t)((SOURCELONG)) // Copy a 6-byte Index pointed by a uint8_t * to a Word_t: // #define JU_COPY6_PINDEX_TO_LONG(DESTLONG,PINDEX) \ DESTLONG = (Word_t)(PINDEX)[0] << 40; \ DESTLONG += (Word_t)(PINDEX)[1] << 32; \ DESTLONG += (Word_t)(PINDEX)[2] << 24; \ DESTLONG += (Word_t)(PINDEX)[3] << 16; \ DESTLONG += (Word_t)(PINDEX)[4] << 8; \ DESTLONG += (Word_t)(PINDEX)[5] // Copy a Word_t to a 6-byte Index pointed at by a uint8_t *: #define JU_COPY6_LONG_TO_PINDEX(PINDEX,SOURCELONG) \ (PINDEX)[0] = (uint8_t)((SOURCELONG) >> 40); \ (PINDEX)[1] = (uint8_t)((SOURCELONG) >> 32); \ (PINDEX)[2] = (uint8_t)((SOURCELONG) >> 24); \ (PINDEX)[3] = (uint8_t)((SOURCELONG) >> 16); \ (PINDEX)[4] = (uint8_t)((SOURCELONG) >> 8); \ (PINDEX)[5] = (uint8_t)((SOURCELONG)) // Copy a 7-byte Index pointed by a uint8_t * to a Word_t: // #define JU_COPY7_PINDEX_TO_LONG(DESTLONG,PINDEX) \ DESTLONG = (Word_t)(PINDEX)[0] << 48; \ DESTLONG += (Word_t)(PINDEX)[1] << 40; \ DESTLONG += (Word_t)(PINDEX)[2] << 32; \ DESTLONG += (Word_t)(PINDEX)[3] << 24; \ DESTLONG += (Word_t)(PINDEX)[4] << 16; \ DESTLONG += (Word_t)(PINDEX)[5] << 8; \ DESTLONG += (Word_t)(PINDEX)[6] // Copy a Word_t to a 7-byte Index pointed at by a uint8_t *: #define JU_COPY7_LONG_TO_PINDEX(PINDEX,SOURCELONG) \ (PINDEX)[0] = (uint8_t)((SOURCELONG) >> 48); \ (PINDEX)[1] = (uint8_t)((SOURCELONG) >> 40); \ (PINDEX)[2] = (uint8_t)((SOURCELONG) >> 32); \ (PINDEX)[3] = (uint8_t)((SOURCELONG) >> 24); \ (PINDEX)[4] = (uint8_t)((SOURCELONG) >> 16); \ (PINDEX)[5] = (uint8_t)((SOURCELONG) >> 8); \ (PINDEX)[6] = (uint8_t)((SOURCELONG)) #endif // JU_64BIT // **************************************************************************** // COMMON CODE FRAGMENTS (MACROS) // **************************************************************************** // // These code chunks are shared between various source files. // SET (REPLACE) ONE DIGIT IN AN INDEX: // // To avoid endian issues, use masking and ORing, which operates in a // big-endian register, rather than treating the Index as an array of bytes, // though that would be simpler, but would operate in endian-specific memory. // // TBD: This contains two variable shifts, is that bad? #define JU_SETDIGIT(INDEX,DIGIT,STATE) \ (INDEX) = ((INDEX) & (~cJU_MASKATSTATE(STATE))) \ | (((Word_t) (DIGIT)) \ << (((STATE) - 1) * cJU_BITSPERBYTE)) // Fast version for single LSB: #define JU_SETDIGIT1(INDEX,DIGIT) (INDEX) = ((INDEX) & ~0xff) | (DIGIT) // SET (REPLACE) "N" LEAST DIGITS IN AN INDEX: #define JU_SETDIGITS(INDEX,INDEX2,cSTATE) \ (INDEX) = ((INDEX ) & (~JU_LEASTBYTESMASK(cSTATE))) \ | ((INDEX2) & ( JU_LEASTBYTESMASK(cSTATE))) // COPY DECODE BYTES FROM JP TO INDEX: // // Modify Index digit(s) to match the bytes in jp_DcdPopO in case one or more // branches are skipped and the digits are significant. Its probably faster // to just do this unconditionally than to check if its necessary. // // To avoid endian issues, use masking and ORing, which operates in a // big-endian register, rather than treating the Index as an array of bytes, // though that would be simpler, but would operate in endian-specific memory. // // WARNING: Must not call JU_LEASTBYTESMASK (via cJU_DCDMASK) with Bytes = // cJU_ROOTSTATE or a bad mask is generated, but there are no Dcd bytes to copy // in this case anyway. In fact there are no Dcd bytes unless State < // cJU_ROOTSTATE - 1, so dont call this macro except in those cases. // // TBD: It would be nice to validate jp_DcdPopO against known digits to ensure // no corruption, but this is non-trivial. #define JU_SETDCD(INDEX,PJP,cSTATE) \ (INDEX) = ((INDEX) & ~cJU_DCDMASK(cSTATE)) \ | (JU_JPDCDPOP0(PJP) & cJU_DCDMASK(cSTATE)) // INSERT/DELETE AN INDEX IN-PLACE IN MEMORY: // // Given a pointer to an array of "even" (native), same-sized objects // (indexes), the current population of the array, an offset in the array, and // a new Index to insert, "shift up" the array elements (Indexes) above the // insertion point and insert the new Index. Assume there is sufficient memory // to do this. // // In these macros, "i_offset" is an index offset, and "b_off" is a byte // offset for odd Index sizes. // // Note: Endian issues only arise fro insertion, not deletion, and even for // insertion, they are transparent when native (even) objects are used, and // handled explicitly for odd (non-native) Index sizes. // // Note: The following macros are tricky enough that there is some test code // for them appended to this file. #define JU_INSERTINPLACE(PARRAY,POP1,OFFSET,INDEX) \ assert((long) (POP1) > 0); \ assert((Word_t) (OFFSET) <= (Word_t) (POP1)); \ { \ Word_t i_offset = (POP1); \ \ while (i_offset-- > (OFFSET)) \ (PARRAY)[i_offset + 1] = (PARRAY)[i_offset]; \ \ (PARRAY)[OFFSET] = (INDEX); \ } // Variation for non-native Indexes, where cIS = Index Size // and PByte must point to a uint8_t (byte); shift byte-by-byte: // #define JU_INSERTINPLACE3(PBYTE,POP1,OFFSET,INDEX) \ { \ Word_t i_off = POP1; \ \ while (i_off-- > (OFFSET)) \ { \ Word_t i_dx = i_off * 3; \ (PBYTE)[i_dx + 0 + 3] = (PBYTE)[i_dx + 0]; \ (PBYTE)[i_dx + 1 + 3] = (PBYTE)[i_dx + 1]; \ (PBYTE)[i_dx + 2 + 3] = (PBYTE)[i_dx + 2]; \ } \ JU_COPY3_LONG_TO_PINDEX(&((PBYTE)[(OFFSET) * 3]), INDEX); \ } #ifdef JU_64BIT #define JU_INSERTINPLACE5(PBYTE,POP1,OFFSET,INDEX) \ { \ Word_t i_off = POP1; \ \ while (i_off-- > (OFFSET)) \ { \ Word_t i_dx = i_off * 5; \ (PBYTE)[i_dx + 0 + 5] = (PBYTE)[i_dx + 0]; \ (PBYTE)[i_dx + 1 + 5] = (PBYTE)[i_dx + 1]; \ (PBYTE)[i_dx + 2 + 5] = (PBYTE)[i_dx + 2]; \ (PBYTE)[i_dx + 3 + 5] = (PBYTE)[i_dx + 3]; \ (PBYTE)[i_dx + 4 + 5] = (PBYTE)[i_dx + 4]; \ } \ JU_COPY5_LONG_TO_PINDEX(&((PBYTE)[(OFFSET) * 5]), INDEX); \ } #define JU_INSERTINPLACE6(PBYTE,POP1,OFFSET,INDEX) \ { \ Word_t i_off = POP1; \ \ while (i_off-- > (OFFSET)) \ { \ Word_t i_dx = i_off * 6; \ (PBYTE)[i_dx + 0 + 6] = (PBYTE)[i_dx + 0]; \ (PBYTE)[i_dx + 1 + 6] = (PBYTE)[i_dx + 1]; \ (PBYTE)[i_dx + 2 + 6] = (PBYTE)[i_dx + 2]; \ (PBYTE)[i_dx + 3 + 6] = (PBYTE)[i_dx + 3]; \ (PBYTE)[i_dx + 4 + 6] = (PBYTE)[i_dx + 4]; \ (PBYTE)[i_dx + 5 + 6] = (PBYTE)[i_dx + 5]; \ } \ JU_COPY6_LONG_TO_PINDEX(&((PBYTE)[(OFFSET) * 6]), INDEX); \ } #define JU_INSERTINPLACE7(PBYTE,POP1,OFFSET,INDEX) \ { \ Word_t i_off = POP1; \ \ while (i_off-- > (OFFSET)) \ { \ Word_t i_dx = i_off * 7; \ (PBYTE)[i_dx + 0 + 7] = (PBYTE)[i_dx + 0]; \ (PBYTE)[i_dx + 1 + 7] = (PBYTE)[i_dx + 1]; \ (PBYTE)[i_dx + 2 + 7] = (PBYTE)[i_dx + 2]; \ (PBYTE)[i_dx + 3 + 7] = (PBYTE)[i_dx + 3]; \ (PBYTE)[i_dx + 4 + 7] = (PBYTE)[i_dx + 4]; \ (PBYTE)[i_dx + 5 + 7] = (PBYTE)[i_dx + 5]; \ (PBYTE)[i_dx + 6 + 7] = (PBYTE)[i_dx + 6]; \ } \ JU_COPY7_LONG_TO_PINDEX(&((PBYTE)[(OFFSET) * 7]), INDEX); \ } #endif // JU_64BIT // Counterparts to the above for deleting an Index: // // "Shift down" the array elements starting at the Index to be deleted. #define JU_DELETEINPLACE(PARRAY,POP1,OFFSET,IGNORE) \ assert((long) (POP1) > 0); \ assert((Word_t) (OFFSET) < (Word_t) (POP1)); \ { \ Word_t i_offset = (OFFSET); \ \ while (++i_offset < (POP1)) \ (PARRAY)[i_offset - 1] = (PARRAY)[i_offset]; \ } // Variation for odd-byte-sized (non-native) Indexes, where cIS = Index Size // and PByte must point to a uint8_t (byte); copy byte-by-byte: // // Note: If cIS == 1, JU_DELETEINPLACE_ODD == JU_DELETEINPLACE. // // Note: There are no endian issues here because bytes are just shifted as-is, // not converted to/from an Index. #define JU_DELETEINPLACE_ODD(PBYTE,POP1,OFFSET,cIS) \ assert((long) (POP1) > 0); \ assert((Word_t) (OFFSET) < (Word_t) (POP1)); \ { \ Word_t b_off = (((OFFSET) + 1) * (cIS)) - 1; \ \ while (++b_off < ((POP1) * (cIS))) \ (PBYTE)[b_off - (cIS)] = (PBYTE)[b_off]; \ } // INSERT/DELETE AN INDEX WHILE COPYING OTHERS: // // Copy PSource[] to PDest[], where PSource[] has Pop1 elements (Indexes), // inserting Index at PDest[Offset]. Unlike JU_*INPLACE*() above, these macros // are used when moving Indexes from one memory object to another. #define JU_INSERTCOPY(PDEST,PSOURCE,POP1,OFFSET,INDEX) \ assert((long) (POP1) > 0); \ assert((Word_t) (OFFSET) <= (Word_t) (POP1)); \ { \ Word_t i_offset; \ \ for (i_offset = 0; i_offset < (OFFSET); ++i_offset) \ (PDEST)[i_offset] = (PSOURCE)[i_offset]; \ \ (PDEST)[i_offset] = (INDEX); \ \ for (/* null */; i_offset < (POP1); ++i_offset) \ (PDEST)[i_offset + 1] = (PSOURCE)[i_offset]; \ } #define JU_INSERTCOPY3(PDEST,PSOURCE,POP1,OFFSET,INDEX) \ assert((long) (POP1) > 0); \ assert((Word_t) (OFFSET) <= (Word_t) (POP1)); \ { \ Word_t o_ff; \ \ for (o_ff = 0; o_ff < (OFFSET); o_ff++) \ { \ Word_t i_dx = o_ff * 3; \ (PDEST)[i_dx + 0] = (PSOURCE)[i_dx + 0]; \ (PDEST)[i_dx + 1] = (PSOURCE)[i_dx + 1]; \ (PDEST)[i_dx + 2] = (PSOURCE)[i_dx + 2]; \ } \ JU_COPY3_LONG_TO_PINDEX(&((PDEST)[(OFFSET) * 3]), INDEX); \ \ for (/* null */; o_ff < (POP1); o_ff++) \ { \ Word_t i_dx = o_ff * 3; \ (PDEST)[i_dx + 0 + 3] = (PSOURCE)[i_dx + 0]; \ (PDEST)[i_dx + 1 + 3] = (PSOURCE)[i_dx + 1]; \ (PDEST)[i_dx + 2 + 3] = (PSOURCE)[i_dx + 2]; \ } \ } #ifdef JU_64BIT #define JU_INSERTCOPY5(PDEST,PSOURCE,POP1,OFFSET,INDEX) \ assert((long) (POP1) > 0); \ assert((Word_t) (OFFSET) <= (Word_t) (POP1)); \ { \ Word_t o_ff; \ \ for (o_ff = 0; o_ff < (OFFSET); o_ff++) \ { \ Word_t i_dx = o_ff * 5; \ (PDEST)[i_dx + 0] = (PSOURCE)[i_dx + 0]; \ (PDEST)[i_dx + 1] = (PSOURCE)[i_dx + 1]; \ (PDEST)[i_dx + 2] = (PSOURCE)[i_dx + 2]; \ (PDEST)[i_dx + 3] = (PSOURCE)[i_dx + 3]; \ (PDEST)[i_dx + 4] = (PSOURCE)[i_dx + 4]; \ } \ JU_COPY5_LONG_TO_PINDEX(&((PDEST)[(OFFSET) * 5]), INDEX); \ \ for (/* null */; o_ff < (POP1); o_ff++) \ { \ Word_t i_dx = o_ff * 5; \ (PDEST)[i_dx + 0 + 5] = (PSOURCE)[i_dx + 0]; \ (PDEST)[i_dx + 1 + 5] = (PSOURCE)[i_dx + 1]; \ (PDEST)[i_dx + 2 + 5] = (PSOURCE)[i_dx + 2]; \ (PDEST)[i_dx + 3 + 5] = (PSOURCE)[i_dx + 3]; \ (PDEST)[i_dx + 4 + 5] = (PSOURCE)[i_dx + 4]; \ } \ } #define JU_INSERTCOPY6(PDEST,PSOURCE,POP1,OFFSET,INDEX) \ assert((long) (POP1) > 0); \ assert((Word_t) (OFFSET) <= (Word_t) (POP1)); \ { \ Word_t o_ff; \ \ for (o_ff = 0; o_ff < (OFFSET); o_ff++) \ { \ Word_t i_dx = o_ff * 6; \ (PDEST)[i_dx + 0] = (PSOURCE)[i_dx + 0]; \ (PDEST)[i_dx + 1] = (PSOURCE)[i_dx + 1]; \ (PDEST)[i_dx + 2] = (PSOURCE)[i_dx + 2]; \ (PDEST)[i_dx + 3] = (PSOURCE)[i_dx + 3]; \ (PDEST)[i_dx + 4] = (PSOURCE)[i_dx + 4]; \ (PDEST)[i_dx + 5] = (PSOURCE)[i_dx + 5]; \ } \ JU_COPY6_LONG_TO_PINDEX(&((PDEST)[(OFFSET) * 6]), INDEX); \ \ for (/* null */; o_ff < (POP1); o_ff++) \ { \ Word_t i_dx = o_ff * 6; \ (PDEST)[i_dx + 0 + 6] = (PSOURCE)[i_dx + 0]; \ (PDEST)[i_dx + 1 + 6] = (PSOURCE)[i_dx + 1]; \ (PDEST)[i_dx + 2 + 6] = (PSOURCE)[i_dx + 2]; \ (PDEST)[i_dx + 3 + 6] = (PSOURCE)[i_dx + 3]; \ (PDEST)[i_dx + 4 + 6] = (PSOURCE)[i_dx + 4]; \ (PDEST)[i_dx + 5 + 6] = (PSOURCE)[i_dx + 5]; \ } \ } #define JU_INSERTCOPY7(PDEST,PSOURCE,POP1,OFFSET,INDEX) \ assert((long) (POP1) > 0); \ assert((Word_t) (OFFSET) <= (Word_t) (POP1)); \ { \ Word_t o_ff; \ \ for (o_ff = 0; o_ff < (OFFSET); o_ff++) \ { \ Word_t i_dx = o_ff * 7; \ (PDEST)[i_dx + 0] = (PSOURCE)[i_dx + 0]; \ (PDEST)[i_dx + 1] = (PSOURCE)[i_dx + 1]; \ (PDEST)[i_dx + 2] = (PSOURCE)[i_dx + 2]; \ (PDEST)[i_dx + 3] = (PSOURCE)[i_dx + 3]; \ (PDEST)[i_dx + 4] = (PSOURCE)[i_dx + 4]; \ (PDEST)[i_dx + 5] = (PSOURCE)[i_dx + 5]; \ (PDEST)[i_dx + 6] = (PSOURCE)[i_dx + 6]; \ } \ JU_COPY7_LONG_TO_PINDEX(&((PDEST)[(OFFSET) * 7]), INDEX); \ \ for (/* null */; o_ff < (POP1); o_ff++) \ { \ Word_t i_dx = o_ff * 7; \ (PDEST)[i_dx + 0 + 7] = (PSOURCE)[i_dx + 0]; \ (PDEST)[i_dx + 1 + 7] = (PSOURCE)[i_dx + 1]; \ (PDEST)[i_dx + 2 + 7] = (PSOURCE)[i_dx + 2]; \ (PDEST)[i_dx + 3 + 7] = (PSOURCE)[i_dx + 3]; \ (PDEST)[i_dx + 4 + 7] = (PSOURCE)[i_dx + 4]; \ (PDEST)[i_dx + 5 + 7] = (PSOURCE)[i_dx + 5]; \ (PDEST)[i_dx + 6 + 7] = (PSOURCE)[i_dx + 6]; \ } \ } #endif // JU_64BIT // Counterparts to the above for deleting an Index: #define JU_DELETECOPY(PDEST,PSOURCE,POP1,OFFSET,IGNORE) \ assert((long) (POP1) > 0); \ assert((Word_t) (OFFSET) < (Word_t) (POP1)); \ { \ Word_t i_offset; \ \ for (i_offset = 0; i_offset < (OFFSET); ++i_offset) \ (PDEST)[i_offset] = (PSOURCE)[i_offset]; \ \ for (++i_offset; i_offset < (POP1); ++i_offset) \ (PDEST)[i_offset - 1] = (PSOURCE)[i_offset]; \ } // Variation for odd-byte-sized (non-native) Indexes, where cIS = Index Size; // copy byte-by-byte: // // Note: There are no endian issues here because bytes are just shifted as-is, // not converted to/from an Index. // // Note: If cIS == 1, JU_DELETECOPY_ODD == JU_DELETECOPY, at least in concept. #define JU_DELETECOPY_ODD(PDEST,PSOURCE,POP1,OFFSET,cIS) \ assert((long) (POP1) > 0); \ assert((Word_t) (OFFSET) < (Word_t) (POP1)); \ { \ uint8_t *_Pdest = (uint8_t *) (PDEST); \ uint8_t *_Psource = (uint8_t *) (PSOURCE); \ Word_t b_off; \ \ for (b_off = 0; b_off < ((OFFSET) * (cIS)); ++b_off) \ *_Pdest++ = *_Psource++; \ \ _Psource += (cIS); \ \ for (b_off += (cIS); b_off < ((POP1) * (cIS)); ++b_off) \ *_Pdest++ = *_Psource++; \ } // GENERIC RETURN CODE HANDLING FOR JUDY1 (NO VALUE AREAS) AND JUDYL (VALUE // AREAS): // // This common code hides Judy1 versus JudyL details of how to return various // conditions, including a pointer to a value area for JudyL. // // First, define an internal variation of JERR called JERRI (I = int) to make // lint happy. We accidentally shipped to 11.11 OEUR with all functions that // return int or Word_t using JERR, which is type Word_t, for errors. Lint // complains about this for functions that return int. So, internally use // JERRI for error returns from the int functions. Experiments show that // callers which compare int Foo() to (Word_t) JERR (~0UL) are OK, since JERRI // sign-extends to match JERR. #define JERRI ((int) ~0) // see above. #ifdef JUDY1 #define JU_RET_FOUND return(1) #define JU_RET_NOTFOUND return(0) // For Judy1, these all "fall through" to simply JU_RET_FOUND, since there is no // value area pointer to return: #define JU_RET_FOUND_LEAFW(PJLW,POP1,OFFSET) JU_RET_FOUND #define JU_RET_FOUND_JPM(Pjpm) JU_RET_FOUND #define JU_RET_FOUND_PVALUE(Pjv,OFFSET) JU_RET_FOUND #ifndef JU_64BIT #define JU_RET_FOUND_LEAF1(Pjll,POP1,OFFSET) JU_RET_FOUND #endif #define JU_RET_FOUND_LEAF2(Pjll,POP1,OFFSET) JU_RET_FOUND #define JU_RET_FOUND_LEAF3(Pjll,POP1,OFFSET) JU_RET_FOUND #ifdef JU_64BIT #define JU_RET_FOUND_LEAF4(Pjll,POP1,OFFSET) JU_RET_FOUND #define JU_RET_FOUND_LEAF5(Pjll,POP1,OFFSET) JU_RET_FOUND #define JU_RET_FOUND_LEAF6(Pjll,POP1,OFFSET) JU_RET_FOUND #define JU_RET_FOUND_LEAF7(Pjll,POP1,OFFSET) JU_RET_FOUND #endif #define JU_RET_FOUND_IMM_01(Pjp) JU_RET_FOUND #define JU_RET_FOUND_IMM(Pjp,OFFSET) JU_RET_FOUND // Note: No JudyL equivalent: #define JU_RET_FOUND_FULLPOPU1 JU_RET_FOUND #define JU_RET_FOUND_LEAF_B1(PJLB,SUBEXP,OFFSET) JU_RET_FOUND #else // JUDYL // JU_RET_FOUND // see below; must NOT be defined for JudyL. #define JU_RET_NOTFOUND return((PPvoid_t) NULL) // For JudyL, the location of the value area depends on the JP type and other // factors: // // TBD: The value areas should be accessed via data structures, here and in // Dougs code, not by hard-coded address calculations. // // This is useful in insert/delete code when the value area is returned from // lower levels in the JPM: #define JU_RET_FOUND_JPM(Pjpm) return((PPvoid_t) ((Pjpm)->jpm_PValue)) // This is useful in insert/delete code when the value area location is already // computed: #define JU_RET_FOUND_PVALUE(Pjv,OFFSET) return((PPvoid_t) ((Pjv) + OFFSET)) #define JU_RET_FOUND_LEAFW(PJLW,POP1,OFFSET) \ return((PPvoid_t) (JL_LEAFWVALUEAREA(PJLW, POP1) + (OFFSET))) #define JU_RET_FOUND_LEAF1(Pjll,POP1,OFFSET) \ return((PPvoid_t) (JL_LEAF1VALUEAREA(Pjll, POP1) + (OFFSET))) #define JU_RET_FOUND_LEAF2(Pjll,POP1,OFFSET) \ return((PPvoid_t) (JL_LEAF2VALUEAREA(Pjll, POP1) + (OFFSET))) #define JU_RET_FOUND_LEAF3(Pjll,POP1,OFFSET) \ return((PPvoid_t) (JL_LEAF3VALUEAREA(Pjll, POP1) + (OFFSET))) #ifdef JU_64BIT #define JU_RET_FOUND_LEAF4(Pjll,POP1,OFFSET) \ return((PPvoid_t) (JL_LEAF4VALUEAREA(Pjll, POP1) + (OFFSET))) #define JU_RET_FOUND_LEAF5(Pjll,POP1,OFFSET) \ return((PPvoid_t) (JL_LEAF5VALUEAREA(Pjll, POP1) + (OFFSET))) #define JU_RET_FOUND_LEAF6(Pjll,POP1,OFFSET) \ return((PPvoid_t) (JL_LEAF6VALUEAREA(Pjll, POP1) + (OFFSET))) #define JU_RET_FOUND_LEAF7(Pjll,POP1,OFFSET) \ return((PPvoid_t) (JL_LEAF7VALUEAREA(Pjll, POP1) + (OFFSET))) #endif // Note: Here jp_Addr is a value area itself and not an address, so P_JV() is // not needed: #define JU_RET_FOUND_IMM_01(PJP) return((PPvoid_t) (&((PJP)->jp_Addr))) // Note: Here jp_Addr is a pointer to a separately-mallocd value area, so // P_JV() is required; likewise for JL_JLB_PVALUE: #define JU_RET_FOUND_IMM(PJP,OFFSET) \ return((PPvoid_t) (P_JV((PJP)->jp_Addr) + (OFFSET))) #define JU_RET_FOUND_LEAF_B1(PJLB,SUBEXP,OFFSET) \ return((PPvoid_t) (P_JV(JL_JLB_PVALUE(PJLB, SUBEXP)) + (OFFSET))) #endif // JUDYL // GENERIC ERROR HANDLING: // // This is complicated by variations in the needs of the callers of these // macros. Only use JU_SET_ERRNO() for PJError, because it can be null; use // JU_SET_ERRNO_NONNULL() for Pjpm, which is never null, and also in other // cases where the pointer is known not to be null (to save dead branches). // // Note: Most cases of JU_ERRNO_OVERRUN or JU_ERRNO_CORRUPT should result in // an assertion failure in debug code, so they are more likely to be caught, so // do that here in each macro. #define JU_SET_ERRNO(PJError, JErrno) \ { \ assert((JErrno) != JU_ERRNO_OVERRUN); \ assert((JErrno) != JU_ERRNO_CORRUPT); \ \ if (PJError != (PJError_t) NULL) \ { \ JU_ERRNO(PJError) = (JErrno); \ JU_ERRID(PJError) = __LINE__; \ } \ } // Variation for callers who know already that PJError is non-null; and, it can // also be Pjpm (both PJError_t and Pjpm_t have je_* fields), so only assert it // for null, not cast to any specific pointer type: #define JU_SET_ERRNO_NONNULL(PJError, JErrno) \ { \ assert((JErrno) != JU_ERRNO_OVERRUN); \ assert((JErrno) != JU_ERRNO_CORRUPT); \ assert(PJError); \ \ JU_ERRNO(PJError) = (JErrno); \ JU_ERRID(PJError) = __LINE__; \ } // Variation to copy error info from a (required) JPM to an (optional) // PJError_t: // // Note: The assertions above about JU_ERRNO_OVERRUN and JU_ERRNO_CORRUPT // should have already popped, so they are not needed here. #define JU_COPY_ERRNO(PJError, Pjpm) \ { \ if (PJError) \ { \ JU_ERRNO(PJError) = (uint8_t)JU_ERRNO(Pjpm); \ JU_ERRID(PJError) = JU_ERRID(Pjpm); \ } \ } // For JErrno parameter to previous macros upon return from Judy*Alloc*(): // // The memory allocator returns an address of 0 for out of memory, // 1..sizeof(Word_t)-1 for corruption (an invalid pointer), otherwise a valid // pointer. #define JU_ALLOC_ERRNO(ADDR) \ (((void *) (ADDR) != (void *) NULL) ? JU_ERRNO_OVERRUN : JU_ERRNO_NOMEM) #define JU_CHECKALLOC(Type,Ptr,Retval) \ if ((Ptr) < (Type) sizeof(Word_t)) \ { \ JU_SET_ERRNO(PJError, JU_ALLOC_ERRNO(Ptr)); \ return(Retval); \ } // Leaf search routines #ifdef JU_NOINLINE int j__udySearchLeaf1(Pjll_t Pjll, Word_t LeafPop1, Word_t Index); int j__udySearchLeaf2(Pjll_t Pjll, Word_t LeafPop1, Word_t Index); int j__udySearchLeaf3(Pjll_t Pjll, Word_t LeafPop1, Word_t Index); #ifdef JU_64BIT int j__udySearchLeaf4(Pjll_t Pjll, Word_t LeafPop1, Word_t Index); int j__udySearchLeaf5(Pjll_t Pjll, Word_t LeafPop1, Word_t Index); int j__udySearchLeaf6(Pjll_t Pjll, Word_t LeafPop1, Word_t Index); int j__udySearchLeaf7(Pjll_t Pjll, Word_t LeafPop1, Word_t Index); #endif // JU_64BIT int j__udySearchLeafW(Pjlw_t Pjlw, Word_t LeafPop1, Word_t Index); #else // complier support for inline #ifdef JU_WIN static __inline int j__udySearchLeaf1(Pjll_t Pjll, Word_t LeafPop1, Word_t Index) #else static inline int j__udySearchLeaf1(Pjll_t Pjll, Word_t LeafPop1, Word_t Index) #endif { SEARCHLEAFNATIVE(uint8_t, Pjll, LeafPop1, Index); } #ifdef JU_WIN static __inline int j__udySearchLeaf2(Pjll_t Pjll, Word_t LeafPop1, Word_t Index) #else static inline int j__udySearchLeaf2(Pjll_t Pjll, Word_t LeafPop1, Word_t Index) #endif { SEARCHLEAFNATIVE(uint16_t, Pjll, LeafPop1, Index); } #ifdef JU_WIN static __inline int j__udySearchLeaf3(Pjll_t Pjll, Word_t LeafPop1, Word_t Index) #else static inline int j__udySearchLeaf3(Pjll_t Pjll, Word_t LeafPop1, Word_t Index) #endif { SEARCHLEAFNONNAT(Pjll, LeafPop1, Index, 3, JU_COPY3_PINDEX_TO_LONG); } #ifdef JU_64BIT #ifdef JU_WIN static __inline int j__udySearchLeaf4(Pjll_t Pjll, Word_t LeafPop1, Word_t Index) #else static inline int j__udySearchLeaf4(Pjll_t Pjll, Word_t LeafPop1, Word_t Index) #endif { SEARCHLEAFNATIVE(uint32_t, Pjll, LeafPop1, Index); } #ifdef JU_WIN static __inline int j__udySearchLeaf5(Pjll_t Pjll, Word_t LeafPop1, Word_t Index) #else static inline int j__udySearchLeaf5(Pjll_t Pjll, Word_t LeafPop1, Word_t Index) #endif { SEARCHLEAFNONNAT(Pjll, LeafPop1, Index, 5, JU_COPY5_PINDEX_TO_LONG); } #ifdef JU_WIN static __inline int j__udySearchLeaf6(Pjll_t Pjll, Word_t LeafPop1, Word_t Index) #else static inline int j__udySearchLeaf6(Pjll_t Pjll, Word_t LeafPop1, Word_t Index) #endif { SEARCHLEAFNONNAT(Pjll, LeafPop1, Index, 6, JU_COPY6_PINDEX_TO_LONG); } #ifdef JU_WIN static __inline int j__udySearchLeaf7(Pjll_t Pjll, Word_t LeafPop1, Word_t Index) #else static inline int j__udySearchLeaf7(Pjll_t Pjll, Word_t LeafPop1, Word_t Index) #endif { SEARCHLEAFNONNAT(Pjll, LeafPop1, Index, 7, JU_COPY7_PINDEX_TO_LONG); } #endif // JU_64BIT #ifdef JU_WIN static __inline int j__udySearchLeafW(Pjlw_t Pjlw, Word_t LeafPop1, Word_t Index) #else static inline int j__udySearchLeafW(Pjlw_t Pjlw, Word_t LeafPop1, Word_t Index) #endif { SEARCHLEAFNATIVE(Word_t, Pjlw, LeafPop1, Index); } #endif // compiler support for inline #endif // ! _JUDYPRIVATE_INCLUDED judy-1.0.5/src/JudyCommon/JudyFreeArray.c0000644000175000017500000002216210204462077020454 0ustar troyhebetroyhebe// Copyright (C) 2000 - 2002 Hewlett-Packard Company // // This program is free software; you can redistribute it and/or modify it // under the term of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License // for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program; if not, write to the Free Software Foundation, // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // _________________ // @(#) $Revision: 4.51 $ $Source: /judy/src/JudyCommon/JudyFreeArray.c $ // // Judy1FreeArray() and JudyLFreeArray() functions for Judy1 and JudyL. // Compile with one of -DJUDY1 or -DJUDYL. // Return the number of bytes freed from the array. #if (! (defined(JUDY1) || defined(JUDYL))) #error: One of -DJUDY1 or -DJUDYL must be specified. #endif #ifdef JUDY1 #include "Judy1.h" #else #include "JudyL.h" #endif #include "JudyPrivate1L.h" DBGCODE(extern void JudyCheckPop(Pvoid_t PArray);) // **************************************************************************** // J U D Y 1 F R E E A R R A Y // J U D Y L F R E E A R R A Y // // See the Judy*(3C) manual entry for details. // // This code is written recursively, at least at first, because thats much // simpler. Hope its fast enough. #ifdef JUDY1 FUNCTION Word_t Judy1FreeArray #else FUNCTION Word_t JudyLFreeArray #endif ( PPvoid_t PPArray, // array to free. PJError_t PJError // optional, for returning error info. ) { jpm_t jpm; // local to accumulate free statistics. // CHECK FOR NULL POINTER (error by caller): if (PPArray == (PPvoid_t) NULL) { JU_SET_ERRNO(PJError, JU_ERRNO_NULLPPARRAY); return(JERR); } DBGCODE(JudyCheckPop(*PPArray);) // Zero jpm.jpm_Pop0 (meaning the array will be empty in a moment) for accurate // logging in TRACEMI2. jpm.jpm_Pop0 = 0; // see above. jpm.jpm_TotalMemWords = 0; // initialize memory freed. // Empty array: if (P_JLW(*PPArray) == (Pjlw_t) NULL) return(0); // PROCESS TOP LEVEL "JRP" BRANCHES AND LEAF: if (JU_LEAFW_POP0(*PPArray) < cJU_LEAFW_MAXPOP1) // must be a LEAFW { Pjlw_t Pjlw = P_JLW(*PPArray); // first word of leaf. j__udyFreeJLW(Pjlw, Pjlw[0] + 1, &jpm); *PPArray = (Pvoid_t) NULL; // make an empty array. return (-(jpm.jpm_TotalMemWords * cJU_BYTESPERWORD)); // see above. } else // Rootstate leaves: just free the leaf: // Common code for returning the amount of memory freed. // // Note: In a an ordinary LEAFW, pop0 = *PPArray[0]. // // Accumulate (negative) words freed, while freeing objects. // Return the positive bytes freed. { Pjpm_t Pjpm = P_JPM(*PPArray); Word_t TotalMem = Pjpm->jpm_TotalMemWords; j__udyFreeSM(&(Pjpm->jpm_JP), &jpm); // recurse through tree. j__udyFreeJPM(Pjpm, &jpm); // Verify the array was not corrupt. This means that amount of memory freed // (which is negative) is equal to the initial amount: if (TotalMem + jpm.jpm_TotalMemWords) { JU_SET_ERRNO(PJError, JU_ERRNO_CORRUPT); return(JERR); } *PPArray = (Pvoid_t) NULL; // make an empty array. return (TotalMem * cJU_BYTESPERWORD); } } // Judy1FreeArray() / JudyLFreeArray() // **************************************************************************** // __ J U D Y F R E E S M // // Given a pointer to a JP, recursively visit and free (depth first) all nodes // in a Judy array BELOW the JP, but not the JP itself. Accumulate in *Pjpm // the total words freed (as a negative value). "SM" = State Machine. // // Note: Corruption is not detected at this level because during a FreeArray, // if the code hasnt already core dumped, its better to remain silent, even // if some memory has not been freed, than to bother the caller about the // corruption. TBD: Is this true? If not, must list all legitimate JPNULL // and JPIMMED above first, and revert to returning bool_t (see 4.34). FUNCTION void j__udyFreeSM( Pjp_t Pjp, // top of Judy (top-state). Pjpm_t Pjpm) // to return words freed. { Word_t Pop1; switch (JU_JPTYPE(Pjp)) { #ifdef JUDY1 // FULL EXPANSE -- nothing to free for this jp_Type. case cJ1_JPFULLPOPU1: break; #endif // JUDY BRANCH -- free the sub-tree depth first: // LINEAR BRANCH -- visit each JP in the JBLs list, then free the JBL: // // Note: There are no null JPs in a JBL. case cJU_JPBRANCH_L: case cJU_JPBRANCH_L2: case cJU_JPBRANCH_L3: #ifdef JU_64BIT case cJU_JPBRANCH_L4: case cJU_JPBRANCH_L5: case cJU_JPBRANCH_L6: case cJU_JPBRANCH_L7: #endif // JU_64BIT { Pjbl_t Pjbl = P_JBL(Pjp->jp_Addr); Word_t offset; for (offset = 0; offset < Pjbl->jbl_NumJPs; ++offset) j__udyFreeSM((Pjbl->jbl_jp) + offset, Pjpm); j__udyFreeJBL((Pjbl_t) (Pjp->jp_Addr), Pjpm); break; } // BITMAP BRANCH -- visit each JP in the JBBs list based on the bitmap, also // // Note: There are no null JPs in a JBB. case cJU_JPBRANCH_B: case cJU_JPBRANCH_B2: case cJU_JPBRANCH_B3: #ifdef JU_64BIT case cJU_JPBRANCH_B4: case cJU_JPBRANCH_B5: case cJU_JPBRANCH_B6: case cJU_JPBRANCH_B7: #endif // JU_64BIT { Word_t subexp; Word_t offset; Word_t jpcount; Pjbb_t Pjbb = P_JBB(Pjp->jp_Addr); for (subexp = 0; subexp < cJU_NUMSUBEXPB; ++subexp) { jpcount = j__udyCountBitsB(JU_JBB_BITMAP(Pjbb, subexp)); if (jpcount) { for (offset = 0; offset < jpcount; ++offset) { j__udyFreeSM(P_JP(JU_JBB_PJP(Pjbb, subexp)) + offset, Pjpm); } j__udyFreeJBBJP(JU_JBB_PJP(Pjbb, subexp), jpcount, Pjpm); } } j__udyFreeJBB((Pjbb_t) (Pjp->jp_Addr), Pjpm); break; } // UNCOMPRESSED BRANCH -- visit each JP in the JBU array, then free the JBU // itself: // // Note: Null JPs are handled during recursion at a lower state. case cJU_JPBRANCH_U: case cJU_JPBRANCH_U2: case cJU_JPBRANCH_U3: #ifdef JU_64BIT case cJU_JPBRANCH_U4: case cJU_JPBRANCH_U5: case cJU_JPBRANCH_U6: case cJU_JPBRANCH_U7: #endif // JU_64BIT { Word_t offset; Pjbu_t Pjbu = P_JBU(Pjp->jp_Addr); for (offset = 0; offset < cJU_BRANCHUNUMJPS; ++offset) j__udyFreeSM((Pjbu->jbu_jp) + offset, Pjpm); j__udyFreeJBU((Pjbu_t) (Pjp->jp_Addr), Pjpm); break; } // -- Cases below here terminate and do not recurse. -- // LINEAR LEAF -- just free the leaf; size is computed from jp_Type: // // Note: cJU_JPLEAF1 is a special case, see discussion in ../Judy1/Judy1.h #if (defined(JUDYL) || (! defined(JU_64BIT))) case cJU_JPLEAF1: Pop1 = JU_JPLEAF_POP0(Pjp) + 1; j__udyFreeJLL1((Pjll_t) (Pjp->jp_Addr), Pop1, Pjpm); break; #endif case cJU_JPLEAF2: Pop1 = JU_JPLEAF_POP0(Pjp) + 1; j__udyFreeJLL2((Pjll_t) (Pjp->jp_Addr), Pop1, Pjpm); break; case cJU_JPLEAF3: Pop1 = JU_JPLEAF_POP0(Pjp) + 1; j__udyFreeJLL3((Pjll_t) (Pjp->jp_Addr), Pop1, Pjpm); break; #ifdef JU_64BIT case cJU_JPLEAF4: Pop1 = JU_JPLEAF_POP0(Pjp) + 1; j__udyFreeJLL4((Pjll_t) (Pjp->jp_Addr), Pop1, Pjpm); break; case cJU_JPLEAF5: Pop1 = JU_JPLEAF_POP0(Pjp) + 1; j__udyFreeJLL5((Pjll_t) (Pjp->jp_Addr), Pop1, Pjpm); break; case cJU_JPLEAF6: Pop1 = JU_JPLEAF_POP0(Pjp) + 1; j__udyFreeJLL6((Pjll_t) (Pjp->jp_Addr), Pop1, Pjpm); break; case cJU_JPLEAF7: Pop1 = JU_JPLEAF_POP0(Pjp) + 1; j__udyFreeJLL7((Pjll_t) (Pjp->jp_Addr), Pop1, Pjpm); break; #endif // JU_64BIT // BITMAP LEAF -- free sub-expanse arrays of JPs, then free the JBB. case cJU_JPLEAF_B1: { #ifdef JUDYL Word_t subexp; Word_t jpcount; Pjlb_t Pjlb = P_JLB(Pjp->jp_Addr); // Free the value areas in the bitmap leaf: for (subexp = 0; subexp < cJU_NUMSUBEXPL; ++subexp) { jpcount = j__udyCountBitsL(JU_JLB_BITMAP(Pjlb, subexp)); if (jpcount) j__udyLFreeJV(JL_JLB_PVALUE(Pjlb, subexp), jpcount, Pjpm); } #endif // JUDYL j__udyFreeJLB1((Pjlb_t) (Pjp->jp_Addr), Pjpm); break; } // case cJU_JPLEAF_B1 #ifdef JUDYL // IMMED*: // // For JUDYL, all non JPIMMED_*_01s have a LeafV which must be freed: case cJU_JPIMMED_1_02: case cJU_JPIMMED_1_03: #ifdef JU_64BIT case cJU_JPIMMED_1_04: case cJU_JPIMMED_1_05: case cJU_JPIMMED_1_06: case cJU_JPIMMED_1_07: #endif Pop1 = JU_JPTYPE(Pjp) - cJU_JPIMMED_1_02 + 2; j__udyLFreeJV((Pjv_t) (Pjp->jp_Addr), Pop1, Pjpm); break; #ifdef JU_64BIT case cJU_JPIMMED_2_02: case cJU_JPIMMED_2_03: Pop1 = JU_JPTYPE(Pjp) - cJU_JPIMMED_2_02 + 2; j__udyLFreeJV((Pjv_t) (Pjp->jp_Addr), Pop1, Pjpm); break; case cJU_JPIMMED_3_02: j__udyLFreeJV((Pjv_t) (Pjp->jp_Addr), 2, Pjpm); break; #endif // JU_64BIT #endif // JUDYL // OTHER JPNULL, JPIMMED, OR UNEXPECTED TYPE -- nothing to free for this type: // // Note: Lump together no-op and invalid JP types; see function header // comments. default: break; } // switch (JU_JPTYPE(Pjp)) } // j__udyFreeSM() judy-1.0.5/src/JudyCommon/README0000644000175000017500000000430010204462077016446 0ustar troyhebetroyhebe# @(#) $Revision: 4.24 $ $Source: /judy/src/JudyCommon/README $ # # This tree contains sources for Judy common files. These include shared # header files, ifdef'd common source files for Judy1/JudyL functions, and # shared utility functions. # SHARED HEADER FILES: JudyPrivate.h global private header file for all Judy internal sources JudyPrivateBranch.h global private header file for all Judy internal sources, specifically for branch-related declarations JudyPrivate1L.h global private header file for Judy internal sources that generate both Judy1 and JudyL object files, via -DJUDY1 or -DJUDYL, using common names for JP Types, plus some other generic declarations too # IFDEF'D COMMON SOURCE FILES FOR JUDY1/JUDYL FUNCTIONS: # # See Judy(3C) manual entry about these sources for exported functions. JudyGet.c common code for Judy1Test() and JudyLGet() JudyIns.c common code for Judy1Set() and JudyLIns() JudyDel.c common code for Judy1Unset() and JudyLDel() JudyFirst.c common code for Judy1 and JudyL JudyPrevNext.c common code for Judy1, JudyL; Judy*Prev(), Judy*Next() JudyPrevNextEmpty.c common code for Judy1, JudyL; Judy*PrevEmpty(), Judy*NextEmpty() JudyCount.c common code for Judy1 and JudyL JudyByCount.c common code for Judy1 and JudyL JudyFreeArray.c common code for Judy1 and JudyL JudyMemUsed.c common code for Judy1 and JudyL JudyMemActive.c common code for Judy1 and JudyL JudyInsArray.c common code for Judy1 and JudyL # SHARED UTILITY FUNCTIONS: JudyMalloc.c source file JudyTables.c static definitions of translation tables; a main program is #ifdef-embedded to generate these tables # Common code for Judy1 and JudyL that is compiled twice with -DJUDY1 or # -DJUDYL: JudyInsertBranch.c insert a linear branch between a branch and a leaf JudyCreateBranch.c create and copy all types of branches JudyCascade.c handles overflow insertion of an Index, including common Decode bytes and branch creation JudyDecascade.c handles underflow deletion of an Index, including common Decode bytes and branch deletion JudyMallocIF.c a Judy malloc/free interface, for statistics and debugging JudyPrintJP.c debug/trace code #included in other *.c files judy-1.0.5/src/JudyCommon/Makefile.in0000644000175000017500000003222610624600216017636 0ustar troyhebetroyhebe# Makefile.in generated by automake 1.9.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ top_builddir = ../.. am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd INSTALL = @INSTALL@ install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/JudyCommon DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libJudyMalloc_la_LIBADD = am_libJudyMalloc_la_OBJECTS = JudyMalloc.lo libJudyMalloc_la_OBJECTS = $(am_libJudyMalloc_la_OBJECTS) DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ SOURCES = $(libJudyMalloc_la_SOURCES) DIST_SOURCES = $(libJudyMalloc_la_SOURCES) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMDEP_FALSE = @AMDEP_FALSE@ AMDEP_TRUE = @AMDEP_TRUE@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO = @ECHO@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ F77 = @F77@ FFLAGS = @FFLAGS@ FLAVOR = @FLAVOR@ GREP = @GREP@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ MAKEINFO = @MAKEINFO@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ VERSION_INFO = @VERSION_INFO@ WARN_CFLAGS = @WARN_CFLAGS@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_F77 = @ac_ct_F77@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ INCLUDES = -I. -I.. AM_CFLAGS = @CFLAGS@ @WARN_CFLAGS@ noinst_LTLIBRARIES = libJudyMalloc.la libJudyMalloc_la_SOURCES = JudyMalloc.c DISTCLEANFILES = .deps Makefile all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/JudyCommon/Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --gnu src/JudyCommon/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libJudyMalloc.la: $(libJudyMalloc_la_OBJECTS) $(libJudyMalloc_la_DEPENDENCIES) $(LINK) $(libJudyMalloc_la_LDFLAGS) $(libJudyMalloc_la_OBJECTS) $(libJudyMalloc_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/JudyMalloc.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs distclean-libtool: -rm -f libtool uninstall-info-am: ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$tags $$unique; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ test -z "$(CTAGS_ARGS)$$tags$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$tags $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && cd $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) $$here distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ list='$(DISTFILES)'; for file in $$list; do \ case $$file in \ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ esac; \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ if test "$$dir" != "$$file" && test "$$dir" != "."; then \ dir="/$$dir"; \ $(mkdir_p) "$(distdir)$$dir"; \ else \ dir=''; \ fi; \ if test -d $$d/$$file; then \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-libtool distclean-tags dvi: dvi-am dvi-am: html: html-am info: info-am info-am: install-data-am: install-exec-am: install-info: install-info-am install-man: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-info-am .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLTLIBRARIES ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-exec \ install-exec-am install-info install-info-am install-man \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags uninstall uninstall-am \ uninstall-info-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: judy-1.0.5/src/JudyCommon/JudyInsertBranch.c0000644000175000017500000001072210204462077021155 0ustar troyhebetroyhebe// Copyright (C) 2000 - 2002 Hewlett-Packard Company // // This program is free software; you can redistribute it and/or modify it // under the term of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License // for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program; if not, write to the Free Software Foundation, // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // _________________ // @(#) $Revision: 4.17 $ $Source: /judy/src/JudyCommon/JudyInsertBranch.c $ // BranchL insertion functions for Judy1 and JudyL. // Compile with one of -DJUDY1 or -DJUDYL. #if (! (defined(JUDY1) || defined(JUDYL))) #error: One of -DJUDY1 or -DJUDYL must be specified. #endif #ifdef JUDY1 #include "Judy1.h" #else #include "JudyL.h" #endif #include "JudyPrivate1L.h" extern int j__udyCreateBranchL(Pjp_t, Pjp_t, uint8_t *, Word_t, Pvoid_t); // **************************************************************************** // __ J U D Y I N S E R T B R A N C H // // Insert 2-element BranchL in between Pjp and Pjp->jp_Addr. // // Return -1 if out of memory, otherwise return 1. FUNCTION int j__udyInsertBranch( Pjp_t Pjp, // JP containing narrow pointer. Word_t Index, // outlier to Pjp. Word_t BranchLevel, // of what JP points to, mapped from JP type. Pjpm_t Pjpm) // for global accounting. { jp_t JP2 [2]; jp_t JP; Pjp_t PjpNull; Word_t XorExp; Word_t Inew, Iold; Word_t DCDMask; // initially for original BranchLevel. int Ret; uint8_t Exp2[2]; uint8_t DecodeByteN, DecodeByteO; // Get the current mask for the DCD digits: DCDMask = cJU_DCDMASK(BranchLevel); // Obtain Dcd bits that differ between Index and JP, shifted so the // digit for BranchLevel is the LSB: XorExp = ((Index ^ JU_JPDCDPOP0(Pjp)) & (cJU_ALLONES >> cJU_BITSPERBYTE)) >> (BranchLevel * cJU_BITSPERBYTE); assert(XorExp); // Index must be an outlier. // Count levels between object under narrow pointer and the level at which // the outlier diverges from it, which is always at least initial // BranchLevel + 1, to end up with the level (JP type) at which to insert // the new intervening BranchL: do { ++BranchLevel; } while ((XorExp >>= cJU_BITSPERBYTE)); assert((BranchLevel > 1) && (BranchLevel < cJU_ROOTSTATE)); // Get the MSB (highest digit) that differs between the old expanse and // the new Index to insert: DecodeByteO = JU_DIGITATSTATE(JU_JPDCDPOP0(Pjp), BranchLevel); DecodeByteN = JU_DIGITATSTATE(Index, BranchLevel); assert(DecodeByteO != DecodeByteN); // Determine sorted order for old expanse and new Index digits: if (DecodeByteN > DecodeByteO) { Iold = 0; Inew = 1; } else { Iold = 1; Inew = 0; } // Copy old JP into staging area for new Branch JP2 [Iold] = *Pjp; Exp2[Iold] = DecodeByteO; Exp2[Inew] = DecodeByteN; // Create a 2 Expanse Linear branch // // Note: Pjp->jp_Addr is set by j__udyCreateBranchL() Ret = j__udyCreateBranchL(Pjp, JP2, Exp2, 2, Pjpm); if (Ret == -1) return(-1); // Get Pjp to the NULL of where to do insert PjpNull = ((P_JBL(Pjp->jp_Addr))->jbl_jp) + Inew; // Convert to a cJU_JPIMMED_*_01 at the correct level: // Build JP and set type below to: cJU_JPIMMED_X_01 JU_JPSETADT(PjpNull, 0, Index, cJU_JPIMMED_1_01 - 2 + BranchLevel); // Return pointer to Value area in cJU_JPIMMED_X_01 JUDYLCODE(Pjpm->jpm_PValue = (Pjv_t) PjpNull;) // The old JP now points to a BranchL that is at higher level. Therefore // it contains excess DCD bits (in the least significant position) that // must be removed (zeroed); that is, they become part of the Pop0 // subfield. Note that the remaining (lower) bytes in the Pop0 field do // not change. // // Take from the old DCDMask, which went "down" to a lower BranchLevel, // and zero any high bits that are still in the mask at the new, higher // BranchLevel; then use this mask to zero the bits in jp_DcdPopO: // Set old JP to a BranchL at correct level Pjp->jp_Type = cJU_JPBRANCH_L2 - 2 + BranchLevel; DCDMask ^= cJU_DCDMASK(BranchLevel); DCDMask = ~DCDMask & JU_JPDCDPOP0(Pjp); JP = *Pjp; JU_JPSETADT(Pjp, JP.jp_Addr, DCDMask, JP.jp_Type); return(1); } // j__udyInsertBranch() judy-1.0.5/src/JudyCommon/JudyCascade.c0000644000175000017500000015641410204462077020127 0ustar troyhebetroyhebe// Copyright (C) 2000 - 2002 Hewlett-Packard Company // // This program is free software; you can redistribute it and/or modify it // under the term of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License // for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program; if not, write to the Free Software Foundation, // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // _________________ // @(#) $Revision: 4.38 $ $Source: /judy/src/JudyCommon/JudyCascade.c $ #ifdef JUDY1 #include "Judy1.h" #else #include "JudyL.h" #endif #include "JudyPrivate1L.h" extern int j__udyCreateBranchL(Pjp_t, Pjp_t, uint8_t *, Word_t, Pvoid_t); extern int j__udyCreateBranchB(Pjp_t, Pjp_t, uint8_t *, Word_t, Pvoid_t); DBGCODE(extern void JudyCheckSorted(Pjll_t Pjll, Word_t Pop1, long IndexSize);) static const jbb_t StageJBBZero; // zeroed versions of namesake struct. // TBD: There are multiple copies of (some of) these CopyWto3, Copy3toW, // CopyWto7 and Copy7toW functions in Judy1Cascade.c, JudyLCascade.c, and // JudyDecascade.c. These static functions should probably be moved to a // common place, made macros, or something to avoid having four copies. // **************************************************************************** // __ J U D Y C O P Y X T O W FUNCTION static void j__udyCopy3toW( PWord_t PDest, uint8_t * PSrc, Word_t LeafIndexes) { do { JU_COPY3_PINDEX_TO_LONG(*PDest, PSrc); PSrc += 3; PDest += 1; } while(--LeafIndexes); } //j__udyCopy3toW() #ifdef JU_64BIT FUNCTION static void j__udyCopy4toW( PWord_t PDest, uint32_t * PSrc, Word_t LeafIndexes) { do { *PDest++ = *PSrc++; } while(--LeafIndexes); } // j__udyCopy4toW() FUNCTION static void j__udyCopy5toW( PWord_t PDest, uint8_t * PSrc, Word_t LeafIndexes) { do { JU_COPY5_PINDEX_TO_LONG(*PDest, PSrc); PSrc += 5; PDest += 1; } while(--LeafIndexes); } // j__udyCopy5toW() FUNCTION static void j__udyCopy6toW( PWord_t PDest, uint8_t * PSrc, Word_t LeafIndexes) { do { JU_COPY6_PINDEX_TO_LONG(*PDest, PSrc); PSrc += 6; PDest += 1; } while(--LeafIndexes); } // j__udyCopy6toW() FUNCTION static void j__udyCopy7toW( PWord_t PDest, uint8_t * PSrc, Word_t LeafIndexes) { do { JU_COPY7_PINDEX_TO_LONG(*PDest, PSrc); PSrc += 7; PDest += 1; } while(--LeafIndexes); } // j__udyCopy7toW() #endif // JU_64BIT // **************************************************************************** // __ J U D Y C O P Y W T O X FUNCTION static void j__udyCopyWto3( uint8_t * PDest, PWord_t PSrc, Word_t LeafIndexes) { do { JU_COPY3_LONG_TO_PINDEX(PDest, *PSrc); PSrc += 1; PDest += 3; } while(--LeafIndexes); } // j__udyCopyWto3() #ifdef JU_64BIT FUNCTION static void j__udyCopyWto4( uint8_t * PDest, PWord_t PSrc, Word_t LeafIndexes) { uint32_t *PDest32 = (uint32_t *)PDest; do { *PDest32 = *PSrc; PSrc += 1; PDest32 += 1; } while(--LeafIndexes); } // j__udyCopyWto4() FUNCTION static void j__udyCopyWto5( uint8_t * PDest, PWord_t PSrc, Word_t LeafIndexes) { do { JU_COPY5_LONG_TO_PINDEX(PDest, *PSrc); PSrc += 1; PDest += 5; } while(--LeafIndexes); } // j__udyCopyWto5() FUNCTION static void j__udyCopyWto6( uint8_t * PDest, PWord_t PSrc, Word_t LeafIndexes) { do { JU_COPY6_LONG_TO_PINDEX(PDest, *PSrc); PSrc += 1; PDest += 6; } while(--LeafIndexes); } // j__udyCopyWto6() FUNCTION static void j__udyCopyWto7( uint8_t * PDest, PWord_t PSrc, Word_t LeafIndexes) { do { JU_COPY7_LONG_TO_PINDEX(PDest, *PSrc); PSrc += 1; PDest += 7; } while(--LeafIndexes); } // j__udyCopyWto7() #endif // JU_64BIT // **************************************************************************** // COMMON CODE (MACROS): // // Free objects in an array of valid JPs, StageJP[ExpCnt] == last one may // include Immeds, which are ignored. #define FREEALLEXIT(ExpCnt,StageJP,Pjpm) \ { \ Word_t _expct = (ExpCnt); \ while (_expct--) j__udyFreeSM(&((StageJP)[_expct]), Pjpm); \ return(-1); \ } // Clear the array that keeps track of the number of JPs in a subexpanse: #define ZEROJP(SubJPCount) \ { \ int ii; \ for (ii = 0; ii < cJU_NUMSUBEXPB; ii++) (SubJPCount[ii]) = 0; \ } // **************************************************************************** // __ J U D Y S T A G E J B B T O J B B // // Create a mallocd BranchB (jbb_t) from a staged BranchB while "splaying" a // single old leaf. Return -1 if out of memory, otherwise 1. static int j__udyStageJBBtoJBB( Pjp_t PjpLeaf, // JP of leaf being splayed. Pjbb_t PStageJBB, // temp jbb_t on stack. Pjp_t PjpArray, // array of JPs to splayed new leaves. uint8_t * PSubCount, // count of JPs for each subexpanse. Pjpm_t Pjpm) // the jpm_t for JudyAlloc*(). { Pjbb_t PjbbRaw; // pointer to new bitmap branch. Pjbb_t Pjbb; Word_t subexp; // Get memory for new BranchB: if ((PjbbRaw = j__udyAllocJBB(Pjpm)) == (Pjbb_t) NULL) return(-1); Pjbb = P_JBB(PjbbRaw); // Copy staged BranchB into just-allocated BranchB: *Pjbb = *PStageJBB; // Allocate the JP subarrays (BJP) for the new BranchB: for (subexp = 0; subexp < cJU_NUMSUBEXPB; subexp++) { Pjp_t PjpRaw; Pjp_t Pjp; Word_t NumJP; // number of JPs in each subexpanse. if ((NumJP = PSubCount[subexp]) == 0) continue; // empty. // Out of memory, back out previous allocations: if ((PjpRaw = j__udyAllocJBBJP(NumJP, Pjpm)) == (Pjp_t) NULL) { while(subexp--) { if ((NumJP = PSubCount[subexp]) == 0) continue; PjpRaw = JU_JBB_PJP(Pjbb, subexp); j__udyFreeJBBJP(PjpRaw, NumJP, Pjpm); } j__udyFreeJBB(PjbbRaw, Pjpm); return(-1); // out of memory. } Pjp = P_JP(PjpRaw); // Place the JP subarray pointer in the new BranchB, copy subarray JPs, and // advance to the next subexpanse: JU_JBB_PJP(Pjbb, subexp) = PjpRaw; JU_COPYMEM(Pjp, PjpArray, NumJP); PjpArray += NumJP; } // for each subexpanse. // Change the PjpLeaf from Leaf to BranchB: PjpLeaf->jp_Addr = (Word_t) PjbbRaw; PjpLeaf->jp_Type += cJU_JPBRANCH_B2 - cJU_JPLEAF2; // Leaf to BranchB. return(1); } // j__udyStageJBBtoJBB() // **************************************************************************** // __ J U D Y J L L 2 T O J L B 1 // // Create a LeafB1 (jlb_t = JLB1) from a Leaf2 (2-byte Indexes and for JudyL, // Word_t Values). Return NULL if out of memory, else a pointer to the new // LeafB1. // // NOTE: Caller must release the Leaf2 that was passed in. FUNCTION static Pjlb_t j__udyJLL2toJLB1( uint16_t * Pjll, // array of 16-bit indexes. #ifdef JUDYL Pjv_t Pjv, // array of associated values. #endif Word_t LeafPop1, // number of indexes/values. Pvoid_t Pjpm) // jpm_t for JudyAlloc*()/JudyFree*(). { Pjlb_t PjlbRaw; Pjlb_t Pjlb; int offset; JUDYLCODE(int subexp;) // Allocate the LeafB1: if ((PjlbRaw = j__udyAllocJLB1(Pjpm)) == (Pjlb_t) NULL) return((Pjlb_t) NULL); Pjlb = P_JLB(PjlbRaw); // Copy Leaf2 indexes to LeafB1: for (offset = 0; offset < LeafPop1; ++offset) JU_BITMAPSETL(Pjlb, Pjll[offset]); #ifdef JUDYL // Build LeafVs from bitmap: for (subexp = 0; subexp < cJU_NUMSUBEXPL; ++subexp) { struct _POINTER_VALUES { Word_t pv_Pop1; // size of value area. Pjv_t pv_Pjv; // raw pointer to value area. } pv[cJU_NUMSUBEXPL]; // Get the population of the subexpanse, and if any, allocate a LeafV: pv[subexp].pv_Pop1 = j__udyCountBitsL(JU_JLB_BITMAP(Pjlb, subexp)); if (pv[subexp].pv_Pop1) { Pjv_t Pjvnew; // TBD: There is an opportunity to put pop == 1 value in pointer: pv[subexp].pv_Pjv = j__udyLAllocJV(pv[subexp].pv_Pop1, Pjpm); // Upon out of memory, free all previously allocated: if (pv[subexp].pv_Pjv == (Pjv_t) NULL) { while(subexp--) { if (pv[subexp].pv_Pop1) { j__udyLFreeJV(pv[subexp].pv_Pjv, pv[subexp].pv_Pop1, Pjpm); } } j__udyFreeJLB1(PjlbRaw, Pjpm); return((Pjlb_t) NULL); } Pjvnew = P_JV(pv[subexp].pv_Pjv); JU_COPYMEM(Pjvnew, Pjv, pv[subexp].pv_Pop1); Pjv += pv[subexp].pv_Pop1; // advance value pointer. // Place raw pointer to value array in bitmap subexpanse: JL_JLB_PVALUE(Pjlb, subexp) = pv[subexp].pv_Pjv; } // populated subexpanse. } // each subexpanse. #endif // JUDYL return(PjlbRaw); // pointer to LeafB1. } // j__udyJLL2toJLB1() // **************************************************************************** // __ J U D Y C A S C A D E 1 // // Create bitmap leaf from 1-byte Indexes and Word_t Values. // // TBD: There must be a better way. // // Only for JudyL 32 bit: (note, unifdef disallows comment on next line) #if (defined(JUDYL) || (! defined(JU_64BIT))) FUNCTION int j__udyCascade1( Pjp_t Pjp, Pvoid_t Pjpm) { Word_t DcdP0; uint8_t * PLeaf; Pjlb_t PjlbRaw; Pjlb_t Pjlb; Word_t Pop1; Word_t ii; // temp for loop counter JUDYLCODE(Pjv_t Pjv;) assert(JU_JPTYPE(Pjp) == cJU_JPLEAF1); assert((JU_JPDCDPOP0(Pjp) & 0xFF) == (cJU_LEAF1_MAXPOP1-1)); PjlbRaw = j__udyAllocJLB1(Pjpm); if (PjlbRaw == (Pjlb_t) NULL) return(-1); Pjlb = P_JLB(PjlbRaw); PLeaf = (uint8_t *) P_JLL(Pjp->jp_Addr); Pop1 = JU_JPLEAF_POP0(Pjp) + 1; JUDYLCODE(Pjv = JL_LEAF1VALUEAREA(PLeaf, Pop1);) // Copy 1 byte index Leaf to bitmap Leaf for (ii = 0; ii < Pop1; ii++) JU_BITMAPSETL(Pjlb, PLeaf[ii]); #ifdef JUDYL // Build 8 subexpanse Value leaves from bitmap for (ii = 0; ii < cJU_NUMSUBEXPL; ii++) { // Get number of Indexes in subexpanse if ((Pop1 = j__udyCountBitsL(JU_JLB_BITMAP(Pjlb, ii)))) { Pjv_t PjvnewRaw; // value area of new leaf. Pjv_t Pjvnew; PjvnewRaw = j__udyLAllocJV(Pop1, Pjpm); if (PjvnewRaw == (Pjv_t) NULL) // out of memory. { // Free prevously allocated LeafVs: while(ii--) { if ((Pop1 = j__udyCountBitsL(JU_JLB_BITMAP(Pjlb, ii)))) { PjvnewRaw = JL_JLB_PVALUE(Pjlb, ii); j__udyLFreeJV(PjvnewRaw, Pop1, Pjpm); } } // Free the bitmap leaf j__udyLFreeJLB1(PjlbRaw,Pjpm); return(-1); } Pjvnew = P_JV(PjvnewRaw); JU_COPYMEM(Pjvnew, Pjv, Pop1); Pjv += Pop1; JL_JLB_PVALUE(Pjlb, ii) = PjvnewRaw; } } #endif // JUDYL DcdP0 = JU_JPDCDPOP0(Pjp) | (PLeaf[0] & cJU_DCDMASK(1)); JU_JPSETADT(Pjp, (Word_t)PjlbRaw, DcdP0, cJU_JPLEAF_B1); return(1); // return success } // j__udyCascade1() #endif // (!(JUDY1 && JU_64BIT)) // **************************************************************************** // __ J U D Y C A S C A D E 2 // // Entry PLeaf of size LeafPop1 is either compressed or splayed with pointer // returned in Pjp. Entry Levels sizeof(Word_t) down to level 2. // // Splay or compress the 2-byte Index Leaf that Pjp point to. Return *Pjp as a // (compressed) cJU_LEAFB1 or a cJU_BRANCH_*2 FUNCTION int j__udyCascade2( Pjp_t Pjp, Pvoid_t Pjpm) { uint16_t * PLeaf; // pointer to leaf, explicit type. Word_t End, Start; // temporaries. Word_t ExpCnt; // count of expanses of splay. Word_t CIndex; // current Index word. JUDYLCODE(Pjv_t Pjv;) // value area of leaf. // Temp staging for parts(Leaves) of newly splayed leaf jp_t StageJP [cJU_LEAF2_MAXPOP1]; // JPs of new leaves uint8_t StageExp [cJU_LEAF2_MAXPOP1]; // Expanses of new leaves uint8_t SubJPCount[cJU_NUMSUBEXPB]; // JPs in each subexpanse jbb_t StageJBB; // staged bitmap branch assert(JU_JPTYPE(Pjp) == cJU_JPLEAF2); assert((JU_JPDCDPOP0(Pjp) & 0xFFFF) == (cJU_LEAF2_MAXPOP1-1)); // Get the address of the Leaf PLeaf = (uint16_t *) P_JLL(Pjp->jp_Addr); // And its Value area JUDYLCODE(Pjv = JL_LEAF2VALUEAREA(PLeaf, cJU_LEAF2_MAXPOP1);) // If Leaf is in 1 expanse -- just compress it to a Bitmap Leaf CIndex = PLeaf[0]; if (!JU_DIGITATSTATE(CIndex ^ PLeaf[cJU_LEAF2_MAXPOP1-1], 2)) { // cJU_JPLEAF_B1 Word_t DcdP0; Pjlb_t PjlbRaw; PjlbRaw = j__udyJLL2toJLB1(PLeaf, #ifdef JUDYL Pjv, #endif cJU_LEAF2_MAXPOP1, Pjpm); if (PjlbRaw == (Pjlb_t)NULL) return(-1); // out of memory // Merge in another Dcd byte because compressing DcdP0 = (CIndex & cJU_DCDMASK(1)) | JU_JPDCDPOP0(Pjp); JU_JPSETADT(Pjp, (Word_t)PjlbRaw, DcdP0, cJU_JPLEAF_B1); return(1); } // Else in 2+ expanses, splay Leaf into smaller leaves at higher compression StageJBB = StageJBBZero; // zero staged bitmap branch ZEROJP(SubJPCount); // Splay the 2 byte index Leaf to 1 byte Index Leaves for (ExpCnt = Start = 0, End = 1; ; End++) { // Check if new expanse or last one if ( (End == cJU_LEAF2_MAXPOP1) || (JU_DIGITATSTATE(CIndex ^ PLeaf[End], 2)) ) { // Build a leaf below the previous expanse // Pjp_t PjpJP = StageJP + ExpCnt; Word_t Pop1 = End - Start; Word_t expanse = JU_DIGITATSTATE(CIndex, 2); Word_t subexp = expanse / cJU_BITSPERSUBEXPB; // // set the bit that is the current expanse JU_JBB_BITMAP(&StageJBB, subexp) |= JU_BITPOSMASKB(expanse); #ifdef SUBEXPCOUNTS StageJBB.jbb_subPop1[subexp] += Pop1; // pop of subexpanse #endif // count number of expanses in each subexpanse SubJPCount[subexp]++; // Save byte expanse of leaf StageExp[ExpCnt] = JU_DIGITATSTATE(CIndex, 2); if (Pop1 == 1) // cJU_JPIMMED_1_01 { Word_t DcdP0; DcdP0 = (JU_JPDCDPOP0(Pjp) & cJU_DCDMASK(1)) | CIndex; #ifdef JUDY1 JU_JPSETADT(PjpJP, 0, DcdP0, cJ1_JPIMMED_1_01); #else // JUDYL JU_JPSETADT(PjpJP, Pjv[Start], DcdP0, cJL_JPIMMED_1_01); #endif // JUDYL } else if (Pop1 <= cJU_IMMED1_MAXPOP1) // bigger { // cJL_JPIMMED_1_02..3: JudyL 32 // cJ1_JPIMMED_1_02..7: Judy1 32 // cJL_JPIMMED_1_02..7: JudyL 64 // cJ1_JPIMMED_1_02..15: Judy1 64 #ifdef JUDYL Pjv_t PjvnewRaw; // value area of leaf. Pjv_t Pjvnew; // Allocate Value area for Immediate Leaf PjvnewRaw = j__udyLAllocJV(Pop1, Pjpm); if (PjvnewRaw == (Pjv_t) NULL) FREEALLEXIT(ExpCnt, StageJP, Pjpm); Pjvnew = P_JV(PjvnewRaw); // Copy to Values to Value Leaf JU_COPYMEM(Pjvnew, Pjv + Start, Pop1); PjpJP->jp_Addr = (Word_t) PjvnewRaw; // Copy to JP as an immediate Leaf JU_COPYMEM(PjpJP->jp_LIndex, PLeaf + Start, Pop1); #else JU_COPYMEM(PjpJP->jp_1Index, PLeaf + Start, Pop1); #endif // Set Type, Population and Index size PjpJP->jp_Type = cJU_JPIMMED_1_02 + Pop1 - 2; } // 64Bit Judy1 does not have Leaf1: (note, unifdef disallows comment on next // line) #if (! (defined(JUDY1) && defined(JU_64BIT))) else if (Pop1 <= cJU_LEAF1_MAXPOP1) // still bigger { // cJU_JPLEAF1 Word_t DcdP0; Pjll_t PjllRaw; // pointer to new leaf. Pjll_t Pjll; JUDYLCODE(Pjv_t Pjvnew;) // value area of new leaf. // Get a new Leaf PjllRaw = j__udyAllocJLL1(Pop1, Pjpm); if (PjllRaw == (Pjll_t)NULL) FREEALLEXIT(ExpCnt, StageJP, Pjpm); Pjll = P_JLL(PjllRaw); #ifdef JUDYL // Copy to Values to new Leaf Pjvnew = JL_LEAF1VALUEAREA(Pjll, Pop1); JU_COPYMEM(Pjvnew, Pjv + Start, Pop1); #endif // Copy Indexes to new Leaf JU_COPYMEM((uint8_t *)Pjll, PLeaf+Start, Pop1); DBGCODE(JudyCheckSorted(Pjll, Pop1, 1);) DcdP0 = (JU_JPDCDPOP0(Pjp) & cJU_DCDMASK(2)) | (CIndex & cJU_DCDMASK(2-1)) | (Pop1 - 1); JU_JPSETADT(PjpJP, (Word_t)PjllRaw, DcdP0, cJU_JPLEAF1); } #endif // (!(JUDY1 && JU_64BIT)) // Not 64Bit Judy1 else // biggest { // cJU_JPLEAF_B1 Word_t DcdP0; Pjlb_t PjlbRaw; PjlbRaw = j__udyJLL2toJLB1( PLeaf + Start, #ifdef JUDYL Pjv + Start, #endif Pop1, Pjpm); if (PjlbRaw == (Pjlb_t)NULL) FREEALLEXIT(ExpCnt, StageJP, Pjpm); DcdP0 = (JU_JPDCDPOP0(Pjp) & cJU_DCDMASK(2)) | (CIndex & cJU_DCDMASK(2-1)) | (Pop1 - 1); JU_JPSETADT(PjpJP, (Word_t)PjlbRaw, DcdP0, cJU_JPLEAF_B1); } ExpCnt++; // Done? if (End == cJU_LEAF2_MAXPOP1) break; // New Expanse, Start and Count CIndex = PLeaf[End]; Start = End; } } // Now put all the Leaves below a BranchL or BranchB: if (ExpCnt <= cJU_BRANCHLMAXJPS) // put the Leaves below a BranchL { if (j__udyCreateBranchL(Pjp, StageJP, StageExp, ExpCnt, Pjpm) == -1) FREEALLEXIT(ExpCnt, StageJP, Pjpm); Pjp->jp_Type = cJU_JPBRANCH_L2; } else { if (j__udyStageJBBtoJBB(Pjp, &StageJBB, StageJP, SubJPCount, Pjpm) == -1) FREEALLEXIT(ExpCnt, StageJP, Pjpm); } return(1); } // j__udyCascade2() // **************************************************************************** // __ J U D Y C A S C A D E 3 // // Return *Pjp as a (compressed) cJU_LEAF2, cJU_BRANCH_L3, cJU_BRANCH_B3. FUNCTION int j__udyCascade3( Pjp_t Pjp, Pvoid_t Pjpm) { uint8_t * PLeaf; // pointer to leaf, explicit type. Word_t End, Start; // temporaries. Word_t ExpCnt; // count of expanses of splay. Word_t CIndex; // current Index word. JUDYLCODE(Pjv_t Pjv;) // value area of leaf. // Temp staging for parts(Leaves) of newly splayed leaf jp_t StageJP [cJU_LEAF3_MAXPOP1]; // JPs of new leaves Word_t StageA [cJU_LEAF3_MAXPOP1]; uint8_t StageExp [cJU_LEAF3_MAXPOP1]; // Expanses of new leaves uint8_t SubJPCount[cJU_NUMSUBEXPB]; // JPs in each subexpanse jbb_t StageJBB; // staged bitmap branch assert(JU_JPTYPE(Pjp) == cJU_JPLEAF3); assert((JU_JPDCDPOP0(Pjp) & 0xFFFFFF) == (cJU_LEAF3_MAXPOP1-1)); // Get the address of the Leaf PLeaf = (uint8_t *) P_JLL(Pjp->jp_Addr); // Extract leaf to Word_t and insert-sort Index into it j__udyCopy3toW(StageA, PLeaf, cJU_LEAF3_MAXPOP1); // Get the address of the Leaf and Value area JUDYLCODE(Pjv = JL_LEAF3VALUEAREA(PLeaf, cJU_LEAF3_MAXPOP1);) // If Leaf is in 1 expanse -- just compress it (compare 1st, last & Index) CIndex = StageA[0]; if (!JU_DIGITATSTATE(CIndex ^ StageA[cJU_LEAF3_MAXPOP1-1], 3)) { Word_t DcdP0; Pjll_t PjllRaw; // pointer to new leaf. Pjll_t Pjll; JUDYLCODE(Pjv_t Pjvnew;) // value area of new leaf. // Alloc a 2 byte Index Leaf PjllRaw = j__udyAllocJLL2(cJU_LEAF3_MAXPOP1, Pjpm); if (PjllRaw == (Pjlb_t)NULL) return(-1); // out of memory Pjll = P_JLL(PjllRaw); // Copy just 2 bytes Indexes to new Leaf // j__udyCopyWto2((uint16_t *) Pjll, StageA, cJU_LEAF3_MAXPOP1); JU_COPYMEM ((uint16_t *) Pjll, StageA, cJU_LEAF3_MAXPOP1); #ifdef JUDYL // Copy Value area into new Leaf Pjvnew = JL_LEAF2VALUEAREA(Pjll, cJU_LEAF3_MAXPOP1); JU_COPYMEM(Pjvnew, Pjv, cJU_LEAF3_MAXPOP1); #endif DBGCODE(JudyCheckSorted(Pjll, cJU_LEAF3_MAXPOP1, 2);) // Form new JP, Pop0 field is unchanged // Add in another Dcd byte because compressing DcdP0 = (CIndex & cJU_DCDMASK(2)) | JU_JPDCDPOP0(Pjp); JU_JPSETADT(Pjp, (Word_t) PjllRaw, DcdP0, cJU_JPLEAF2); return(1); // Success } // Else in 2+ expanses, splay Leaf into smaller leaves at higher compression StageJBB = StageJBBZero; // zero staged bitmap branch ZEROJP(SubJPCount); // Splay the 3 byte index Leaf to 2 byte Index Leaves for (ExpCnt = Start = 0, End = 1; ; End++) { // Check if new expanse or last one if ( (End == cJU_LEAF3_MAXPOP1) || (JU_DIGITATSTATE(CIndex ^ StageA[End], 3)) ) { // Build a leaf below the previous expanse Pjp_t PjpJP = StageJP + ExpCnt; Word_t Pop1 = End - Start; Word_t expanse = JU_DIGITATSTATE(CIndex, 3); Word_t subexp = expanse / cJU_BITSPERSUBEXPB; // // set the bit that is the current expanse JU_JBB_BITMAP(&StageJBB, subexp) |= JU_BITPOSMASKB(expanse); #ifdef SUBEXPCOUNTS StageJBB.jbb_subPop1[subexp] += Pop1; // pop of subexpanse #endif // count number of expanses in each subexpanse SubJPCount[subexp]++; // Save byte expanse of leaf StageExp[ExpCnt] = JU_DIGITATSTATE(CIndex, 3); if (Pop1 == 1) // cJU_JPIMMED_2_01 { Word_t DcdP0; DcdP0 = (JU_JPDCDPOP0(Pjp) & cJU_DCDMASK(2)) | CIndex; #ifdef JUDY1 JU_JPSETADT(PjpJP, 0, DcdP0, cJ1_JPIMMED_2_01); #else // JUDYL JU_JPSETADT(PjpJP, Pjv[Start], DcdP0, cJL_JPIMMED_2_01); #endif // JUDYL } #if (defined(JUDY1) || defined(JU_64BIT)) else if (Pop1 <= cJU_IMMED2_MAXPOP1) { // cJ1_JPIMMED_2_02..3: Judy1 32 // cJL_JPIMMED_2_02..3: JudyL 64 // cJ1_JPIMMED_2_02..7: Judy1 64 #ifdef JUDYL // Alloc is 1st in case of malloc fail Pjv_t PjvnewRaw; // value area of new leaf. Pjv_t Pjvnew; // Allocate Value area for Immediate Leaf PjvnewRaw = j__udyLAllocJV(Pop1, Pjpm); if (PjvnewRaw == (Pjv_t) NULL) FREEALLEXIT(ExpCnt, StageJP, Pjpm); Pjvnew = P_JV(PjvnewRaw); // Copy to Values to Value Leaf JU_COPYMEM(Pjvnew, Pjv + Start, Pop1); PjpJP->jp_Addr = (Word_t) PjvnewRaw; // Copy to Index to JP as an immediate Leaf JU_COPYMEM((uint16_t *) (PjpJP->jp_LIndex), StageA + Start, Pop1); #else // JUDY1 JU_COPYMEM((uint16_t *) (PjpJP->jp_1Index), StageA + Start, Pop1); #endif // JUDY1 // Set Type, Population and Index size PjpJP->jp_Type = cJU_JPIMMED_2_02 + Pop1 - 2; } #endif // (JUDY1 || JU_64BIT) else // Make a linear leaf2 { // cJU_JPLEAF2 Word_t DcdP0; Pjll_t PjllRaw; // pointer to new leaf. Pjll_t Pjll; JUDYLCODE(Pjv_t Pjvnew;) // value area of new leaf. PjllRaw = j__udyAllocJLL2(Pop1, Pjpm); if (PjllRaw == (Pjll_t) NULL) FREEALLEXIT(ExpCnt, StageJP, Pjpm); Pjll = P_JLL(PjllRaw); #ifdef JUDYL // Copy to Values to new Leaf Pjvnew = JL_LEAF2VALUEAREA(Pjll, Pop1); JU_COPYMEM(Pjvnew, Pjv + Start, Pop1); #endif // Copy least 2 bytes per Index of Leaf to new Leaf JU_COPYMEM((uint16_t *) Pjll, StageA+Start, Pop1); DBGCODE(JudyCheckSorted(Pjll, Pop1, 2);) DcdP0 = (JU_JPDCDPOP0(Pjp) & cJU_DCDMASK(3)) | (CIndex & cJU_DCDMASK(3-1)) | (Pop1 - 1); JU_JPSETADT(PjpJP, (Word_t)PjllRaw, DcdP0, cJU_JPLEAF2); } ExpCnt++; // Done? if (End == cJU_LEAF3_MAXPOP1) break; // New Expanse, Start and Count CIndex = StageA[End]; Start = End; } } // Now put all the Leaves below a BranchL or BranchB: if (ExpCnt <= cJU_BRANCHLMAXJPS) // put the Leaves below a BranchL { if (j__udyCreateBranchL(Pjp, StageJP, StageExp, ExpCnt, Pjpm) == -1) FREEALLEXIT(ExpCnt, StageJP, Pjpm); Pjp->jp_Type = cJU_JPBRANCH_L3; } else { if (j__udyStageJBBtoJBB(Pjp, &StageJBB, StageJP, SubJPCount, Pjpm) == -1) FREEALLEXIT(ExpCnt, StageJP, Pjpm); } return(1); } // j__udyCascade3() #ifdef JU_64BIT // JudyCascade[4567] // **************************************************************************** // __ J U D Y C A S C A D E 4 // // Cascade from a cJU_JPLEAF4 to one of the following: // 1. if leaf is in 1 expanse: // compress it into a JPLEAF3 // 2. if leaf contains multiple expanses: // create linear or bitmap branch containing // each new expanse is either a: // JPIMMED_3_01 branch // JPIMMED_3_02 branch // JPLEAF3 FUNCTION int j__udyCascade4( Pjp_t Pjp, Pvoid_t Pjpm) { uint32_t * PLeaf; // pointer to leaf, explicit type. Word_t End, Start; // temporaries. Word_t ExpCnt; // count of expanses of splay. Word_t CIndex; // current Index word. JUDYLCODE(Pjv_t Pjv;) // value area of leaf. // Temp staging for parts(Leaves) of newly splayed leaf jp_t StageJP [cJU_LEAF4_MAXPOP1]; // JPs of new leaves Word_t StageA [cJU_LEAF4_MAXPOP1]; uint8_t StageExp [cJU_LEAF4_MAXPOP1]; // Expanses of new leaves uint8_t SubJPCount[cJU_NUMSUBEXPB]; // JPs in each subexpanse jbb_t StageJBB; // staged bitmap branch assert(JU_JPTYPE(Pjp) == cJU_JPLEAF4); assert((JU_JPDCDPOP0(Pjp) & 0xFFFFFFFF) == (cJU_LEAF4_MAXPOP1-1)); // Get the address of the Leaf PLeaf = (uint32_t *) P_JLL(Pjp->jp_Addr); // Extract 4 byte index Leaf to Word_t j__udyCopy4toW(StageA, PLeaf, cJU_LEAF4_MAXPOP1); // Get the address of the Leaf and Value area JUDYLCODE(Pjv = JL_LEAF4VALUEAREA(PLeaf, cJU_LEAF4_MAXPOP1);) // If Leaf is in 1 expanse -- just compress it (compare 1st, last & Index) CIndex = StageA[0]; if (!JU_DIGITATSTATE(CIndex ^ StageA[cJU_LEAF4_MAXPOP1-1], 4)) { Word_t DcdP0; Pjll_t PjllRaw; // pointer to new leaf. Pjll_t Pjll; JUDYLCODE(Pjv_t Pjvnew;) // value area of new Leaf. // Alloc a 3 byte Index Leaf PjllRaw = j__udyAllocJLL3(cJU_LEAF4_MAXPOP1, Pjpm); if (PjllRaw == (Pjlb_t)NULL) return(-1); // out of memory Pjll = P_JLL(PjllRaw); // Copy Index area into new Leaf j__udyCopyWto3((uint8_t *) Pjll, StageA, cJU_LEAF4_MAXPOP1); #ifdef JUDYL // Copy Value area into new Leaf Pjvnew = JL_LEAF3VALUEAREA(Pjll, cJU_LEAF4_MAXPOP1); JU_COPYMEM(Pjvnew, Pjv, cJU_LEAF4_MAXPOP1); #endif DBGCODE(JudyCheckSorted(Pjll, cJU_LEAF4_MAXPOP1, 3);) DcdP0 = JU_JPDCDPOP0(Pjp) | (CIndex & cJU_DCDMASK(3)); JU_JPSETADT(Pjp, (Word_t)PjllRaw, DcdP0, cJU_JPLEAF3); return(1); } // Else in 2+ expanses, splay Leaf into smaller leaves at higher compression StageJBB = StageJBBZero; // zero staged bitmap branch ZEROJP(SubJPCount); // Splay the 4 byte index Leaf to 3 byte Index Leaves for (ExpCnt = Start = 0, End = 1; ; End++) { // Check if new expanse or last one if ( (End == cJU_LEAF4_MAXPOP1) || (JU_DIGITATSTATE(CIndex ^ StageA[End], 4)) ) { // Build a leaf below the previous expanse Pjp_t PjpJP = StageJP + ExpCnt; Word_t Pop1 = End - Start; Word_t expanse = JU_DIGITATSTATE(CIndex, 4); Word_t subexp = expanse / cJU_BITSPERSUBEXPB; // // set the bit that is the current expanse JU_JBB_BITMAP(&StageJBB, subexp) |= JU_BITPOSMASKB(expanse); #ifdef SUBEXPCOUNTS StageJBB.jbb_subPop1[subexp] += Pop1; // pop of subexpanse #endif // count number of expanses in each subexpanse SubJPCount[subexp]++; // Save byte expanse of leaf StageExp[ExpCnt] = JU_DIGITATSTATE(CIndex, 4); if (Pop1 == 1) // cJU_JPIMMED_3_01 { Word_t DcdP0; DcdP0 = (JU_JPDCDPOP0(Pjp) & cJU_DCDMASK(3)) | CIndex; #ifdef JUDY1 JU_JPSETADT(PjpJP, 0, DcdP0, cJ1_JPIMMED_3_01); #else // JUDYL JU_JPSETADT(PjpJP, Pjv[Start], DcdP0, cJL_JPIMMED_3_01); #endif // JUDYL } else if (Pop1 <= cJU_IMMED3_MAXPOP1) { // cJ1_JPIMMED_3_02 : Judy1 32 // cJL_JPIMMED_3_02 : JudyL 64 // cJ1_JPIMMED_3_02..5: Judy1 64 #ifdef JUDYL // Alloc is 1st in case of malloc fail Pjv_t PjvnewRaw; // value area of new leaf. Pjv_t Pjvnew; // Allocate Value area for Immediate Leaf PjvnewRaw = j__udyLAllocJV(Pop1, Pjpm); if (PjvnewRaw == (Pjv_t) NULL) FREEALLEXIT(ExpCnt, StageJP, Pjpm); Pjvnew = P_JV(PjvnewRaw); // Copy to Values to Value Leaf JU_COPYMEM(Pjvnew, Pjv + Start, Pop1); PjpJP->jp_Addr = (Word_t) PjvnewRaw; // Copy to Index to JP as an immediate Leaf j__udyCopyWto3(PjpJP->jp_LIndex, StageA + Start, Pop1); #else j__udyCopyWto3(PjpJP->jp_1Index, StageA + Start, Pop1); #endif // Set type, population and Index size PjpJP->jp_Type = cJU_JPIMMED_3_02 + Pop1 - 2; } else { // cJU_JPLEAF3 Word_t DcdP0; Pjll_t PjllRaw; // pointer to new leaf. Pjll_t Pjll; JUDYLCODE(Pjv_t Pjvnew;) // value area of new leaf. PjllRaw = j__udyAllocJLL3(Pop1, Pjpm); if (PjllRaw == (Pjll_t)NULL) FREEALLEXIT(ExpCnt, StageJP, Pjpm); Pjll = P_JLL(PjllRaw); // Copy Indexes to new Leaf j__udyCopyWto3((uint8_t *) Pjll, StageA + Start, Pop1); #ifdef JUDYL // Copy to Values to new Leaf Pjvnew = JL_LEAF3VALUEAREA(Pjll, Pop1); JU_COPYMEM(Pjvnew, Pjv + Start, Pop1); #endif DBGCODE(JudyCheckSorted(Pjll, Pop1, 3);) DcdP0 = (JU_JPDCDPOP0(Pjp) & cJU_DCDMASK(4)) | (CIndex & cJU_DCDMASK(4-1)) | (Pop1 - 1); JU_JPSETADT(PjpJP, (Word_t)PjllRaw, DcdP0, cJU_JPLEAF3); } ExpCnt++; // Done? if (End == cJU_LEAF4_MAXPOP1) break; // New Expanse, Start and Count CIndex = StageA[End]; Start = End; } } // Now put all the Leaves below a BranchL or BranchB: if (ExpCnt <= cJU_BRANCHLMAXJPS) // put the Leaves below a BranchL { if (j__udyCreateBranchL(Pjp, StageJP, StageExp, ExpCnt, Pjpm) == -1) FREEALLEXIT(ExpCnt, StageJP, Pjpm); Pjp->jp_Type = cJU_JPBRANCH_L4; } else { if (j__udyStageJBBtoJBB(Pjp, &StageJBB, StageJP, SubJPCount, Pjpm) == -1) FREEALLEXIT(ExpCnt, StageJP, Pjpm); } return(1); } // j__udyCascade4() // **************************************************************************** // __ J U D Y C A S C A D E 5 // // Cascade from a cJU_JPLEAF5 to one of the following: // 1. if leaf is in 1 expanse: // compress it into a JPLEAF4 // 2. if leaf contains multiple expanses: // create linear or bitmap branch containing // each new expanse is either a: // JPIMMED_4_01 branch // JPLEAF4 FUNCTION int j__udyCascade5( Pjp_t Pjp, Pvoid_t Pjpm) { uint8_t * PLeaf; // pointer to leaf, explicit type. Word_t End, Start; // temporaries. Word_t ExpCnt; // count of expanses of splay. Word_t CIndex; // current Index word. JUDYLCODE(Pjv_t Pjv;) // value area of leaf. // Temp staging for parts(Leaves) of newly splayed leaf jp_t StageJP [cJU_LEAF5_MAXPOP1]; // JPs of new leaves Word_t StageA [cJU_LEAF5_MAXPOP1]; uint8_t StageExp [cJU_LEAF5_MAXPOP1]; // Expanses of new leaves uint8_t SubJPCount[cJU_NUMSUBEXPB]; // JPs in each subexpanse jbb_t StageJBB; // staged bitmap branch assert(JU_JPTYPE(Pjp) == cJU_JPLEAF5); assert((JU_JPDCDPOP0(Pjp) & 0xFFFFFFFFFF) == (cJU_LEAF5_MAXPOP1-1)); // Get the address of the Leaf PLeaf = (uint8_t *) P_JLL(Pjp->jp_Addr); // Extract 5 byte index Leaf to Word_t j__udyCopy5toW(StageA, PLeaf, cJU_LEAF5_MAXPOP1); // Get the address of the Leaf and Value area JUDYLCODE(Pjv = JL_LEAF5VALUEAREA(PLeaf, cJU_LEAF5_MAXPOP1);) // If Leaf is in 1 expanse -- just compress it (compare 1st, last & Index) CIndex = StageA[0]; if (!JU_DIGITATSTATE(CIndex ^ StageA[cJU_LEAF5_MAXPOP1-1], 5)) { Word_t DcdP0; Pjll_t PjllRaw; // pointer to new leaf. Pjll_t Pjll; JUDYLCODE(Pjv_t Pjvnew;) // value area of new leaf. // Alloc a 4 byte Index Leaf PjllRaw = j__udyAllocJLL4(cJU_LEAF5_MAXPOP1, Pjpm); if (PjllRaw == (Pjlb_t)NULL) return(-1); // out of memory Pjll = P_JLL(PjllRaw); // Copy Index area into new Leaf j__udyCopyWto4((uint8_t *) Pjll, StageA, cJU_LEAF5_MAXPOP1); #ifdef JUDYL // Copy Value area into new Leaf Pjvnew = JL_LEAF4VALUEAREA(Pjll, cJU_LEAF5_MAXPOP1); JU_COPYMEM(Pjvnew, Pjv, cJU_LEAF5_MAXPOP1); #endif DBGCODE(JudyCheckSorted(Pjll, cJU_LEAF5_MAXPOP1, 4);) DcdP0 = JU_JPDCDPOP0(Pjp) | (CIndex & cJU_DCDMASK(4)); JU_JPSETADT(Pjp, (Word_t)PjllRaw, DcdP0, cJU_JPLEAF4); return(1); } // Else in 2+ expanses, splay Leaf into smaller leaves at higher compression StageJBB = StageJBBZero; // zero staged bitmap branch ZEROJP(SubJPCount); // Splay the 5 byte index Leaf to 4 byte Index Leaves for (ExpCnt = Start = 0, End = 1; ; End++) { // Check if new expanse or last one if ( (End == cJU_LEAF5_MAXPOP1) || (JU_DIGITATSTATE(CIndex ^ StageA[End], 5)) ) { // Build a leaf below the previous expanse Pjp_t PjpJP = StageJP + ExpCnt; Word_t Pop1 = End - Start; Word_t expanse = JU_DIGITATSTATE(CIndex, 5); Word_t subexp = expanse / cJU_BITSPERSUBEXPB; // // set the bit that is the current expanse JU_JBB_BITMAP(&StageJBB, subexp) |= JU_BITPOSMASKB(expanse); #ifdef SUBEXPCOUNTS StageJBB.jbb_subPop1[subexp] += Pop1; // pop of subexpanse #endif // count number of expanses in each subexpanse SubJPCount[subexp]++; // Save byte expanse of leaf StageExp[ExpCnt] = JU_DIGITATSTATE(CIndex, 5); if (Pop1 == 1) // cJU_JPIMMED_4_01 { Word_t DcdP0; DcdP0 = (JU_JPDCDPOP0(Pjp) & cJU_DCDMASK(4)) | CIndex; #ifdef JUDY1 JU_JPSETADT(PjpJP, 0, DcdP0, cJ1_JPIMMED_4_01); #else // JUDYL JU_JPSETADT(PjpJP, Pjv[Start], DcdP0, cJL_JPIMMED_4_01); #endif // JUDYL } #ifdef JUDY1 else if (Pop1 <= cJ1_IMMED4_MAXPOP1) { // cJ1_JPIMMED_4_02..3: Judy1 64 // Copy to Index to JP as an immediate Leaf j__udyCopyWto4(PjpJP->jp_1Index, StageA + Start, Pop1); // Set pointer, type, population and Index size PjpJP->jp_Type = cJ1_JPIMMED_4_02 + Pop1 - 2; } #endif else { // cJU_JPLEAF4 Word_t DcdP0; Pjll_t PjllRaw; // pointer to new leaf. Pjll_t Pjll; JUDYLCODE(Pjv_t Pjvnew;) // value area of new leaf. // Get a new Leaf PjllRaw = j__udyAllocJLL4(Pop1, Pjpm); if (PjllRaw == (Pjll_t)NULL) FREEALLEXIT(ExpCnt, StageJP, Pjpm); Pjll = P_JLL(PjllRaw); // Copy Indexes to new Leaf j__udyCopyWto4((uint8_t *) Pjll, StageA + Start, Pop1); #ifdef JUDYL // Copy to Values to new Leaf Pjvnew = JL_LEAF4VALUEAREA(Pjll, Pop1); JU_COPYMEM(Pjvnew, Pjv + Start, Pop1); #endif DBGCODE(JudyCheckSorted(Pjll, Pop1, 4);) DcdP0 = (JU_JPDCDPOP0(Pjp) & cJU_DCDMASK(5)) | (CIndex & cJU_DCDMASK(5-1)) | (Pop1 - 1); JU_JPSETADT(PjpJP, (Word_t)PjllRaw, DcdP0, cJU_JPLEAF4); } ExpCnt++; // Done? if (End == cJU_LEAF5_MAXPOP1) break; // New Expanse, Start and Count CIndex = StageA[End]; Start = End; } } // Now put all the Leaves below a BranchL or BranchB: if (ExpCnt <= cJU_BRANCHLMAXJPS) // put the Leaves below a BranchL { if (j__udyCreateBranchL(Pjp, StageJP, StageExp, ExpCnt, Pjpm) == -1) FREEALLEXIT(ExpCnt, StageJP, Pjpm); Pjp->jp_Type = cJU_JPBRANCH_L5; } else { if (j__udyStageJBBtoJBB(Pjp, &StageJBB, StageJP, SubJPCount, Pjpm) == -1) FREEALLEXIT(ExpCnt, StageJP, Pjpm); } return(1); } // j__udyCascade5() // **************************************************************************** // __ J U D Y C A S C A D E 6 // // Cascade from a cJU_JPLEAF6 to one of the following: // 1. if leaf is in 1 expanse: // compress it into a JPLEAF5 // 2. if leaf contains multiple expanses: // create linear or bitmap branch containing // each new expanse is either a: // JPIMMED_5_01 ... JPIMMED_5_03 branch // JPIMMED_5_01 branch // JPLEAF5 FUNCTION int j__udyCascade6( Pjp_t Pjp, Pvoid_t Pjpm) { uint8_t * PLeaf; // pointer to leaf, explicit type. Word_t End, Start; // temporaries. Word_t ExpCnt; // count of expanses of splay. Word_t CIndex; // current Index word. JUDYLCODE(Pjv_t Pjv;) // value area of leaf. // Temp staging for parts(Leaves) of newly splayed leaf jp_t StageJP [cJU_LEAF6_MAXPOP1]; // JPs of new leaves Word_t StageA [cJU_LEAF6_MAXPOP1]; uint8_t StageExp [cJU_LEAF6_MAXPOP1]; // Expanses of new leaves uint8_t SubJPCount[cJU_NUMSUBEXPB]; // JPs in each subexpanse jbb_t StageJBB; // staged bitmap branch assert(JU_JPTYPE(Pjp) == cJU_JPLEAF6); assert((JU_JPDCDPOP0(Pjp) & 0xFFFFFFFFFFFF) == (cJU_LEAF6_MAXPOP1-1)); // Get the address of the Leaf PLeaf = (uint8_t *) P_JLL(Pjp->jp_Addr); // Extract 6 byte index Leaf to Word_t j__udyCopy6toW(StageA, PLeaf, cJU_LEAF6_MAXPOP1); // Get the address of the Leaf and Value area JUDYLCODE(Pjv = JL_LEAF6VALUEAREA(PLeaf, cJU_LEAF6_MAXPOP1);) // If Leaf is in 1 expanse -- just compress it (compare 1st, last & Index) CIndex = StageA[0]; if (!JU_DIGITATSTATE(CIndex ^ StageA[cJU_LEAF6_MAXPOP1-1], 6)) { Word_t DcdP0; Pjll_t PjllRaw; // pointer to new leaf. Pjll_t Pjll; JUDYLCODE(Pjv_t Pjvnew;) // value area of new leaf. // Alloc a 5 byte Index Leaf PjllRaw = j__udyAllocJLL5(cJU_LEAF6_MAXPOP1, Pjpm); if (PjllRaw == (Pjlb_t)NULL) return(-1); // out of memory Pjll = P_JLL(PjllRaw); // Copy Index area into new Leaf j__udyCopyWto5((uint8_t *) Pjll, StageA, cJU_LEAF6_MAXPOP1); #ifdef JUDYL // Copy Value area into new Leaf Pjvnew = JL_LEAF5VALUEAREA(Pjll, cJU_LEAF6_MAXPOP1); JU_COPYMEM(Pjvnew, Pjv, cJU_LEAF6_MAXPOP1); #endif DBGCODE(JudyCheckSorted(Pjll, cJU_LEAF6_MAXPOP1, 5);) DcdP0 = JU_JPDCDPOP0(Pjp) | (CIndex & cJU_DCDMASK(5)); JU_JPSETADT(Pjp, (Word_t)PjllRaw, DcdP0, cJU_JPLEAF5); return(1); } // Else in 2+ expanses, splay Leaf into smaller leaves at higher compression StageJBB = StageJBBZero; // zero staged bitmap branch ZEROJP(SubJPCount); // Splay the 6 byte index Leaf to 5 byte Index Leaves for (ExpCnt = Start = 0, End = 1; ; End++) { // Check if new expanse or last one if ( (End == cJU_LEAF6_MAXPOP1) || (JU_DIGITATSTATE(CIndex ^ StageA[End], 6)) ) { // Build a leaf below the previous expanse Pjp_t PjpJP = StageJP + ExpCnt; Word_t Pop1 = End - Start; Word_t expanse = JU_DIGITATSTATE(CIndex, 6); Word_t subexp = expanse / cJU_BITSPERSUBEXPB; // // set the bit that is the current expanse JU_JBB_BITMAP(&StageJBB, subexp) |= JU_BITPOSMASKB(expanse); #ifdef SUBEXPCOUNTS StageJBB.jbb_subPop1[subexp] += Pop1; // pop of subexpanse #endif // count number of expanses in each subexpanse SubJPCount[subexp]++; // Save byte expanse of leaf StageExp[ExpCnt] = JU_DIGITATSTATE(CIndex, 6); if (Pop1 == 1) // cJU_JPIMMED_5_01 { Word_t DcdP0; DcdP0 = (JU_JPDCDPOP0(Pjp) & cJU_DCDMASK(5)) | CIndex; #ifdef JUDY1 JU_JPSETADT(PjpJP, 0, DcdP0, cJ1_JPIMMED_5_01); #else // JUDYL JU_JPSETADT(PjpJP, Pjv[Start], DcdP0, cJL_JPIMMED_5_01); #endif // JUDYL } #ifdef JUDY1 else if (Pop1 <= cJ1_IMMED5_MAXPOP1) { // cJ1_JPIMMED_5_02..3: Judy1 64 // Copy to Index to JP as an immediate Leaf j__udyCopyWto5(PjpJP->jp_1Index, StageA + Start, Pop1); // Set pointer, type, population and Index size PjpJP->jp_Type = cJ1_JPIMMED_5_02 + Pop1 - 2; } #endif else { // cJU_JPLEAF5 Word_t DcdP0; Pjll_t PjllRaw; // pointer to new leaf. Pjll_t Pjll; JUDYLCODE(Pjv_t Pjvnew;) // value area of new leaf. // Get a new Leaf PjllRaw = j__udyAllocJLL5(Pop1, Pjpm); if (PjllRaw == (Pjll_t)NULL) FREEALLEXIT(ExpCnt, StageJP, Pjpm); Pjll = P_JLL(PjllRaw); // Copy Indexes to new Leaf j__udyCopyWto5((uint8_t *) Pjll, StageA + Start, Pop1); // Copy to Values to new Leaf #ifdef JUDYL Pjvnew = JL_LEAF5VALUEAREA(Pjll, Pop1); JU_COPYMEM(Pjvnew, Pjv + Start, Pop1); #endif DBGCODE(JudyCheckSorted(Pjll, Pop1, 5);) DcdP0 = (JU_JPDCDPOP0(Pjp) & cJU_DCDMASK(6)) | (CIndex & cJU_DCDMASK(6-1)) | (Pop1 - 1); JU_JPSETADT(PjpJP, (Word_t)PjllRaw, DcdP0, cJU_JPLEAF5); } ExpCnt++; // Done? if (End == cJU_LEAF6_MAXPOP1) break; // New Expanse, Start and Count CIndex = StageA[End]; Start = End; } } // Now put all the Leaves below a BranchL or BranchB: if (ExpCnt <= cJU_BRANCHLMAXJPS) // put the Leaves below a BranchL { if (j__udyCreateBranchL(Pjp, StageJP, StageExp, ExpCnt, Pjpm) == -1) FREEALLEXIT(ExpCnt, StageJP, Pjpm); Pjp->jp_Type = cJU_JPBRANCH_L6; } else { if (j__udyStageJBBtoJBB(Pjp, &StageJBB, StageJP, SubJPCount, Pjpm) == -1) FREEALLEXIT(ExpCnt, StageJP, Pjpm); } return(1); } // j__udyCascade6() // **************************************************************************** // __ J U D Y C A S C A D E 7 // // Cascade from a cJU_JPLEAF7 to one of the following: // 1. if leaf is in 1 expanse: // compress it into a JPLEAF6 // 2. if leaf contains multiple expanses: // create linear or bitmap branch containing // each new expanse is either a: // JPIMMED_6_01 ... JPIMMED_6_02 branch // JPIMMED_6_01 branch // JPLEAF6 FUNCTION int j__udyCascade7( Pjp_t Pjp, Pvoid_t Pjpm) { uint8_t * PLeaf; // pointer to leaf, explicit type. Word_t End, Start; // temporaries. Word_t ExpCnt; // count of expanses of splay. Word_t CIndex; // current Index word. JUDYLCODE(Pjv_t Pjv;) // value area of leaf. // Temp staging for parts(Leaves) of newly splayed leaf jp_t StageJP [cJU_LEAF7_MAXPOP1]; // JPs of new leaves Word_t StageA [cJU_LEAF7_MAXPOP1]; uint8_t StageExp [cJU_LEAF7_MAXPOP1]; // Expanses of new leaves uint8_t SubJPCount[cJU_NUMSUBEXPB]; // JPs in each subexpanse jbb_t StageJBB; // staged bitmap branch assert(JU_JPTYPE(Pjp) == cJU_JPLEAF7); assert(JU_JPDCDPOP0(Pjp) == (cJU_LEAF7_MAXPOP1-1)); // Get the address of the Leaf PLeaf = (uint8_t *) P_JLL(Pjp->jp_Addr); // Extract 7 byte index Leaf to Word_t j__udyCopy7toW(StageA, PLeaf, cJU_LEAF7_MAXPOP1); // Get the address of the Leaf and Value area JUDYLCODE(Pjv = JL_LEAF7VALUEAREA(PLeaf, cJU_LEAF7_MAXPOP1);) // If Leaf is in 1 expanse -- just compress it (compare 1st, last & Index) CIndex = StageA[0]; if (!JU_DIGITATSTATE(CIndex ^ StageA[cJU_LEAF7_MAXPOP1-1], 7)) { Word_t DcdP0; Pjll_t PjllRaw; // pointer to new leaf. Pjll_t Pjll; JUDYLCODE(Pjv_t Pjvnew;) // value area of new leaf. // Alloc a 6 byte Index Leaf PjllRaw = j__udyAllocJLL6(cJU_LEAF7_MAXPOP1, Pjpm); if (PjllRaw == (Pjlb_t)NULL) return(-1); // out of memory Pjll = P_JLL(PjllRaw); // Copy Index area into new Leaf j__udyCopyWto6((uint8_t *) Pjll, StageA, cJU_LEAF7_MAXPOP1); #ifdef JUDYL // Copy Value area into new Leaf Pjvnew = JL_LEAF6VALUEAREA(Pjll, cJU_LEAF7_MAXPOP1); JU_COPYMEM(Pjvnew, Pjv, cJU_LEAF7_MAXPOP1); #endif DBGCODE(JudyCheckSorted(Pjll, cJU_LEAF7_MAXPOP1, 6);) DcdP0 = JU_JPDCDPOP0(Pjp) | (CIndex & cJU_DCDMASK(6)); JU_JPSETADT(Pjp, (Word_t)PjllRaw, DcdP0, cJU_JPLEAF6); return(1); } // Else in 2+ expanses, splay Leaf into smaller leaves at higher compression StageJBB = StageJBBZero; // zero staged bitmap branch ZEROJP(SubJPCount); // Splay the 7 byte index Leaf to 6 byte Index Leaves for (ExpCnt = Start = 0, End = 1; ; End++) { // Check if new expanse or last one if ( (End == cJU_LEAF7_MAXPOP1) || (JU_DIGITATSTATE(CIndex ^ StageA[End], 7)) ) { // Build a leaf below the previous expanse Pjp_t PjpJP = StageJP + ExpCnt; Word_t Pop1 = End - Start; Word_t expanse = JU_DIGITATSTATE(CIndex, 7); Word_t subexp = expanse / cJU_BITSPERSUBEXPB; // // set the bit that is the current expanse JU_JBB_BITMAP(&StageJBB, subexp) |= JU_BITPOSMASKB(expanse); #ifdef SUBEXPCOUNTS StageJBB.jbb_subPop1[subexp] += Pop1; // pop of subexpanse #endif // count number of expanses in each subexpanse SubJPCount[subexp]++; // Save byte expanse of leaf StageExp[ExpCnt] = JU_DIGITATSTATE(CIndex, 7); if (Pop1 == 1) // cJU_JPIMMED_6_01 { Word_t DcdP0; DcdP0 = (JU_JPDCDPOP0(Pjp) & cJU_DCDMASK(6)) | CIndex; #ifdef JUDY1 JU_JPSETADT(PjpJP, 0, DcdP0, cJ1_JPIMMED_6_01); #else // JUDYL JU_JPSETADT(PjpJP, Pjv[Start], DcdP0, cJL_JPIMMED_6_01); #endif // JUDYL } #ifdef JUDY1 else if (Pop1 == cJ1_IMMED6_MAXPOP1) { // cJ1_JPIMMED_6_02: Judy1 64 // Copy to Index to JP as an immediate Leaf j__udyCopyWto6(PjpJP->jp_1Index, StageA + Start, 2); // Set pointer, type, population and Index size PjpJP->jp_Type = cJ1_JPIMMED_6_02; } #endif else { // cJU_JPLEAF6 Word_t DcdP0; Pjll_t PjllRaw; // pointer to new leaf. Pjll_t Pjll; JUDYLCODE(Pjv_t Pjvnew;) // value area of new leaf. // Get a new Leaf PjllRaw = j__udyAllocJLL6(Pop1, Pjpm); if (PjllRaw == (Pjll_t)NULL) FREEALLEXIT(ExpCnt, StageJP, Pjpm); Pjll = P_JLL(PjllRaw); // Copy Indexes to new Leaf j__udyCopyWto6((uint8_t *) Pjll, StageA + Start, Pop1); #ifdef JUDYL // Copy to Values to new Leaf Pjvnew = JL_LEAF6VALUEAREA(Pjll, Pop1); JU_COPYMEM(Pjvnew, Pjv + Start, Pop1); #endif DBGCODE(JudyCheckSorted(Pjll, Pop1, 6);) DcdP0 = (JU_JPDCDPOP0(Pjp) & cJU_DCDMASK(7)) | (CIndex & cJU_DCDMASK(7-1)) | (Pop1 - 1); JU_JPSETADT(PjpJP, (Word_t)PjllRaw, DcdP0, cJU_JPLEAF6); } ExpCnt++; // Done? if (End == cJU_LEAF7_MAXPOP1) break; // New Expanse, Start and Count CIndex = StageA[End]; Start = End; } } // Now put all the Leaves below a BranchL or BranchB: if (ExpCnt <= cJU_BRANCHLMAXJPS) // put the Leaves below a BranchL { if (j__udyCreateBranchL(Pjp, StageJP, StageExp, ExpCnt, Pjpm) == -1) FREEALLEXIT(ExpCnt, StageJP, Pjpm); Pjp->jp_Type = cJU_JPBRANCH_L7; } else { if (j__udyStageJBBtoJBB(Pjp, &StageJBB, StageJP, SubJPCount, Pjpm) == -1) FREEALLEXIT(ExpCnt, StageJP, Pjpm); } return(1); } // j__udyCascade7() #endif // JU_64BIT // **************************************************************************** // __ J U D Y C A S C A D E L // // (Compressed) cJU_LEAF3[7], cJ1_JPBRANCH_L. // // Cascade from a LEAFW (under Pjp) to one of the following: // 1. if LEAFW is in 1 expanse: // create linear branch with a JPLEAF3[7] under it // 2. LEAFW contains multiple expanses: // create linear or bitmap branch containing new expanses // each new expanse is either a: 32 64 // JPIMMED_3_01 branch Y N // JPIMMED_7_01 branch N Y // JPLEAF3 Y N // JPLEAF7 N Y FUNCTION int j__udyCascadeL( Pjp_t Pjp, Pvoid_t Pjpm) { Pjlw_t Pjlw; // leaf to work on. Word_t End, Start; // temporaries. Word_t ExpCnt; // count of expanses of splay. Word_t CIndex; // current Index word. JUDYLCODE(Pjv_t Pjv;) // value area of leaf. // Temp staging for parts(Leaves) of newly splayed leaf jp_t StageJP [cJU_LEAFW_MAXPOP1]; uint8_t StageExp[cJU_LEAFW_MAXPOP1]; uint8_t SubJPCount[cJU_NUMSUBEXPB]; // JPs in each subexpanse jbb_t StageJBB; // staged bitmap branch // Get the address of the Leaf Pjlw = P_JLW(Pjp->jp_Addr); assert(Pjlw[0] == (cJU_LEAFW_MAXPOP1 - 1)); // Get pointer to Value area of old Leaf JUDYLCODE(Pjv = JL_LEAFWVALUEAREA(Pjlw, cJU_LEAFW_MAXPOP1);) Pjlw++; // Now point to Index area // If Leaf is in 1 expanse -- first compress it (compare 1st, last & Index): CIndex = Pjlw[0]; // also used far below if (!JU_DIGITATSTATE(CIndex ^ Pjlw[cJU_LEAFW_MAXPOP1 - 1], cJU_ROOTSTATE)) { Pjll_t PjllRaw; // pointer to new leaf. Pjll_t Pjll; JUDYLCODE(Pjv_t Pjvnew;) // value area of new leaf. // Get the common expanse to all elements in Leaf StageExp[0] = JU_DIGITATSTATE(CIndex, cJU_ROOTSTATE); // Alloc a 3[7] byte Index Leaf #ifdef JU_64BIT PjllRaw = j__udyAllocJLL7(cJU_LEAFW_MAXPOP1, Pjpm); if (PjllRaw == (Pjlb_t)NULL) return(-1); // out of memory Pjll = P_JLL(PjllRaw); // Copy LEAFW to a cJU_JPLEAF7 j__udyCopyWto7((uint8_t *) Pjll, Pjlw, cJU_LEAFW_MAXPOP1); #ifdef JUDYL // Get the Value area of new Leaf Pjvnew = JL_LEAF7VALUEAREA(Pjll, cJU_LEAFW_MAXPOP1); JU_COPYMEM(Pjvnew, Pjv, cJU_LEAFW_MAXPOP1); #endif DBGCODE(JudyCheckSorted(Pjll, cJU_LEAFW_MAXPOP1, 7);) #else // 32 Bit PjllRaw = j__udyAllocJLL3(cJU_LEAFW_MAXPOP1, Pjpm); if (PjllRaw == (Pjll_t) NULL) return(-1); Pjll = P_JLL(PjllRaw); // Copy LEAFW to a cJU_JPLEAF3 j__udyCopyWto3((uint8_t *) Pjll, Pjlw, cJU_LEAFW_MAXPOP1); #ifdef JUDYL // Get the Value area of new Leaf Pjvnew = JL_LEAF3VALUEAREA(Pjll, cJU_LEAFW_MAXPOP1); JU_COPYMEM(Pjvnew, Pjv, cJU_LEAFW_MAXPOP1); #endif DBGCODE(JudyCheckSorted(Pjll, cJU_LEAFW_MAXPOP1, 3);) #endif // 32 Bit // Following not needed because cJU_DCDMASK(3[7]) is == 0 ////// StageJP[0].jp_DcdPopO |= (CIndex & cJU_DCDMASK(3[7])); #ifdef JU_64BIT JU_JPSETADT(&(StageJP[0]), (Word_t)PjllRaw, cJU_LEAFW_MAXPOP1-1, cJU_JPLEAF7); #else // 32BIT JU_JPSETADT(&(StageJP[0]), (Word_t)PjllRaw, cJU_LEAFW_MAXPOP1-1, cJU_JPLEAF3); #endif // 32BIT // Create a 1 element Linear branch if (j__udyCreateBranchL(Pjp, StageJP, StageExp, 1, Pjpm) == -1) return(-1); // Change the type of callers JP Pjp->jp_Type = cJU_JPBRANCH_L; return(1); } // Else in 2+ expanses, splay Leaf into smaller leaves at higher compression StageJBB = StageJBBZero; // zero staged bitmap branch ZEROJP(SubJPCount); // Splay the 4[8] byte Index Leaf to 3[7] byte Index Leaves for (ExpCnt = Start = 0, End = 1; ; End++) { // Check if new expanse or last one if ( (End == cJU_LEAFW_MAXPOP1) || (JU_DIGITATSTATE(CIndex ^ Pjlw[End], cJU_ROOTSTATE)) ) { // Build a leaf below the previous expanse Pjp_t PjpJP = StageJP + ExpCnt; Word_t Pop1 = End - Start; Word_t expanse = JU_DIGITATSTATE(CIndex, cJU_ROOTSTATE); Word_t subexp = expanse / cJU_BITSPERSUBEXPB; // // set the bit that is the current expanse JU_JBB_BITMAP(&StageJBB, subexp) |= JU_BITPOSMASKB(expanse); #ifdef SUBEXPCOUNTS StageJBB.jbb_subPop1[subexp] += Pop1; // pop of subexpanse #endif // count number of expanses in each subexpanse SubJPCount[subexp]++; // Save byte expanse of leaf StageExp[ExpCnt] = JU_DIGITATSTATE(CIndex, cJU_ROOTSTATE); if (Pop1 == 1) // cJU_JPIMMED_3[7]_01 { #ifdef JU_64BIT #ifdef JUDY1 JU_JPSETADT(PjpJP, 0, CIndex, cJ1_JPIMMED_7_01); #else // JUDYL JU_JPSETADT(PjpJP, Pjv[Start], CIndex, cJL_JPIMMED_7_01); #endif // JUDYL #else // JU_32BIT #ifdef JUDY1 JU_JPSETADT(PjpJP, 0, CIndex, cJ1_JPIMMED_3_01); #else // JUDYL JU_JPSETADT(PjpJP, Pjv[Start], CIndex, cJL_JPIMMED_3_01); #endif // JUDYL #endif // JU_32BIT } #ifdef JUDY1 #ifdef JU_64BIT else if (Pop1 <= cJ1_IMMED7_MAXPOP1) #else else if (Pop1 <= cJ1_IMMED3_MAXPOP1) #endif { // cJ1_JPIMMED_3_02 : Judy1 32 // cJ1_JPIMMED_7_02 : Judy1 64 // Copy to JP as an immediate Leaf #ifdef JU_64BIT j__udyCopyWto7(PjpJP->jp_1Index, Pjlw+Start, 2); PjpJP->jp_Type = cJ1_JPIMMED_7_02; #else j__udyCopyWto3(PjpJP->jp_1Index, Pjlw+Start, 2); PjpJP->jp_Type = cJ1_JPIMMED_3_02; #endif // 32 Bit } #endif // JUDY1 else // Linear Leaf JPLEAF3[7] { // cJU_JPLEAF3[7] Pjll_t PjllRaw; // pointer to new leaf. Pjll_t Pjll; JUDYLCODE(Pjv_t Pjvnew;) // value area of new leaf. #ifdef JU_64BIT PjllRaw = j__udyAllocJLL7(Pop1, Pjpm); if (PjllRaw == (Pjll_t) NULL) return(-1); Pjll = P_JLL(PjllRaw); j__udyCopyWto7((uint8_t *) Pjll, Pjlw + Start, Pop1); #ifdef JUDYL Pjvnew = JL_LEAF7VALUEAREA(Pjll, Pop1); JU_COPYMEM(Pjvnew, Pjv + Start, Pop1); #endif // JUDYL DBGCODE(JudyCheckSorted(Pjll, Pop1, 7);) #else // JU_64BIT - 32 Bit PjllRaw = j__udyAllocJLL3(Pop1, Pjpm); if (PjllRaw == (Pjll_t) NULL) return(-1); Pjll = P_JLL(PjllRaw); j__udyCopyWto3((uint8_t *) Pjll, Pjlw + Start, Pop1); #ifdef JUDYL Pjvnew = JL_LEAF3VALUEAREA(Pjll, Pop1); JU_COPYMEM(Pjvnew, Pjv + Start, Pop1); #endif // JUDYL DBGCODE(JudyCheckSorted(Pjll, Pop1, 3);) #endif // 32 Bit #ifdef JU_64BIT JU_JPSETADT(PjpJP, (Word_t)PjllRaw, Pop1 - 1, cJU_JPLEAF7); #else // JU_64BIT - 32 Bit JU_JPSETADT(PjpJP, (Word_t)PjllRaw, Pop1 - 1, cJU_JPLEAF3); #endif // 32 Bit } ExpCnt++; // Done? if (End == cJU_LEAFW_MAXPOP1) break; // New Expanse, Start and Count CIndex = Pjlw[End]; Start = End; } } // Now put all the Leaves below a BranchL or BranchB: if (ExpCnt <= cJU_BRANCHLMAXJPS) // put the Leaves below a BranchL { if (j__udyCreateBranchL(Pjp, StageJP, StageExp, ExpCnt, Pjpm) == -1) FREEALLEXIT(ExpCnt, StageJP, Pjpm); Pjp->jp_Type = cJU_JPBRANCH_L; } else { if (j__udyStageJBBtoJBB(Pjp, &StageJBB, StageJP, SubJPCount, Pjpm) == -1) FREEALLEXIT(ExpCnt, StageJP, Pjpm); Pjp->jp_Type = cJU_JPBRANCH_B; // cJU_LEAFW is out of sequence } return(1); } // j__udyCascadeL() judy-1.0.5/src/JudyCommon/JudyByCount.c0000644000175000017500000006724510204462077020172 0ustar troyhebetroyhebe// Copyright (C) 2000 - 2002 Hewlett-Packard Company // // This program is free software; you can redistribute it and/or modify it // under the term of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License // for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program; if not, write to the Free Software Foundation, // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // _________________ // @(#) $Revision: 4.28 $ $Source: /judy/src/JudyCommon/JudyByCount.c $ // // Judy*ByCount() function for Judy1 and JudyL. // Compile with one of -DJUDY1 or -DJUDYL. // // Compile with -DNOSMARTJBB, -DNOSMARTJBU, and/or -DNOSMARTJLB to build a // version with cache line optimizations deleted, for testing. // // Judy*ByCount() is a conceptual although not literal inverse of Judy*Count(). // Judy*Count() takes a pair of Indexes, and allows finding the ordinal of a // given Index (that is, its position in the list of valid indexes from the // beginning) as a degenerate case, because in general the count between two // Indexes, inclusive, is not always just the difference in their ordinals. // However, it suffices for Judy*ByCount() to simply be an ordinal-to-Index // mapper. // // Note: Like Judy*Count(), this code must "count sideways" in branches, which // can result in a lot of cache line fills. However, unlike Judy*Count(), this // code does not receive a specific Index, hence digit, where to start in each // branch, so it cant accurately calculate cache line fills required in each // direction. The best it can do is an approximation based on the total // population of the expanse (pop1 from Pjp) and the ordinal of the target // Index (see SETOFFSET()) within the expanse. // // Compile with -DSMARTMETRICS to obtain global variables containing smart // cache line metrics. Note: Dont turn this on simultaneously for this file // and JudyCount.c because they export the same globals. // **************************************************************************** #if (! (defined(JUDY1) || defined(JUDYL))) #error: One of -DJUDY1 or -DJUDYL must be specified. #endif #ifdef JUDY1 #include "Judy1.h" #else #include "JudyL.h" #endif #include "JudyPrivate1L.h" // These are imported from JudyCount.c: // // TBD: Should this be in common code? Exported from a header file? #ifdef JUDY1 extern Word_t j__udy1JPPop1(const Pjp_t Pjp); #define j__udyJPPop1 j__udy1JPPop1 #else extern Word_t j__udyLJPPop1(const Pjp_t Pjp); #define j__udyJPPop1 j__udyLJPPop1 #endif // Avoid duplicate symbols since this file is multi-compiled: #ifdef SMARTMETRICS #ifdef JUDY1 Word_t jbb_upward = 0; // counts of directions taken: Word_t jbb_downward = 0; Word_t jbu_upward = 0; Word_t jbu_downward = 0; Word_t jlb_upward = 0; Word_t jlb_downward = 0; #else extern Word_t jbb_upward; extern Word_t jbb_downward; extern Word_t jbu_upward; extern Word_t jbu_downward; extern Word_t jlb_upward; extern Word_t jlb_downward; #endif #endif // **************************************************************************** // J U D Y 1 B Y C O U N T // J U D Y L B Y C O U N T // // See the manual entry. #ifdef JUDY1 FUNCTION int Judy1ByCount #else FUNCTION PPvoid_t JudyLByCount #endif ( Pcvoid_t PArray, // root pointer to first branch/leaf in SM. Word_t Count, // ordinal of Index to find, 1..MAX. Word_t * PIndex, // to return found Index. PJError_t PJError // optional, for returning error info. ) { Word_t Count0; // Count, base-0, to match pop0. Word_t state; // current state in SM. Word_t pop1; // of current branch or leaf, or of expanse. Word_t pop1lower; // pop1 of expanses (JPs) below that for Count. Word_t digit; // current word in branch. Word_t jpcount; // JPs in a BranchB subexpanse. long jpnum; // JP number in a branch (base 0). long subexp; // for stepping through layer 1 (subexpanses). int offset; // index ordinal within a leaf, base 0. Pjp_t Pjp; // current JP in branch. Pjll_t Pjll; // current Judy linear leaf. // CHECK FOR EMPTY ARRAY OR NULL PINDEX: if (PArray == (Pvoid_t) NULL) JU_RET_NOTFOUND; if (PIndex == (PWord_t) NULL) { JU_SET_ERRNO(PJError, JU_ERRNO_NULLPINDEX); JUDY1CODE(return(JERRI );) JUDYLCODE(return(PPJERR);) } // Convert Count to Count0; assume special case of Count = 0 maps to ~0, as // desired, to represent the last index in a full array: // // Note: Think of Count0 as a reliable "number of Indexes below the target." Count0 = Count - 1; assert((Count || Count0 == ~0)); // ensure CPU is sane about 0 - 1. pop1lower = 0; if (JU_LEAFW_POP0(PArray) < cJU_LEAFW_MAXPOP1) // must be a LEAFW { Pjlw_t Pjlw = P_JLW(PArray); // first word of leaf. if (Count0 > Pjlw[0]) JU_RET_NOTFOUND; // too high. *PIndex = Pjlw[Count]; // Index, base 1. JU_RET_FOUND_LEAFW(Pjlw, Pjlw[0] + 1, Count0); } else { Pjpm_t Pjpm = P_JPM(PArray); if (Count0 > (Pjpm->jpm_Pop0)) JU_RET_NOTFOUND; // too high. Pjp = &(Pjpm->jpm_JP); pop1 = (Pjpm->jpm_Pop0) + 1; // goto SMByCount; } // COMMON CODE: // // Prepare to handle a root-level or lower-level branch: Save the current // state, obtain the total population for the branch in a state-dependent way, // and then branch to common code for multiple cases. // // For root-level branches, the state is always cJU_ROOTSTATE, and the array // population must already be set in pop1; it is not available in jp_DcdPopO. // // Note: The total population is only needed in cases where the common code // "counts down" instead of up to minimize cache line fills. However, its // available cheaply, and its better to do it with a constant shift (constant // state value) instead of a variable shift later "when needed". #define PREPB_ROOT(Next) \ state = cJU_ROOTSTATE; \ goto Next // Use PREPB_DCD() to first copy the Dcd bytes to *PIndex if there are any // (only if state < cJU_ROOTSTATE - 1): #define PREPB_DCD(Pjp,cState,Next) \ JU_SETDCD(*PIndex, Pjp, cState); \ PREPB((Pjp), cState, Next) #define PREPB(Pjp,cState,Next) \ state = (cState); \ pop1 = JU_JPBRANCH_POP0(Pjp, (cState)) + 1; \ goto Next // Calculate whether the ordinal of an Index within a given expanse falls in // the lower or upper half of the expanses population, taking care with // unsigned math and boundary conditions: // // Note: Assume the ordinal falls within the expanses population, that is, // 0 < (Count - Pop1lower) <= Pop1exp (assuming infinite math). // // Note: If the ordinal is the middle element, it doesnt matter whether // LOWERHALF() is TRUE or FALSE. #define LOWERHALF(Count0,Pop1lower,Pop1exp) \ (((Count0) - (Pop1lower)) < ((Pop1exp) / 2)) // Calculate the (signed) offset within a leaf to the desired ordinal (Count - // Pop1lower; offset is one less), and optionally ensure its in range: #define SETOFFSET(Offset,Count0,Pop1lower,Pjp) \ (Offset) = (Count0) - (Pop1lower); \ assert((Offset) >= 0); \ assert((Offset) <= JU_JPLEAF_POP0(Pjp)) // Variations for immediate indexes, with and without pop1-specific assertions: #define SETOFFSET_IMM_CK(Offset,Count0,Pop1lower,cPop1) \ (Offset) = (Count0) - (Pop1lower); \ assert((Offset) >= 0); \ assert((Offset) < (cPop1)) #define SETOFFSET_IMM(Offset,Count0,Pop1lower) \ (Offset) = (Count0) - (Pop1lower) // STATE MACHINE -- TRAVERSE TREE: // // In branches, look for the expanse (digit), if any, where the total pop1 // below or at that expanse would meet or exceed Count, meaning the Index must // be in this expanse. SMByCount: // return here for next branch/leaf. switch (JU_JPTYPE(Pjp)) { // ---------------------------------------------------------------------------- // LINEAR BRANCH; count populations in JPs in the JBL upwards until finding the // expanse (digit) containing Count, and "recurse". // // Note: There are no null JPs in a JBL; watch out for pop1 == 0. // // Note: A JBL should always fit in one cache line => no need to count up // versus down to save cache line fills. // // TBD: The previous is no longer true. Consider enhancing this code to count // up/down, but it can wait for a later tuning phase. In the meantime, PREPB() // sets pop1 for the whole array, but that value is not used here. 001215: // Maybe its true again? case cJU_JPBRANCH_L2: PREPB_DCD(Pjp, 2, BranchL); #ifndef JU_64BIT case cJU_JPBRANCH_L3: PREPB( Pjp, 3, BranchL); #else case cJU_JPBRANCH_L3: PREPB_DCD(Pjp, 3, BranchL); case cJU_JPBRANCH_L4: PREPB_DCD(Pjp, 4, BranchL); case cJU_JPBRANCH_L5: PREPB_DCD(Pjp, 5, BranchL); case cJU_JPBRANCH_L6: PREPB_DCD(Pjp, 6, BranchL); case cJU_JPBRANCH_L7: PREPB( Pjp, 7, BranchL); #endif case cJU_JPBRANCH_L: PREPB_ROOT( BranchL); { Pjbl_t Pjbl; // Common code (state-independent) for all cases of linear branches: BranchL: Pjbl = P_JBL(Pjp->jp_Addr); for (jpnum = 0; jpnum < (Pjbl->jbl_NumJPs); ++jpnum) { if ((pop1 = j__udyJPPop1((Pjbl->jbl_jp) + jpnum)) == cJU_ALLONES) { JU_SET_ERRNO(PJError, JU_ERRNO_CORRUPT); JUDY1CODE(return(JERRI );) JUDYLCODE(return(PPJERR);) } assert(pop1 != 0); // Warning: pop1lower and pop1 are unsigned, so do not subtract 1 and compare // >=, but instead use the following expression: if (pop1lower + pop1 > Count0) // Index is in this expanse. { JU_SETDIGIT(*PIndex, Pjbl->jbl_Expanse[jpnum], state); Pjp = (Pjbl->jbl_jp) + jpnum; goto SMByCount; // look under this expanse. } pop1lower += pop1; // add this JPs pop1. } JU_SET_ERRNO(PJError, JU_ERRNO_CORRUPT); // should never get here. JUDY1CODE(return(JERRI );) JUDYLCODE(return(PPJERR);) } // case cJU_JPBRANCH_L // ---------------------------------------------------------------------------- // BITMAP BRANCH; count populations in JPs in the JBB upwards or downwards // until finding the expanse (digit) containing Count, and "recurse". // // Note: There are no null JPs in a JBB; watch out for pop1 == 0. case cJU_JPBRANCH_B2: PREPB_DCD(Pjp, 2, BranchB); #ifndef JU_64BIT case cJU_JPBRANCH_B3: PREPB( Pjp, 3, BranchB); #else case cJU_JPBRANCH_B3: PREPB_DCD(Pjp, 3, BranchB); case cJU_JPBRANCH_B4: PREPB_DCD(Pjp, 4, BranchB); case cJU_JPBRANCH_B5: PREPB_DCD(Pjp, 5, BranchB); case cJU_JPBRANCH_B6: PREPB_DCD(Pjp, 6, BranchB); case cJU_JPBRANCH_B7: PREPB( Pjp, 7, BranchB); #endif case cJU_JPBRANCH_B: PREPB_ROOT( BranchB); { Pjbb_t Pjbb; // Common code (state-independent) for all cases of bitmap branches: BranchB: Pjbb = P_JBB(Pjp->jp_Addr); // Shorthand for one subexpanse in a bitmap and for one JP in a bitmap branch: // // Note: BMPJP0 exists separately to support assertions. #define BMPJP0(Subexp) (P_JP(JU_JBB_PJP(Pjbb, Subexp))) #define BMPJP(Subexp,JPnum) (BMPJP0(Subexp) + (JPnum)) // Common code for descending through a JP: // // Determine the digit for the expanse and save it in *PIndex; then "recurse". #define JBB_FOUNDEXPANSE \ { \ JU_BITMAPDIGITB(digit, subexp, JU_JBB_BITMAP(Pjbb,subexp), jpnum); \ JU_SETDIGIT(*PIndex, digit, state); \ Pjp = BMPJP(subexp, jpnum); \ goto SMByCount; \ } #ifndef NOSMARTJBB // enable to turn off smart code for comparison purposes. // FIGURE OUT WHICH DIRECTION CAUSES FEWER CACHE LINE FILLS; adding the pop1s // in JPs upwards, or subtracting the pop1s in JPs downwards: // // See header comments about limitations of this for Judy*ByCount(). #endif // COUNT UPWARD, adding each "below" JPs pop1: #ifndef NOSMARTJBB // enable to turn off smart code for comparison purposes. if (LOWERHALF(Count0, pop1lower, pop1)) { #endif #ifdef SMARTMETRICS ++jbb_upward; #endif for (subexp = 0; subexp < cJU_NUMSUBEXPB; ++subexp) { if ((jpcount = j__udyCountBitsB(JU_JBB_BITMAP(Pjbb,subexp))) && (BMPJP0(subexp) == (Pjp_t) NULL)) { JU_SET_ERRNO(PJError, JU_ERRNO_CORRUPT); // null ptr. JUDY1CODE(return(JERRI );) JUDYLCODE(return(PPJERR);) } // Note: An empty subexpanse (jpcount == 0) is handled "for free": for (jpnum = 0; jpnum < jpcount; ++jpnum) { if ((pop1 = j__udyJPPop1(BMPJP(subexp, jpnum))) == cJU_ALLONES) { JU_SET_ERRNO(PJError, JU_ERRNO_CORRUPT); JUDY1CODE(return(JERRI );) JUDYLCODE(return(PPJERR);) } assert(pop1 != 0); // Warning: pop1lower and pop1 are unsigned, see earlier comment: if (pop1lower + pop1 > Count0) JBB_FOUNDEXPANSE; // Index is in this expanse. pop1lower += pop1; // add this JPs pop1. } } #ifndef NOSMARTJBB // enable to turn off smart code for comparison purposes. } // COUNT DOWNWARD, subtracting each "above" JPs pop1 from the whole expanses // pop1: else { #ifdef SMARTMETRICS ++jbb_downward; #endif pop1lower += pop1; // add whole branch to start. for (subexp = cJU_NUMSUBEXPB - 1; subexp >= 0; --subexp) { if ((jpcount = j__udyCountBitsB(JU_JBB_BITMAP(Pjbb, subexp))) && (BMPJP0(subexp) == (Pjp_t) NULL)) { JU_SET_ERRNO(PJError, JU_ERRNO_CORRUPT); // null ptr. JUDY1CODE(return(JERRI );) JUDYLCODE(return(PPJERR);) } // Note: An empty subexpanse (jpcount == 0) is handled "for free": for (jpnum = jpcount - 1; jpnum >= 0; --jpnum) { if ((pop1 = j__udyJPPop1(BMPJP(subexp, jpnum))) == cJU_ALLONES) { JU_SET_ERRNO(PJError, JU_ERRNO_CORRUPT); JUDY1CODE(return(JERRI );) JUDYLCODE(return(PPJERR);) } assert(pop1 != 0); // Warning: pop1lower and pop1 are unsigned, see earlier comment: pop1lower -= pop1; // Beware unsigned math problems: if ((pop1lower == 0) || (pop1lower - 1 < Count0)) JBB_FOUNDEXPANSE; // Index is in this expanse. } } } #endif // NOSMARTJBB JU_SET_ERRNO(PJError, JU_ERRNO_CORRUPT); // should never get here. JUDY1CODE(return(JERRI );) JUDYLCODE(return(PPJERR);) } // case cJU_JPBRANCH_B // ---------------------------------------------------------------------------- // UNCOMPRESSED BRANCH; count populations in JPs in the JBU upwards or // downwards until finding the expanse (digit) containing Count, and "recurse". case cJU_JPBRANCH_U2: PREPB_DCD(Pjp, 2, BranchU); #ifndef JU_64BIT case cJU_JPBRANCH_U3: PREPB( Pjp, 3, BranchU); #else case cJU_JPBRANCH_U3: PREPB_DCD(Pjp, 3, BranchU); case cJU_JPBRANCH_U4: PREPB_DCD(Pjp, 4, BranchU); case cJU_JPBRANCH_U5: PREPB_DCD(Pjp, 5, BranchU); case cJU_JPBRANCH_U6: PREPB_DCD(Pjp, 6, BranchU); case cJU_JPBRANCH_U7: PREPB( Pjp, 7, BranchU); #endif case cJU_JPBRANCH_U: PREPB_ROOT( BranchU); { Pjbu_t Pjbu; // Common code (state-independent) for all cases of uncompressed branches: BranchU: Pjbu = P_JBU(Pjp->jp_Addr); // Common code for descending through a JP: // // Save the digit for the expanse in *PIndex, then "recurse". #define JBU_FOUNDEXPANSE \ { \ JU_SETDIGIT(*PIndex, jpnum, state); \ Pjp = (Pjbu->jbu_jp) + jpnum; \ goto SMByCount; \ } #ifndef NOSMARTJBU // enable to turn off smart code for comparison purposes. // FIGURE OUT WHICH DIRECTION CAUSES FEWER CACHE LINE FILLS; adding the pop1s // in JPs upwards, or subtracting the pop1s in JPs downwards: // // See header comments about limitations of this for Judy*ByCount(). #endif // COUNT UPWARD, simply adding the pop1 of each JP: #ifndef NOSMARTJBU // enable to turn off smart code for comparison purposes. if (LOWERHALF(Count0, pop1lower, pop1)) { #endif #ifdef SMARTMETRICS ++jbu_upward; #endif for (jpnum = 0; jpnum < cJU_BRANCHUNUMJPS; ++jpnum) { // shortcut, save a function call: if ((Pjbu->jbu_jp[jpnum].jp_Type) <= cJU_JPNULLMAX) continue; if ((pop1 = j__udyJPPop1((Pjbu->jbu_jp) + jpnum)) == cJU_ALLONES) { JU_SET_ERRNO(PJError, JU_ERRNO_CORRUPT); JUDY1CODE(return(JERRI );) JUDYLCODE(return(PPJERR);) } assert(pop1 != 0); // Warning: pop1lower and pop1 are unsigned, see earlier comment: if (pop1lower + pop1 > Count0) JBU_FOUNDEXPANSE; // Index is in this expanse. pop1lower += pop1; // add this JPs pop1. } #ifndef NOSMARTJBU // enable to turn off smart code for comparison purposes. } // COUNT DOWNWARD, subtracting the pop1 of each JP above from the whole // expanses pop1: else { #ifdef SMARTMETRICS ++jbu_downward; #endif pop1lower += pop1; // add whole branch to start. for (jpnum = cJU_BRANCHUNUMJPS - 1; jpnum >= 0; --jpnum) { // shortcut, save a function call: if ((Pjbu->jbu_jp[jpnum].jp_Type) <= cJU_JPNULLMAX) continue; if ((pop1 = j__udyJPPop1(Pjbu->jbu_jp + jpnum)) == cJU_ALLONES) { JU_SET_ERRNO(PJError, JU_ERRNO_CORRUPT); JUDY1CODE(return(JERRI );) JUDYLCODE(return(PPJERR);) } assert(pop1 != 0); // Warning: pop1lower and pop1 are unsigned, see earlier comment: pop1lower -= pop1; // Beware unsigned math problems: if ((pop1lower == 0) || (pop1lower - 1 < Count0)) JBU_FOUNDEXPANSE; // Index is in this expanse. } } #endif // NOSMARTJBU JU_SET_ERRNO(PJError, JU_ERRNO_CORRUPT); // should never get here. JUDY1CODE(return(JERRI );) JUDYLCODE(return(PPJERR);) } // case cJU_JPBRANCH_U // ---------------------------------------------------------------------------- // LINEAR LEAF: // // Return the Index at the proper ordinal (see SETOFFSET()) in the leaf. First // copy Dcd bytes, if there are any (only if state < cJU_ROOTSTATE - 1), to // *PIndex. // // Note: The preceding branch traversal code MIGHT set pop1 for this expanse // (linear leaf) as a side-effect, but dont depend on that (for JUDYL, which // is the only cases that need it anyway). #define PREPL_DCD(cState) \ JU_SETDCD(*PIndex, Pjp, cState); \ PREPL #ifdef JUDY1 #define PREPL_SETPOP1 // not needed in any cases. #else #define PREPL_SETPOP1 pop1 = JU_JPLEAF_POP0(Pjp) + 1 #endif #define PREPL \ Pjll = P_JLL(Pjp->jp_Addr); \ PREPL_SETPOP1; \ SETOFFSET(offset, Count0, pop1lower, Pjp) #if (defined(JUDYL) || (! defined(JU_64BIT))) case cJU_JPLEAF1: PREPL_DCD(1); JU_SETDIGIT1(*PIndex, ((uint8_t *) Pjll)[offset]); JU_RET_FOUND_LEAF1(Pjll, pop1, offset); #endif case cJU_JPLEAF2: PREPL_DCD(2); *PIndex = (*PIndex & (~JU_LEASTBYTESMASK(2))) | ((uint16_t *) Pjll)[offset]; JU_RET_FOUND_LEAF2(Pjll, pop1, offset); #ifndef JU_64BIT case cJU_JPLEAF3: { Word_t lsb; PREPL; JU_COPY3_PINDEX_TO_LONG(lsb, ((uint8_t *) Pjll) + (3 * offset)); *PIndex = (*PIndex & (~JU_LEASTBYTESMASK(3))) | lsb; JU_RET_FOUND_LEAF3(Pjll, pop1, offset); } #else case cJU_JPLEAF3: { Word_t lsb; PREPL_DCD(3); JU_COPY3_PINDEX_TO_LONG(lsb, ((uint8_t *) Pjll) + (3 * offset)); *PIndex = (*PIndex & (~JU_LEASTBYTESMASK(3))) | lsb; JU_RET_FOUND_LEAF3(Pjll, pop1, offset); } case cJU_JPLEAF4: PREPL_DCD(4); *PIndex = (*PIndex & (~JU_LEASTBYTESMASK(4))) | ((uint32_t *) Pjll)[offset]; JU_RET_FOUND_LEAF4(Pjll, pop1, offset); case cJU_JPLEAF5: { Word_t lsb; PREPL_DCD(5); JU_COPY5_PINDEX_TO_LONG(lsb, ((uint8_t *) Pjll) + (5 * offset)); *PIndex = (*PIndex & (~JU_LEASTBYTESMASK(5))) | lsb; JU_RET_FOUND_LEAF5(Pjll, pop1, offset); } case cJU_JPLEAF6: { Word_t lsb; PREPL_DCD(6); JU_COPY6_PINDEX_TO_LONG(lsb, ((uint8_t *) Pjll) + (6 * offset)); *PIndex = (*PIndex & (~JU_LEASTBYTESMASK(6))) | lsb; JU_RET_FOUND_LEAF6(Pjll, pop1, offset); } case cJU_JPLEAF7: { Word_t lsb; PREPL; JU_COPY7_PINDEX_TO_LONG(lsb, ((uint8_t *) Pjll) + (7 * offset)); *PIndex = (*PIndex & (~JU_LEASTBYTESMASK(7))) | lsb; JU_RET_FOUND_LEAF7(Pjll, pop1, offset); } #endif // ---------------------------------------------------------------------------- // BITMAP LEAF: // // Return the Index at the proper ordinal (see SETOFFSET()) in the leaf by // counting bits. First copy Dcd bytes (always present since state 1 < // cJU_ROOTSTATE) to *PIndex. // // Note: The preceding branch traversal code MIGHT set pop1 for this expanse // (bitmap leaf) as a side-effect, but dont depend on that. case cJU_JPLEAF_B1: { Pjlb_t Pjlb; JU_SETDCD(*PIndex, Pjp, 1); Pjlb = P_JLB(Pjp->jp_Addr); pop1 = JU_JPLEAF_POP0(Pjp) + 1; // COUNT UPWARD, adding the pop1 of each subexpanse: // // The entire bitmap should fit in one cache line, but still try to save some // CPU time by counting the fewest possible number of subexpanses from the // bitmap. // // See header comments about limitations of this for Judy*ByCount(). #ifndef NOSMARTJLB // enable to turn off smart code for comparison purposes. if (LOWERHALF(Count0, pop1lower, pop1)) { #endif #ifdef SMARTMETRICS ++jlb_upward; #endif for (subexp = 0; subexp < cJU_NUMSUBEXPL; ++subexp) { pop1 = j__udyCountBitsL(JU_JLB_BITMAP(Pjlb, subexp)); // Warning: pop1lower and pop1 are unsigned, see earlier comment: if (pop1lower + pop1 > Count0) goto LeafB1; // Index is in this subexpanse. pop1lower += pop1; // add this subexpanses pop1. } #ifndef NOSMARTJLB // enable to turn off smart code for comparison purposes. } // COUNT DOWNWARD, subtracting each "above" subexpanses pop1 from the whole // expanses pop1: else { #ifdef SMARTMETRICS ++jlb_downward; #endif pop1lower += pop1; // add whole leaf to start. for (subexp = cJU_NUMSUBEXPL - 1; subexp >= 0; --subexp) { pop1lower -= j__udyCountBitsL(JU_JLB_BITMAP(Pjlb, subexp)); // Beware unsigned math problems: if ((pop1lower == 0) || (pop1lower - 1 < Count0)) goto LeafB1; // Index is in this subexpanse. } } #endif // NOSMARTJLB JU_SET_ERRNO(PJError, JU_ERRNO_CORRUPT); // should never get here. JUDY1CODE(return(JERRI );) JUDYLCODE(return(PPJERR);) // RETURN INDEX FOUND: // // Come here with subexp set to the correct subexpanse, and pop1lower set to // the sum for all lower expanses and subexpanses in the Judy tree. Calculate // and save in *PIndex the digit corresponding to the ordinal in this // subexpanse. LeafB1: SETOFFSET(offset, Count0, pop1lower, Pjp); JU_BITMAPDIGITL(digit, subexp, JU_JLB_BITMAP(Pjlb, subexp), offset); JU_SETDIGIT1(*PIndex, digit); JU_RET_FOUND_LEAF_B1(Pjlb, subexp, offset); // == return((PPvoid_t) (P_JV(JL_JLB_PVALUE(Pjlb, subexp)) + offset)) } // case cJU_JPLEAF_B1 #ifdef JUDY1 // ---------------------------------------------------------------------------- // FULL POPULATION: // // Copy Dcd bytes (always present since state 1 < cJU_ROOTSTATE) to *PIndex, // then set the appropriate digit for the ordinal (see SETOFFSET()) in the leaf // as the LSB in *PIndex. case cJ1_JPFULLPOPU1: JU_SETDCD(*PIndex, Pjp, 1); SETOFFSET(offset, Count0, pop1lower, Pjp); assert(offset >= 0); assert(offset <= cJU_JPFULLPOPU1_POP0); JU_SETDIGIT1(*PIndex, offset); JU_RET_FOUND_FULLPOPU1; #endif // ---------------------------------------------------------------------------- // IMMEDIATE: // // Locate the Index with the proper ordinal (see SETOFFSET()) in the Immediate, // depending on leaf Index Size and pop1. Note: There are no Dcd bytes in an // Immediate JP, but in a cJU_JPIMMED_*_01 JP, the field holds the least bytes // of the immediate Index. #define SET_01(cState) JU_SETDIGITS(*PIndex, JU_JPDCDPOP0(Pjp), cState) case cJU_JPIMMED_1_01: SET_01(1); goto Imm_01; case cJU_JPIMMED_2_01: SET_01(2); goto Imm_01; case cJU_JPIMMED_3_01: SET_01(3); goto Imm_01; #ifdef JU_64BIT case cJU_JPIMMED_4_01: SET_01(4); goto Imm_01; case cJU_JPIMMED_5_01: SET_01(5); goto Imm_01; case cJU_JPIMMED_6_01: SET_01(6); goto Imm_01; case cJU_JPIMMED_7_01: SET_01(7); goto Imm_01; #endif Imm_01: DBGCODE(SETOFFSET_IMM_CK(offset, Count0, pop1lower, 1);) JU_RET_FOUND_IMM_01(Pjp); // Shorthand for where to find start of Index bytes array: #ifdef JUDY1 #define PJI (Pjp->jp_1Index) #else #define PJI (Pjp->jp_LIndex) #endif // Optional code to check the remaining ordinal (see SETOFFSET_IMM()) against // the Index Size of the Immediate: #ifndef DEBUG // simple placeholder: #define IMM(cPop1,Next) \ goto Next #else // extra pop1-specific checking: #define IMM(cPop1,Next) \ SETOFFSET_IMM_CK(offset, Count0, pop1lower, cPop1); \ goto Next #endif case cJU_JPIMMED_1_02: IMM( 2, Imm1); case cJU_JPIMMED_1_03: IMM( 3, Imm1); #if (defined(JUDY1) || defined(JU_64BIT)) case cJU_JPIMMED_1_04: IMM( 4, Imm1); case cJU_JPIMMED_1_05: IMM( 5, Imm1); case cJU_JPIMMED_1_06: IMM( 6, Imm1); case cJU_JPIMMED_1_07: IMM( 7, Imm1); #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_1_08: IMM( 8, Imm1); case cJ1_JPIMMED_1_09: IMM( 9, Imm1); case cJ1_JPIMMED_1_10: IMM(10, Imm1); case cJ1_JPIMMED_1_11: IMM(11, Imm1); case cJ1_JPIMMED_1_12: IMM(12, Imm1); case cJ1_JPIMMED_1_13: IMM(13, Imm1); case cJ1_JPIMMED_1_14: IMM(14, Imm1); case cJ1_JPIMMED_1_15: IMM(15, Imm1); #endif Imm1: SETOFFSET_IMM(offset, Count0, pop1lower); JU_SETDIGIT1(*PIndex, ((uint8_t *) PJI)[offset]); JU_RET_FOUND_IMM(Pjp, offset); #if (defined(JUDY1) || defined(JU_64BIT)) case cJU_JPIMMED_2_02: IMM(2, Imm2); case cJU_JPIMMED_2_03: IMM(3, Imm2); #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_2_04: IMM(4, Imm2); case cJ1_JPIMMED_2_05: IMM(5, Imm2); case cJ1_JPIMMED_2_06: IMM(6, Imm2); case cJ1_JPIMMED_2_07: IMM(7, Imm2); #endif #if (defined(JUDY1) || defined(JU_64BIT)) Imm2: SETOFFSET_IMM(offset, Count0, pop1lower); *PIndex = (*PIndex & (~JU_LEASTBYTESMASK(2))) | ((uint16_t *) PJI)[offset]; JU_RET_FOUND_IMM(Pjp, offset); #endif #if (defined(JUDY1) || defined(JU_64BIT)) case cJU_JPIMMED_3_02: IMM(2, Imm3); #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_3_03: IMM(3, Imm3); case cJ1_JPIMMED_3_04: IMM(4, Imm3); case cJ1_JPIMMED_3_05: IMM(5, Imm3); #endif #if (defined(JUDY1) || defined(JU_64BIT)) Imm3: { Word_t lsb; SETOFFSET_IMM(offset, Count0, pop1lower); JU_COPY3_PINDEX_TO_LONG(lsb, ((uint8_t *) PJI) + (3 * offset)); *PIndex = (*PIndex & (~JU_LEASTBYTESMASK(3))) | lsb; JU_RET_FOUND_IMM(Pjp, offset); } #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_4_02: IMM(2, Imm4); case cJ1_JPIMMED_4_03: IMM(3, Imm4); Imm4: SETOFFSET_IMM(offset, Count0, pop1lower); *PIndex = (*PIndex & (~JU_LEASTBYTESMASK(4))) | ((uint32_t *) PJI)[offset]; JU_RET_FOUND_IMM(Pjp, offset); case cJ1_JPIMMED_5_02: IMM(2, Imm5); case cJ1_JPIMMED_5_03: IMM(3, Imm5); Imm5: { Word_t lsb; SETOFFSET_IMM(offset, Count0, pop1lower); JU_COPY5_PINDEX_TO_LONG(lsb, ((uint8_t *) PJI) + (5 * offset)); *PIndex = (*PIndex & (~JU_LEASTBYTESMASK(5))) | lsb; JU_RET_FOUND_IMM(Pjp, offset); } case cJ1_JPIMMED_6_02: IMM(2, Imm6); Imm6: { Word_t lsb; SETOFFSET_IMM(offset, Count0, pop1lower); JU_COPY6_PINDEX_TO_LONG(lsb, ((uint8_t *) PJI) + (6 * offset)); *PIndex = (*PIndex & (~JU_LEASTBYTESMASK(6))) | lsb; JU_RET_FOUND_IMM(Pjp, offset); } case cJ1_JPIMMED_7_02: IMM(2, Imm7); Imm7: { Word_t lsb; SETOFFSET_IMM(offset, Count0, pop1lower); JU_COPY7_PINDEX_TO_LONG(lsb, ((uint8_t *) PJI) + (7 * offset)); *PIndex = (*PIndex & (~JU_LEASTBYTESMASK(7))) | lsb; JU_RET_FOUND_IMM(Pjp, offset); } #endif // (JUDY1 && JU_64BIT) // ---------------------------------------------------------------------------- // UNEXPECTED JP TYPES: default: JU_SET_ERRNO(PJError, JU_ERRNO_CORRUPT); JUDY1CODE(return(JERRI );) JUDYLCODE(return(PPJERR);) } // SMByCount switch. /*NOTREACHED*/ } // Judy1ByCount() / JudyLByCount() judy-1.0.5/src/JudyCommon/JudyMallocIF.c0000644000175000017500000005663010622113030020213 0ustar troyhebetroyhebe// Copyright (C) 2000 - 2002 Hewlett-Packard Company // // This program is free software; you can redistribute it and/or modify it // under the term of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License // for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program; if not, write to the Free Software Foundation, // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // _________________ // @(#) $Revision: 4.45 $ $Source: /judy/src/JudyCommon/JudyMallocIF.c $ // // Judy malloc/free interface functions for Judy1 and JudyL. // // Compile with one of -DJUDY1 or -DJUDYL. // // Compile with -DTRACEMI (Malloc Interface) to turn on tracing of malloc/free // calls at the interface level. (See also TRACEMF in lower-level code.) // Use -DTRACEMI2 for a terser format suitable for trace analysis. // // There can be malloc namespace bits in the LSBs of "raw" addresses from most, // but not all, of the j__udy*Alloc*() functions; see also JudyPrivate.h. To // test the Judy code, compile this file with -DMALLOCBITS and use debug flavor // only (for assertions). This test ensures that (a) all callers properly mask // the namespace bits out before dereferencing a pointer (or else a core dump // occurs), and (b) all callers send "raw" (unmasked) addresses to // j__udy*Free*() calls. // // Note: Currently -DDEBUG turns on MALLOCBITS automatically. #if (! (defined(JUDY1) || defined(JUDYL))) #error: One of -DJUDY1 or -DJUDYL must be specified. #endif #ifdef JUDY1 #include "Judy1.h" #else #include "JudyL.h" #endif #include "JudyPrivate1L.h" // Set "hidden" global j__uMaxWords to the maximum number of words to allocate // to any one array (large enough to have a JPM, otherwise j__uMaxWords is // ignored), to trigger a fake malloc error when the number is exceeded. Note, // this code is always executed, not #ifdefd, because its virtually free. // // Note: To keep the MALLOC macro faster and simpler, set j__uMaxWords to // MAXINT, not zero, by default. Word_t j__uMaxWords = ~0UL; // This macro hides the faking of a malloc failure: // // Note: To keep this fast, just compare WordsPrev to j__uMaxWords without the // complexity of first adding WordsNow, meaning the trigger point is not // exactly where you might assume, but it shouldnt matter. #define MALLOC(MallocFunc,WordsPrev,WordsNow) \ (((WordsPrev) > j__uMaxWords) ? 0UL : MallocFunc(WordsNow)) // Clear words starting at address: // // Note: Only use this for objects that care; in other cases, it doesnt // matter if the objects memory is pre-zeroed. #define ZEROWORDS(Addr,Words) \ { \ Word_t Words__ = (Words); \ PWord_t Addr__ = (PWord_t) (Addr); \ while (Words__--) *Addr__++ = 0UL; \ } #ifdef TRACEMI // TRACING SUPPORT: // // Note: For TRACEMI, use a format for address printing compatible with other // tracing facilities; in particular, %x not %lx, to truncate the "noisy" high // part on 64-bit systems. // // TBD: The trace macros need fixing for alternate address types. // // Note: TRACEMI2 supports trace analysis no matter the underlying malloc/free // engine used. #include static Word_t j__udyMemSequence = 0L; // event sequence number. #define TRACE_ALLOC5(a,b,c,d,e) (void) printf(a, (b), c, d) #define TRACE_FREE5( a,b,c,d,e) (void) printf(a, (b), c, d) #define TRACE_ALLOC6(a,b,c,d,e,f) (void) printf(a, (b), c, d, e) #define TRACE_FREE6( a,b,c,d,e,f) (void) printf(a, (b), c, d, e) #else #ifdef TRACEMI2 #include #define b_pw cJU_BYTESPERWORD #define TRACE_ALLOC5(a,b,c,d,e) \ (void) printf("a %lx %lx %lx\n", (b), (d) * b_pw, e) #define TRACE_FREE5( a,b,c,d,e) \ (void) printf("f %lx %lx %lx\n", (b), (d) * b_pw, e) #define TRACE_ALLOC6(a,b,c,d,e,f) \ (void) printf("a %lx %lx %lx\n", (b), (e) * b_pw, f) #define TRACE_FREE6( a,b,c,d,e,f) \ (void) printf("f %lx %lx %lx\n", (b), (e) * b_pw, f) static Word_t j__udyMemSequence = 0L; // event sequence number. #else #define TRACE_ALLOC5(a,b,c,d,e) // null. #define TRACE_FREE5( a,b,c,d,e) // null. #define TRACE_ALLOC6(a,b,c,d,e,f) // null. #define TRACE_FREE6( a,b,c,d,e,f) // null. #endif // ! TRACEMI2 #endif // ! TRACEMI // MALLOC NAMESPACE SUPPORT: #if (defined(DEBUG) && (! defined(MALLOCBITS))) // for now, DEBUG => MALLOCBITS: #define MALLOCBITS 1 #endif #ifdef MALLOCBITS #define MALLOCBITS_VALUE 0x3 // bit pattern to use. #define MALLOCBITS_MASK 0x7 // note: matches mask__ in JudyPrivate.h. #define MALLOCBITS_SET( Type,Addr) \ ((Addr) = (Type) ((Word_t) (Addr) | MALLOCBITS_VALUE)) #define MALLOCBITS_TEST(Type,Addr) \ assert((((Word_t) (Addr)) & MALLOCBITS_MASK) == MALLOCBITS_VALUE); \ ((Addr) = (Type) ((Word_t) (Addr) & ~MALLOCBITS_VALUE)) #else #define MALLOCBITS_SET( Type,Addr) // null. #define MALLOCBITS_TEST(Type,Addr) // null. #endif // SAVE ERROR INFORMATION IN A Pjpm: // // "Small" (invalid) Addr values are used to distinguish overrun and no-mem // errors. (TBD, non-zero invalid values are no longer returned from // lower-level functions, that is, JU_ERRNO_OVERRUN is no longer detected.) #define J__UDYSETALLOCERROR(Addr) \ { \ JU_ERRID(Pjpm) = __LINE__; \ if ((Word_t) (Addr) > 0) JU_ERRNO(Pjpm) = JU_ERRNO_OVERRUN; \ else JU_ERRNO(Pjpm) = JU_ERRNO_NOMEM; \ return(0); \ } // **************************************************************************** // ALLOCATION FUNCTIONS: // // To help the compiler catch coding errors, each function returns a specific // object type. // // Note: Only j__udyAllocJPM() and j__udyAllocJLW() return multiple values <= // sizeof(Word_t) to indicate the type of memory allocation failure. Other // allocation functions convert this failure to a JU_ERRNO. // Note: Unlike other j__udyAlloc*() functions, Pjpms are returned non-raw, // that is, without malloc namespace or root pointer type bits: FUNCTION Pjpm_t j__udyAllocJPM(void) { Word_t Words = (sizeof(jpm_t) + cJU_BYTESPERWORD - 1) / cJU_BYTESPERWORD; Pjpm_t Pjpm = (Pjpm_t) MALLOC(JudyMalloc, Words, Words); assert((Words * cJU_BYTESPERWORD) == sizeof(jpm_t)); if ((Word_t) Pjpm > sizeof(Word_t)) { ZEROWORDS(Pjpm, Words); Pjpm->jpm_TotalMemWords = Words; } TRACE_ALLOC5("0x%x %8lu = j__udyAllocJPM(), Words = %lu\n", Pjpm, j__udyMemSequence++, Words, cJU_LEAFW_MAXPOP1 + 1); // MALLOCBITS_SET(Pjpm_t, Pjpm); // see above. return(Pjpm); } // j__udyAllocJPM() FUNCTION Pjbl_t j__udyAllocJBL(Pjpm_t Pjpm) { Word_t Words = sizeof(jbl_t) / cJU_BYTESPERWORD; Pjbl_t PjblRaw = (Pjbl_t) MALLOC(JudyMallocVirtual, Pjpm->jpm_TotalMemWords, Words); assert((Words * cJU_BYTESPERWORD) == sizeof(jbl_t)); if ((Word_t) PjblRaw > sizeof(Word_t)) { ZEROWORDS(P_JBL(PjblRaw), Words); Pjpm->jpm_TotalMemWords += Words; } else { J__UDYSETALLOCERROR(PjblRaw); } TRACE_ALLOC5("0x%x %8lu = j__udyAllocJBL(), Words = %lu\n", PjblRaw, j__udyMemSequence++, Words, (Pjpm->jpm_Pop0) + 2); MALLOCBITS_SET(Pjbl_t, PjblRaw); return(PjblRaw); } // j__udyAllocJBL() FUNCTION Pjbb_t j__udyAllocJBB(Pjpm_t Pjpm) { Word_t Words = sizeof(jbb_t) / cJU_BYTESPERWORD; Pjbb_t PjbbRaw = (Pjbb_t) MALLOC(JudyMallocVirtual, Pjpm->jpm_TotalMemWords, Words); assert((Words * cJU_BYTESPERWORD) == sizeof(jbb_t)); if ((Word_t) PjbbRaw > sizeof(Word_t)) { ZEROWORDS(P_JBB(PjbbRaw), Words); Pjpm->jpm_TotalMemWords += Words; } else { J__UDYSETALLOCERROR(PjbbRaw); } TRACE_ALLOC5("0x%x %8lu = j__udyAllocJBB(), Words = %lu\n", PjbbRaw, j__udyMemSequence++, Words, (Pjpm->jpm_Pop0) + 2); MALLOCBITS_SET(Pjbb_t, PjbbRaw); return(PjbbRaw); } // j__udyAllocJBB() FUNCTION Pjp_t j__udyAllocJBBJP(Word_t NumJPs, Pjpm_t Pjpm) { Word_t Words = JU_BRANCHJP_NUMJPSTOWORDS(NumJPs); Pjp_t PjpRaw; PjpRaw = (Pjp_t) MALLOC(JudyMalloc, Pjpm->jpm_TotalMemWords, Words); if ((Word_t) PjpRaw > sizeof(Word_t)) { Pjpm->jpm_TotalMemWords += Words; } else { J__UDYSETALLOCERROR(PjpRaw); } TRACE_ALLOC6("0x%x %8lu = j__udyAllocJBBJP(%lu), Words = %lu\n", PjpRaw, j__udyMemSequence++, NumJPs, Words, (Pjpm->jpm_Pop0) + 2); MALLOCBITS_SET(Pjp_t, PjpRaw); return(PjpRaw); } // j__udyAllocJBBJP() FUNCTION Pjbu_t j__udyAllocJBU(Pjpm_t Pjpm) { Word_t Words = sizeof(jbu_t) / cJU_BYTESPERWORD; Pjbu_t PjbuRaw = (Pjbu_t) MALLOC(JudyMallocVirtual, Pjpm->jpm_TotalMemWords, Words); assert((Words * cJU_BYTESPERWORD) == sizeof(jbu_t)); if ((Word_t) PjbuRaw > sizeof(Word_t)) { Pjpm->jpm_TotalMemWords += Words; } else { J__UDYSETALLOCERROR(PjbuRaw); } TRACE_ALLOC5("0x%x %8lu = j__udyAllocJBU(), Words = %lu\n", PjbuRaw, j__udyMemSequence++, Words, (Pjpm->jpm_Pop0) + 2); MALLOCBITS_SET(Pjbu_t, PjbuRaw); return(PjbuRaw); } // j__udyAllocJBU() #if (defined(JUDYL) || (! defined(JU_64BIT))) FUNCTION Pjll_t j__udyAllocJLL1(Word_t Pop1, Pjpm_t Pjpm) { Word_t Words = JU_LEAF1POPTOWORDS(Pop1); Pjll_t PjllRaw; PjllRaw = (Pjll_t) MALLOC(JudyMalloc, Pjpm->jpm_TotalMemWords, Words); if ((Word_t) PjllRaw > sizeof(Word_t)) { Pjpm->jpm_TotalMemWords += Words; } else { J__UDYSETALLOCERROR(PjllRaw); } TRACE_ALLOC6("0x%x %8lu = j__udyAllocJLL1(%lu), Words = %lu\n", PjllRaw, j__udyMemSequence++, Pop1, Words, (Pjpm->jpm_Pop0) + 2); MALLOCBITS_SET(Pjll_t, PjllRaw); return(PjllRaw); } // j__udyAllocJLL1() #endif // (JUDYL || (! JU_64BIT)) FUNCTION Pjll_t j__udyAllocJLL2(Word_t Pop1, Pjpm_t Pjpm) { Word_t Words = JU_LEAF2POPTOWORDS(Pop1); Pjll_t PjllRaw; PjllRaw = (Pjll_t) MALLOC(JudyMalloc, Pjpm->jpm_TotalMemWords, Words); if ((Word_t) PjllRaw > sizeof(Word_t)) { Pjpm->jpm_TotalMemWords += Words; } else { J__UDYSETALLOCERROR(PjllRaw); } TRACE_ALLOC6("0x%x %8lu = j__udyAllocJLL2(%lu), Words = %lu\n", PjllRaw, j__udyMemSequence++, Pop1, Words, (Pjpm->jpm_Pop0) + 2); MALLOCBITS_SET(Pjll_t, PjllRaw); return(PjllRaw); } // j__udyAllocJLL2() FUNCTION Pjll_t j__udyAllocJLL3(Word_t Pop1, Pjpm_t Pjpm) { Word_t Words = JU_LEAF3POPTOWORDS(Pop1); Pjll_t PjllRaw; PjllRaw = (Pjll_t) MALLOC(JudyMalloc, Pjpm->jpm_TotalMemWords, Words); if ((Word_t) PjllRaw > sizeof(Word_t)) { Pjpm->jpm_TotalMemWords += Words; } else { J__UDYSETALLOCERROR(PjllRaw); } TRACE_ALLOC6("0x%x %8lu = j__udyAllocJLL3(%lu), Words = %lu\n", PjllRaw, j__udyMemSequence++, Pop1, Words, (Pjpm->jpm_Pop0) + 2); MALLOCBITS_SET(Pjll_t, PjllRaw); return(PjllRaw); } // j__udyAllocJLL3() #ifdef JU_64BIT FUNCTION Pjll_t j__udyAllocJLL4(Word_t Pop1, Pjpm_t Pjpm) { Word_t Words = JU_LEAF4POPTOWORDS(Pop1); Pjll_t PjllRaw; PjllRaw = (Pjll_t) MALLOC(JudyMalloc, Pjpm->jpm_TotalMemWords, Words); if ((Word_t) PjllRaw > sizeof(Word_t)) { Pjpm->jpm_TotalMemWords += Words; } else { J__UDYSETALLOCERROR(PjllRaw); } TRACE_ALLOC6("0x%x %8lu = j__udyAllocJLL4(%lu), Words = %lu\n", PjllRaw, j__udyMemSequence++, Pop1, Words, (Pjpm->jpm_Pop0) + 2); MALLOCBITS_SET(Pjll_t, PjllRaw); return(PjllRaw); } // j__udyAllocJLL4() FUNCTION Pjll_t j__udyAllocJLL5(Word_t Pop1, Pjpm_t Pjpm) { Word_t Words = JU_LEAF5POPTOWORDS(Pop1); Pjll_t PjllRaw; PjllRaw = (Pjll_t) MALLOC(JudyMalloc, Pjpm->jpm_TotalMemWords, Words); if ((Word_t) PjllRaw > sizeof(Word_t)) { Pjpm->jpm_TotalMemWords += Words; } else { J__UDYSETALLOCERROR(PjllRaw); } TRACE_ALLOC6("0x%x %8lu = j__udyAllocJLL5(%lu), Words = %lu\n", PjllRaw, j__udyMemSequence++, Pop1, Words, (Pjpm->jpm_Pop0) + 2); MALLOCBITS_SET(Pjll_t, PjllRaw); return(PjllRaw); } // j__udyAllocJLL5() FUNCTION Pjll_t j__udyAllocJLL6(Word_t Pop1, Pjpm_t Pjpm) { Word_t Words = JU_LEAF6POPTOWORDS(Pop1); Pjll_t PjllRaw; PjllRaw = (Pjll_t) MALLOC(JudyMalloc, Pjpm->jpm_TotalMemWords, Words); if ((Word_t) PjllRaw > sizeof(Word_t)) { Pjpm->jpm_TotalMemWords += Words; } else { J__UDYSETALLOCERROR(PjllRaw); } TRACE_ALLOC6("0x%x %8lu = j__udyAllocJLL6(%lu), Words = %lu\n", PjllRaw, j__udyMemSequence++, Pop1, Words, (Pjpm->jpm_Pop0) + 2); MALLOCBITS_SET(Pjll_t, PjllRaw); return(PjllRaw); } // j__udyAllocJLL6() FUNCTION Pjll_t j__udyAllocJLL7(Word_t Pop1, Pjpm_t Pjpm) { Word_t Words = JU_LEAF7POPTOWORDS(Pop1); Pjll_t PjllRaw; PjllRaw = (Pjll_t) MALLOC(JudyMalloc, Pjpm->jpm_TotalMemWords, Words); if ((Word_t) PjllRaw > sizeof(Word_t)) { Pjpm->jpm_TotalMemWords += Words; } else { J__UDYSETALLOCERROR(PjllRaw); } TRACE_ALLOC6("0x%x %8lu = j__udyAllocJLL7(%lu), Words = %lu\n", PjllRaw, j__udyMemSequence++, Pop1, Words, (Pjpm->jpm_Pop0) + 2); MALLOCBITS_SET(Pjll_t, PjllRaw); return(PjllRaw); } // j__udyAllocJLL7() #endif // JU_64BIT // Note: Root-level leaf addresses are always whole words (Pjlw_t), and unlike // other j__udyAlloc*() functions, they are returned non-raw, that is, without // malloc namespace or root pointer type bits (the latter are added later by // the caller): FUNCTION Pjlw_t j__udyAllocJLW(Word_t Pop1) { Word_t Words = JU_LEAFWPOPTOWORDS(Pop1); Pjlw_t Pjlw = (Pjlw_t) MALLOC(JudyMalloc, Words, Words); TRACE_ALLOC6("0x%x %8lu = j__udyAllocJLW(%lu), Words = %lu\n", Pjlw, j__udyMemSequence++, Pop1, Words, Pop1); // MALLOCBITS_SET(Pjlw_t, Pjlw); // see above. return(Pjlw); } // j__udyAllocJLW() FUNCTION Pjlb_t j__udyAllocJLB1(Pjpm_t Pjpm) { Word_t Words = sizeof(jlb_t) / cJU_BYTESPERWORD; Pjlb_t PjlbRaw; PjlbRaw = (Pjlb_t) MALLOC(JudyMalloc, Pjpm->jpm_TotalMemWords, Words); assert((Words * cJU_BYTESPERWORD) == sizeof(jlb_t)); if ((Word_t) PjlbRaw > sizeof(Word_t)) { ZEROWORDS(P_JLB(PjlbRaw), Words); Pjpm->jpm_TotalMemWords += Words; } else { J__UDYSETALLOCERROR(PjlbRaw); } TRACE_ALLOC5("0x%x %8lu = j__udyAllocJLB1(), Words = %lu\n", PjlbRaw, j__udyMemSequence++, Words, (Pjpm->jpm_Pop0) + 2); MALLOCBITS_SET(Pjlb_t, PjlbRaw); return(PjlbRaw); } // j__udyAllocJLB1() #ifdef JUDYL FUNCTION Pjv_t j__udyLAllocJV(Word_t Pop1, Pjpm_t Pjpm) { Word_t Words = JL_LEAFVPOPTOWORDS(Pop1); Pjv_t PjvRaw; PjvRaw = (Pjv_t) MALLOC(JudyMalloc, Pjpm->jpm_TotalMemWords, Words); if ((Word_t) PjvRaw > sizeof(Word_t)) { Pjpm->jpm_TotalMemWords += Words; } else { J__UDYSETALLOCERROR(PjvRaw); } TRACE_ALLOC6("0x%x %8lu = j__udyLAllocJV(%lu), Words = %lu\n", PjvRaw, j__udyMemSequence++, Pop1, Words, (Pjpm->jpm_Pop0) + 2); MALLOCBITS_SET(Pjv_t, PjvRaw); return(PjvRaw); } // j__udyLAllocJV() #endif // JUDYL // **************************************************************************** // FREE FUNCTIONS: // // To help the compiler catch coding errors, each function takes a specific // object type to free. // Note: j__udyFreeJPM() receives a root pointer with NO root pointer type // bits present, that is, they must be stripped by the caller using P_JPM(): FUNCTION void j__udyFreeJPM(Pjpm_t PjpmFree, Pjpm_t PjpmStats) { Word_t Words = (sizeof(jpm_t) + cJU_BYTESPERWORD - 1) / cJU_BYTESPERWORD; // MALLOCBITS_TEST(Pjpm_t, PjpmFree); // see above. JudyFree((Pvoid_t) PjpmFree, Words); if (PjpmStats != (Pjpm_t) NULL) PjpmStats->jpm_TotalMemWords -= Words; // Note: Log PjpmFree->jpm_Pop0, similar to other j__udyFree*() functions, not // an assumed value of cJU_LEAFW_MAXPOP1, for when the caller is // Judy*FreeArray(), jpm_Pop0 is set to 0, and the population after the free // really will be 0, not cJU_LEAFW_MAXPOP1. TRACE_FREE6("0x%x %8lu = j__udyFreeJPM(%lu), Words = %lu\n", PjpmFree, j__udyMemSequence++, Words, Words, PjpmFree->jpm_Pop0); } // j__udyFreeJPM() FUNCTION void j__udyFreeJBL(Pjbl_t Pjbl, Pjpm_t Pjpm) { Word_t Words = sizeof(jbl_t) / cJU_BYTESPERWORD; MALLOCBITS_TEST(Pjbl_t, Pjbl); JudyFreeVirtual((Pvoid_t) Pjbl, Words); Pjpm->jpm_TotalMemWords -= Words; TRACE_FREE5("0x%x %8lu = j__udyFreeJBL(), Words = %lu\n", Pjbl, j__udyMemSequence++, Words, Pjpm->jpm_Pop0); } // j__udyFreeJBL() FUNCTION void j__udyFreeJBB(Pjbb_t Pjbb, Pjpm_t Pjpm) { Word_t Words = sizeof(jbb_t) / cJU_BYTESPERWORD; MALLOCBITS_TEST(Pjbb_t, Pjbb); JudyFreeVirtual((Pvoid_t) Pjbb, Words); Pjpm->jpm_TotalMemWords -= Words; TRACE_FREE5("0x%x %8lu = j__udyFreeJBB(), Words = %lu\n", Pjbb, j__udyMemSequence++, Words, Pjpm->jpm_Pop0); } // j__udyFreeJBB() FUNCTION void j__udyFreeJBBJP(Pjp_t Pjp, Word_t NumJPs, Pjpm_t Pjpm) { Word_t Words = JU_BRANCHJP_NUMJPSTOWORDS(NumJPs); MALLOCBITS_TEST(Pjp_t, Pjp); JudyFree((Pvoid_t) Pjp, Words); Pjpm->jpm_TotalMemWords -= Words; TRACE_FREE6("0x%x %8lu = j__udyFreeJBBJP(%lu), Words = %lu\n", Pjp, j__udyMemSequence++, NumJPs, Words, Pjpm->jpm_Pop0); } // j__udyFreeJBBJP() FUNCTION void j__udyFreeJBU(Pjbu_t Pjbu, Pjpm_t Pjpm) { Word_t Words = sizeof(jbu_t) / cJU_BYTESPERWORD; MALLOCBITS_TEST(Pjbu_t, Pjbu); JudyFreeVirtual((Pvoid_t) Pjbu, Words); Pjpm->jpm_TotalMemWords -= Words; TRACE_FREE5("0x%x %8lu = j__udyFreeJBU(), Words = %lu\n", Pjbu, j__udyMemSequence++, Words, Pjpm->jpm_Pop0); } // j__udyFreeJBU() #if (defined(JUDYL) || (! defined(JU_64BIT))) FUNCTION void j__udyFreeJLL1(Pjll_t Pjll, Word_t Pop1, Pjpm_t Pjpm) { Word_t Words = JU_LEAF1POPTOWORDS(Pop1); MALLOCBITS_TEST(Pjll_t, Pjll); JudyFree((Pvoid_t) Pjll, Words); Pjpm->jpm_TotalMemWords -= Words; TRACE_FREE6("0x%x %8lu = j__udyFreeJLL1(%lu), Words = %lu\n", Pjll, j__udyMemSequence++, Pop1, Words, Pjpm->jpm_Pop0); } // j__udyFreeJLL1() #endif // (JUDYL || (! JU_64BIT)) FUNCTION void j__udyFreeJLL2(Pjll_t Pjll, Word_t Pop1, Pjpm_t Pjpm) { Word_t Words = JU_LEAF2POPTOWORDS(Pop1); MALLOCBITS_TEST(Pjll_t, Pjll); JudyFree((Pvoid_t) Pjll, Words); Pjpm->jpm_TotalMemWords -= Words; TRACE_FREE6("0x%x %8lu = j__udyFreeJLL2(%lu), Words = %lu\n", Pjll, j__udyMemSequence++, Pop1, Words, Pjpm->jpm_Pop0); } // j__udyFreeJLL2() FUNCTION void j__udyFreeJLL3(Pjll_t Pjll, Word_t Pop1, Pjpm_t Pjpm) { Word_t Words = JU_LEAF3POPTOWORDS(Pop1); MALLOCBITS_TEST(Pjll_t, Pjll); JudyFree((Pvoid_t) Pjll, Words); Pjpm->jpm_TotalMemWords -= Words; TRACE_FREE6("0x%x %8lu = j__udyFreeJLL3(%lu), Words = %lu\n", Pjll, j__udyMemSequence++, Pop1, Words, Pjpm->jpm_Pop0); } // j__udyFreeJLL3() #ifdef JU_64BIT FUNCTION void j__udyFreeJLL4(Pjll_t Pjll, Word_t Pop1, Pjpm_t Pjpm) { Word_t Words = JU_LEAF4POPTOWORDS(Pop1); MALLOCBITS_TEST(Pjll_t, Pjll); JudyFree((Pvoid_t) Pjll, Words); Pjpm->jpm_TotalMemWords -= Words; TRACE_FREE6("0x%x %8lu = j__udyFreeJLL4(%lu), Words = %lu\n", Pjll, j__udyMemSequence++, Pop1, Words, Pjpm->jpm_Pop0); } // j__udyFreeJLL4() FUNCTION void j__udyFreeJLL5(Pjll_t Pjll, Word_t Pop1, Pjpm_t Pjpm) { Word_t Words = JU_LEAF5POPTOWORDS(Pop1); MALLOCBITS_TEST(Pjll_t, Pjll); JudyFree((Pvoid_t) Pjll, Words); Pjpm->jpm_TotalMemWords -= Words; TRACE_FREE6("0x%x %8lu = j__udyFreeJLL5(%lu), Words = %lu\n", Pjll, j__udyMemSequence++, Pop1, Words, Pjpm->jpm_Pop0); } // j__udyFreeJLL5() FUNCTION void j__udyFreeJLL6(Pjll_t Pjll, Word_t Pop1, Pjpm_t Pjpm) { Word_t Words = JU_LEAF6POPTOWORDS(Pop1); MALLOCBITS_TEST(Pjll_t, Pjll); JudyFree((Pvoid_t) Pjll, Words); Pjpm->jpm_TotalMemWords -= Words; TRACE_FREE6("0x%x %8lu = j__udyFreeJLL6(%lu), Words = %lu\n", Pjll, j__udyMemSequence++, Pop1, Words, Pjpm->jpm_Pop0); } // j__udyFreeJLL6() FUNCTION void j__udyFreeJLL7(Pjll_t Pjll, Word_t Pop1, Pjpm_t Pjpm) { Word_t Words = JU_LEAF7POPTOWORDS(Pop1); MALLOCBITS_TEST(Pjll_t, Pjll); JudyFree((Pvoid_t) Pjll, Words); Pjpm->jpm_TotalMemWords -= Words; TRACE_FREE6("0x%x %8lu = j__udyFreeJLL7(%lu), Words = %lu\n", Pjll, j__udyMemSequence++, Pop1, Words, Pjpm->jpm_Pop0); } // j__udyFreeJLL7() #endif // JU_64BIT // Note: j__udyFreeJLW() receives a root pointer with NO root pointer type // bits present, that is, they are stripped by P_JLW(): FUNCTION void j__udyFreeJLW(Pjlw_t Pjlw, Word_t Pop1, Pjpm_t Pjpm) { Word_t Words = JU_LEAFWPOPTOWORDS(Pop1); // MALLOCBITS_TEST(Pjlw_t, Pjlw); // see above. JudyFree((Pvoid_t) Pjlw, Words); if (Pjpm) Pjpm->jpm_TotalMemWords -= Words; TRACE_FREE6("0x%x %8lu = j__udyFreeJLW(%lu), Words = %lu\n", Pjlw, j__udyMemSequence++, Pop1, Words, Pop1 - 1); } // j__udyFreeJLW() FUNCTION void j__udyFreeJLB1(Pjlb_t Pjlb, Pjpm_t Pjpm) { Word_t Words = sizeof(jlb_t) / cJU_BYTESPERWORD; MALLOCBITS_TEST(Pjlb_t, Pjlb); JudyFree((Pvoid_t) Pjlb, Words); Pjpm->jpm_TotalMemWords -= Words; TRACE_FREE5("0x%x %8lu = j__udyFreeJLB1(), Words = %lu\n", Pjlb, j__udyMemSequence++, Words, Pjpm->jpm_Pop0); } // j__udyFreeJLB1() #ifdef JUDYL FUNCTION void j__udyLFreeJV(Pjv_t Pjv, Word_t Pop1, Pjpm_t Pjpm) { Word_t Words = JL_LEAFVPOPTOWORDS(Pop1); MALLOCBITS_TEST(Pjv_t, Pjv); JudyFree((Pvoid_t) Pjv, Words); Pjpm->jpm_TotalMemWords -= Words; TRACE_FREE6("0x%x %8lu = j__udyLFreeJV(%lu), Words = %lu\n", Pjv, j__udyMemSequence++, Pop1, Words, Pjpm->jpm_Pop0); } // j__udyLFreeJV() #endif // JUDYL judy-1.0.5/src/JudyCommon/JudyPrintJP.c0000644000175000017500000004611210204462077020123 0ustar troyhebetroyhebe// Copyright (C) 2000 - 2002 Hewlett-Packard Company // // This program is free software; you can redistribute it and/or modify it // under the term of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License // for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program; if not, write to the Free Software Foundation, // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // _________________ // @(#) $Revision: 4.13 $ $Source: /judy/src/JudyCommon/JudyPrintJP.c $ // // JudyPrintJP() debugging/tracing function for Judy1 or JudyL code. // The caller should #include this file, with its static function (replicated // in each compilation unit), in another *.c file, and compile with one of // -DJUDY1 or -DJUDYL. // // The caller can set j__udyIndex and/or j__udyPopulation non-zero to have // those values reported, and also to control trace-enabling (see below). // // Tracing is disabled by default unless one or both of two env parameters is // set (regardless of value). If either value is set but null or evaluates to // zero, tracing is immediately enabled. To disable tracing until a particular // j__udy*Index value is seen, set STARTINDEX= in the env. To // disable it until a particular j__udy*Population value is seen, set // STARTPOP= in the env. Once either condition is met, // tracing "latches on". // // Example: // // STARTPOP=0 // immediate tracing. // STARTINDEX=f35430a8 // not until one of these is met. // STARTPOP=1000000 // // Note: Trace-enabling does nothing unless the caller sets the appropriate // global variable non-zero. #if (! (defined(JUDY1) || defined(JUDYL))) #error: One of -DJUDY1 or -DJUDYL must be specified. #endif #include // for getenv() and strtoul(). // GLOBALS FROM CALLER: // // Note: This storage is declared once in each compilation unit that includes // this file, but the linker should merge all cases into single locations, but // ONLY if these are uninitialized, so ASSUME they are 0 to start. Word_t j__udyIndex; // current Index itself, optional from caller. Word_t j__udyPopulation; // Indexes in array, optional from caller. // Other globals: static Word_t startindex = 0; // see usage below. static Word_t startpop = 0; static bool_t enabled = FALSE; // by default, unless env params set. // Shorthand for announcing JP addresses, Desc (in context), and JP types: // // Note: Width is at least one blank wider than any JP type name, and the line // is left unfinished. // // Note: Use a format for address printing compatible with other tracing // facilities; in particular, %x not %lx, to truncate the "noisy" high part on // 64-bit systems. #define JPTYPE(Type) printf("0x%lx %s %-17s", (Word_t) Pjp, Desc, Type) // Shorthands for announcing expanse populations from DcdPopO fields: #define POP0 printf("Pop1 = 0 ") #define POP1 printf("Pop1 = %ld ", (Word_t) ((JU_JPDCDPOP0(Pjp) & 0xff) + 1)) #define POP2 printf("Pop1 = %ld ", (Word_t) ((JU_JPDCDPOP0(Pjp) & 0xffff) + 1)) #define POP3 printf("Pop1 = %ld ", (Word_t) ((JU_JPDCDPOP0(Pjp) & 0xffffff) + 1)) #ifdef JU_64BIT #define POP4 printf("Pop1 = %ld ", (Word_t) ((JU_JPDCDPOP0(Pjp) & 0xffffffff) + 1)) #define POP5 printf("Pop1 = %ld ", (Word_t) ((JU_JPDCDPOP0(Pjp) & 0xffffffffff) + 1)) #define POP6 printf("Pop1 = %ld ", (Word_t) ((JU_JPDCDPOP0(Pjp) & 0xffffffffffff) + 1)) #define POP7 printf("Pop1 = %ld ", (Word_t) ((JU_JPDCDPOP0(Pjp) & 0xffffffffffffff) + 1)) #endif // Shorthands for announcing populations of Immeds: // // Note: Line up the small populations that often occur together, but beyond // that, dont worry about it because populations can get arbitrarily large. #define POP_1 printf("Pop1 = 1 ") #define POP_2 printf("Pop1 = 2 ") #define POP_3 printf("Pop1 = 3 ") #define POP_4 printf("Pop1 = 4 ") #define POP_5 printf("Pop1 = 5 ") #define POP_6 printf("Pop1 = 6 ") #define POP_7 printf("Pop1 = 7 ") #define POP_8 printf("Pop1 = 8 ") #define POP_9 printf("Pop1 = 8 ") #define POP_10 printf("Pop1 = 10 ") #define POP_11 printf("Pop1 = 11 ") #define POP_12 printf("Pop1 = 12 ") #define POP_13 printf("Pop1 = 13 ") #define POP_14 printf("Pop1 = 14 ") #define POP_15 printf("Pop1 = 15 ") // Shorthands for other announcements: #define NUMJPSL printf("NumJPs = %d ", P_JBL(Pjp->jp_Addr)->jbl_NumJPs) #define OOPS printf("-- OOPS, invalid Type\n"); exit(1) // This is harder to compute: #define NUMJPSB \ { \ Pjbb_t Pjbb = P_JBB(Pjp->jp_Addr); \ Word_t subexp; \ int numJPs = 0; \ \ for (subexp = 0; subexp < cJU_NUMSUBEXPB; ++subexp) \ numJPs += j__udyCountBitsB(JU_JBB_BITMAP(Pjbb, subexp));\ \ printf("NumJPs = %d ", numJPs); \ } // **************************************************************************** // J U D Y P R I N T J P // // Dump information about a JP, at least its address, type, population, and // number of JPs, as appropriate. Error out upon any unexpected JP type. // // TBD: Dump more detailed information about the JP? FUNCTION static void JudyPrintJP( Pjp_t Pjp, // JP to describe. char * Desc, // brief description of caller, such as "i". int Line) // callers source line number. { static bool_t checked = FALSE; // set upon first entry and check for params. char * value; // for getenv(). // CHECK FOR EXTERNAL ENABLING: // // If a parameter is set, report the value, even if it is null or otherwise // evaluates to zero, in which case enable tracing immediately; otherwise wait // for the value to be hit. #define GETENV(Name,Value,Base) \ if ((value = getenv (Name)) != (char *) NULL) \ { \ (Value) = strtoul (value, (char **) NULL, Base); \ enabled |= ((Value) == 0); /* see above */ \ \ (void) printf ("JudyPrintJP(\"%s\"): $%s = %lu\n", \ Desc, Name, Value); \ } if (! checked) // only check once. { checked = TRUE; GETENV ("STARTINDEX", startindex, 16); GETENV ("STARTPOP", startpop, 10); (void) printf ("JudyPrintJP(\"%s\"): Tracing present %s\n", Desc, enabled ? "and immediately enabled" : (startindex || startpop) ? "but disabled until start condition met" : "but not enabled by env parameter"); } if (! enabled) // check repeatedly until latched enabled: { if (startindex && (startindex == j__udyIndex)) { (void) printf ("=== TRACING ENABLED (\"%s\"), " "startindex = 0x%lx\n", Desc, startindex); enabled = TRUE; } else if (startpop && (startpop == j__udyPopulation)) { (void) printf ("=== TRACING ENABLED (\"%s\"), " "startpop = %lu\n", Desc, startpop); enabled = TRUE; } else { return; // print nothing this time. } } // SWITCH ON JP TYPE: switch (JU_JPTYPE(Pjp)) { // Note: The following COULD be merged more tightly between Judy1 and JudyL, // but we decided that the output should say cJ1*/cJL*, not cJU*, to be more // specific. #ifdef JUDY1 case cJ1_JPNULL1: JPTYPE("cJ1_JPNULL1"); POP0; break; case cJ1_JPNULL2: JPTYPE("cJ1_JPNULL2"); POP0; break; case cJ1_JPNULL3: JPTYPE("cJ1_JPNULL3"); POP0; break; #ifdef JU_64BIT case cJ1_JPNULL4: JPTYPE("cJ1_JPNULL4"); POP0; break; case cJ1_JPNULL5: JPTYPE("cJ1_JPNULL5"); POP0; break; case cJ1_JPNULL6: JPTYPE("cJ1_JPNULL6"); POP0; break; case cJ1_JPNULL7: JPTYPE("cJ1_JPNULL7"); POP0; break; #endif case cJ1_JPBRANCH_L2: JPTYPE("cJ1_JPBRANCH_L2"); POP2;NUMJPSL;break; case cJ1_JPBRANCH_L3: JPTYPE("cJ1_JPBRANCH_L3"); POP3;NUMJPSL;break; #ifdef JU_64BIT case cJ1_JPBRANCH_L4: JPTYPE("cJ1_JPBRANCH_L4"); POP4;NUMJPSL;break; case cJ1_JPBRANCH_L5: JPTYPE("cJ1_JPBRANCH_L5"); POP5;NUMJPSL;break; case cJ1_JPBRANCH_L6: JPTYPE("cJ1_JPBRANCH_L6"); POP6;NUMJPSL;break; case cJ1_JPBRANCH_L7: JPTYPE("cJ1_JPBRANCH_L7"); POP7;NUMJPSL;break; #endif case cJ1_JPBRANCH_L: JPTYPE("cJ1_JPBRANCH_L"); NUMJPSL;break; case cJ1_JPBRANCH_B2: JPTYPE("cJ1_JPBRANCH_B2"); POP2;NUMJPSB;break; case cJ1_JPBRANCH_B3: JPTYPE("cJ1_JPBRANCH_B3"); POP3;NUMJPSB;break; #ifdef JU_64BIT case cJ1_JPBRANCH_B4: JPTYPE("cJ1_JPBRANCH_B4"); POP4;NUMJPSB;break; case cJ1_JPBRANCH_B5: JPTYPE("cJ1_JPBRANCH_B5"); POP5;NUMJPSB;break; case cJ1_JPBRANCH_B6: JPTYPE("cJ1_JPBRANCH_B6"); POP6;NUMJPSB;break; case cJ1_JPBRANCH_B7: JPTYPE("cJ1_JPBRANCH_B7"); POP7;NUMJPSB;break; #endif case cJ1_JPBRANCH_B: JPTYPE("cJ1_JPBRANCH_B"); NUMJPSB;break; case cJ1_JPBRANCH_U2: JPTYPE("cJ1_JPBRANCH_U2"); POP2; break; case cJ1_JPBRANCH_U3: JPTYPE("cJ1_JPBRANCH_U3"); POP3; break; #ifdef JU_64BIT case cJ1_JPBRANCH_U4: JPTYPE("cJ1_JPBRANCH_U4"); POP4; break; case cJ1_JPBRANCH_U5: JPTYPE("cJ1_JPBRANCH_U5"); POP5; break; case cJ1_JPBRANCH_U6: JPTYPE("cJ1_JPBRANCH_U6"); POP6; break; case cJ1_JPBRANCH_U7: JPTYPE("cJ1_JPBRANCH_U7"); POP7; break; #endif case cJ1_JPBRANCH_U: JPTYPE("cJ1_JPBRANCH_U"); break; #ifndef JU_64BIT case cJ1_JPLEAF1: JPTYPE("cJ1_JPLEAF1"); POP1; break; #endif case cJ1_JPLEAF2: JPTYPE("cJ1_JPLEAF2"); POP2; break; case cJ1_JPLEAF3: JPTYPE("cJ1_JPLEAF3"); POP3; break; #ifdef JU_64BIT case cJ1_JPLEAF4: JPTYPE("cJ1_JPLEAF4"); POP4; break; case cJ1_JPLEAF5: JPTYPE("cJ1_JPLEAF5"); POP5; break; case cJ1_JPLEAF6: JPTYPE("cJ1_JPLEAF6"); POP6; break; case cJ1_JPLEAF7: JPTYPE("cJ1_JPLEAF7"); POP7; break; #endif case cJ1_JPLEAF_B1: JPTYPE("cJ1_JPLEAF_B1"); POP1; break; case cJ1_JPFULLPOPU1: JPTYPE("cJ1_JPFULLPOPU1"); POP1; break; case cJ1_JPIMMED_1_01: JPTYPE("cJ1_JPIMMED_1_01"); POP_1; break; case cJ1_JPIMMED_2_01: JPTYPE("cJ1_JPIMMED_2_01"); POP_1; break; case cJ1_JPIMMED_3_01: JPTYPE("cJ1_JPIMMED_3_01"); POP_1; break; #ifdef JU_64BIT case cJ1_JPIMMED_4_01: JPTYPE("cJ1_JPIMMED_4_01"); POP_1; break; case cJ1_JPIMMED_5_01: JPTYPE("cJ1_JPIMMED_5_01"); POP_1; break; case cJ1_JPIMMED_6_01: JPTYPE("cJ1_JPIMMED_6_01"); POP_1; break; case cJ1_JPIMMED_7_01: JPTYPE("cJ1_JPIMMED_7_01"); POP_1; break; #endif case cJ1_JPIMMED_1_02: JPTYPE("cJ1_JPIMMED_1_02"); POP_2; break; case cJ1_JPIMMED_1_03: JPTYPE("cJ1_JPIMMED_1_03"); POP_3; break; case cJ1_JPIMMED_1_04: JPTYPE("cJ1_JPIMMED_1_04"); POP_4; break; case cJ1_JPIMMED_1_05: JPTYPE("cJ1_JPIMMED_1_05"); POP_5; break; case cJ1_JPIMMED_1_06: JPTYPE("cJ1_JPIMMED_1_06"); POP_6; break; case cJ1_JPIMMED_1_07: JPTYPE("cJ1_JPIMMED_1_07"); POP_7; break; #ifdef JU_64BIT case cJ1_JPIMMED_1_08: JPTYPE("cJ1_JPIMMED_1_08"); POP_8; break; case cJ1_JPIMMED_1_09: JPTYPE("cJ1_JPIMMED_1_09"); POP_9; break; case cJ1_JPIMMED_1_10: JPTYPE("cJ1_JPIMMED_1_10"); POP_10; break; case cJ1_JPIMMED_1_11: JPTYPE("cJ1_JPIMMED_1_11"); POP_11; break; case cJ1_JPIMMED_1_12: JPTYPE("cJ1_JPIMMED_1_12"); POP_12; break; case cJ1_JPIMMED_1_13: JPTYPE("cJ1_JPIMMED_1_13"); POP_13; break; case cJ1_JPIMMED_1_14: JPTYPE("cJ1_JPIMMED_1_14"); POP_14; break; case cJ1_JPIMMED_1_15: JPTYPE("cJ1_JPIMMED_1_15"); POP_15; break; #endif case cJ1_JPIMMED_2_02: JPTYPE("cJ1_JPIMMED_2_02"); POP_2; break; case cJ1_JPIMMED_2_03: JPTYPE("cJ1_JPIMMED_2_03"); POP_3; break; #ifdef JU_64BIT case cJ1_JPIMMED_2_04: JPTYPE("cJ1_JPIMMED_2_04"); POP_4; break; case cJ1_JPIMMED_2_05: JPTYPE("cJ1_JPIMMED_2_05"); POP_5; break; case cJ1_JPIMMED_2_06: JPTYPE("cJ1_JPIMMED_2_06"); POP_6; break; case cJ1_JPIMMED_2_07: JPTYPE("cJ1_JPIMMED_2_07"); POP_7; break; #endif case cJ1_JPIMMED_3_02: JPTYPE("cJ1_JPIMMED_3_02"); POP_2; break; #ifdef JU_64BIT case cJ1_JPIMMED_3_03: JPTYPE("cJ1_JPIMMED_3_03"); POP_3; break; case cJ1_JPIMMED_3_04: JPTYPE("cJ1_JPIMMED_3_04"); POP_4; break; case cJ1_JPIMMED_3_05: JPTYPE("cJ1_JPIMMED_3_05"); POP_5; break; case cJ1_JPIMMED_4_02: JPTYPE("cJ1_JPIMMED_4_02"); POP_2; break; case cJ1_JPIMMED_4_03: JPTYPE("cJ1_JPIMMED_4_03"); POP_3; break; case cJ1_JPIMMED_5_02: JPTYPE("cJ1_JPIMMED_5_02"); POP_2; break; case cJ1_JPIMMED_5_03: JPTYPE("cJ1_JPIMMED_5_03"); POP_3; break; case cJ1_JPIMMED_6_02: JPTYPE("cJ1_JPIMMED_6_02"); POP_2; break; case cJ1_JPIMMED_7_02: JPTYPE("cJ1_JPIMMED_7_02"); POP_2; break; #endif case cJ1_JPIMMED_CAP: JPTYPE("cJ1_JPIMMED_CAP"); OOPS; #else // JUDYL =============================================================== case cJL_JPNULL1: JPTYPE("cJL_JPNULL1"); POP0; break; case cJL_JPNULL2: JPTYPE("cJL_JPNULL2"); POP0; break; case cJL_JPNULL3: JPTYPE("cJL_JPNULL3"); POP0; break; #ifdef JU_64BIT case cJL_JPNULL4: JPTYPE("cJL_JPNULL4"); POP0; break; case cJL_JPNULL5: JPTYPE("cJL_JPNULL5"); POP0; break; case cJL_JPNULL6: JPTYPE("cJL_JPNULL6"); POP0; break; case cJL_JPNULL7: JPTYPE("cJL_JPNULL7"); POP0; break; #endif case cJL_JPBRANCH_L2: JPTYPE("cJL_JPBRANCH_L2"); POP2;NUMJPSL;break; case cJL_JPBRANCH_L3: JPTYPE("cJL_JPBRANCH_L3"); POP3;NUMJPSL;break; #ifdef JU_64BIT case cJL_JPBRANCH_L4: JPTYPE("cJL_JPBRANCH_L4"); POP4;NUMJPSL;break; case cJL_JPBRANCH_L5: JPTYPE("cJL_JPBRANCH_L5"); POP5;NUMJPSL;break; case cJL_JPBRANCH_L6: JPTYPE("cJL_JPBRANCH_L6"); POP6;NUMJPSL;break; case cJL_JPBRANCH_L7: JPTYPE("cJL_JPBRANCH_L7"); POP7;NUMJPSL;break; #endif case cJL_JPBRANCH_L: JPTYPE("cJL_JPBRANCH_L"); NUMJPSL;break; case cJL_JPBRANCH_B2: JPTYPE("cJL_JPBRANCH_B2"); POP2;NUMJPSB;break; case cJL_JPBRANCH_B3: JPTYPE("cJL_JPBRANCH_B3"); POP3;NUMJPSB;break; #ifdef JU_64BIT case cJL_JPBRANCH_B4: JPTYPE("cJL_JPBRANCH_B4"); POP4;NUMJPSB;break; case cJL_JPBRANCH_B5: JPTYPE("cJL_JPBRANCH_B5"); POP5;NUMJPSB;break; case cJL_JPBRANCH_B6: JPTYPE("cJL_JPBRANCH_B6"); POP6;NUMJPSB;break; case cJL_JPBRANCH_B7: JPTYPE("cJL_JPBRANCH_B7"); POP7;NUMJPSB;break; #endif case cJL_JPBRANCH_B: JPTYPE("cJL_JPBRANCH_B"); NUMJPSB;break; case cJL_JPBRANCH_U2: JPTYPE("cJL_JPBRANCH_U2"); POP2; break; case cJL_JPBRANCH_U3: JPTYPE("cJL_JPBRANCH_U3"); POP3; break; #ifdef JU_64BIT case cJL_JPBRANCH_U4: JPTYPE("cJL_JPBRANCH_U4"); POP4; break; case cJL_JPBRANCH_U5: JPTYPE("cJL_JPBRANCH_U5"); POP5; break; case cJL_JPBRANCH_U6: JPTYPE("cJL_JPBRANCH_U6"); POP6; break; case cJL_JPBRANCH_U7: JPTYPE("cJL_JPBRANCH_U7"); POP7; break; #endif case cJL_JPBRANCH_U: JPTYPE("cJL_JPBRANCH_U"); break; case cJL_JPLEAF1: JPTYPE("cJL_JPLEAF1"); POP1; break; case cJL_JPLEAF2: JPTYPE("cJL_JPLEAF2"); POP2; break; case cJL_JPLEAF3: JPTYPE("cJL_JPLEAF3"); POP3; break; #ifdef JU_64BIT case cJL_JPLEAF4: JPTYPE("cJL_JPLEAF4"); POP4; break; case cJL_JPLEAF5: JPTYPE("cJL_JPLEAF5"); POP5; break; case cJL_JPLEAF6: JPTYPE("cJL_JPLEAF6"); POP6; break; case cJL_JPLEAF7: JPTYPE("cJL_JPLEAF7"); POP7; break; #endif case cJL_JPLEAF_B1: JPTYPE("cJL_JPLEAF_B1"); POP1; break; case cJL_JPIMMED_1_01: JPTYPE("cJL_JPIMMED_1_01"); POP_1; break; case cJL_JPIMMED_2_01: JPTYPE("cJL_JPIMMED_2_01"); POP_1; break; case cJL_JPIMMED_3_01: JPTYPE("cJL_JPIMMED_3_01"); POP_1; break; #ifdef JU_64BIT case cJL_JPIMMED_4_01: JPTYPE("cJL_JPIMMED_4_01"); POP_1; break; case cJL_JPIMMED_5_01: JPTYPE("cJL_JPIMMED_5_01"); POP_1; break; case cJL_JPIMMED_6_01: JPTYPE("cJL_JPIMMED_6_01"); POP_1; break; case cJL_JPIMMED_7_01: JPTYPE("cJL_JPIMMED_7_01"); POP_1; break; #endif case cJL_JPIMMED_1_02: JPTYPE("cJL_JPIMMED_1_02"); POP_2; break; case cJL_JPIMMED_1_03: JPTYPE("cJL_JPIMMED_1_03"); POP_3; break; #ifdef JU_64BIT case cJL_JPIMMED_1_04: JPTYPE("cJL_JPIMMED_1_04"); POP_4; break; case cJL_JPIMMED_1_05: JPTYPE("cJL_JPIMMED_1_05"); POP_5; break; case cJL_JPIMMED_1_06: JPTYPE("cJL_JPIMMED_1_06"); POP_6; break; case cJL_JPIMMED_1_07: JPTYPE("cJL_JPIMMED_1_07"); POP_7; break; case cJL_JPIMMED_2_02: JPTYPE("cJL_JPIMMED_2_02"); POP_2; break; case cJL_JPIMMED_2_03: JPTYPE("cJL_JPIMMED_2_03"); POP_3; break; case cJL_JPIMMED_3_02: JPTYPE("cJL_JPIMMED_3_02"); POP_2; break; #endif case cJL_JPIMMED_CAP: JPTYPE("cJL_JPIMMED_CAP"); OOPS; #endif // JUDYL default: printf("Unknown Type = %d", JU_JPTYPE(Pjp)); OOPS; } if (j__udyIndex) printf("Index = 0x%lx", j__udyIndex); if (j__udyPopulation) printf("Pop = %lu", j__udyPopulation); printf("line = %d\n", Line); } // JudyPrintJP() judy-1.0.5/src/JudyCommon/JudyFirst.c0000644000175000017500000001257710204462077017674 0ustar troyhebetroyhebe// Copyright (C) 2000 - 2002 Hewlett-Packard Company // // This program is free software; you can redistribute it and/or modify it // under the term of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License // for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program; if not, write to the Free Software Foundation, // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // _________________ // @(#) $Revision: 4.12 $ $Source: /judy/src/JudyCommon/JudyFirst.c $ // // Judy*First[Empty]() and Judy*Last[Empty]() routines for Judy1 and JudyL. // Compile with one of -DJUDY1 or -DJUDYL. // // These are inclusive versions of Judy*Next[Empty]() and Judy*Prev[Empty](). #if (! (defined(JUDY1) || defined(JUDYL))) #error: One of -DJUDY1 or -DJUDYL must be specified. #endif #ifdef JUDY1 #include "Judy1.h" #else #include "JudyL.h" #endif // **************************************************************************** // J U D Y 1 F I R S T // J U D Y L F I R S T // // See the manual entry for details. #ifdef JUDY1 FUNCTION int Judy1First #else FUNCTION PPvoid_t JudyLFirst #endif ( Pcvoid_t PArray, // Judy array to search. Word_t * PIndex, // starting point and result. PJError_t PJError // optional, for returning error info. ) { if (PIndex == (PWord_t) NULL) // caller error: { JU_SET_ERRNO(PJError, JU_ERRNO_NULLPINDEX); JUDY1CODE(return(JERRI );) JUDYLCODE(return(PPJERR);) } #ifdef JUDY1 switch (Judy1Test(PArray, *PIndex, PJError)) { case 1: return(1); // found *PIndex itself. case 0: return(Judy1Next(PArray, PIndex, PJError)); default: return(JERRI); } #else { PPvoid_t PValue; if ((PValue = JudyLGet(PArray, *PIndex, PJError)) == PPJERR) return(PPJERR); if (PValue != (PPvoid_t) NULL) return(PValue); // found *PIndex. return(JudyLNext(PArray, PIndex, PJError)); } #endif } // Judy1First() / JudyLFirst() // **************************************************************************** // J U D Y 1 L A S T // J U D Y L L A S T // // See the manual entry for details. #ifdef JUDY1 FUNCTION int Judy1Last( #else FUNCTION PPvoid_t JudyLLast( #endif Pcvoid_t PArray, // Judy array to search. Word_t * PIndex, // starting point and result. PJError_t PJError) // optional, for returning error info. { if (PIndex == (PWord_t) NULL) { JU_SET_ERRNO(PJError, JU_ERRNO_NULLPINDEX); // caller error. JUDY1CODE(return(JERRI );) JUDYLCODE(return(PPJERR);) } #ifdef JUDY1 switch (Judy1Test(PArray, *PIndex, PJError)) { case 1: return(1); // found *PIndex itself. case 0: return(Judy1Prev(PArray, PIndex, PJError)); default: return(JERRI); } #else { PPvoid_t PValue; if ((PValue = JudyLGet(PArray, *PIndex, PJError)) == PPJERR) return(PPJERR); if (PValue != (PPvoid_t) NULL) return(PValue); // found *PIndex. return(JudyLPrev(PArray, PIndex, PJError)); } #endif } // Judy1Last() / JudyLLast() // **************************************************************************** // J U D Y 1 F I R S T E M P T Y // J U D Y L F I R S T E M P T Y // // See the manual entry for details. #ifdef JUDY1 FUNCTION int Judy1FirstEmpty( #else FUNCTION int JudyLFirstEmpty( #endif Pcvoid_t PArray, // Judy array to search. Word_t * PIndex, // starting point and result. PJError_t PJError) // optional, for returning error info. { if (PIndex == (PWord_t) NULL) // caller error: { JU_SET_ERRNO(PJError, JU_ERRNO_NULLPINDEX); return(JERRI); } #ifdef JUDY1 switch (Judy1Test(PArray, *PIndex, PJError)) { case 0: return(1); // found *PIndex itself. case 1: return(Judy1NextEmpty(PArray, PIndex, PJError)); default: return(JERRI); } #else { PPvoid_t PValue; if ((PValue = JudyLGet(PArray, *PIndex, PJError)) == PPJERR) return(JERRI); if (PValue == (PPvoid_t) NULL) return(1); // found *PIndex. return(JudyLNextEmpty(PArray, PIndex, PJError)); } #endif } // Judy1FirstEmpty() / JudyLFirstEmpty() // **************************************************************************** // J U D Y 1 L A S T E M P T Y // J U D Y L L A S T E M P T Y // // See the manual entry for details. #ifdef JUDY1 FUNCTION int Judy1LastEmpty( #else FUNCTION int JudyLLastEmpty( #endif Pcvoid_t PArray, // Judy array to search. Word_t * PIndex, // starting point and result. PJError_t PJError) // optional, for returning error info. { if (PIndex == (PWord_t) NULL) { JU_SET_ERRNO(PJError, JU_ERRNO_NULLPINDEX); // caller error. return(JERRI); } #ifdef JUDY1 switch (Judy1Test(PArray, *PIndex, PJError)) { case 0: return(1); // found *PIndex itself. case 1: return(Judy1PrevEmpty(PArray, PIndex, PJError)); default: return(JERRI); } #else { PPvoid_t PValue; if ((PValue = JudyLGet(PArray, *PIndex, PJError)) == PPJERR) return(JERRI); if (PValue == (PPvoid_t) NULL) return(1); // found *PIndex. return(JudyLPrevEmpty(PArray, PIndex, PJError)); } #endif } // Judy1LastEmpty() / JudyLLastEmpty() judy-1.0.5/src/JudyCommon/JudyInsArray.c0000644000175000017500000012506010204462077020325 0ustar troyhebetroyhebe// Copyright (C) 2000 - 2002 Hewlett-Packard Company // // This program is free software; you can redistribute it and/or modify it // under the term of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License // for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program; if not, write to the Free Software Foundation, // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // _________________ // TBD: It would probably be faster for the caller if the JudyL version took // PIndex as an interleaved array of indexes and values rather than just // indexes with a separate values array (PValue), especially considering // indexes and values are copied here with for-loops anyway and not the // equivalent of memcpy(). All code could be revised to simply count by two // words for JudyL? Supports "streaming" the data to/from disk better later? // In which case get rid of JU_ERRNO_NULLPVALUE, no longer needed, and simplify // the API to this code. // _________________ // @(#) $Revision: 4.21 $ $Source: /judy/src/JudyCommon/JudyInsArray.c $ // // Judy1SetArray() and JudyLInsArray() functions for Judy1 and JudyL. // Compile with one of -DJUDY1 or -DJUDYL. #if (! (defined(JUDY1) || defined(JUDYL))) #error: One of -DJUDY1 or -DJUDYL must be specified. #endif #ifdef JUDY1 #include "Judy1.h" #else #include "JudyL.h" #endif #include "JudyPrivate1L.h" DBGCODE(extern void JudyCheckPop(Pvoid_t PArray);) // IMMED AND LEAF SIZE AND BRANCH TYPE ARRAYS: // // These support fast and easy lookup by level. static uint8_t immed_maxpop1[] = { 0, cJU_IMMED1_MAXPOP1, cJU_IMMED2_MAXPOP1, cJU_IMMED3_MAXPOP1, #ifdef JU_64BIT cJU_IMMED4_MAXPOP1, cJU_IMMED5_MAXPOP1, cJU_IMMED6_MAXPOP1, cJU_IMMED7_MAXPOP1, #endif // note: There are no IMMEDs for whole words. }; static uint8_t leaf_maxpop1[] = { 0, #if (defined(JUDYL) || (! defined(JU_64BIT))) cJU_LEAF1_MAXPOP1, #else 0, // 64-bit Judy1 has no Leaf1. #endif cJU_LEAF2_MAXPOP1, cJU_LEAF3_MAXPOP1, #ifdef JU_64BIT cJU_LEAF4_MAXPOP1, cJU_LEAF5_MAXPOP1, cJU_LEAF6_MAXPOP1, cJU_LEAF7_MAXPOP1, #endif // note: Root-level leaves are handled differently. }; static uint8_t branchL_JPtype[] = { 0, 0, cJU_JPBRANCH_L2, cJU_JPBRANCH_L3, #ifdef JU_64BIT cJU_JPBRANCH_L4, cJU_JPBRANCH_L5, cJU_JPBRANCH_L6, cJU_JPBRANCH_L7, #endif cJU_JPBRANCH_L, }; static uint8_t branchB_JPtype[] = { 0, 0, cJU_JPBRANCH_B2, cJU_JPBRANCH_B3, #ifdef JU_64BIT cJU_JPBRANCH_B4, cJU_JPBRANCH_B5, cJU_JPBRANCH_B6, cJU_JPBRANCH_B7, #endif cJU_JPBRANCH_B, }; static uint8_t branchU_JPtype[] = { 0, 0, cJU_JPBRANCH_U2, cJU_JPBRANCH_U3, #ifdef JU_64BIT cJU_JPBRANCH_U4, cJU_JPBRANCH_U5, cJU_JPBRANCH_U6, cJU_JPBRANCH_U7, #endif cJU_JPBRANCH_U, }; // Subexpanse masks are similer to JU_DCDMASK() but without the need to clear // the first digits bits. Avoid doing variable shifts by precomputing a // lookup array. static Word_t subexp_mask[] = { 0, ~cJU_POP0MASK(1), ~cJU_POP0MASK(2), ~cJU_POP0MASK(3), #ifdef JU_64BIT ~cJU_POP0MASK(4), ~cJU_POP0MASK(5), ~cJU_POP0MASK(6), ~cJU_POP0MASK(7), #endif }; // FUNCTION PROTOTYPES: static bool_t j__udyInsArray(Pjp_t PjpParent, int Level, PWord_t PPop1, PWord_t PIndex, #ifdef JUDYL Pjv_t PValue, #endif Pjpm_t Pjpm); // **************************************************************************** // J U D Y 1 S E T A R R A Y // J U D Y L I N S A R R A Y // // Main entry point. See the manual entry for external overview. // // TBD: Until thats written, note that the function returns 1 for success or // JERRI for serious error, including insufficient memory to build whole array; // use Judy*Count() to see how many were stored, the first N of the total // Count. Also, since it takes Count == Pop1, it cannot handle a full array. // Also, "sorted" means ascending without duplicates, otherwise you get the // "unsorted" error. // // The purpose of these functions is to allow rapid construction of a large // Judy array given a sorted list of indexes (and for JudyL, corresponding // values). At least one customer saw this as useful, and probably it would // also be useful as a sufficient workaround for fast(er) unload/reload to/from // disk. // // This code is written recursively for simplicity, until/unless someone // decides to make it faster and more complex. Hopefully recursion is fast // enough simply because the function is so much faster than a series of // Set/Ins calls. #ifdef JUDY1 FUNCTION int Judy1SetArray #else FUNCTION int JudyLInsArray #endif ( PPvoid_t PPArray, // in which to insert, initially empty. Word_t Count, // number of indexes (and values) to insert. const Word_t * const PIndex, // list of indexes to insert. #ifdef JUDYL const Word_t * const PValue, // list of corresponding values. #endif PJError_t PJError // optional, for returning error info. ) { Pjlw_t Pjlw; // new root-level leaf. Pjlw_t Pjlwindex; // first index in root-level leaf. int offset; // in PIndex. // CHECK FOR NULL OR NON-NULL POINTER (error by caller): if (PPArray == (PPvoid_t) NULL) { JU_SET_ERRNO(PJError, JU_ERRNO_NULLPPARRAY); return(JERRI); } if (*PPArray != (Pvoid_t) NULL) { JU_SET_ERRNO(PJError, JU_ERRNO_NONNULLPARRAY); return(JERRI); } if (PIndex == (PWord_t) NULL) { JU_SET_ERRNO(PJError, JU_ERRNO_NULLPINDEX); return(JERRI); } #ifdef JUDYL if (PValue == (PWord_t) NULL) { JU_SET_ERRNO(PJError, JU_ERRNO_NULLPVALUE); return(JERRI); } #endif // HANDLE LARGE COUNT (= POP1) (typical case): // // Allocate and initialize a JPM, set the root pointer to point to it, and then // build the tree underneath it. // Common code for unusual error handling when no JPM available: if (Count > cJU_LEAFW_MAXPOP1) // too big for root-level leaf. { Pjpm_t Pjpm; // new, to allocate. // Allocate JPM: Pjpm = j__udyAllocJPM(); JU_CHECKALLOC(Pjpm_t, Pjpm, JERRI); *PPArray = (Pvoid_t) Pjpm; // Set some JPM fields: (Pjpm->jpm_Pop0) = Count - 1; // note: (Pjpm->jpm_TotalMemWords) is now initialized. // Build Judy tree: // // In case of error save the final Count, possibly modified, unless modified to // 0, in which case free the JPM itself: if (! j__udyInsArray(&(Pjpm->jpm_JP), cJU_ROOTSTATE, &Count, (PWord_t) PIndex, #ifdef JUDYL (Pjv_t) PValue, #endif Pjpm)) { JU_COPY_ERRNO(PJError, Pjpm); if (Count) // partial success, adjust pop0: { (Pjpm->jpm_Pop0) = Count - 1; } else // total failure, free JPM: { j__udyFreeJPM(Pjpm, (Pjpm_t) NULL); *PPArray = (Pvoid_t) NULL; } DBGCODE(JudyCheckPop(*PPArray);) return(JERRI); } DBGCODE(JudyCheckPop(*PPArray);) return(1); } // large count // HANDLE SMALL COUNT (= POP1): // // First ensure indexes are in sorted order: for (offset = 1; offset < Count; ++offset) { if (PIndex[offset - 1] >= PIndex[offset]) { JU_SET_ERRNO(PJError, JU_ERRNO_UNSORTED); return(JERRI); } } if (Count == 0) return(1); // *PPArray remains null. { Pjlw = j__udyAllocJLW(Count + 1); JU_CHECKALLOC(Pjlw_t, Pjlw, JERRI); *PPArray = (Pvoid_t) Pjlw; Pjlw[0] = Count - 1; // set pop0. Pjlwindex = Pjlw + 1; } // Copy whole-word indexes (and values) to the root-level leaf: JU_COPYMEM(Pjlwindex, PIndex, Count); JUDYLCODE(JU_COPYMEM(JL_LEAFWVALUEAREA(Pjlw, Count), PValue, Count)); DBGCODE(JudyCheckPop(*PPArray);) return(1); } // Judy1SetArray() / JudyLInsArray() // **************************************************************************** // __ J U D Y I N S A R R A Y // // Given: // // - a pointer to a JP // // - the JPs level in the tree, that is, the number of digits left to decode // in the indexes under the JP (one less than the level of the JPM or branch // in which the JP resides); cJU_ROOTSTATE on first entry (when JP is the one // in the JPM), down to 1 for a Leaf1, LeafB1, or FullPop // // - a pointer to the number of indexes (and corresponding values) to store in // this subtree, to modify in case of partial success // // - a list of indexes (and for JudyL, corresponding values) to store in this // subtree // // - a JPM for tracking memory usage and returning errors // // Recursively build a subtree (immediate indexes, leaf, or branch with // subtrees) and modify the JP accordingly. On the way down, build a BranchU // (only) for any expanse with *PPop1 too high for a leaf; on the way out, // convert the BranchU to a BranchL or BranchB if appropriate. Keep memory // statistics in the JPM. // // Return TRUE for success, or FALSE with error information set in the JPM in // case of error, in which case leave a partially constructed but healthy tree, // and modify parent population counts on the way out. // // Note: Each call of this function makes all modifications to the PjpParent // it receives; neither the parent nor child calls do this. FUNCTION static bool_t j__udyInsArray( Pjp_t PjpParent, // parent JP in/under which to store. int Level, // initial digits remaining to decode. PWord_t PPop1, // number of indexes to store. PWord_t PIndex, // list of indexes to store. #ifdef JUDYL Pjv_t PValue, // list of corresponding values. #endif Pjpm_t Pjpm) // for memory and errors. { Pjp_t Pjp; // lower-level JP. Word_t Pjbany; // any type of branch. int levelsub; // actual, of Pjps node, <= Level. Word_t pop1 = *PPop1; // fast local value. Word_t pop1sub; // population of one subexpanse. uint8_t JPtype; // current JP type. uint8_t JPtype_null; // precomputed value for new branch. jp_t JPnull; // precomputed for speed. Pjbu_t PjbuRaw; // constructed BranchU. Pjbu_t Pjbu; int digit; // in BranchU. Word_t digitmask; // for a digit in a BranchU. Word_t digitshifted; // shifted to correct offset. Word_t digitshincr; // increment for digitshifted. int offset; // in PIndex, or a bitmap subexpanse. int numJPs; // number non-null in a BranchU. bool_t retval; // to return from this func. JUDYLCODE(Pjv_t PjvRaw); // destination value area. JUDYLCODE(Pjv_t Pjv); // MACROS FOR COMMON CODE: // // Note: These use function and local parameters from the context. // Note: Assume newly allocated memory is zeroed. // Indicate whether a sorted list of indexes in PIndex, based on the first and // last indexes in the list using pop1, are in the same subexpanse between // Level and L_evel: // // This can be confusing! Note that SAMESUBEXP(L) == TRUE means the indexes // are the same through level L + 1, and it says nothing about level L and // lower; they might be the same or they might differ. // // Note: In principle SAMESUBEXP needs a mask for the digits from Level, // inclusive, to L_evel, exclusive. But in practice, since the indexes are all // known to be identical above Level, it just uses a mask for the digits // through L_evel + 1; see subexp_mask[]. #define SAMESUBEXP(L_evel) \ (! ((PIndex[0] ^ PIndex[pop1 - 1]) & subexp_mask[L_evel])) // Set PjpParent to a null JP appropriate for the level of the node to which it // points, which is 1 less than the level of the node in which the JP resides, // which is by definition Level: // // Note: This can set the JPMs JP to an invalid jp_Type, but it doesnt // matter because the JPM is deleted by the caller. #define SETJPNULL_PARENT \ JU_JPSETADT(PjpParent, 0, 0, cJU_JPNULL1 + Level - 1); // Variation to set a specified JP (in a branch being built) to a precomputed // null JP: #define SETJPNULL(Pjp) *(Pjp) = JPnull // Handle complete (as opposed to partial) memory allocation failure: Set the // parent JP to an appropriate null type (to leave a consistent tree), zero the // callers population count, and return FALSE: // // Note: At Level == cJU_ROOTSTATE this sets the JPMs JPs jp_Type to a bogus // value, but it doesnt matter because the JPM should be deleted by the // caller. #define NOMEM { SETJPNULL_PARENT; *PPop1 = 0; return(FALSE); } // Allocate a Leaf1-N and save the address in Pjll; in case of failure, NOMEM: #define ALLOCLEAF(AllocLeaf) \ if ((PjllRaw = AllocLeaf(pop1, Pjpm)) == (Pjll_t) NULL) NOMEM; \ Pjll = P_JLL(PjllRaw); // Copy indexes smaller than words (and values which are whole words) from // given arrays to immediate indexes or a leaf: // // TBD: These macros overlap with some of the code in JudyCascade.c; do some // merging? That file has functions while these are macros. #define COPYTOLEAF_EVEN_SUB(Pjll,LeafType) \ { \ LeafType * P_leaf = (LeafType *) (Pjll); \ Word_t p_op1 = pop1; \ PWord_t P_Index = PIndex; \ \ assert(pop1 > 0); \ \ do { *P_leaf++ = *P_Index++; /* truncates */\ } while (--(p_op1)); \ } #define COPYTOLEAF_ODD_SUB(cLevel,Pjll,Copy) \ { \ uint8_t * P_leaf = (uint8_t *) (Pjll); \ Word_t p_op1 = pop1; \ PWord_t P_Index = PIndex; \ \ assert(pop1 > 0); \ \ do { \ Copy(P_leaf, *P_Index); \ P_leaf += (cLevel); ++P_Index; \ } while (--(p_op1)); \ } #ifdef JUDY1 #define COPYTOLEAF_EVEN(Pjll,LeafType) COPYTOLEAF_EVEN_SUB(Pjll,LeafType) #define COPYTOLEAF_ODD(cLevel,Pjll,Copy) COPYTOLEAF_ODD_SUB(cLevel,Pjll,Copy) #else // JUDYL adds copying of values: #define COPYTOLEAF_EVEN(Pjll,LeafType) \ { \ COPYTOLEAF_EVEN_SUB(Pjll,LeafType) \ JU_COPYMEM(Pjv, PValue, pop1); \ } #define COPYTOLEAF_ODD(cLevel,Pjll,Copy) \ { \ COPYTOLEAF_ODD_SUB( cLevel,Pjll,Copy) \ JU_COPYMEM(Pjv, PValue, pop1); \ } #endif // Set the JP type for an immediate index, where BaseJPType is JPIMMED_*_02: #define SETIMMTYPE(BaseJPType) (PjpParent->jp_Type) = (BaseJPType) + pop1 - 2 // Allocate and populate a Leaf1-N: // // Build MAKELEAF_EVEN() and MAKELEAF_ODD() using macros for common code. #define MAKELEAF_SUB1(AllocLeaf,ValueArea,LeafType) \ ALLOCLEAF(AllocLeaf); \ JUDYLCODE(Pjv = ValueArea(Pjll, pop1)) #define MAKELEAF_SUB2(cLevel,JPType) \ { \ Word_t D_cdP0; \ assert(pop1 - 1 <= cJU_POP0MASK(cLevel)); \ D_cdP0 = (*PIndex & cJU_DCDMASK(cLevel)) | (pop1 - 1); \ JU_JPSETADT(PjpParent, (Word_t)PjllRaw, D_cdP0, JPType); \ } #define MAKELEAF_EVEN(cLevel,JPType,AllocLeaf,ValueArea,LeafType) \ MAKELEAF_SUB1(AllocLeaf,ValueArea,LeafType); \ COPYTOLEAF_EVEN(Pjll, LeafType); \ MAKELEAF_SUB2(cLevel, JPType) #define MAKELEAF_ODD(cLevel,JPType,AllocLeaf,ValueArea,Copy) \ MAKELEAF_SUB1(AllocLeaf,ValueArea,LeafType); \ COPYTOLEAF_ODD(cLevel, Pjll, Copy); \ MAKELEAF_SUB2(cLevel, JPType) // Ensure that the indexes to be stored in immediate indexes or a leaf are // sorted: // // This check is pure overhead, but required in order to protect the Judy array // against caller error, to avoid a later corruption or core dump from a // seemingly valid Judy array. Do this check piecemeal at the leaf level while // the indexes are already in the cache. Higher-level order-checking occurs // while building branches. // // Note: Any sorting error in the expanse of a single immediate indexes JP or // a leaf => save no indexes in that expanse. #define CHECKLEAFORDER \ { \ for (offset = 1; offset < pop1; ++offset) \ { \ if (PIndex[offset - 1] >= PIndex[offset]) \ { \ SETJPNULL_PARENT; \ *PPop1 = 0; \ JU_SET_ERRNO_NONNULL(Pjpm, JU_ERRNO_UNSORTED); \ return(FALSE); \ } \ } \ } // ------ START OF CODE ------ assert( Level >= 1); assert( Level <= cJU_ROOTSTATE); assert((Level < cJU_ROOTSTATE) || (pop1 > cJU_LEAFW_MAXPOP1)); // CHECK FOR TOP LEVEL: // // Special case: If at the top level (PjpParent is in the JPM), a top-level // branch must be created, even if its a BranchL with just one JP. (The JPM // cannot point to a leaf because the leaf would have to be a lower-level, // higher-capacity leaf under a narrow pointer (otherwise a root-level leaf // would suffice), and the JPMs JP cant handle a narrow pointer because the // jp_DcdPopO field isnt big enough.) Otherwise continue to check for a pop1 // small enough to support immediate indexes or a leaf before giving up and // making a lower-level branch. if (Level == cJU_ROOTSTATE) { levelsub = cJU_ROOTSTATE; goto BuildBranch2; } assert(Level < cJU_ROOTSTATE); // SKIP JPIMMED_*_01: // // Immeds with pop1 == 1 should be handled in-line during branch construction. assert(pop1 > 1); // BUILD JPIMMED_*_02+: // // The starting address of the indexes depends on Judy1 or JudyL; also, JudyL // includes a pointer to a values-only leaf. if (pop1 <= immed_maxpop1[Level]) // note: always < root level. { JUDY1CODE(uint8_t * Pjll = (uint8_t *) (PjpParent->jp_1Index);) JUDYLCODE(uint8_t * Pjll = (uint8_t *) (PjpParent->jp_LIndex);) CHECKLEAFORDER; // indexes to be stored are sorted. #ifdef JUDYL if ((PjvRaw = j__udyLAllocJV(pop1, Pjpm)) == (Pjv_t) NULL) NOMEM; (PjpParent->jp_Addr) = (Word_t) PjvRaw; Pjv = P_JV(PjvRaw); #endif switch (Level) { case 1: COPYTOLEAF_EVEN(Pjll, uint8_t); SETIMMTYPE(cJU_JPIMMED_1_02); break; #if (defined(JUDY1) || defined(JU_64BIT)) case 2: COPYTOLEAF_EVEN(Pjll, uint16_t); SETIMMTYPE(cJU_JPIMMED_2_02); break; case 3: COPYTOLEAF_ODD(3, Pjll, JU_COPY3_LONG_TO_PINDEX); SETIMMTYPE(cJU_JPIMMED_3_02); break; #endif #if (defined(JUDY1) && defined(JU_64BIT)) case 4: COPYTOLEAF_EVEN(Pjll, uint32_t); SETIMMTYPE(cJ1_JPIMMED_4_02); break; case 5: COPYTOLEAF_ODD(5, Pjll, JU_COPY5_LONG_TO_PINDEX); SETIMMTYPE(cJ1_JPIMMED_5_02); break; case 6: COPYTOLEAF_ODD(6, Pjll, JU_COPY6_LONG_TO_PINDEX); SETIMMTYPE(cJ1_JPIMMED_6_02); break; case 7: COPYTOLEAF_ODD(7, Pjll, JU_COPY7_LONG_TO_PINDEX); SETIMMTYPE(cJ1_JPIMMED_7_02); break; #endif default: assert(FALSE); // should be impossible. } return(TRUE); // note: no children => no *PPop1 mods. } // JPIMMED_*_02+ // BUILD JPLEAF*: // // This code is a little tricky. The method is: For each level starting at // the present Level down through levelsub = 1, and then as a special case for // LeafB1 and FullPop (which are also at levelsub = 1 but have different // capacity, see later), check if pop1 fits in a leaf (using leaf_maxpop1[]) // at that level. If so, except for Level == levelsub, check if all of the // current indexes to be stored are in the same (narrow) subexpanse, that is, // the digits from Level to levelsub + 1, inclusive, are identical between the // first and last index in the (sorted) list (in PIndex). If this condition is // satisfied at any level, build a leaf at that level (under a narrow pointer // if Level > levelsub). // // Note: Doing the search in this order results in storing the indexes in // "least compressed form." for (levelsub = Level; levelsub >= 1; --levelsub) { Pjll_t PjllRaw; Pjll_t Pjll; // Check if pop1 is too large to fit in a leaf at levelsub; if so, try the next // lower level: if (pop1 > leaf_maxpop1[levelsub]) continue; // If pop1 fits in a leaf at levelsub, but levelsub is lower than Level, must // also check whether all the indexes in the expanse to store can in fact be // placed under a narrow pointer; if not, a leaf cannot be used, at this or any // lower level (levelsub): if ((levelsub < Level) && (! SAMESUBEXP(levelsub))) goto BuildBranch; // cant use a narrow, need a branch. // Ensure valid pop1 and all indexes are in fact common through Level: assert(pop1 <= cJU_POP0MASK(Level) + 1); assert(! ((PIndex[0] ^ PIndex[pop1 - 1]) & cJU_DCDMASK(Level))); CHECKLEAFORDER; // indexes to be stored are sorted. // Build correct type of leaf: // // Note: The jp_DcdPopO and jp_Type assignments in MAKELEAF_* happen correctly // for the levelsub (not Level) of the new leaf, even if its under a narrow // pointer. switch (levelsub) { #if (defined(JUDYL) || (! defined(JU_64BIT))) case 1: MAKELEAF_EVEN(1, cJU_JPLEAF1, j__udyAllocJLL1, JL_LEAF1VALUEAREA, uint8_t); break; #endif case 2: MAKELEAF_EVEN(2, cJU_JPLEAF2, j__udyAllocJLL2, JL_LEAF2VALUEAREA, uint16_t); break; case 3: MAKELEAF_ODD( 3, cJU_JPLEAF3, j__udyAllocJLL3, JL_LEAF3VALUEAREA, JU_COPY3_LONG_TO_PINDEX); break; #ifdef JU_64BIT case 4: MAKELEAF_EVEN(4, cJU_JPLEAF4, j__udyAllocJLL4, JL_LEAF4VALUEAREA, uint32_t); break; case 5: MAKELEAF_ODD( 5, cJU_JPLEAF5, j__udyAllocJLL5, JL_LEAF5VALUEAREA, JU_COPY5_LONG_TO_PINDEX); break; case 6: MAKELEAF_ODD( 6, cJU_JPLEAF6, j__udyAllocJLL6, JL_LEAF6VALUEAREA, JU_COPY6_LONG_TO_PINDEX); break; case 7: MAKELEAF_ODD( 7, cJU_JPLEAF7, j__udyAllocJLL7, JL_LEAF7VALUEAREA, JU_COPY7_LONG_TO_PINDEX); break; #endif default: assert(FALSE); // should be impossible. } return(TRUE); // note: no children => no *PPop1 mods. } // JPLEAF* // BUILD JPLEAF_B1 OR JPFULLPOPU1: // // See above about JPLEAF*. If pop1 doesnt fit in any level of linear leaf, // it might still fit in a LeafB1 or FullPop, perhaps under a narrow pointer. if ((Level == 1) || SAMESUBEXP(1)) // same until last digit. { Pjlb_t PjlbRaw; // for bitmap leaf. Pjlb_t Pjlb; assert(pop1 <= cJU_JPFULLPOPU1_POP0 + 1); CHECKLEAFORDER; // indexes to be stored are sorted. #ifdef JUDY1 // JPFULLPOPU1: if (pop1 == cJU_JPFULLPOPU1_POP0 + 1) { Word_t Addr = PjpParent->jp_Addr; Word_t DcdP0 = (*PIndex & cJU_DCDMASK(1)) | cJU_JPFULLPOPU1_POP0; JU_JPSETADT(PjpParent, Addr, DcdP0, cJ1_JPFULLPOPU1); return(TRUE); } #endif // JPLEAF_B1: if ((PjlbRaw = j__udyAllocJLB1(Pjpm)) == (Pjlb_t) NULL) NOMEM; Pjlb = P_JLB(PjlbRaw); for (offset = 0; offset < pop1; ++offset) JU_BITMAPSETL(Pjlb, PIndex[offset]); retval = TRUE; // default. #ifdef JUDYL // Build subexpanse values-only leaves (LeafVs) under LeafB1: for (offset = 0; offset < cJU_NUMSUBEXPL; ++offset) { if (! (pop1sub = j__udyCountBitsL(JU_JLB_BITMAP(Pjlb, offset)))) continue; // skip empty subexpanse. // Allocate one LeafV = JP subarray; if out of memory, clear bitmaps for higher // subexpanses and adjust *PPop1: if ((PjvRaw = j__udyLAllocJV(pop1sub, Pjpm)) == (Pjv_t) NULL) { for (/* null */; offset < cJU_NUMSUBEXPL; ++offset) { *PPop1 -= j__udyCountBitsL(JU_JLB_BITMAP(Pjlb, offset)); JU_JLB_BITMAP(Pjlb, offset) = 0; } retval = FALSE; break; } // Populate values-only leaf and save the pointer to it: Pjv = P_JV(PjvRaw); JU_COPYMEM(Pjv, PValue, pop1sub); JL_JLB_PVALUE(Pjlb, offset) = PjvRaw; // first-tier pointer. PValue += pop1sub; } // for each subexpanse #endif // JUDYL // Attach new LeafB1 to parent JP; note use of *PPop1 possibly < pop1: JU_JPSETADT(PjpParent, (Word_t) PjlbRaw, (*PIndex & cJU_DCDMASK(1)) | (*PPop1 - 1), cJU_JPLEAF_B1); return(retval); } // JPLEAF_B1 or JPFULLPOPU1 // BUILD JPBRANCH_U*: // // Arriving at BuildBranch means Level < top level but the pop1 is too large // for immediate indexes or a leaf, even under a narrow pointer, including a // LeafB1 or FullPop at level 1. This implies SAMESUBEXP(1) == FALSE, that is, // the indexes to be stored "branch" at level 2 or higher. BuildBranch: // come here directly if a leaf wont work. assert(Level >= 2); assert(Level < cJU_ROOTSTATE); assert(! SAMESUBEXP(1)); // sanity check, see above. // Determine the appropriate level for a new branch node; see if a narrow // pointer can be used: // // This can be confusing. The branch is required at the lowest level L where // the indexes to store are not in the same subexpanse at level L-1. Work down // from Level to tree level 3, which is 1 above the lowest tree level = 2 at // which a branch can be used. Theres no need to check SAMESUBEXP at level 2 // because its known to be false at level 2-1 = 1. // // Note: Unlike for a leaf node, a narrow pointer is always used for a branch // if possible, that is, maximum compression is always used, except at the top // level of the tree, where a JPM cannot support a narrow pointer, meaning a // top BranchL can have a single JP (fanout = 1); but that case jumps directly // to BuildBranch2. // // Note: For 32-bit systems the only usable values for a narrow pointer are // Level = 3 and levelsub = 2; 64-bit systems have many more choices; but // hopefully this for-loop is fast enough even on a 32-bit system. // // TBD: If not fast enough, #ifdef JU_64BIT and handle the 32-bit case faster. for (levelsub = Level; levelsub >= 3; --levelsub) // see above. if (! SAMESUBEXP(levelsub - 1)) // at limit of narrow pointer. break; // put branch at levelsub. BuildBranch2: // come here directly for Level = levelsub = cJU_ROOTSTATE. assert(levelsub >= 2); assert(levelsub <= Level); // Initially build a BranchU: // // Always start with a BranchU because the number of populated subexpanses is // not yet known. Use digitmask, digitshifted, and digitshincr to avoid // expensive variable shifts within JU_DIGITATSTATE within the loop. // // TBD: The use of digitmask, etc. results in more increment operations per // loop, is there an even faster way? // // TBD: Would it pay to pre-count the populated JPs (subexpanses) and // pre-compress the branch, that is, build a BranchL or BranchB immediately, // also taking account of opportunistic uncompression rules? Probably not // because at high levels of the tree there might be huge numbers of indexes // (hence cache lines) to scan in the PIndex array to determine the fanout // (number of JPs) needed. if ((PjbuRaw = j__udyAllocJBU(Pjpm)) == (Pjbu_t) NULL) NOMEM; Pjbu = P_JBU(PjbuRaw); JPtype_null = cJU_JPNULL1 + levelsub - 2; // in new BranchU. JU_JPSETADT(&JPnull, 0, 0, JPtype_null); Pjp = Pjbu->jbu_jp; // for convenience in loop. numJPs = 0; // non-null in the BranchU. digitmask = cJU_MASKATSTATE(levelsub); // see above. digitshincr = 1UL << (cJU_BITSPERBYTE * (levelsub - 1)); retval = TRUE; // Scan and populate JPs (subexpanses): // // Look for all indexes matching each digit in the BranchU (at the correct // levelsub), and meanwhile notice any sorting error. Increment PIndex (and // PValue) and reduce pop1 for each subexpanse handled successfully. for (digit = digitshifted = 0; digit < cJU_BRANCHUNUMJPS; ++digit, digitshifted += digitshincr, ++Pjp) { DBGCODE(Word_t pop1subprev;) assert(pop1 != 0); // end of indexes is handled elsewhere. // Count indexes in digits subexpanse: for (pop1sub = 0; pop1sub < pop1; ++pop1sub) if (digitshifted != (PIndex[pop1sub] & digitmask)) break; // Empty subexpanse (typical, performance path) or sorting error (rare): if (pop1sub == 0) { if (digitshifted < (PIndex[0] & digitmask)) { SETJPNULL(Pjp); continue; } // empty subexpanse. assert(pop1 < *PPop1); // did save >= 1 index and decr pop1. JU_SET_ERRNO_NONNULL(Pjpm, JU_ERRNO_UNSORTED); goto AbandonBranch; } // Non-empty subexpanse: // // First shortcut by handling pop1sub == 1 (JPIMMED_*_01) inline locally. if (pop1sub == 1) // note: can be at root level. { Word_t Addr = 0; JUDYLCODE(Addr = (Word_t) (*PValue++);) JU_JPSETADT(Pjp, Addr, *PIndex, cJU_JPIMMED_1_01 + levelsub -2); ++numJPs; if (--pop1) { ++PIndex; continue; } // more indexes to store. ++digit; ++Pjp; // skip JP just saved. goto ClearBranch; // save time. } // Recurse to populate one digits (subexpanses) JP; if successful, skip // indexes (and values) just stored (performance path), except when expanse is // completely stored: DBGCODE(pop1subprev = pop1sub;) if (j__udyInsArray(Pjp, levelsub - 1, &pop1sub, (PWord_t) PIndex, #ifdef JUDYL (Pjv_t) PValue, #endif Pjpm)) { // complete success. ++numJPs; assert(pop1subprev == pop1sub); assert(pop1 >= pop1sub); if ((pop1 -= pop1sub) != 0) // more indexes to store: { PIndex += pop1sub; // skip indexes just stored. JUDYLCODE(PValue += pop1sub;) continue; } // else leave PIndex in BranchUs expanse. // No more indexes to store in BranchUs expanse: ++digit; ++Pjp; // skip JP just saved. goto ClearBranch; // save time. } // Handle any error at a lower level of recursion: // // In case of partial success, pop1sub != 0, but it was reduced from the value // passed to j__udyInsArray(); skip this JP later during ClearBranch. assert(pop1subprev > pop1sub); // check j__udyInsArray(). assert(pop1 > pop1sub); // check j__udyInsArray(). if (pop1sub) // partial success. { ++digit; ++Pjp; ++numJPs; } // skip JP just saved. pop1 -= pop1sub; // deduct saved indexes if any. // Same-level sorting error, or any lower-level error; abandon the rest of the // branch: // // Arrive here with pop1 = remaining unsaved indexes (always non-zero). Adjust // the *PPop1 value to record and return, modify retval, and use ClearBranch to // finish up. AbandonBranch: assert(pop1 != 0); // more to store, see above. assert(pop1 <= *PPop1); // sanity check. *PPop1 -= pop1; // deduct unsaved indexes. pop1 = 0; // to avoid error later. retval = FALSE; // Error (rare), or end of indexes while traversing new BranchU (performance // path); either way, mark the remaining JPs, if any, in the BranchU as nulls // and exit the loop: // // Arrive here with digit and Pjp set to the first JP to set to null. ClearBranch: for (/* null */; digit < cJU_BRANCHUNUMJPS; ++digit, ++Pjp) SETJPNULL(Pjp); break; // saves one more compare. } // for each digit // FINISH JPBRANCH_U*: // // Arrive here with a BranchU built under Pjbu, numJPs set, and either: retval // == TRUE and *PPop1 unmodified, or else retval == FALSE, *PPop1 set to the // actual number of indexes saved (possibly 0 for complete failure at a lower // level upon the first call of j__udyInsArray()), and the Judy error set in // Pjpm. Either way, PIndex points to an index within the expanse just // handled. Pjbany = (Word_t) PjbuRaw; // default = use this BranchU. JPtype = branchU_JPtype[levelsub]; // Check for complete failure above: assert((! retval) || *PPop1); // sanity check. if ((! retval) && (*PPop1 == 0)) // nothing stored, full failure. { j__udyFreeJBU(PjbuRaw, Pjpm); SETJPNULL_PARENT; return(FALSE); } // Complete or partial success so far; watch for sorting error after the // maximum digit (255) in the BranchU, which is indicated by having more // indexes to store in the BranchUs expanse: // // For example, if an index to store has a digit of 255 at levelsub, followed // by an index with a digit of 254, the for-loop above runs out of digits // without reducing pop1 to 0. if (pop1 != 0) { JU_SET_ERRNO_NONNULL(Pjpm, JU_ERRNO_UNSORTED); *PPop1 -= pop1; // deduct unsaved indexes. retval = FALSE; } assert(*PPop1 != 0); // branch (still) cannot be empty. // OPTIONALLY COMPRESS JPBRANCH_U*: // // See if the BranchU should be compressed to a BranchL or BranchB; if so, do // that and free the BranchU; otherwise just use the existing BranchU. Follow // the same rules as in JudyIns.c (version 4.95): Only check local population // (cJU_OPP_UNCOMP_POP0) for BranchL, and only check global memory efficiency // (JU_OPP_UNCOMPRESS) for BranchB. TBD: Have the rules changed? // // Note: Because of differing order of operations, the latter compression // might not result in the same set of branch nodes as a series of sequential // insertions. // // Note: Allocating a BranchU only to sometimes convert it to a BranchL or // BranchB is unfortunate, but attempting to work with a temporary BranchU on // the stack and then allocate and keep it as a BranchU in many cases is worse // in terms of error handling. // COMPRESS JPBRANCH_U* TO JPBRANCH_L*: if (numJPs <= cJU_BRANCHLMAXJPS) // JPs fit in a BranchL. { Pjbl_t PjblRaw = (Pjbl_t) NULL; // new BranchL; init for cc. Pjbl_t Pjbl; if ((*PPop1 > JU_BRANCHL_MAX_POP) // pop too high. || ((PjblRaw = j__udyAllocJBL(Pjpm)) == (Pjbl_t) NULL)) { // cant alloc BranchL. goto SetParent; // just keep BranchU. } Pjbl = P_JBL(PjblRaw); // Copy BranchU JPs to BranchL: (Pjbl->jbl_NumJPs) = numJPs; offset = 0; for (digit = 0; digit < cJU_BRANCHUNUMJPS; ++digit) { if ((((Pjbu->jbu_jp) + digit)->jp_Type) == JPtype_null) continue; (Pjbl->jbl_Expanse[offset ]) = digit; (Pjbl->jbl_jp [offset++]) = Pjbu->jbu_jp[digit]; } assert(offset == numJPs); // found same number. // Free the BranchU and prepare to use the new BranchL instead: j__udyFreeJBU(PjbuRaw, Pjpm); Pjbany = (Word_t) PjblRaw; JPtype = branchL_JPtype[levelsub]; } // compress to BranchL // COMPRESS JPBRANCH_U* TO JPBRANCH_B*: // // If unable to allocate the BranchB or any JP subarray, free all related // memory and just keep the BranchU. // // Note: This use of JU_OPP_UNCOMPRESS is a bit conservative because the // BranchU is already allocated while the (presumably smaller) BranchB is not, // the opposite of how its used in single-insert code. else { Pjbb_t PjbbRaw = (Pjbb_t) NULL; // new BranchB; init for cc. Pjbb_t Pjbb; Pjp_t Pjp2; // in BranchU. if ((*PPop1 > JU_BRANCHB_MAX_POP) // pop too high. || ((PjbbRaw = j__udyAllocJBB(Pjpm)) == (Pjbb_t) NULL)) { // cant alloc BranchB. goto SetParent; // just keep BranchU. } Pjbb = P_JBB(PjbbRaw); // Set bits in bitmap for populated subexpanses: Pjp2 = Pjbu->jbu_jp; for (digit = 0; digit < cJU_BRANCHUNUMJPS; ++digit) if ((((Pjbu->jbu_jp) + digit)->jp_Type) != JPtype_null) JU_BITMAPSETB(Pjbb, digit); // Copy non-null JPs to BranchB JP subarrays: for (offset = 0; offset < cJU_NUMSUBEXPB; ++offset) { Pjp_t PjparrayRaw; Pjp_t Pjparray; if (! (numJPs = j__udyCountBitsB(JU_JBB_BITMAP(Pjbb, offset)))) continue; // skip empty subexpanse. // If unable to allocate a JP subarray, free all BranchB memory so far and // continue to use the BranchU: if ((PjparrayRaw = j__udyAllocJBBJP(numJPs, Pjpm)) == (Pjp_t) NULL) { while (offset-- > 0) { if (JU_JBB_PJP(Pjbb, offset) == (Pjp_t) NULL) continue; j__udyFreeJBBJP(JU_JBB_PJP(Pjbb, offset), j__udyCountBitsB(JU_JBB_BITMAP(Pjbb, offset)), Pjpm); } j__udyFreeJBB(PjbbRaw, Pjpm); goto SetParent; // keep BranchU. } // Set one JP subarray pointer and copy the subexpanses JPs to the subarray: // // Scan the BranchU for non-null JPs until numJPs JPs are copied. JU_JBB_PJP(Pjbb, offset) = PjparrayRaw; Pjparray = P_JP(PjparrayRaw); while (numJPs-- > 0) { while ((Pjp2->jp_Type) == JPtype_null) { ++Pjp2; assert(Pjp2 < (Pjbu->jbu_jp) + cJU_BRANCHUNUMJPS); } *Pjparray++ = *Pjp2++; } } // for each subexpanse // Free the BranchU and prepare to use the new BranchB instead: j__udyFreeJBU(PjbuRaw, Pjpm); Pjbany = (Word_t) PjbbRaw; JPtype = branchB_JPtype[levelsub]; } // compress to BranchB // COMPLETE OR PARTIAL SUCCESS: // // Attach new branch (under Pjp, with JPtype) to parent JP; note use of *PPop1, // possibly reduced due to partial failure. SetParent: (PjpParent->jp_Addr) = Pjbany; (PjpParent->jp_Type) = JPtype; if (Level < cJU_ROOTSTATE) // PjpParent not in JPM: { Word_t DcdP0 = (*PIndex & cJU_DCDMASK(levelsub)) | (*PPop1 - 1); JU_JPSETADT(PjpParent ,Pjbany, DcdP0, JPtype); } return(retval); } // j__udyInsArray() judy-1.0.5/src/JudyCommon/JudyCount.c0000644000175000017500000011341110204462077017662 0ustar troyhebetroyhebe// Copyright (C) 2000 - 2002 Hewlett-Packard Company // // This program is free software; you can redistribute it and/or modify it // under the term of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License // for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program; if not, write to the Free Software Foundation, // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // _________________ // @(#) $Revision: 4.78 $ $Source: /judy/src/JudyCommon/JudyCount.c $ // // Judy*Count() function for Judy1 and JudyL. // Compile with one of -DJUDY1 or -DJUDYL. // // Compile with -DNOSMARTJBB, -DNOSMARTJBU, and/or -DNOSMARTJLB to build a // version with cache line optimizations deleted, for testing. // // Compile with -DSMARTMETRICS to obtain global variables containing smart // cache line metrics. Note: Dont turn this on simultaneously for this file // and JudyByCount.c because they export the same globals. // // Judy*Count() returns the "count of Indexes" (inclusive) between the two // specified limits (Indexes). This code is remarkably fast. It traverses the // "Judy array" data structure. // // This count code is the GENERIC untuned version (minimum code size). It // might be possible to tuned to a specific architecture to be faster. // However, in real applications, with a modern machine, it is expected that // the instruction times will be swamped by cache line fills. // **************************************************************************** #if (! (defined(JUDY1) || defined(JUDYL))) #error: One of -DJUDY1 or -DJUDYL must be specified. #endif #ifdef JUDY1 #include "Judy1.h" #else #include "JudyL.h" #endif #include "JudyPrivate1L.h" // define a phoney that is for sure #define cJU_LEAFW cJU_JPIMMED_CAP // Avoid duplicate symbols since this file is multi-compiled: #ifdef SMARTMETRICS #ifdef JUDY1 Word_t jbb_upward = 0; // counts of directions taken: Word_t jbb_downward = 0; Word_t jbu_upward = 0; Word_t jbu_downward = 0; Word_t jlb_upward = 0; Word_t jlb_downward = 0; #else extern Word_t jbb_upward; extern Word_t jbb_downward; extern Word_t jbu_upward; extern Word_t jbu_downward; extern Word_t jlb_upward; extern Word_t jlb_downward; #endif #endif // FORWARD DECLARATIONS (prototypes): static Word_t j__udy1LCountSM(const Pjp_t Pjp, const Word_t Index, const Pjpm_t Pjpm); // Each of Judy1 and JudyL get their own private (static) version of this // function: static int j__udyCountLeafB1(const Pjll_t Pjll, const Word_t Pop1, const Word_t Index); // These functions are not static because they are exported to Judy*ByCount(): // // TBD: Should be made static for performance reasons? And thus duplicated? // // Note: There really are two different functions, but for convenience they // are referred to here with a generic name. #ifdef JUDY1 #define j__udyJPPop1 j__udy1JPPop1 #else #define j__udyJPPop1 j__udyLJPPop1 #endif Word_t j__udyJPPop1(const Pjp_t Pjp); // LOCAL ERROR HANDLING: // // The Judy*Count() functions are unusual because they return 0 instead of JERR // for an error. In this source file, define C_JERR for clarity. #define C_JERR 0 // **************************************************************************** // J U D Y 1 C O U N T // J U D Y L C O U N T // // See the manual entry for details. // // This code is written recursively, at least at first, because thats much // simpler; hope its fast enough. #ifdef JUDY1 FUNCTION Word_t Judy1Count #else FUNCTION Word_t JudyLCount #endif ( Pcvoid_t PArray, // JRP to first branch/leaf in SM. Word_t Index1, // starting Index. Word_t Index2, // ending Index. PJError_t PJError // optional, for returning error info. ) { jpm_t fakejpm; // local temporary for small arrays. Pjpm_t Pjpm; // top JPM or local temporary for error info. jp_t fakejp; // constructed for calling j__udy1LCountSM(). Pjp_t Pjp; // JP to pass to j__udy1LCountSM(). Word_t pop1; // total for the array. Word_t pop1above1; // indexes at or above Index1, inclusive. Word_t pop1above2; // indexes at or above Index2, exclusive. int retcode; // from Judy*First() calls. JUDYLCODE(PPvoid_t PPvalue); // from JudyLFirst() calls. // CHECK FOR SHORTCUTS: // // As documented, return C_JERR if the Judy array is empty or Index1 > Index2. if ((PArray == (Pvoid_t) NULL) || (Index1 > Index2)) { JU_SET_ERRNO(PJError, JU_ERRNO_NONE); return(C_JERR); } // If Index1 == Index2, simply check if the specified Index is set; pass // through the return value from Judy1Test() or JudyLGet() with appropriate // translations. if (Index1 == Index2) { #ifdef JUDY1 retcode = Judy1Test(PArray, Index1, PJError); if (retcode == JERRI) return(C_JERR); // pass through error. if (retcode == 0) { JU_SET_ERRNO(PJError, JU_ERRNO_NONE); return(C_JERR); } #else PPvalue = JudyLGet(PArray, Index1, PJError); if (PPvalue == PPJERR) return(C_JERR); // pass through error. if (PPvalue == (PPvoid_t) NULL) // Index is not set. { JU_SET_ERRNO(PJError, JU_ERRNO_NONE); return(C_JERR); } #endif return(1); // single index is set. } // CHECK JRP TYPE: // // Use an if/then for speed rather than a switch, and put the most common cases // first. // // Note: Since even cJU_LEAFW types require counting between two Indexes, // prepare them here for common code below that calls j__udy1LCountSM(), rather // than handling them even more specially here. if (JU_LEAFW_POP0(PArray) < cJU_LEAFW_MAXPOP1) // must be a LEAFW { Pjlw_t Pjlw = P_JLW(PArray); // first word of leaf. Pjpm = & fakejpm; Pjp = & fakejp; Pjp->jp_Addr = (Word_t) Pjlw; Pjp->jp_Type = cJU_LEAFW; Pjpm->jpm_Pop0 = Pjlw[0]; // from first word of leaf. pop1 = Pjpm->jpm_Pop0 + 1; } else { Pjpm = P_JPM(PArray); Pjp = &(Pjpm->jpm_JP); pop1 = (Pjpm->jpm_Pop0) + 1; // note: can roll over to 0. #if (defined(JUDY1) && (! defined(JU_64BIT))) if (pop1 == 0) // rare special case of full array: { Word_t count = Index2 - Index1 + 1; // can roll over again. if (count == 0) { JU_SET_ERRNO(PJError, JU_ERRNO_FULL); return(C_JERR); } return(count); } #else assert(pop1); // JudyL or 64-bit cannot create a full array! #endif } // COUNT POP1 ABOVE INDEX1, INCLUSIVE: assert(pop1); // just to be safe. if (Index1 == 0) // shortcut, pop1above1 is entire population: { pop1above1 = pop1; } else // find first valid Index above Index1, if any: { #ifdef JUDY1 if ((retcode = Judy1First(PArray, & Index1, PJError)) == JERRI) return(C_JERR); // pass through error. #else if ((PPvalue = JudyLFirst(PArray, & Index1, PJError)) == PPJERR) return(C_JERR); // pass through error. retcode = (PPvalue != (PPvoid_t) NULL); // found a next Index. #endif // If theres no Index at or above Index1, just return C_JERR (early exit): if (retcode == 0) { JU_SET_ERRNO(PJError, JU_ERRNO_NONE); return(C_JERR); } // If a first/next Index was found, call the counting motor starting with that // known valid Index, meaning the return should be positive, not C_JERR except // in case of a real error: if ((pop1above1 = j__udy1LCountSM(Pjp, Index1, Pjpm)) == C_JERR) { JU_COPY_ERRNO(PJError, Pjpm); // pass through error. return(C_JERR); } } // COUNT POP1 ABOVE INDEX2, EXCLUSIVE, AND RETURN THE DIFFERENCE: // // In principle, calculate the ordinal of each Index and take the difference, // with caution about off-by-one errors due to the specified Indexes being set // or unset. In practice: // // - The ordinals computed here are inverse ordinals, that is, the populations // ABOVE the specified Indexes (Index1 inclusive, Index2 exclusive), so // subtract pop1above2 from pop1above1, rather than vice-versa. // // - Index1s result already includes a count for Index1 and/or Index2 if // either is set, so calculate pop1above2 exclusive of Index2. // // TBD: If Index1 and Index2 fall in the same expanse in the top-state // branch(es), would it be faster to walk the SM only once, to their divergence // point, before calling j__udy1LCountSM() or equivalent? Possibly a non-issue // if a top-state pop1 becomes stored with each Judy1 array. Also, consider // whether the first call of j__udy1LCountSM() fills the cache, for common tree // branches, for the second call. // // As for pop1above1, look for shortcuts for special cases when pop1above2 is // zero. Otherwise call the counting "motor". assert(pop1above1); // just to be safe. if (Index2++ == cJU_ALLONES) return(pop1above1); // Index2 at limit. #ifdef JUDY1 if ((retcode = Judy1First(PArray, & Index2, PJError)) == JERRI) return(C_JERR); #else if ((PPvalue = JudyLFirst(PArray, & Index2, PJError)) == PPJERR) return(C_JERR); retcode = (PPvalue != (PPvoid_t) NULL); // found a next Index. #endif if (retcode == 0) return(pop1above1); // no Index above Index2. // Just as for Index1, j__udy1LCountSM() cannot return 0 (locally == C_JERR) // except in case of a real error: if ((pop1above2 = j__udy1LCountSM(Pjp, Index2, Pjpm)) == C_JERR) { JU_COPY_ERRNO(PJError, Pjpm); // pass through error. return(C_JERR); } if (pop1above1 == pop1above2) { JU_SET_ERRNO(PJError, JU_ERRNO_NONE); return(C_JERR); } return(pop1above1 - pop1above2); } // Judy1Count() / JudyLCount() // **************************************************************************** // __ J U D Y 1 L C O U N T S M // // Given a pointer to a JP (with invalid jp_DcdPopO at cJU_ROOTSTATE), a known // valid Index, and a Pjpm for returning error info, recursively visit a Judy // array state machine (SM) and return the count of Indexes, including Index, // through the end of the Judy array at this state or below. In case of error // or a count of 0 (should never happen), return C_JERR with appropriate // JU_ERRNO in the Pjpm. // // Note: This function is not told the current state because its encoded in // the JP Type. // // Method: To minimize cache line fills, while studying each branch, if Index // resides above the midpoint of the branch (which often consists of multiple // cache lines), ADD the populations at or above Index; otherwise, SUBTRACT // from the population of the WHOLE branch (available from the JP) the // populations at or above Index. This is especially tricky for bitmap // branches. // // Note: Unlike, say, the Ins and Del walk routines, this function returns the // same type of returns as Judy*Count(), so it can use *_SET_ERRNO*() macros // the same way. FUNCTION static Word_t j__udy1LCountSM( const Pjp_t Pjp, // top of Judy (sub)SM. const Word_t Index, // count at or above this Index. const Pjpm_t Pjpm) // for returning error info. { Pjbl_t Pjbl; // Pjp->jp_Addr masked and cast to types: Pjbb_t Pjbb; Pjbu_t Pjbu; Pjll_t Pjll; // a Judy lower-level linear leaf. Word_t digit; // next digit to decode from Index. long jpnum; // JP number in a branch (base 0). int offset; // index ordinal within a leaf, base 0. Word_t pop1; // total population of an expanse. Word_t pop1above; // to return. // Common code to check Decode bits in a JP against the equivalent portion of // Index; XOR together, then mask bits of interest; must be all 0: // // Note: Why does this code only assert() compliance rather than actively // checking for outliers? Its because Index is supposed to be valid, hence // always match any Dcd bits traversed. // // Note: This assertion turns out to be always true for cState = 3 on 32-bit // and 7 on 64-bit, but its harmless, probably removed by the compiler. #define CHECKDCD(Pjp,cState) \ assert(! JU_DCDNOTMATCHINDEX(Index, Pjp, cState)) // Common code to prepare to handle a root-level or lower-level branch: // Extract a state-dependent digit from Index in a "constant" way, obtain the // total population for the branch in a state-dependent way, and then branch to // common code for multiple cases: // // For root-level branches, the state is always cJU_ROOTSTATE, and the // population is received in Pjpm->jpm_Pop0. // // Note: The total population is only needed in cases where the common code // "counts up" instead of down to minimize cache line fills. However, its // available cheaply, and its better to do it with a constant shift (constant // state value) instead of a variable shift later "when needed". #define PREPB_ROOT(Pjp,Next) \ digit = JU_DIGITATSTATE(Index, cJU_ROOTSTATE); \ pop1 = (Pjpm->jpm_Pop0) + 1; \ goto Next #define PREPB(Pjp,cState,Next) \ digit = JU_DIGITATSTATE(Index, cState); \ pop1 = JU_JPBRANCH_POP0(Pjp, (cState)) + 1; \ goto Next // SWITCH ON JP TYPE: // // WARNING: For run-time efficiency the following cases replicate code with // varying constants, rather than using common code with variable values! switch (JU_JPTYPE(Pjp)) { // ---------------------------------------------------------------------------- // ROOT-STATE LEAF that starts with a Pop0 word; just count within the leaf: case cJU_LEAFW: { Pjlw_t Pjlw = P_JLW(Pjp->jp_Addr); // first word of leaf. assert((Pjpm->jpm_Pop0) + 1 == Pjlw[0] + 1); // sent correctly. offset = j__udySearchLeafW(Pjlw + 1, Pjpm->jpm_Pop0 + 1, Index); assert(offset >= 0); // Index must exist. assert(offset < (Pjpm->jpm_Pop0) + 1); // Index be in range. return((Pjpm->jpm_Pop0) + 1 - offset); // INCLUSIVE of Index. } // ---------------------------------------------------------------------------- // LINEAR BRANCH; count populations in JPs in the JBL ABOVE the next digit in // Index, and recurse for the next digit in Index: // // Note: There are no null JPs in a JBL; watch out for pop1 == 0. // // Note: A JBL should always fit in one cache line => no need to count up // versus down to save cache line fills. (PREPB() sets pop1 for no reason.) case cJU_JPBRANCH_L2: CHECKDCD(Pjp, 2); PREPB(Pjp, 2, BranchL); case cJU_JPBRANCH_L3: CHECKDCD(Pjp, 3); PREPB(Pjp, 3, BranchL); #ifdef JU_64BIT case cJU_JPBRANCH_L4: CHECKDCD(Pjp, 4); PREPB(Pjp, 4, BranchL); case cJU_JPBRANCH_L5: CHECKDCD(Pjp, 5); PREPB(Pjp, 5, BranchL); case cJU_JPBRANCH_L6: CHECKDCD(Pjp, 6); PREPB(Pjp, 6, BranchL); case cJU_JPBRANCH_L7: CHECKDCD(Pjp, 7); PREPB(Pjp, 7, BranchL); #endif case cJU_JPBRANCH_L: PREPB_ROOT(Pjp, BranchL); // Common code (state-independent) for all cases of linear branches: BranchL: Pjbl = P_JBL(Pjp->jp_Addr); jpnum = Pjbl->jbl_NumJPs; // above last JP. pop1above = 0; while (digit < (Pjbl->jbl_Expanse[--jpnum])) // still ABOVE digit. { if ((pop1 = j__udyJPPop1((Pjbl->jbl_jp) + jpnum)) == cJU_ALLONES) { JU_SET_ERRNO_NONNULL(Pjpm, JU_ERRNO_CORRUPT); return(C_JERR); } pop1above += pop1; assert(jpnum > 0); // should find digit. } assert(digit == (Pjbl->jbl_Expanse[jpnum])); // should find digit. pop1 = j__udy1LCountSM((Pjbl->jbl_jp) + jpnum, Index, Pjpm); if (pop1 == C_JERR) return(C_JERR); // pass error up. assert(pop1above + pop1); return(pop1above + pop1); // ---------------------------------------------------------------------------- // BITMAP BRANCH; count populations in JPs in the JBB ABOVE the next digit in // Index, and recurse for the next digit in Index: // // Note: There are no null JPs in a JBB; watch out for pop1 == 0. case cJU_JPBRANCH_B2: CHECKDCD(Pjp, 2); PREPB(Pjp, 2, BranchB); case cJU_JPBRANCH_B3: CHECKDCD(Pjp, 3); PREPB(Pjp, 3, BranchB); #ifdef JU_64BIT case cJU_JPBRANCH_B4: CHECKDCD(Pjp, 4); PREPB(Pjp, 4, BranchB); case cJU_JPBRANCH_B5: CHECKDCD(Pjp, 5); PREPB(Pjp, 5, BranchB); case cJU_JPBRANCH_B6: CHECKDCD(Pjp, 6); PREPB(Pjp, 6, BranchB); case cJU_JPBRANCH_B7: CHECKDCD(Pjp, 7); PREPB(Pjp, 7, BranchB); #endif case cJU_JPBRANCH_B: PREPB_ROOT(Pjp, BranchB); // Common code (state-independent) for all cases of bitmap branches: BranchB: { long subexp; // for stepping through layer 1 (subexpanses). long findsub; // subexpanse containing Index (digit). Word_t findbit; // bit representing Index (digit). Word_t lowermask; // bits for indexes at or below Index. Word_t jpcount; // JPs in a subexpanse. Word_t clbelow; // cache lines below digits cache line. Word_t clabove; // cache lines above digits cache line. Pjbb = P_JBB(Pjp->jp_Addr); findsub = digit / cJU_BITSPERSUBEXPB; findbit = digit % cJU_BITSPERSUBEXPB; lowermask = JU_MASKLOWERINC(JU_BITPOSMASKB(findbit)); clbelow = clabove = 0; // initial/default => always downward. assert(JU_BITMAPTESTB(Pjbb, digit)); // digit must have a JP. assert(findsub < cJU_NUMSUBEXPB); // falls in expected range. // Shorthand for one subexpanse in a bitmap and for one JP in a bitmap branch: // // Note: BMPJP0 exists separately to support assertions. #define BMPJP0(Subexp) (P_JP(JU_JBB_PJP(Pjbb, Subexp))) #define BMPJP(Subexp,JPnum) (BMPJP0(Subexp) + (JPnum)) #ifndef NOSMARTJBB // enable to turn off smart code for comparison purposes. // FIGURE OUT WHICH DIRECTION CAUSES FEWER CACHE LINE FILLS; adding the pop1s // in JPs above Indexs JP, or subtracting the pop1s in JPs below Indexs JP. // // This is tricky because, while each set bit in the bitmap represents a JP, // the JPs are scattered over cJU_NUMSUBEXPB subexpanses, each of which can // contain JPs packed into multiple cache lines, and this code must visit every // JP either BELOW or ABOVE the JP for Index. // // Number of cache lines required to hold a linear list of the given number of // JPs, assuming the first JP is at the start of a cache line or the JPs in // jpcount fit wholly within a single cache line, which is ensured by // JudyMalloc(): #define CLPERJPS(jpcount) \ ((((jpcount) * cJU_WORDSPERJP) + cJU_WORDSPERCL - 1) / cJU_WORDSPERCL) // Count cache lines below/above for each subexpanse: for (subexp = 0; subexp < cJU_NUMSUBEXPB; ++subexp) { jpcount = j__udyCountBitsB(JU_JBB_BITMAP(Pjbb, subexp)); // When at the subexpanse containing Index (digit), add cache lines // below/above appropriately, excluding the cache line containing the JP for // Index itself: if (subexp < findsub) clbelow += CLPERJPS(jpcount); else if (subexp > findsub) clabove += CLPERJPS(jpcount); else // (subexp == findsub) { Word_t clfind; // cache line containing Index (digit). clfind = CLPERJPS(j__udyCountBitsB( JU_JBB_BITMAP(Pjbb, subexp) & lowermask)); assert(clfind > 0); // digit itself should have 1 CL. clbelow += clfind - 1; clabove += CLPERJPS(jpcount) - clfind; } } #endif // ! NOSMARTJBB // Note: Its impossible to get through the following "if" without setting // jpnum -- see some of the assertions below -- but gcc -Wall doesnt know // this, so preset jpnum to make it happy: jpnum = 0; // COUNT POPULATION FOR A BITMAP BRANCH, in whichever direction should result // in fewer cache line fills: // // Note: If the remainder of Index is zero, pop1above is the pop1 of the // entire expanse and theres no point in recursing to lower levels; but this // should be so rare that its not worth checking for; // Judy1Count()/JudyLCount() never even calls the motor for Index == 0 (all // bytes). // COUNT UPWARD, subtracting each "below or at" JPs pop1 from the whole // expanses pop1: // // Note: If this causes clbelow + 1 cache line fills including JPs cache // line, thats OK; at worst this is the same as clabove. if (clbelow < clabove) { #ifdef SMARTMETRICS ++jbb_upward; #endif pop1above = pop1; // subtract JPs at/below Index. // Count JPs for which to accrue pop1s in this subexpanse: // // TBD: If JU_JBB_BITMAP is cJU_FULLBITMAPB, dont bother counting. for (subexp = 0; subexp <= findsub; ++subexp) { jpcount = j__udyCountBitsB((subexp < findsub) ? JU_JBB_BITMAP(Pjbb, subexp) : JU_JBB_BITMAP(Pjbb, subexp) & lowermask); // should always find findbit: assert((subexp < findsub) || jpcount); // Subtract pop1s from JPs BELOW OR AT Index (digit): // // Note: The pop1 for Indexs JP itself is partially added back later at a // lower state. // // Note: An empty subexpanse (jpcount == 0) is handled "for free". // // Note: Must be null JP subexp pointer in empty subexpanse and non-empty in // non-empty subexpanse: assert( jpcount || (BMPJP0(subexp) == (Pjp_t) NULL)); assert((! jpcount) || (BMPJP0(subexp) != (Pjp_t) NULL)); for (jpnum = 0; jpnum < jpcount; ++jpnum) { if ((pop1 = j__udyJPPop1(BMPJP(subexp, jpnum))) == cJU_ALLONES) { JU_SET_ERRNO_NONNULL(Pjpm, JU_ERRNO_CORRUPT); return(C_JERR); } pop1above -= pop1; } jpnum = jpcount - 1; // make correct for digit. } } // COUNT DOWNWARD, adding each "above" JPs pop1: else { long jpcountbf; // below findbit, inclusive. #ifdef SMARTMETRICS ++jbb_downward; #endif pop1above = 0; // add JPs above Index. jpcountbf = 0; // until subexp == findsub. // Count JPs for which to accrue pop1s in this subexpanse: // // This is more complicated than counting upward because the scan of digits // subexpanse must count ALL JPs, to know where to START counting down, and // ALSO note the offset of digits JP to know where to STOP counting down. for (subexp = cJU_NUMSUBEXPB - 1; subexp >= findsub; --subexp) { jpcount = j__udyCountBitsB(JU_JBB_BITMAP(Pjbb, subexp)); // should always find findbit: assert((subexp > findsub) || jpcount); if (! jpcount) continue; // empty subexpanse, save time. // Count JPs below digit, inclusive: if (subexp == findsub) { jpcountbf = j__udyCountBitsB(JU_JBB_BITMAP(Pjbb, subexp) & lowermask); } // should always find findbit: assert((subexp > findsub) || jpcountbf); assert(jpcount >= jpcountbf); // proper relationship. // Add pop1s from JPs ABOVE Index (digit): // no null JP subexp pointers: assert(BMPJP0(subexp) != (Pjp_t) NULL); for (jpnum = jpcount - 1; jpnum >= jpcountbf; --jpnum) { if ((pop1 = j__udyJPPop1(BMPJP(subexp, jpnum))) == cJU_ALLONES) { JU_SET_ERRNO_NONNULL(Pjpm, JU_ERRNO_CORRUPT); return(C_JERR); } pop1above += pop1; } // jpnum is now correct for digit. } } // else. // Return the net population ABOVE the digits JP at this state (in this JBB) // plus the population AT OR ABOVE Index in the SM under the digits JP: pop1 = j__udy1LCountSM(BMPJP(findsub, jpnum), Index, Pjpm); if (pop1 == C_JERR) return(C_JERR); // pass error up. assert(pop1above + pop1); return(pop1above + pop1); } // case. // ---------------------------------------------------------------------------- // UNCOMPRESSED BRANCH; count populations in JPs in the JBU ABOVE the next // digit in Index, and recurse for the next digit in Index: // // Note: If the remainder of Index is zero, pop1above is the pop1 of the // entire expanse and theres no point in recursing to lower levels; but this // should be so rare that its not worth checking for; // Judy1Count()/JudyLCount() never even calls the motor for Index == 0 (all // bytes). case cJU_JPBRANCH_U2: CHECKDCD(Pjp, 2); PREPB(Pjp, 2, BranchU); case cJU_JPBRANCH_U3: CHECKDCD(Pjp, 3); PREPB(Pjp, 3, BranchU); #ifdef JU_64BIT case cJU_JPBRANCH_U4: CHECKDCD(Pjp, 4); PREPB(Pjp, 4, BranchU); case cJU_JPBRANCH_U5: CHECKDCD(Pjp, 5); PREPB(Pjp, 5, BranchU); case cJU_JPBRANCH_U6: CHECKDCD(Pjp, 6); PREPB(Pjp, 6, BranchU); case cJU_JPBRANCH_U7: CHECKDCD(Pjp, 7); PREPB(Pjp, 7, BranchU); #endif case cJU_JPBRANCH_U: PREPB_ROOT(Pjp, BranchU); // Common code (state-independent) for all cases of uncompressed branches: BranchU: Pjbu = P_JBU(Pjp->jp_Addr); #ifndef NOSMARTJBU // enable to turn off smart code for comparison purposes. // FIGURE OUT WHICH WAY CAUSES FEWER CACHE LINE FILLS; adding the JPs above // Indexs JP, or subtracting the JPs below Indexs JP. // // COUNT UPWARD, subtracting the pop1 of each JP BELOW OR AT Index, from the // whole expanses pop1: if (digit < (cJU_BRANCHUNUMJPS / 2)) { pop1above = pop1; // subtract JPs below Index. #ifdef SMARTMETRICS ++jbu_upward; #endif for (jpnum = 0; jpnum <= digit; ++jpnum) { if ((Pjbu->jbu_jp[jpnum].jp_Type) <= cJU_JPNULLMAX) continue; // shortcut, save a function call. if ((pop1 = j__udyJPPop1(Pjbu->jbu_jp + jpnum)) == cJU_ALLONES) { JU_SET_ERRNO_NONNULL(Pjpm, JU_ERRNO_CORRUPT); return(C_JERR); } pop1above -= pop1; } } // COUNT DOWNWARD, simply adding the pop1 of each JP ABOVE Index: else #endif // NOSMARTJBU { assert(digit < cJU_BRANCHUNUMJPS); #ifdef SMARTMETRICS ++jbu_downward; #endif pop1above = 0; // add JPs above Index. for (jpnum = cJU_BRANCHUNUMJPS - 1; jpnum > digit; --jpnum) { if ((Pjbu->jbu_jp[jpnum].jp_Type) <= cJU_JPNULLMAX) continue; // shortcut, save a function call. if ((pop1 = j__udyJPPop1(Pjbu->jbu_jp + jpnum)) == cJU_ALLONES) { JU_SET_ERRNO_NONNULL(Pjpm, JU_ERRNO_CORRUPT); return(C_JERR); } pop1above += pop1; } } if ((pop1 = j__udy1LCountSM(Pjbu->jbu_jp + digit, Index, Pjpm)) == C_JERR) return(C_JERR); // pass error up. assert(pop1above + pop1); return(pop1above + pop1); // ---------------------------------------------------------------------------- // LEAF COUNT MACROS: // // LEAF*ABOVE() are common code for different JP types (linear leaves, bitmap // leaves, and immediates) and different leaf Index Sizes, which result in // calling different leaf search functions. Linear leaves get the leaf address // from jp_Addr and the Population from jp_DcdPopO, while immediates use Pjp // itself as the leaf address and get Population from jp_Type. #define LEAFLABOVE(Func) \ Pjll = P_JLL(Pjp->jp_Addr); \ pop1 = JU_JPLEAF_POP0(Pjp) + 1; \ LEAFABOVE(Func, Pjll, pop1) #define LEAFB1ABOVE(Func) LEAFLABOVE(Func) // different Func, otherwise same. #ifdef JUDY1 #define IMMABOVE(Func,Pop1) \ Pjll = (Pjll_t) Pjp; \ LEAFABOVE(Func, Pjll, Pop1) #else // Note: For JudyL immediates with >= 2 Indexes, the index bytes are in a // different place than for Judy1: #define IMMABOVE(Func,Pop1) \ LEAFABOVE(Func, (Pjll_t) (Pjp->jp_LIndex), Pop1) #endif // For all leaf types, the population AT OR ABOVE is the total pop1 less the // offset of Index; and Index should always be found: #define LEAFABOVE(Func,Pjll,Pop1) \ offset = Func(Pjll, Pop1, Index); \ assert(offset >= 0); \ assert(offset < (Pop1)); \ return((Pop1) - offset) // IMMABOVE_01 handles the special case of an immediate JP with 1 index, which // the search functions arent used for anyway: // // The target Index should be the one in this Immediate, in which case the // count above (inclusive) is always 1. #define IMMABOVE_01 \ assert((JU_JPDCDPOP0(Pjp)) == JU_TRIMTODCDSIZE(Index)); \ return(1) // ---------------------------------------------------------------------------- // LINEAR LEAF; search the leaf for Index; size is computed from jp_Type: #if (defined(JUDYL) || (! defined(JU_64BIT))) case cJU_JPLEAF1: LEAFLABOVE(j__udySearchLeaf1); #endif case cJU_JPLEAF2: LEAFLABOVE(j__udySearchLeaf2); case cJU_JPLEAF3: LEAFLABOVE(j__udySearchLeaf3); #ifdef JU_64BIT case cJU_JPLEAF4: LEAFLABOVE(j__udySearchLeaf4); case cJU_JPLEAF5: LEAFLABOVE(j__udySearchLeaf5); case cJU_JPLEAF6: LEAFLABOVE(j__udySearchLeaf6); case cJU_JPLEAF7: LEAFLABOVE(j__udySearchLeaf7); #endif // ---------------------------------------------------------------------------- // BITMAP LEAF; search the leaf for Index: // // Since the bitmap describes Indexes digitally rather than linearly, this is // not really a search, but just a count. case cJU_JPLEAF_B1: LEAFB1ABOVE(j__udyCountLeafB1); #ifdef JUDY1 // ---------------------------------------------------------------------------- // FULL POPULATION: // // Return the count of Indexes AT OR ABOVE Index, which is the total population // of the expanse (a constant) less the value of the undecoded digit remaining // in Index (its base-0 offset in the expanse), which yields an inclusive count // above. // // TBD: This only supports a 1-byte full expanse. Should this extract a // stored value for pop0 and possibly more LSBs of Index, to handle larger full // expanses? case cJ1_JPFULLPOPU1: return(cJU_JPFULLPOPU1_POP0 + 1 - JU_DIGITATSTATE(Index, 1)); #endif // ---------------------------------------------------------------------------- // IMMEDIATE: case cJU_JPIMMED_1_01: IMMABOVE_01; case cJU_JPIMMED_2_01: IMMABOVE_01; case cJU_JPIMMED_3_01: IMMABOVE_01; #ifdef JU_64BIT case cJU_JPIMMED_4_01: IMMABOVE_01; case cJU_JPIMMED_5_01: IMMABOVE_01; case cJU_JPIMMED_6_01: IMMABOVE_01; case cJU_JPIMMED_7_01: IMMABOVE_01; #endif case cJU_JPIMMED_1_02: IMMABOVE(j__udySearchLeaf1, 2); case cJU_JPIMMED_1_03: IMMABOVE(j__udySearchLeaf1, 3); #if (defined(JUDY1) || defined(JU_64BIT)) case cJU_JPIMMED_1_04: IMMABOVE(j__udySearchLeaf1, 4); case cJU_JPIMMED_1_05: IMMABOVE(j__udySearchLeaf1, 5); case cJU_JPIMMED_1_06: IMMABOVE(j__udySearchLeaf1, 6); case cJU_JPIMMED_1_07: IMMABOVE(j__udySearchLeaf1, 7); #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_1_08: IMMABOVE(j__udySearchLeaf1, 8); case cJ1_JPIMMED_1_09: IMMABOVE(j__udySearchLeaf1, 9); case cJ1_JPIMMED_1_10: IMMABOVE(j__udySearchLeaf1, 10); case cJ1_JPIMMED_1_11: IMMABOVE(j__udySearchLeaf1, 11); case cJ1_JPIMMED_1_12: IMMABOVE(j__udySearchLeaf1, 12); case cJ1_JPIMMED_1_13: IMMABOVE(j__udySearchLeaf1, 13); case cJ1_JPIMMED_1_14: IMMABOVE(j__udySearchLeaf1, 14); case cJ1_JPIMMED_1_15: IMMABOVE(j__udySearchLeaf1, 15); #endif #if (defined(JUDY1) || defined(JU_64BIT)) case cJU_JPIMMED_2_02: IMMABOVE(j__udySearchLeaf2, 2); case cJU_JPIMMED_2_03: IMMABOVE(j__udySearchLeaf2, 3); #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_2_04: IMMABOVE(j__udySearchLeaf2, 4); case cJ1_JPIMMED_2_05: IMMABOVE(j__udySearchLeaf2, 5); case cJ1_JPIMMED_2_06: IMMABOVE(j__udySearchLeaf2, 6); case cJ1_JPIMMED_2_07: IMMABOVE(j__udySearchLeaf2, 7); #endif #if (defined(JUDY1) || defined(JU_64BIT)) case cJU_JPIMMED_3_02: IMMABOVE(j__udySearchLeaf3, 2); #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_3_03: IMMABOVE(j__udySearchLeaf3, 3); case cJ1_JPIMMED_3_04: IMMABOVE(j__udySearchLeaf3, 4); case cJ1_JPIMMED_3_05: IMMABOVE(j__udySearchLeaf3, 5); case cJ1_JPIMMED_4_02: IMMABOVE(j__udySearchLeaf4, 2); case cJ1_JPIMMED_4_03: IMMABOVE(j__udySearchLeaf4, 3); case cJ1_JPIMMED_5_02: IMMABOVE(j__udySearchLeaf5, 2); case cJ1_JPIMMED_5_03: IMMABOVE(j__udySearchLeaf5, 3); case cJ1_JPIMMED_6_02: IMMABOVE(j__udySearchLeaf6, 2); case cJ1_JPIMMED_7_02: IMMABOVE(j__udySearchLeaf7, 2); #endif // ---------------------------------------------------------------------------- // OTHER CASES: default: JU_SET_ERRNO_NONNULL(Pjpm, JU_ERRNO_CORRUPT); return(C_JERR); } // switch on JP type /*NOTREACHED*/ } // j__udy1LCountSM() // **************************************************************************** // J U D Y C O U N T L E A F B 1 // // This is a private analog of the j__udySearchLeaf*() functions for counting // in bitmap 1-byte leaves. Since a bitmap leaf describes Indexes digitally // rather than linearly, this is not really a search, but just a count of the // valid Indexes == set bits below or including Index, which should be valid. // Return the "offset" (really the ordinal), 0 .. Pop1 - 1, of Index in Pjll; // if Indexs bit is not set (which should never happen, so this is DEBUG-mode // only), return the 1s-complement equivalent (== negative offset minus 1). // // Note: The source code for this function looks identical for both Judy1 and // JudyL, but the JU_JLB_BITMAP macro varies. // // Note: For simpler calling, the first arg is of type Pjll_t but then cast to // Pjlb_t. FUNCTION static int j__udyCountLeafB1( const Pjll_t Pjll, // bitmap leaf, as Pjll_t for consistency. const Word_t Pop1, // Population of whole leaf. const Word_t Index) // to which to count. { Pjlb_t Pjlb = (Pjlb_t) Pjll; // to proper type. Word_t digit = Index & cJU_MASKATSTATE(1); Word_t findsub = digit / cJU_BITSPERSUBEXPL; Word_t findbit = digit % cJU_BITSPERSUBEXPL; int count; // in leaf through Index. long subexp; // for stepping through subexpanses. // COUNT UPWARD: // // The entire bitmap should fit in one cache line, but still try to save some // CPU time by counting the fewest possible number of subexpanses from the // bitmap. #ifndef NOSMARTJLB // enable to turn off smart code for comparison purposes. if (findsub < (cJU_NUMSUBEXPL / 2)) { #ifdef SMARTMETRICS ++jlb_upward; #endif count = 0; for (subexp = 0; subexp < findsub; ++subexp) { count += ((JU_JLB_BITMAP(Pjlb, subexp) == cJU_FULLBITMAPL) ? cJU_BITSPERSUBEXPL : j__udyCountBitsL(JU_JLB_BITMAP(Pjlb, subexp))); } // This count includes findbit, which should be set, resulting in a base-1 // offset: count += j__udyCountBitsL(JU_JLB_BITMAP(Pjlb, findsub) & JU_MASKLOWERINC(JU_BITPOSMASKL(findbit))); DBGCODE(if (! JU_BITMAPTESTL(Pjlb, digit)) return(~count);) assert(count >= 1); return(count - 1); // convert to base-0 offset. } #endif // NOSMARTJLB // COUNT DOWNWARD: // // Count the valid Indexes above or at Index, and subtract from Pop1. #ifdef SMARTMETRICS ++jlb_downward; #endif count = Pop1; // base-1 for now. for (subexp = cJU_NUMSUBEXPL - 1; subexp > findsub; --subexp) { count -= ((JU_JLB_BITMAP(Pjlb, subexp) == cJU_FULLBITMAPL) ? cJU_BITSPERSUBEXPL : j__udyCountBitsL(JU_JLB_BITMAP(Pjlb, subexp))); } // This count includes findbit, which should be set, resulting in a base-0 // offset: count -= j__udyCountBitsL(JU_JLB_BITMAP(Pjlb, findsub) & JU_MASKHIGHERINC(JU_BITPOSMASKL(findbit))); DBGCODE(if (! JU_BITMAPTESTL(Pjlb, digit)) return(~count);) assert(count >= 0); // should find Index itself. return(count); // is already a base-0 offset. } // j__udyCountLeafB1() // **************************************************************************** // J U D Y J P P O P 1 // // This function takes any type of JP other than a root-level JP (cJU_LEAFW* or // cJU_JPBRANCH* with no number suffix) and extracts the Pop1 from it. In some // sense this is a wrapper around the JU_JP*_POP0 macros. Why write it as a // function instead of a complex macro containing a trinary? (See version // Judy1.h version 4.17.) We think its cheaper to call a function containing // a switch statement with "constant" cases than to do the variable // calculations in a trinary. // // For invalid JP Types return cJU_ALLONES. Note that this is an impossibly // high Pop1 for any JP below a top level branch. FUNCTION Word_t j__udyJPPop1( const Pjp_t Pjp) // JP to count. { switch (JU_JPTYPE(Pjp)) { #ifdef notdef // caller should shortcut and not even call with these: case cJU_JPNULL1: case cJU_JPNULL2: case cJU_JPNULL3: return(0); #ifdef JU_64BIT case cJU_JPNULL4: case cJU_JPNULL5: case cJU_JPNULL6: case cJU_JPNULL7: return(0); #endif #endif // notdef case cJU_JPBRANCH_L2: case cJU_JPBRANCH_B2: case cJU_JPBRANCH_U2: return(JU_JPBRANCH_POP0(Pjp,2) + 1); case cJU_JPBRANCH_L3: case cJU_JPBRANCH_B3: case cJU_JPBRANCH_U3: return(JU_JPBRANCH_POP0(Pjp,3) + 1); #ifdef JU_64BIT case cJU_JPBRANCH_L4: case cJU_JPBRANCH_B4: case cJU_JPBRANCH_U4: return(JU_JPBRANCH_POP0(Pjp,4) + 1); case cJU_JPBRANCH_L5: case cJU_JPBRANCH_B5: case cJU_JPBRANCH_U5: return(JU_JPBRANCH_POP0(Pjp,5) + 1); case cJU_JPBRANCH_L6: case cJU_JPBRANCH_B6: case cJU_JPBRANCH_U6: return(JU_JPBRANCH_POP0(Pjp,6) + 1); case cJU_JPBRANCH_L7: case cJU_JPBRANCH_B7: case cJU_JPBRANCH_U7: return(JU_JPBRANCH_POP0(Pjp,7) + 1); #endif #if (defined(JUDYL) || (! defined(JU_64BIT))) case cJU_JPLEAF1: #endif case cJU_JPLEAF2: case cJU_JPLEAF3: #ifdef JU_64BIT case cJU_JPLEAF4: case cJU_JPLEAF5: case cJU_JPLEAF6: case cJU_JPLEAF7: #endif case cJU_JPLEAF_B1: return(JU_JPLEAF_POP0(Pjp) + 1); #ifdef JUDY1 case cJ1_JPFULLPOPU1: return(cJU_JPFULLPOPU1_POP0 + 1); #endif case cJU_JPIMMED_1_01: case cJU_JPIMMED_2_01: case cJU_JPIMMED_3_01: return(1); #ifdef JU_64BIT case cJU_JPIMMED_4_01: case cJU_JPIMMED_5_01: case cJU_JPIMMED_6_01: case cJU_JPIMMED_7_01: return(1); #endif case cJU_JPIMMED_1_02: return(2); case cJU_JPIMMED_1_03: return(3); #if (defined(JUDY1) || defined(JU_64BIT)) case cJU_JPIMMED_1_04: return(4); case cJU_JPIMMED_1_05: return(5); case cJU_JPIMMED_1_06: return(6); case cJU_JPIMMED_1_07: return(7); #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_1_08: return(8); case cJ1_JPIMMED_1_09: return(9); case cJ1_JPIMMED_1_10: return(10); case cJ1_JPIMMED_1_11: return(11); case cJ1_JPIMMED_1_12: return(12); case cJ1_JPIMMED_1_13: return(13); case cJ1_JPIMMED_1_14: return(14); case cJ1_JPIMMED_1_15: return(15); #endif #if (defined(JUDY1) || defined(JU_64BIT)) case cJU_JPIMMED_2_02: return(2); case cJU_JPIMMED_2_03: return(3); #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_2_04: return(4); case cJ1_JPIMMED_2_05: return(5); case cJ1_JPIMMED_2_06: return(6); case cJ1_JPIMMED_2_07: return(7); #endif #if (defined(JUDY1) || defined(JU_64BIT)) case cJU_JPIMMED_3_02: return(2); #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_3_03: return(3); case cJ1_JPIMMED_3_04: return(4); case cJ1_JPIMMED_3_05: return(5); case cJ1_JPIMMED_4_02: return(2); case cJ1_JPIMMED_4_03: return(3); case cJ1_JPIMMED_5_02: return(2); case cJ1_JPIMMED_5_03: return(3); case cJ1_JPIMMED_6_02: return(2); case cJ1_JPIMMED_7_02: return(2); #endif default: return(cJU_ALLONES); } /*NOTREACHED*/ } // j__udyJPPop1() judy-1.0.5/src/JudyCommon/JudyIns.c0000644000175000017500000021550510204462077017332 0ustar troyhebetroyhebe// Copyright (C) 2000 - 2002 Hewlett-Packard Company // // This program is free software; you can redistribute it and/or modify it // under the term of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License // for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program; if not, write to the Free Software Foundation, // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // _________________ // @(#) $Revision: 4.116 $ $Source: /judy/src/JudyCommon/JudyIns.c $ // // Judy1Set() and JudyLIns() functions for Judy1 and JudyL. // Compile with one of -DJUDY1 or -DJUDYL. // // TBD: Should some of the assertions here be converted to product code that // returns JU_ERRNO_CORRUPT? #if (! (defined(JUDY1) || defined(JUDYL))) #error: One of -DJUDY1 or -DJUDYL must be specified. #endif #ifdef JUDY1 #include "Judy1.h" #else #include "JudyL.h" #endif #include "JudyPrivate1L.h" // Note: Call JudyCheckPop() even before "already inserted" returns, to catch // population errors; see fix in 4.84: DBGCODE(extern void JudyCheckPop(Pvoid_t PArray);) DBGCODE(extern void JudyCheckSorted(Pjll_t Pjll, Word_t Pop1, long IndexSize);) #ifdef TRACEJP #include "JudyPrintJP.c" #endif // These are defined to generic values in JudyCommon/JudyPrivateTypes.h: // // TBD: These should be exported from a header file, but perhaps not, as they // are only used here, and exported from Judy*Decascade, which is a separate // file for profiling reasons (to prevent inlining), but which potentially // could be merged with this file, either in SoftCM or at compile-time. #ifdef JUDY1 extern int j__udy1CreateBranchB(Pjp_t, Pjp_t, uint8_t *, Word_t, Pvoid_t); extern int j__udy1CreateBranchU(Pjp_t, Pvoid_t); #ifndef JU_64BIT extern int j__udy1Cascade1(Pjp_t, Pvoid_t); #endif extern int j__udy1Cascade2(Pjp_t, Pvoid_t); extern int j__udy1Cascade3(Pjp_t, Pvoid_t); #ifdef JU_64BIT extern int j__udy1Cascade4(Pjp_t, Pvoid_t); extern int j__udy1Cascade5(Pjp_t, Pvoid_t); extern int j__udy1Cascade6(Pjp_t, Pvoid_t); extern int j__udy1Cascade7(Pjp_t, Pvoid_t); #endif extern int j__udy1CascadeL(Pjp_t, Pvoid_t); extern int j__udy1InsertBranch(Pjp_t Pjp, Word_t Index, Word_t Btype, Pjpm_t); #else // JUDYL extern int j__udyLCreateBranchB(Pjp_t, Pjp_t, uint8_t *, Word_t, Pvoid_t); extern int j__udyLCreateBranchU(Pjp_t, Pvoid_t); extern int j__udyLCascade1(Pjp_t, Pvoid_t); extern int j__udyLCascade2(Pjp_t, Pvoid_t); extern int j__udyLCascade3(Pjp_t, Pvoid_t); #ifdef JU_64BIT extern int j__udyLCascade4(Pjp_t, Pvoid_t); extern int j__udyLCascade5(Pjp_t, Pvoid_t); extern int j__udyLCascade6(Pjp_t, Pvoid_t); extern int j__udyLCascade7(Pjp_t, Pvoid_t); #endif extern int j__udyLCascadeL(Pjp_t, Pvoid_t); extern int j__udyLInsertBranch(Pjp_t Pjp, Word_t Index, Word_t Btype, Pjpm_t); #endif // **************************************************************************** // MACROS FOR COMMON CODE: // // Check if Index is an outlier to (that is, not a member of) this expanse: // // An outlier is an Index in-the-expanse of the slot containing the pointer, // but not-in-the-expanse of the "narrow" pointer in that slot. (This means // the Dcd part of the Index differs from the equivalent part of jp_DcdPopO.) // Therefore, the remedy is to put a cJU_JPBRANCH_L* between the narrow pointer // and the object to which it points, and add the outlier Index as an Immediate // in the cJU_JPBRANCH_L*. The "trick" is placing the cJU_JPBRANCH_L* at a // Level that is as low as possible. This is determined by counting the digits // in the existing narrow pointer that are the same as the digits in the new // Index (see j__udyInsertBranch()). // // Note: At some high Levels, cJU_DCDMASK() is all zeros => dead code; assume // the compiler optimizes this out. #define JU_CHECK_IF_OUTLIER(Pjp, Index, cLevel, Pjpm) \ if (JU_DCDNOTMATCHINDEX(Index, Pjp, cLevel)) \ return(j__udyInsertBranch(Pjp, Index, cLevel, Pjpm)) // Check if an Index is already in a leaf or immediate, after calling // j__udySearchLeaf*() to set Offset: // // A non-negative Offset means the Index already exists, so return 0; otherwise // complement Offset to proceed. #ifdef JUDY1 #define Pjv ignore // placeholder. #define JU_CHECK_IF_EXISTS(Offset,ignore,Pjpm) \ { \ if ((Offset) >= 0) return(0); \ (Offset) = ~(Offset); \ } #else // For JudyL, also set the value area pointer in the Pjpm: #define JU_CHECK_IF_EXISTS(Offset,Pjv,Pjpm) \ { \ if ((Offset) >= 0) \ { \ (Pjpm)->jpm_PValue = (Pjv) + (Offset); \ return(0); \ } \ (Offset) = ~(Offset); \ } #endif // **************************************************************************** // __ J U D Y I N S W A L K // // Walk the Judy tree to do a set/insert. This is only called internally, and // recursively. Unlike Judy1Test() and JudyLGet(), the extra time required for // recursion should be negligible compared with the total. // // Return -1 for error (details in JPM), 0 for Index already inserted, 1 for // new Index inserted. FUNCTION static int j__udyInsWalk( Pjp_t Pjp, // current JP to descend. Word_t Index, // to insert. Pjpm_t Pjpm) // for returning info to top Level. { uint8_t digit; // from Index, current offset into a branch. jp_t newJP; // for creating a new Immed JP. Word_t exppop1; // expanse (leaf) population. int retcode; // return codes: -1, 0, 1. #ifdef SUBEXPCOUNTS // Pointer to BranchB/U subexpanse counter: // // Note: Very important for performance reasons (avoids cache fills). PWord_t PSubExp = (PWord_t) NULL; #endif ContinueInsWalk: // for modifying state without recursing. #ifdef TRACEJP JudyPrintJP(Pjp, "i", __LINE__); #endif switch (JU_JPTYPE(Pjp)) // entry: Pjp, Index. { // **************************************************************************** // JPNULL*: // // Convert JP in place from current null type to cJU_JPIMMED_*_01 by // calculating new JP type. case cJU_JPNULL1: case cJU_JPNULL2: case cJU_JPNULL3: #ifdef JU_64BIT case cJU_JPNULL4: case cJU_JPNULL5: case cJU_JPNULL6: case cJU_JPNULL7: #endif assert((Pjp->jp_Addr) == 0); JU_JPSETADT(Pjp, 0, Index, JU_JPTYPE(Pjp) + cJU_JPIMMED_1_01 - cJU_JPNULL1); #ifdef JUDYL // value area is first word of new Immed_01 JP: Pjpm->jpm_PValue = (Pjv_t) (&(Pjp->jp_Addr)); #endif return(1); // **************************************************************************** // JPBRANCH_L*: // // If the new Index is not an outlier to the branchs expanse, and the branch // should not be converted to uncompressed, extract the digit and record the // Immediate type to create for a new Immed JP, before going to common code. // // Note: JU_CHECK_IF_OUTLIER() is a no-op for BranchB3[7] on 32[64]-bit. #define JU_BRANCH_OUTLIER(DIGIT,POP1,cLEVEL,PJP,INDEX,PJPM) \ JU_CHECK_IF_OUTLIER(PJP, INDEX, cLEVEL, PJPM); \ (DIGIT) = JU_DIGITATSTATE(INDEX, cLEVEL); \ (POP1) = JU_JPBRANCH_POP0(PJP, cLEVEL) case cJU_JPBRANCH_L2: JU_BRANCH_OUTLIER(digit, exppop1, 2, Pjp, Index, Pjpm); goto JudyBranchL; case cJU_JPBRANCH_L3: JU_BRANCH_OUTLIER(digit, exppop1, 3, Pjp, Index, Pjpm); goto JudyBranchL; #ifdef JU_64BIT case cJU_JPBRANCH_L4: JU_BRANCH_OUTLIER(digit, exppop1, 4, Pjp, Index, Pjpm); goto JudyBranchL; case cJU_JPBRANCH_L5: JU_BRANCH_OUTLIER(digit, exppop1, 5, Pjp, Index, Pjpm); goto JudyBranchL; case cJU_JPBRANCH_L6: JU_BRANCH_OUTLIER(digit, exppop1, 6, Pjp, Index, Pjpm); goto JudyBranchL; case cJU_JPBRANCH_L7: JU_BRANCH_OUTLIER(digit, exppop1, 7, Pjp, Index, Pjpm); goto JudyBranchL; #endif // Similar to common code above, but no outlier check is needed, and the Immed // type depends on the word size: case cJU_JPBRANCH_L: { Pjbl_t PjblRaw; // pointer to old linear branch. Pjbl_t Pjbl; Pjbu_t PjbuRaw; // pointer to new uncompressed branch. Pjbu_t Pjbu; Word_t numJPs; // number of JPs = populated expanses. int offset; // in branch. digit = JU_DIGITATSTATE(Index, cJU_ROOTSTATE); exppop1 = Pjpm->jpm_Pop0; // fall through: // COMMON CODE FOR LINEAR BRANCHES: // // Come here with digit and exppop1 already set. JudyBranchL: PjblRaw = (Pjbl_t) (Pjp->jp_Addr); Pjbl = P_JBL(PjblRaw); // If population under this branch greater than: if (exppop1 > JU_BRANCHL_MAX_POP) goto ConvertBranchLtoU; numJPs = Pjbl->jbl_NumJPs; if ((numJPs == 0) || (numJPs > cJU_BRANCHLMAXJPS)) { JU_SET_ERRNO_NONNULL(Pjpm, JU_ERRNO_CORRUPT); return(-1); } // Search for a match to the digit: offset = j__udySearchLeaf1((Pjll_t) (Pjbl->jbl_Expanse), numJPs, digit); // If Index is found, offset is into an array of 1..cJU_BRANCHLMAXJPS JPs: if (offset >= 0) { Pjp = (Pjbl->jbl_jp) + offset; // address of next JP. break; // continue walk. } // Expanse is missing (not populated) for the passed Index, so insert an Immed // -- if theres room: if (numJPs < cJU_BRANCHLMAXJPS) { offset = ~offset; // insertion offset. JU_JPSETADT(&newJP, 0, Index, JU_JPTYPE(Pjp) + cJU_JPIMMED_1_01-cJU_JPBRANCH_L2); JU_INSERTINPLACE(Pjbl->jbl_Expanse, numJPs, offset, digit); JU_INSERTINPLACE(Pjbl->jbl_jp, numJPs, offset, newJP); DBGCODE(JudyCheckSorted((Pjll_t) (Pjbl->jbl_Expanse), numJPs + 1, /* IndexSize = */ 1);) ++(Pjbl->jbl_NumJPs); #ifdef JUDYL // value area is first word of new Immed 01 JP: Pjpm->jpm_PValue = (Pjv_t) ((Pjbl->jbl_jp) + offset); #endif return(1); } // MAXED OUT LINEAR BRANCH, CONVERT TO A BITMAP BRANCH, THEN INSERT: // // Copy the linear branch to a bitmap branch. // // TBD: Consider renaming j__udyCreateBranchB() to j__udyConvertBranchLtoB(). assert((numJPs) <= cJU_BRANCHLMAXJPS); if (j__udyCreateBranchB(Pjp, Pjbl->jbl_jp, Pjbl->jbl_Expanse, numJPs, Pjpm) == -1) { return(-1); } // Convert jp_Type from linear branch to equivalent bitmap branch: Pjp->jp_Type += cJU_JPBRANCH_B - cJU_JPBRANCH_L; j__udyFreeJBL(PjblRaw, Pjpm); // free old BranchL. // Having changed branch types, now do the insert in the new branch type: goto ContinueInsWalk; // OPPORTUNISTICALLY CONVERT FROM BRANCHL TO BRANCHU: // // Memory efficiency is no object because the branchs pop1 is large enough, so // speed up array access. Come here with PjblRaw set. Note: This is goto // code because the previous block used to fall through into it as well, but no // longer. ConvertBranchLtoU: // Allocate memory for an uncompressed branch: if ((PjbuRaw = j__udyAllocJBU(Pjpm)) == (Pjbu_t) NULL) return(-1); Pjbu = P_JBU(PjbuRaw); // Set the proper NULL type for most of the uncompressed branchs JPs: JU_JPSETADT(&newJP, 0, 0, JU_JPTYPE(Pjp) - cJU_JPBRANCH_L2 + cJU_JPNULL1); // Initialize: Pre-set uncompressed branch to mostly JPNULL*s: for (numJPs = 0; numJPs < cJU_BRANCHUNUMJPS; ++numJPs) Pjbu->jbu_jp[numJPs] = newJP; // Copy JPs from linear branch to uncompressed branch: { #ifdef SUBEXPCOUNTS Word_t popmask = cJU_POP0MASK(JU_JPTYPE(Pjp)) - cJU_JPBRANCH_L2 - 2; for (numJPs = 0; numJPs < cJU_NUMSUBEXPU; ++numJPs) Pjbu->jbu_subPop1[numJPs] = 0; #endif for (numJPs = 0; numJPs < Pjbl->jbl_NumJPs; ++numJPs) { Pjp_t Pjp1 = &(Pjbl->jbl_jp[numJPs]); offset = Pjbl->jbl_Expanse[numJPs]; Pjbu->jbu_jp[offset] = *Pjp1; #ifdef SUBEXPCOUNTS Pjbu->jbu_subPop1[offset/cJU_NUMSUBEXPU] += JU_JPDCDPOP0(Pjp1) & popmask + 1; #endif } } j__udyFreeJBL(PjblRaw, Pjpm); // free old BranchL. // Plug new values into parent JP: Pjp->jp_Addr = (Word_t) PjbuRaw; Pjp->jp_Type += cJU_JPBRANCH_U - cJU_JPBRANCH_L; // to BranchU. // Save global population of last BranchU conversion: Pjpm->jpm_LastUPop0 = Pjpm->jpm_Pop0; goto ContinueInsWalk; } // case cJU_JPBRANCH_L. // **************************************************************************** // JPBRANCH_B*: // // If the new Index is not an outlier to the branchs expanse, extract the // digit and record the Immediate type to create for a new Immed JP, before // going to common code. // // Note: JU_CHECK_IF_OUTLIER() is a no-op for BranchB3[7] on 32[64]-bit. case cJU_JPBRANCH_B2: JU_BRANCH_OUTLIER(digit, exppop1, 2, Pjp, Index, Pjpm); goto JudyBranchB; case cJU_JPBRANCH_B3: JU_BRANCH_OUTLIER(digit, exppop1, 3, Pjp, Index, Pjpm); goto JudyBranchB; #ifdef JU_64BIT case cJU_JPBRANCH_B4: JU_BRANCH_OUTLIER(digit, exppop1, 4, Pjp, Index, Pjpm); goto JudyBranchB; case cJU_JPBRANCH_B5: JU_BRANCH_OUTLIER(digit, exppop1, 5, Pjp, Index, Pjpm); goto JudyBranchB; case cJU_JPBRANCH_B6: JU_BRANCH_OUTLIER(digit, exppop1, 6, Pjp, Index, Pjpm); goto JudyBranchB; case cJU_JPBRANCH_B7: JU_BRANCH_OUTLIER(digit, exppop1, 7, Pjp, Index, Pjpm); goto JudyBranchB; #endif case cJU_JPBRANCH_B: { Pjbb_t Pjbb; // pointer to bitmap branch. Pjbb_t PjbbRaw; // pointer to bitmap branch. Pjp_t Pjp2Raw; // 1 of N arrays of JPs. Pjp_t Pjp2; // 1 of N arrays of JPs. Word_t subexp; // 1 of N subexpanses in bitmap. BITMAPB_t bitmap; // for one subexpanse. BITMAPB_t bitmask; // bit set for Indexs digit. Word_t numJPs; // number of JPs = populated expanses. int offset; // in bitmap branch. // Similar to common code above, but no outlier check is needed, and the Immed // type depends on the word size: digit = JU_DIGITATSTATE(Index, cJU_ROOTSTATE); exppop1 = Pjpm->jpm_Pop0; // fall through: // COMMON CODE FOR BITMAP BRANCHES: // // Come here with digit and exppop1 already set. JudyBranchB: // If population increment is greater than.. (300): if ((Pjpm->jpm_Pop0 - Pjpm->jpm_LastUPop0) > JU_BTOU_POP_INCREMENT) { // If total population of array is greater than.. (750): if (Pjpm->jpm_Pop0 > JU_BRANCHB_MAX_POP) { // If population under the branch is greater than.. (135): if (exppop1 > JU_BRANCHB_MIN_POP) { if (j__udyCreateBranchU(Pjp, Pjpm) == -1) return(-1); // Save global population of last BranchU conversion: Pjpm->jpm_LastUPop0 = Pjpm->jpm_Pop0; goto ContinueInsWalk; } } } // CONTINUE TO USE BRANCHB: // // Get pointer to bitmap branch (JBB): PjbbRaw = (Pjbb_t) (Pjp->jp_Addr); Pjbb = P_JBB(PjbbRaw); // Form the Int32 offset, and Bit offset values: // // 8 bit Decode | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | // |SubExpanse | Bit offset | // // Get the 1 of 8 expanses from digit, Bits 5..7 = 1 of 8, and get the 32-bit // word that may have a bit set: subexp = digit / cJU_BITSPERSUBEXPB; bitmap = JU_JBB_BITMAP(Pjbb, subexp); Pjp2Raw = JU_JBB_PJP(Pjbb, subexp); Pjp2 = P_JP(Pjp2Raw); // Get the bit position that represents the desired expanse, and get the offset // into the array of JPs for the JP that matches the bit. bitmask = JU_BITPOSMASKB(digit); offset = j__udyCountBitsB(bitmap & (bitmask - 1)); // If JP is already in this expanse, get Pjp and continue the walk: if (bitmap & bitmask) { #ifdef SUBEXPCOUNTS PSubExp = &(Pjbb->jbb_Counts[subexp]); // ptr to subexp counts. #endif Pjp = Pjp2 + offset; break; // continue walk. } // ADD NEW EXPANSE FOR NEW INDEX: // // The new expanse always an cJU_JPIMMED_*_01 containing just the new Index, so // finish setting up an Immed JP. JU_JPSETADT(&newJP, 0, Index, JU_JPTYPE(Pjp) + cJU_JPIMMED_1_01-cJU_JPBRANCH_B2); // Get 1 of the 8 JP arrays and calculate number of JPs in subexpanse array: Pjp2Raw = JU_JBB_PJP(Pjbb, subexp); Pjp2 = P_JP(Pjp2Raw); numJPs = j__udyCountBitsB(bitmap); // Expand branch JP subarray in-place: if (JU_BRANCHBJPGROWINPLACE(numJPs)) { assert(numJPs > 0); JU_INSERTINPLACE(Pjp2, numJPs, offset, newJP); #ifdef JUDYL // value area is first word of new Immed 01 JP: Pjpm->jpm_PValue = (Pjv_t) (Pjp2 + offset); #endif } // No room, allocate a bigger bitmap branch JP subarray: else { Pjp_t PjpnewRaw; Pjp_t Pjpnew; if ((PjpnewRaw = j__udyAllocJBBJP(numJPs + 1, Pjpm)) == 0) return(-1); Pjpnew = P_JP(PjpnewRaw); // If there was an old JP array, then copy it, insert the new Immed JP, and // free the old array: if (numJPs) { JU_INSERTCOPY(Pjpnew, Pjp2, numJPs, offset, newJP); j__udyFreeJBBJP(Pjp2Raw, numJPs, Pjpm); #ifdef JUDYL // value area is first word of new Immed 01 JP: Pjpm->jpm_PValue = (Pjv_t) (Pjpnew + offset); #endif } // New JP subarray; point to cJU_JPIMMED_*_01 and place it: else { assert(JU_JBB_PJP(Pjbb, subexp) == (Pjp_t) NULL); Pjp = Pjpnew; *Pjp = newJP; // copy to new memory. #ifdef JUDYL // value area is first word of new Immed 01 JP: Pjpm->jpm_PValue = (Pjv_t) (&(Pjp->jp_Addr)); #endif } // Place new JP subarray in BranchB: JU_JBB_PJP(Pjbb, subexp) = PjpnewRaw; } // else // Set the new Indexs bit: JU_JBB_BITMAP(Pjbb, subexp) |= bitmask; return(1); } // case // **************************************************************************** // JPBRANCH_U*: // // Just drop through the JP for the correct digit. If the JP turns out to be a // JPNULL*, thats OK, the memory is already allocated, and the next walk // simply places an Immed in it. // #ifdef SUBEXPCOUNTS #define JU_GETSUBEXP(PSubExp,Pjbu,Digit) \ (PSubExp) = &((Pjbu)->jbu_subPop1[(Digit) / cJU_NUMSUBEXPU]) #else #define JU_GETSUBEXP(PSubExp,Pjbu,Digit) // null. #endif #define JU_JBU_PJP_SUBEXP(Pjp,PSubExp,Index,Level) \ { \ uint8_t digit = JU_DIGITATSTATE(Index, Level); \ Pjbu_t P_jbu = P_JBU((Pjp)->jp_Addr); \ (Pjp) = &(P_jbu->jbu_jp[digit]); \ JU_GETSUBEXP(PSubExp, P_jbu, digit); \ } case cJU_JPBRANCH_U2: JU_CHECK_IF_OUTLIER(Pjp, Index, 2, Pjpm); JU_JBU_PJP_SUBEXP(Pjp, PSubExp, Index, 2); break; #ifdef JU_64BIT case cJU_JPBRANCH_U3: JU_CHECK_IF_OUTLIER(Pjp, Index, 3, Pjpm); JU_JBU_PJP_SUBEXP(Pjp, PSubExp, Index, 3); break; case cJU_JPBRANCH_U4: JU_CHECK_IF_OUTLIER(Pjp, Index, 4, Pjpm); JU_JBU_PJP_SUBEXP(Pjp, PSubExp, Index, 4); break; case cJU_JPBRANCH_U5: JU_CHECK_IF_OUTLIER(Pjp, Index, 5, Pjpm); JU_JBU_PJP_SUBEXP(Pjp, PSubExp, Index, 5); break; case cJU_JPBRANCH_U6: JU_CHECK_IF_OUTLIER(Pjp, Index, 6, Pjpm); JU_JBU_PJP_SUBEXP(Pjp, PSubExp, Index, 6); break; case cJU_JPBRANCH_U7: JU_JBU_PJP_SUBEXP(Pjp, PSubExp, Index, 7); #else case cJU_JPBRANCH_U3: JU_JBU_PJP_SUBEXP(Pjp, PSubExp, Index, 3); #endif break; case cJU_JPBRANCH_U: JU_JBU_PJP_SUBEXP(Pjp, PSubExp, Index, cJU_ROOTSTATE); break; // **************************************************************************** // JPLEAF*: // // COMMON CODE FRAGMENTS TO MINIMIZE REDUNDANCY BELOW: // // These are necessary to support performance by function and loop unrolling // while avoiding huge amounts of nearly identical code. // // Prepare to handle a linear leaf: Check for an outlier; set pop1 and pointer // to leaf: #ifdef JUDY1 #define JU_LEAFVALUE(Pjv) // null. #define JU_LEAFPREPVALUE(Pjv, ValueArea) // null. #else #define JU_LEAFVALUE(Pjv) Pjv_t Pjv #define JU_LEAFPREPVALUE(Pjv, ValueArea) (Pjv) = ValueArea(Pleaf, exppop1) #endif #define JU_LEAFPREP(cIS,Type,MaxPop1,ValueArea) \ Pjll_t PjllRaw; \ Type Pleaf; /* specific type */ \ int offset; \ JU_LEAFVALUE(Pjv); \ \ JU_CHECK_IF_OUTLIER(Pjp, Index, cIS, Pjpm); \ \ exppop1 = JU_JPLEAF_POP0(Pjp) + 1; \ assert(exppop1 <= (MaxPop1)); \ PjllRaw = (Pjll_t) (Pjp->jp_Addr); \ Pleaf = (Type) P_JLL(PjllRaw); \ JU_LEAFPREPVALUE(Pjv, ValueArea) // Add to, or grow, a linear leaf: Find Index position; if the Index is // absent, if theres room in the leaf, insert the Index [and value of 0] in // place, otherwise grow the leaf: // // Note: These insertions always take place with whole words, using // JU_INSERTINPLACE() or JU_INSERTCOPY(). #ifdef JUDY1 #define JU_LEAFGROWVALUEADD(Pjv,ExpPop1,Offset) // null. #else #define JU_LEAFGROWVALUEADD(Pjv,ExpPop1,Offset) \ JU_INSERTINPLACE(Pjv, ExpPop1, Offset, 0); \ Pjpm->jpm_PValue = (Pjv) + (Offset) #endif #ifdef JUDY1 #define JU_LEAFGROWVALUENEW(ValueArea,Pjv,ExpPop1,Offset) // null. #else #define JU_LEAFGROWVALUENEW(ValueArea,Pjv,ExpPop1,Offset) \ { \ Pjv_t Pjvnew = ValueArea(Pleafnew, (ExpPop1) + 1); \ JU_INSERTCOPY(Pjvnew, Pjv, ExpPop1, Offset, 0); \ Pjpm->jpm_PValue = (Pjvnew) + (Offset); \ } #endif #define JU_LEAFGROW(cIS,Type,MaxPop1,Search,ValueArea,GrowInPlace, \ InsertInPlace,InsertCopy,Alloc,Free) \ \ offset = Search(Pleaf, exppop1, Index); \ JU_CHECK_IF_EXISTS(offset, Pjv, Pjpm); \ \ if (GrowInPlace(exppop1)) /* add to current leaf */ \ { \ InsertInPlace(Pleaf, exppop1, offset, Index); \ JU_LEAFGROWVALUEADD(Pjv, exppop1, offset); \ DBGCODE(JudyCheckSorted((Pjll_t) Pleaf, exppop1 + 1, cIS);) \ return(1); \ } \ \ if (exppop1 < (MaxPop1)) /* grow to new leaf */ \ { \ Pjll_t PjllnewRaw; \ Type Pleafnew; \ if ((PjllnewRaw = Alloc(exppop1 + 1, Pjpm)) == 0) return(-1); \ Pleafnew = (Type) P_JLL(PjllnewRaw); \ InsertCopy(Pleafnew, Pleaf, exppop1, offset, Index); \ JU_LEAFGROWVALUENEW(ValueArea, Pjv, exppop1, offset); \ DBGCODE(JudyCheckSorted((Pjll_t) Pleafnew, exppop1 + 1, cIS);) \ Free(PjllRaw, exppop1, Pjpm); \ (Pjp->jp_Addr) = (Word_t) PjllnewRaw; \ return(1); \ } \ assert(exppop1 == (MaxPop1)) // Handle linear leaf overflow (cascade): Splay or compress into smaller // leaves: #define JU_LEAFCASCADE(MaxPop1,Cascade,Free) \ if (Cascade(Pjp, Pjpm) == -1) return(-1); \ Free(PjllRaw, MaxPop1, Pjpm); \ goto ContinueInsWalk // Wrapper around all of the above: #define JU_LEAFSET(cIS,Type,MaxPop1,Search,GrowInPlace,InsertInPlace, \ InsertCopy,Cascade,Alloc,Free,ValueArea) \ { \ JU_LEAFPREP(cIS,Type,MaxPop1,ValueArea); \ JU_LEAFGROW(cIS,Type,MaxPop1,Search,ValueArea,GrowInPlace, \ InsertInPlace,InsertCopy,Alloc,Free); \ JU_LEAFCASCADE(MaxPop1,Cascade,Free); \ } // END OF MACROS; LEAFL CASES START HERE: // // 64-bit Judy1 does not have 1-byte leaves: #if (defined(JUDYL) || (! defined(JU_64BIT))) case cJU_JPLEAF1: JU_LEAFSET(1, uint8_t *, cJU_LEAF1_MAXPOP1, j__udySearchLeaf1, JU_LEAF1GROWINPLACE, JU_INSERTINPLACE, JU_INSERTCOPY, j__udyCascade1, j__udyAllocJLL1, j__udyFreeJLL1, JL_LEAF1VALUEAREA); #endif // (JUDYL || ! JU_64BIT) case cJU_JPLEAF2: JU_LEAFSET(2, uint16_t *, cJU_LEAF2_MAXPOP1, j__udySearchLeaf2, JU_LEAF2GROWINPLACE, JU_INSERTINPLACE, JU_INSERTCOPY, j__udyCascade2, j__udyAllocJLL2, j__udyFreeJLL2, JL_LEAF2VALUEAREA); case cJU_JPLEAF3: JU_LEAFSET(3, uint8_t *, cJU_LEAF3_MAXPOP1, j__udySearchLeaf3, JU_LEAF3GROWINPLACE, JU_INSERTINPLACE3, JU_INSERTCOPY3, j__udyCascade3, j__udyAllocJLL3, j__udyFreeJLL3, JL_LEAF3VALUEAREA); #ifdef JU_64BIT case cJU_JPLEAF4: JU_LEAFSET(4, uint32_t *, cJU_LEAF4_MAXPOP1, j__udySearchLeaf4, JU_LEAF4GROWINPLACE, JU_INSERTINPLACE, JU_INSERTCOPY, j__udyCascade4, j__udyAllocJLL4, j__udyFreeJLL4, JL_LEAF4VALUEAREA); case cJU_JPLEAF5: JU_LEAFSET(5, uint8_t *, cJU_LEAF5_MAXPOP1, j__udySearchLeaf5, JU_LEAF5GROWINPLACE, JU_INSERTINPLACE5, JU_INSERTCOPY5, j__udyCascade5, j__udyAllocJLL5, j__udyFreeJLL5, JL_LEAF5VALUEAREA); case cJU_JPLEAF6: JU_LEAFSET(6, uint8_t *, cJU_LEAF6_MAXPOP1, j__udySearchLeaf6, JU_LEAF6GROWINPLACE, JU_INSERTINPLACE6, JU_INSERTCOPY6, j__udyCascade6, j__udyAllocJLL6, j__udyFreeJLL6, JL_LEAF6VALUEAREA); case cJU_JPLEAF7: JU_LEAFSET(7, uint8_t *, cJU_LEAF7_MAXPOP1, j__udySearchLeaf7, JU_LEAF7GROWINPLACE, JU_INSERTINPLACE7, JU_INSERTCOPY7, j__udyCascade7, j__udyAllocJLL7, j__udyFreeJLL7, JL_LEAF7VALUEAREA); #endif // JU_64BIT // **************************************************************************** // JPLEAF_B1: // // 8 bit Decode | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | // |SubExpanse | Bit offset | // // Note: For JudyL, values are stored in 8 subexpanses, each a linear word // array of up to 32 values each. case cJU_JPLEAF_B1: { #ifdef JUDYL Pjv_t PjvRaw; // pointer to value part of the leaf. Pjv_t Pjv; // pointer to value part of the leaf. Pjv_t PjvnewRaw; // new value area. Pjv_t Pjvnew; // new value area. Word_t subexp; // 1 of 8 subexpanses in bitmap. Pjlb_t Pjlb; // pointer to bitmap part of the leaf. BITMAPL_t bitmap; // for one subexpanse. BITMAPL_t bitmask; // bit set for Indexs digit. int offset; // of index in value area. #endif JU_CHECK_IF_OUTLIER(Pjp, Index, 1, Pjpm); #ifdef JUDY1 // If Index (bit) is already set, return now: if (JU_BITMAPTESTL(P_JLB(Pjp->jp_Addr), Index)) return(0); // If bitmap is not full, set the new Indexs bit; otherwise convert to a Full: if ((exppop1 = JU_JPLEAF_POP0(Pjp) + 1) < cJU_JPFULLPOPU1_POP0) { JU_BITMAPSETL(P_JLB(Pjp->jp_Addr), Index); } else { j__udyFreeJLB1((Pjlb_t) (Pjp->jp_Addr), Pjpm); // free LeafB1. Pjp->jp_Type = cJ1_JPFULLPOPU1; Pjp->jp_Addr = 0; } #else // JUDYL // This is very different from Judy1 because of the need to return a value area // even for an existing Index, or manage the value area for a new Index, and // because JudyL has no Full type: // Get last byte to decode from Index, and pointer to bitmap leaf: digit = JU_DIGITATSTATE(Index, 1); Pjlb = P_JLB(Pjp->jp_Addr); // Prepare additional values: subexp = digit / cJU_BITSPERSUBEXPL; // which subexpanse. bitmap = JU_JLB_BITMAP(Pjlb, subexp); // subexps 32-bit map. PjvRaw = JL_JLB_PVALUE(Pjlb, subexp); // corresponding values. Pjv = P_JV(PjvRaw); // corresponding values. bitmask = JU_BITPOSMASKL(digit); // mask for Index. offset = j__udyCountBitsL(bitmap & (bitmask - 1)); // of Index. // If Index already exists, get value pointer and exit: if (bitmap & bitmask) { assert(Pjv); Pjpm->jpm_PValue = Pjv + offset; // existing value. return(0); } // Get the total bits set = expanse population of Value area: exppop1 = j__udyCountBitsL(bitmap); // If the value area can grow in place, do it: if (JL_LEAFVGROWINPLACE(exppop1)) { JU_INSERTINPLACE(Pjv, exppop1, offset, 0); JU_JLB_BITMAP(Pjlb, subexp) |= bitmask; // set Indexs bit. Pjpm->jpm_PValue = Pjv + offset; // new value area. return(1); } // Increase size of value area: if ((PjvnewRaw = j__udyLAllocJV(exppop1 + 1, Pjpm)) == (Pjv_t) NULL) return(-1); Pjvnew = P_JV(PjvnewRaw); if (exppop1) // have existing value area. { assert(Pjv); JU_INSERTCOPY(Pjvnew, Pjv, exppop1, offset, 0); Pjpm->jpm_PValue = Pjvnew + offset; j__udyLFreeJV(PjvRaw, exppop1, Pjpm); // free old values. } else // first index, new value area: { Pjpm->jpm_PValue = Pjvnew; *(Pjpm->jpm_PValue) = 0; } // Set bit for new Index and place new leaf value area in bitmap: JU_JLB_BITMAP(Pjlb, subexp) |= bitmask; JL_JLB_PVALUE(Pjlb, subexp) = PjvnewRaw; #endif // JUDYL return(1); } // case #ifdef JUDY1 // **************************************************************************** // JPFULLPOPU1: // // If Index is not an outlier, then by definition its already set. case cJ1_JPFULLPOPU1: JU_CHECK_IF_OUTLIER(Pjp, Index, 1, Pjpm); return(0); #endif // **************************************************************************** // JPIMMED*: // // This is some of the most complex code in Judy considering Judy1 versus JudyL // and 32-bit versus 64-bit variations. The following comments attempt to make // this clearer. // // Of the 2 words in a JP, for immediate indexes Judy1 can use 2 words - 1 byte // = 7 [15] bytes, but JudyL can only use 1 word - 1 byte = 3 [7] bytes because // the other word is needed for a value area or a pointer to a value area. // // For both Judy1 and JudyL, cJU_JPIMMED_*_01 indexes are in word 2; otherwise // for Judy1 only, a list of 2 or more indexes starts in word 1. JudyL keeps // the list in word 2 because word 1 is a pointer (to a LeafV, that is, a leaf // containing only values). Furthermore, cJU_JPIMMED_*_01 indexes are stored // all-but-first-byte in jp_DcdPopO, not just the Index Sizes bytes. // // TBD: This can be confusing because Doug didnt use data structures for it. // Instead he often directly accesses Pjp for the first word and jp_DcdPopO for // the second word. It would be nice to use data structs, starting with // jp_1Index and jp_LIndex where possible. // // Maximum Immed JP types for Judy1/JudyL, depending on Index Size (cIS): // // 32-bit 64-bit // // bytes: 7/ 3 15/ 7 (Judy1/JudyL) // // cIS // 1_ 07/03 15/07 (as in: cJ1_JPIMMED_1_07) // 2_ 03/01 07/03 // 3_ 02/01 05/02 // 4_ 03/01 // 5_ 03/01 // 6_ 02/01 // 7_ 02/01 // // State transitions while inserting an Index, matching the above table: // (Yes, this is very terse... Study it and it will make sense.) // (Note, parts of this diagram are repeated below for quick reference.) // // +-- reformat JP here for Judy1 only, from word-2 to word-1 // | // | JUDY1 || JU_64BIT JUDY1 && JU_64BIT // V // 1_01 => 1_02 => 1_03 => [ 1_04 => ... => 1_07 => [ 1_08..15 => ]] Leaf1 (*) // 2_01 => [ 2_02 => 2_03 => [ 2_04..07 => ]] Leaf2 // 3_01 => [ 3_02 => [ 3_03..05 => ]] Leaf3 // JU_64BIT only: // 4_01 => [[ 4_02..03 => ]] Leaf4 // 5_01 => [[ 5_02..03 => ]] Leaf5 // 6_01 => [[ 6_02 => ]] Leaf6 // 7_01 => [[ 7_02 => ]] Leaf7 // // (*) For Judy1 & 64-bit, go directly from cJU_JPIMMED_1_15 to a LeafB1; skip // Leaf1, as described in Judy1.h regarding cJ1_JPLEAF1. // COMMON CODE FRAGMENTS TO MINIMIZE REDUNDANCY BELOW: // // These are necessary to support performance by function and loop unrolling // while avoiding huge amounts of nearly identical code. // // The differences between Judy1 and JudyL with respect to value area handling // are just too large for completely common code between them... Oh well, some // big ifdefs follow. However, even in the following ifdefd code, use cJU_*, // JU_*, and Judy*() instead of cJ1_* / cJL_*, J1_* / JL_*, and // Judy1*()/JudyL*(), for minimum diffs. // // Handle growth of cJU_JPIMMED_*_01 to cJU_JPIMMED_*_02, for an even or odd // Index Size (cIS), given oldIndex, Index, and Pjll in the context: // // Put oldIndex and Index in their proper order. For odd indexes, must copy // bytes. #ifdef JUDY1 #define JU_IMMSET_01_COPY_EVEN(ignore1,ignore2) \ if (oldIndex < Index) { Pjll[0] = oldIndex; Pjll[1] = Index; } \ else { Pjll[0] = Index; Pjll[1] = oldIndex; } #define JU_IMMSET_01_COPY_ODD(cIS,CopyWord) \ if (oldIndex < Index) \ { \ CopyWord(Pjll + 0, oldIndex); \ CopyWord(Pjll + (cIS), Index); \ } \ else \ { \ CopyWord(Pjll + 0, Index); \ CopyWord(Pjll + (cIS), oldIndex); \ } // The "real" *_01 Copy macro: // // Trim the high byte off Index, look for a match with the old Index, and if // none, insert the new Index in the leaf in the correct place, given Pjp and // Index in the context. // // Note: A single immediate index lives in the jp_DcdPopO field, but two or // more reside starting at Pjp->jp_1Index. #define JU_IMMSET_01_COPY(cIS,LeafType,NewJPType,Copy,CopyWord) \ { \ LeafType Pjll; \ Word_t oldIndex = JU_JPDCDPOP0(Pjp); \ \ Index = JU_TRIMTODCDSIZE(Index); \ if (oldIndex == Index) return(0); \ \ Pjll = (LeafType) (Pjp->jp_1Index); \ Copy(cIS,CopyWord); \ DBGCODE(JudyCheckSorted(Pjll, 2, cIS);) \ \ Pjp->jp_Type = (NewJPType); \ return(1); \ } #else // JUDYL // Variations to also handle value areas; see comments above: // // For JudyL, Pjv (start of value area) and oldValue are also in the context; // leave Pjv set to the value area for Index. #define JU_IMMSET_01_COPY_EVEN(cIS,CopyWord) \ if (oldIndex < Index) \ { \ Pjll[0] = oldIndex; \ Pjv [0] = oldValue; \ Pjll[1] = Index; \ ++Pjv; \ } \ else \ { \ Pjll[0] = Index; \ Pjll[1] = oldIndex; \ Pjv [1] = oldValue; \ } #define JU_IMMSET_01_COPY_ODD(cIS,CopyWord) \ if (oldIndex < Index) \ { \ CopyWord(Pjll + 0, oldIndex); \ CopyWord(Pjll + (cIS), Index); \ Pjv[0] = oldValue; \ ++Pjv; \ } \ else \ { \ CopyWord(Pjll + 0, Index); \ CopyWord(Pjll + (cIS), oldIndex); \ Pjv[1] = oldValue; \ } // The old value area is in the first word (*Pjp), and Pjv and Pjpm are also in // the context. Also, unlike Judy1, indexes remain in word 2 (jp_LIndex), // meaning insert-in-place rather than copy. // // Return jpm_PValue pointing to Indexs value area. If Index is new, allocate // a 2-value-leaf and attach it to the JP. #define JU_IMMSET_01_COPY(cIS,LeafType,NewJPType,Copy,CopyWord) \ { \ LeafType Pjll; \ Word_t oldIndex = JU_JPDCDPOP0(Pjp); \ Word_t oldValue; \ Pjv_t PjvRaw; \ Pjv_t Pjv; \ \ Index = JU_TRIMTODCDSIZE(Index); \ \ if (oldIndex == Index) \ { \ Pjpm->jpm_PValue = (Pjv_t) Pjp; \ return(0); \ } \ \ if ((PjvRaw = j__udyLAllocJV(2, Pjpm)) == (Pjv_t) NULL) \ return(-1); \ Pjv = P_JV(PjvRaw); \ \ oldValue = Pjp->jp_Addr; \ (Pjp->jp_Addr) = (Word_t) PjvRaw; \ Pjll = (LeafType) (Pjp->jp_LIndex); \ \ Copy(cIS,CopyWord); \ DBGCODE(JudyCheckSorted(Pjll, 2, cIS);) \ \ Pjp->jp_Type = (NewJPType); \ *Pjv = 0; \ Pjpm->jpm_PValue = Pjv; \ return(1); \ } // The following is a unique mix of JU_IMMSET_01() and JU_IMMSETCASCADE() for // going from cJU_JPIMMED_*_01 directly to a cJU_JPLEAF* for JudyL: // // If Index is not already set, allocate a leaf, copy the old and new indexes // into it, clear and return the new value area, and modify the current JP. // Note that jp_DcdPop is set to a pop0 of 0 for now, and incremented later. #define JU_IMMSET_01_CASCADE(cIS,LeafType,NewJPType,ValueArea, \ Copy,CopyWord,Alloc) \ { \ Word_t D_P0; \ LeafType PjllRaw; \ LeafType Pjll; \ Word_t oldIndex = JU_JPDCDPOP0(Pjp); \ Word_t oldValue; \ Pjv_t Pjv; \ \ Index = JU_TRIMTODCDSIZE(Index); \ \ if (oldIndex == Index) \ { \ Pjpm->jpm_PValue = (Pjv_t) (&(Pjp->jp_Addr)); \ return(0); \ } \ \ if ((PjllRaw = (LeafType) Alloc(2, Pjpm)) == (LeafType) NULL) \ return(-1); \ Pjll = (LeafType) P_JLL(PjllRaw); \ Pjv = ValueArea(Pjll, 2); \ \ oldValue = Pjp->jp_Addr; \ \ Copy(cIS,CopyWord); \ DBGCODE(JudyCheckSorted(Pjll, 2, cIS);) \ \ *Pjv = 0; \ Pjpm->jpm_PValue = Pjv; \ D_P0 = Index & cJU_DCDMASK(cIS); /* pop0 = 0 */ \ JU_JPSETADT(Pjp, (Word_t)PjllRaw, D_P0, NewJPType); \ \ return(1); \ } #endif // JUDYL // Handle growth of cJU_JPIMMED_*_[02..15]: #ifdef JUDY1 // Insert an Index into an immediate JP that has room for more, if the Index is // not already present; given Pjp, Index, exppop1, Pjv, and Pjpm in the // context: // // Note: Use this only when the JP format doesnt change, that is, going from // cJU_JPIMMED_X_0Y to cJU_JPIMMED_X_0Z, where X >= 2 and Y+1 = Z. // // Note: Incrementing jp_Type is how to increase the Index population. #define JU_IMMSETINPLACE(cIS,LeafType,BaseJPType_02,Search,InsertInPlace) \ { \ LeafType Pjll; \ int offset; \ \ exppop1 = JU_JPTYPE(Pjp) - (BaseJPType_02) + 2; \ offset = Search((Pjll_t) (Pjp->jp_1Index), exppop1, Index); \ \ JU_CHECK_IF_EXISTS(offset, ignore, Pjpm); \ \ Pjll = (LeafType) (Pjp->jp_1Index); \ InsertInPlace(Pjll, exppop1, offset, Index); \ DBGCODE(JudyCheckSorted(Pjll, exppop1 + 1, cIS);) \ ++(Pjp->jp_Type); \ return(1); \ } // Insert an Index into an immediate JP that has no room for more: // // If the Index is not already present, do a cascade (to a leaf); given Pjp, // Index, Pjv, and Pjpm in the context. #define JU_IMMSETCASCADE(cIS,OldPop1,LeafType,NewJPType, \ ignore,Search,InsertCopy,Alloc) \ { \ Word_t D_P0; \ Pjll_t PjllRaw; \ Pjll_t Pjll; \ int offset; \ \ offset = Search((Pjll_t) (Pjp->jp_1Index), (OldPop1), Index); \ JU_CHECK_IF_EXISTS(offset, ignore, Pjpm); \ \ if ((PjllRaw = Alloc((OldPop1) + 1, Pjpm)) == 0) return(-1); \ Pjll = P_JLL(PjllRaw); \ \ InsertCopy((LeafType) Pjll, (LeafType) (Pjp->jp_1Index), \ OldPop1, offset, Index); \ DBGCODE(JudyCheckSorted(Pjll, (OldPop1) + 1, cIS);) \ \ D_P0 = (Index & cJU_DCDMASK(cIS)) + (OldPop1) - 1; \ JU_JPSETADT(Pjp, (Word_t)PjllRaw, D_P0, NewJPType); \ return(1); \ } #else // JUDYL // Variations to also handle value areas; see comments above: // // For JudyL, Pjv (start of value area) is also in the context. // // TBD: This code makes a true but weak assumption that a JudyL 32-bit 2-index // value area must be copied to a new 3-index value area. AND it doesnt know // anything about JudyL 64-bit cases (cJU_JPIMMED_1_0[3-7] only) where the // value area can grow in place! However, this should not break it, just slow // it down. #define JU_IMMSETINPLACE(cIS,LeafType,BaseJPType_02,Search,InsertInPlace) \ { \ LeafType Pleaf; \ int offset; \ Pjv_t PjvRaw; \ Pjv_t Pjv; \ Pjv_t PjvnewRaw; \ Pjv_t Pjvnew; \ \ exppop1 = JU_JPTYPE(Pjp) - (BaseJPType_02) + 2; \ offset = Search((Pjll_t) (Pjp->jp_LIndex), exppop1, Index); \ PjvRaw = (Pjv_t) (Pjp->jp_Addr); \ Pjv = P_JV(PjvRaw); \ \ JU_CHECK_IF_EXISTS(offset, Pjv, Pjpm); \ \ if ((PjvnewRaw = j__udyLAllocJV(exppop1 + 1, Pjpm)) \ == (Pjv_t) NULL) return(-1); \ Pjvnew = P_JV(PjvnewRaw); \ \ Pleaf = (LeafType) (Pjp->jp_LIndex); \ \ InsertInPlace(Pleaf, exppop1, offset, Index); \ /* see TBD above about this: */ \ JU_INSERTCOPY(Pjvnew, Pjv, exppop1, offset, 0); \ DBGCODE(JudyCheckSorted(Pleaf, exppop1 + 1, cIS);) \ j__udyLFreeJV(PjvRaw, exppop1, Pjpm); \ Pjp->jp_Addr = (Word_t) PjvnewRaw; \ Pjpm->jpm_PValue = Pjvnew + offset; \ \ ++(Pjp->jp_Type); \ return(1); \ } #define JU_IMMSETCASCADE(cIS,OldPop1,LeafType,NewJPType, \ ValueArea,Search,InsertCopy,Alloc) \ { \ Word_t D_P0; \ Pjll_t PjllRaw; \ Pjll_t Pjll; \ int offset; \ Pjv_t PjvRaw; \ Pjv_t Pjv; \ Pjv_t Pjvnew; \ \ PjvRaw = (Pjv_t) (Pjp->jp_Addr); \ Pjv = P_JV(PjvRaw); \ offset = Search((Pjll_t) (Pjp->jp_LIndex), (OldPop1), Index); \ JU_CHECK_IF_EXISTS(offset, Pjv, Pjpm); \ \ if ((PjllRaw = Alloc((OldPop1) + 1, Pjpm)) == 0) \ return(-1); \ Pjll = P_JLL(PjllRaw); \ InsertCopy((LeafType) Pjll, (LeafType) (Pjp->jp_LIndex), \ OldPop1, offset, Index); \ DBGCODE(JudyCheckSorted(Pjll, (OldPop1) + 1, cIS);) \ \ Pjvnew = ValueArea(Pjll, (OldPop1) + 1); \ JU_INSERTCOPY(Pjvnew, Pjv, OldPop1, offset, 0); \ j__udyLFreeJV(PjvRaw, (OldPop1), Pjpm); \ Pjpm->jpm_PValue = Pjvnew + offset; \ \ D_P0 = (Index & cJU_DCDMASK(cIS)) + (OldPop1) - 1; \ JU_JPSETADT(Pjp, (Word_t)PjllRaw, D_P0, NewJPType); \ return(1); \ } #endif // JUDYL // Common convenience/shorthand wrappers around JU_IMMSET_01_COPY() for // even/odd index sizes: #define JU_IMMSET_01( cIS, LeafType, NewJPType) \ JU_IMMSET_01_COPY(cIS, LeafType, NewJPType, JU_IMMSET_01_COPY_EVEN, \ ignore) #define JU_IMMSET_01_ODD( cIS, NewJPType, CopyWord) \ JU_IMMSET_01_COPY(cIS, uint8_t *, NewJPType, JU_IMMSET_01_COPY_ODD, \ CopyWord) // END OF MACROS; IMMED CASES START HERE: // cJU_JPIMMED_*_01 cases: // // 1_01 always leads to 1_02: // // (1_01 => 1_02 => 1_03 => [ 1_04 => ... => 1_07 => [ 1_08..15 => ]] LeafL) case cJU_JPIMMED_1_01: JU_IMMSET_01(1, uint8_t *, cJU_JPIMMED_1_02); // 2_01 leads to 2_02, and 3_01 leads to 3_02, except for JudyL 32-bit, where // they lead to a leaf: // // (2_01 => [ 2_02 => 2_03 => [ 2_04..07 => ]] LeafL) // (3_01 => [ 3_02 => [ 3_03..05 => ]] LeafL) #if (defined(JUDY1) || defined(JU_64BIT)) case cJU_JPIMMED_2_01: JU_IMMSET_01(2, uint16_t *, cJU_JPIMMED_2_02); case cJU_JPIMMED_3_01: JU_IMMSET_01_ODD (3, cJU_JPIMMED_3_02, JU_COPY3_LONG_TO_PINDEX); #else case cJU_JPIMMED_2_01: JU_IMMSET_01_CASCADE(2, uint16_t *, cJU_JPLEAF2, JL_LEAF2VALUEAREA, JU_IMMSET_01_COPY_EVEN, ignore, j__udyAllocJLL2); case cJU_JPIMMED_3_01: JU_IMMSET_01_CASCADE(3, uint8_t *, cJU_JPLEAF3, JL_LEAF3VALUEAREA, JU_IMMSET_01_COPY_ODD, JU_COPY3_LONG_TO_PINDEX, j__udyAllocJLL3); #endif #ifdef JU_64BIT // [4-7]_01 lead to [4-7]_02 for Judy1, and to leaves for JudyL: // // (4_01 => [[ 4_02..03 => ]] LeafL) // (5_01 => [[ 5_02..03 => ]] LeafL) // (6_01 => [[ 6_02 => ]] LeafL) // (7_01 => [[ 7_02 => ]] LeafL) #ifdef JUDY1 case cJU_JPIMMED_4_01: JU_IMMSET_01(4, uint32_t *, cJ1_JPIMMED_4_02); case cJU_JPIMMED_5_01: JU_IMMSET_01_ODD(5, cJ1_JPIMMED_5_02, JU_COPY5_LONG_TO_PINDEX); case cJU_JPIMMED_6_01: JU_IMMSET_01_ODD(6, cJ1_JPIMMED_6_02, JU_COPY6_LONG_TO_PINDEX); case cJU_JPIMMED_7_01: JU_IMMSET_01_ODD(7, cJ1_JPIMMED_7_02, JU_COPY7_LONG_TO_PINDEX); #else // JUDYL case cJU_JPIMMED_4_01: JU_IMMSET_01_CASCADE(4, uint32_t *, cJU_JPLEAF4, JL_LEAF4VALUEAREA, JU_IMMSET_01_COPY_EVEN, ignore, j__udyAllocJLL4); case cJU_JPIMMED_5_01: JU_IMMSET_01_CASCADE(5, uint8_t *, cJU_JPLEAF5, JL_LEAF5VALUEAREA, JU_IMMSET_01_COPY_ODD, JU_COPY5_LONG_TO_PINDEX, j__udyAllocJLL5); case cJU_JPIMMED_6_01: JU_IMMSET_01_CASCADE(6, uint8_t *, cJU_JPLEAF6, JL_LEAF6VALUEAREA, JU_IMMSET_01_COPY_ODD, JU_COPY6_LONG_TO_PINDEX, j__udyAllocJLL6); case cJU_JPIMMED_7_01: JU_IMMSET_01_CASCADE(7, uint8_t *, cJU_JPLEAF7, JL_LEAF7VALUEAREA, JU_IMMSET_01_COPY_ODD, JU_COPY7_LONG_TO_PINDEX, j__udyAllocJLL7); #endif // JUDYL #endif // JU_64BIT // cJU_JPIMMED_1_* cases that can grow in place: // // (1_01 => 1_02 => 1_03 => [ 1_04 => ... => 1_07 => [ 1_08..15 => ]] LeafL) case cJU_JPIMMED_1_02: #if (defined(JUDY1) || defined(JU_64BIT)) case cJU_JPIMMED_1_03: case cJU_JPIMMED_1_04: case cJU_JPIMMED_1_05: case cJU_JPIMMED_1_06: #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJU_JPIMMED_1_07: case cJ1_JPIMMED_1_08: case cJ1_JPIMMED_1_09: case cJ1_JPIMMED_1_10: case cJ1_JPIMMED_1_11: case cJ1_JPIMMED_1_12: case cJ1_JPIMMED_1_13: case cJ1_JPIMMED_1_14: #endif JU_IMMSETINPLACE(1, uint8_t *, cJU_JPIMMED_1_02, j__udySearchLeaf1, JU_INSERTINPLACE); // cJU_JPIMMED_1_* cases that must cascade: // // (1_01 => 1_02 => 1_03 => [ 1_04 => ... => 1_07 => [ 1_08..15 => ]] LeafL) #if (defined(JUDYL) && (! defined(JU_64BIT))) case cJU_JPIMMED_1_03: JU_IMMSETCASCADE(1, 3, uint8_t *, cJU_JPLEAF1, JL_LEAF1VALUEAREA, j__udySearchLeaf1, JU_INSERTCOPY, j__udyAllocJLL1); #endif #if (defined(JUDY1) && (! defined(JU_64BIT))) case cJU_JPIMMED_1_07: JU_IMMSETCASCADE(1, 7, uint8_t *, cJU_JPLEAF1, ignore, j__udySearchLeaf1, JU_INSERTCOPY, j__udyAllocJLL1); #endif #if (defined(JUDYL) && defined(JU_64BIT)) case cJU_JPIMMED_1_07: JU_IMMSETCASCADE(1, 7, uint8_t *, cJU_JPLEAF1, JL_LEAF1VALUEAREA, j__udySearchLeaf1, JU_INSERTCOPY, j__udyAllocJLL1); #endif #if (defined(JUDY1) && defined(JU_64BIT)) // Special case, as described above, go directly from Immed to LeafB1: case cJ1_JPIMMED_1_15: { Word_t DcdP0; int offset; Pjlb_t PjlbRaw; Pjlb_t Pjlb; offset = j__udySearchLeaf1((Pjll_t) Pjp->jp_1Index, 15, Index); JU_CHECK_IF_EXISTS(offset, ignore, Pjpm); // Create a bitmap leaf (special case for Judy1 64-bit only, see usage): Set // new Index in bitmap, copy an Immed1_15 to the bitmap, and set the parent JP // EXCEPT jp_DcdPopO, leaving any followup to the caller: if ((PjlbRaw = j__udyAllocJLB1(Pjpm)) == (Pjlb_t) NULL) return(-1); Pjlb = P_JLB(PjlbRaw); JU_BITMAPSETL(Pjlb, Index); for (offset = 0; offset < 15; ++offset) JU_BITMAPSETL(Pjlb, Pjp->jp_1Index[offset]); // Set jp_DcdPopO including the current pop0; incremented later: DcdP0 = (Index & cJU_DCDMASK(1)) + 15 - 1; JU_JPSETADT(Pjp, (Word_t)PjlbRaw, DcdP0, cJU_JPLEAF_B1); return(1); } #endif // cJU_JPIMMED_[2..7]_[02..15] cases that grow in place or cascade: // // (2_01 => [ 2_02 => 2_03 => [ 2_04..07 => ]] LeafL) #if (defined(JUDY1) || defined(JU_64BIT)) case cJU_JPIMMED_2_02: #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJU_JPIMMED_2_03: case cJ1_JPIMMED_2_04: case cJ1_JPIMMED_2_05: case cJ1_JPIMMED_2_06: #endif #if (defined(JUDY1) || defined(JU_64BIT)) JU_IMMSETINPLACE(2, uint16_t *, cJU_JPIMMED_2_02, j__udySearchLeaf2, JU_INSERTINPLACE); #endif #undef OLDPOP1 #if ((defined(JUDY1) && (! defined(JU_64BIT))) || (defined(JUDYL) && defined(JU_64BIT))) case cJU_JPIMMED_2_03: #define OLDPOP1 3 #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_2_07: #define OLDPOP1 7 #endif #if (defined(JUDY1) || defined(JU_64BIT)) JU_IMMSETCASCADE(2, OLDPOP1, uint16_t *, cJU_JPLEAF2, JL_LEAF2VALUEAREA, j__udySearchLeaf2, JU_INSERTCOPY, j__udyAllocJLL2); #endif // (3_01 => [ 3_02 => [ 3_03..05 => ]] LeafL) #if (defined(JUDY1) && defined(JU_64BIT)) case cJU_JPIMMED_3_02: case cJ1_JPIMMED_3_03: case cJ1_JPIMMED_3_04: JU_IMMSETINPLACE(3, uint8_t *, cJU_JPIMMED_3_02, j__udySearchLeaf3, JU_INSERTINPLACE3); #endif #undef OLDPOP1 #if ((defined(JUDY1) && (! defined(JU_64BIT))) || (defined(JUDYL) && defined(JU_64BIT))) case cJU_JPIMMED_3_02: #define OLDPOP1 2 #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_3_05: #define OLDPOP1 5 #endif #if (defined(JUDY1) || defined(JU_64BIT)) JU_IMMSETCASCADE(3, OLDPOP1, uint8_t *, cJU_JPLEAF3, JL_LEAF3VALUEAREA, j__udySearchLeaf3, JU_INSERTCOPY3, j__udyAllocJLL3); #endif #if (defined(JUDY1) && defined(JU_64BIT)) // (4_01 => [[ 4_02..03 => ]] LeafL) case cJ1_JPIMMED_4_02: JU_IMMSETINPLACE(4, uint32_t *, cJ1_JPIMMED_4_02, j__udySearchLeaf4, JU_INSERTINPLACE); case cJ1_JPIMMED_4_03: JU_IMMSETCASCADE(4, 3, uint32_t *, cJU_JPLEAF4, ignore, j__udySearchLeaf4, JU_INSERTCOPY, j__udyAllocJLL4); // (5_01 => [[ 5_02..03 => ]] LeafL) case cJ1_JPIMMED_5_02: JU_IMMSETINPLACE(5, uint8_t *, cJ1_JPIMMED_5_02, j__udySearchLeaf5, JU_INSERTINPLACE5); case cJ1_JPIMMED_5_03: JU_IMMSETCASCADE(5, 3, uint8_t *, cJU_JPLEAF5, ignore, j__udySearchLeaf5, JU_INSERTCOPY5, j__udyAllocJLL5); // (6_01 => [[ 6_02 => ]] LeafL) case cJ1_JPIMMED_6_02: JU_IMMSETCASCADE(6, 2, uint8_t *, cJU_JPLEAF6, ignore, j__udySearchLeaf6, JU_INSERTCOPY6, j__udyAllocJLL6); // (7_01 => [[ 7_02 => ]] LeafL) case cJ1_JPIMMED_7_02: JU_IMMSETCASCADE(7, 2, uint8_t *, cJU_JPLEAF7, ignore, j__udySearchLeaf7, JU_INSERTCOPY7, j__udyAllocJLL7); #endif // (JUDY1 && JU_64BIT) // **************************************************************************** // INVALID JP TYPE: default: JU_SET_ERRNO_NONNULL(Pjpm, JU_ERRNO_CORRUPT); return(-1); } // switch on JP type { #ifdef SUBEXPCOUNTS // This code might seem strange here. However it saves some memory read time // during insert (~70nS) because a pipelined processor does not need to "stall" // waiting for the memory read to complete. Hope the compiler is not too smart // or dumb and moves the code down to where it looks like it belongs (below a // few lines). Word_t SubExpCount = 0; // current subexpanse counter. if (PSubExp != (PWord_t) NULL) // only if BranchB/U. SubExpCount = PSubExp[0]; #endif // PROCESS JP -- RECURSIVELY: // // For non-Immed JP types, if successful, post-increment the population count // at this Level. retcode = j__udyInsWalk(Pjp, Index, Pjpm); // Successful insert, increment JP and subexpanse count: if ((JU_JPTYPE(Pjp) < cJU_JPIMMED_1_01) && (retcode == 1)) { jp_t JP; Word_t DcdP0; #ifdef SUBEXPCOUNTS // Note: Pjp must be a pointer to a BranchB/U: if (PSubExp != (PWord_t) NULL) PSubExp[0] = SubExpCount + 1; #endif JP = *Pjp; DcdP0 = JU_JPDCDPOP0(Pjp) + 1; JU_JPSETADT(Pjp, JP.jp_Addr, DcdP0, JU_JPTYPE(&JP)); } } return(retcode); } // j__udyInsWalk() // **************************************************************************** // J U D Y 1 S E T // J U D Y L I N S // // Main entry point. See the manual entry for details. #ifdef JUDY1 FUNCTION int Judy1Set #else FUNCTION PPvoid_t JudyLIns #endif ( PPvoid_t PPArray, // in which to insert. Word_t Index, // to insert. PJError_t PJError // optional, for returning error info. ) { #ifdef JUDY1 #define Pjv ignore // placeholders for macros. #define Pjvnew ignore #else Pjv_t Pjv; // value area in old leaf. Pjv_t Pjvnew; // value area in new leaf. #endif Pjpm_t Pjpm; // array-global info. int offset; // position in which to store new Index. Pjlw_t Pjlw; // CHECK FOR NULL POINTER (error by caller): if (PPArray == (PPvoid_t) NULL) { JU_SET_ERRNO(PJError, JU_ERRNO_NULLPPARRAY); JUDY1CODE(return(JERRI );) JUDYLCODE(return(PPJERR);) } Pjlw = P_JLW(*PPArray); // first word of leaf. // **************************************************************************** // PROCESS TOP LEVEL "JRP" BRANCHES AND LEAVES: // **************************************************************************** // JRPNULL (EMPTY ARRAY): BUILD A LEAFW WITH ONE INDEX: // if a valid empty array (null pointer), so create an array of population == 1: if (Pjlw == (Pjlw_t)NULL) { Pjlw_t Pjlwnew; Pjlwnew = j__udyAllocJLW(1); JUDY1CODE(JU_CHECKALLOC(Pjlw_t, Pjlwnew, JERRI );) JUDYLCODE(JU_CHECKALLOC(Pjlw_t, Pjlwnew, PPJERR);) Pjlwnew[0] = 1 - 1; // pop0 = 0. Pjlwnew[1] = Index; *PPArray = (Pvoid_t) Pjlwnew; DBGCODE(JudyCheckPop(*PPArray);) JUDY1CODE(return(1); ) JUDYLCODE(Pjlwnew[2] = 0; ) // value area. JUDYLCODE(return((PPvoid_t) (Pjlwnew + 2)); ) } // NULL JRP // **************************************************************************** // LEAFW, OTHER SIZE: if (JU_LEAFW_POP0(*PPArray) < cJU_LEAFW_MAXPOP1) // must be a LEAFW { Pjlw_t Pjlwnew; Word_t pop1; Pjlw = P_JLW(*PPArray); // first word of leaf. pop1 = Pjlw[0] + 1; #ifdef JUDYL Pjv = JL_LEAFWVALUEAREA(Pjlw, pop1); #endif offset = j__udySearchLeafW(Pjlw + 1, pop1, Index); if (offset >= 0) // index is already valid: { DBGCODE(JudyCheckPop(*PPArray);) JUDY1CODE(return(0); ) JUDYLCODE(return((PPvoid_t) (Pjv + offset)); ) } offset = ~offset; // Insert index in cases where no new memory is needed: if (JU_LEAFWGROWINPLACE(pop1)) { ++Pjlw[0]; // increase population. JU_INSERTINPLACE(Pjlw + 1, pop1, offset, Index); #ifdef JUDYL JU_INSERTINPLACE(Pjv, pop1, offset, 0); #endif DBGCODE(JudyCheckPop(*PPArray);) DBGCODE(JudyCheckSorted(Pjlw + 1, pop1 + 1, cJU_ROOTSTATE);) JUDY1CODE(return(1); ) JUDYLCODE(return((PPvoid_t) (Pjv + offset)); ) } // Insert index into a new, larger leaf: if (pop1 < cJU_LEAFW_MAXPOP1) // can grow to a larger leaf. { Pjlwnew = j__udyAllocJLW(pop1 + 1); JUDY1CODE(JU_CHECKALLOC(Pjlw_t, Pjlwnew, JERRI );) JUDYLCODE(JU_CHECKALLOC(Pjlw_t, Pjlwnew, PPJERR);) Pjlwnew[0] = pop1; // set pop0 in new leaf. JU_INSERTCOPY(Pjlwnew + 1, Pjlw + 1, pop1, offset, Index); #ifdef JUDYL Pjvnew = JL_LEAFWVALUEAREA(Pjlwnew, pop1 + 1); JU_INSERTCOPY(Pjvnew, Pjv, pop1, offset, 0); #endif DBGCODE(JudyCheckSorted(Pjlwnew + 1, pop1 + 1, cJU_ROOTSTATE);) j__udyFreeJLW(Pjlw, pop1, NULL); *PPArray = (Pvoid_t) Pjlwnew; DBGCODE(JudyCheckPop(*PPArray);) JUDY1CODE(return(1); ) JUDYLCODE(return((PPvoid_t) (Pjvnew + offset)); ) } assert(pop1 == cJU_LEAFW_MAXPOP1); // Leaf at max size => cannot insert new index, so cascade instead: // // Upon cascading from a LEAFW leaf to the first branch, must allocate and // initialize a JPM. Pjpm = j__udyAllocJPM(); JUDY1CODE(JU_CHECKALLOC(Pjpm_t, Pjpm, JERRI );) JUDYLCODE(JU_CHECKALLOC(Pjpm_t, Pjpm, PPJERR);) (Pjpm->jpm_Pop0) = cJU_LEAFW_MAXPOP1 - 1; (Pjpm->jpm_JP.jp_Addr) = (Word_t) Pjlw; if (j__udyCascadeL(&(Pjpm->jpm_JP), Pjpm) == -1) { JU_COPY_ERRNO(PJError, Pjpm); JUDY1CODE(return(JERRI );) JUDYLCODE(return(PPJERR);) } // Note: No need to pass Pjpm for memory decrement; LEAFW memory is never // counted in a JPM at all: j__udyFreeJLW(Pjlw, cJU_LEAFW_MAXPOP1, NULL); *PPArray = (Pvoid_t) Pjpm; } // JU_LEAFW // **************************************************************************** // BRANCH: { int retcode; // really only needed for Judy1, but free for JudyL. Pjpm = P_JPM(*PPArray); retcode = j__udyInsWalk(&(Pjpm->jpm_JP), Index, Pjpm); if (retcode == -1) { JU_COPY_ERRNO(PJError, Pjpm); JUDY1CODE(return(JERRI );) JUDYLCODE(return(PPJERR);) } if (retcode == 1) ++(Pjpm->jpm_Pop0); // incr total array popu. assert(((Pjpm->jpm_JP.jp_Type) == cJU_JPBRANCH_L) || ((Pjpm->jpm_JP.jp_Type) == cJU_JPBRANCH_B) || ((Pjpm->jpm_JP.jp_Type) == cJU_JPBRANCH_U)); DBGCODE(JudyCheckPop(*PPArray);) #ifdef JUDY1 assert((retcode == 0) || (retcode == 1)); return(retcode); // == JU_RET_*_JPM(). #else assert(Pjpm->jpm_PValue != (Pjv_t) NULL); return((PPvoid_t) Pjpm->jpm_PValue); #endif } /*NOTREACHED*/ } // Judy1Set() / JudyLIns() judy-1.0.5/src/JudyCommon/JudyPrevNextEmpty.c0000644000175000017500000013604410204462077021373 0ustar troyhebetroyhebe// Copyright (C) 2000 - 2002 Hewlett-Packard Company // // This program is free software; you can redistribute it and/or modify it // under the term of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License // for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program; if not, write to the Free Software Foundation, // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // _________________ // @(#) $Revision: 4.32 $ $Source: /judy/src/JudyCommon/JudyPrevNextEmpty.c $ // // Judy*PrevEmpty() and Judy*NextEmpty() functions for Judy1 and JudyL. // Compile with one of -DJUDY1 or -DJUDYL. // // Compile with -DJUDYNEXT for the Judy*NextEmpty() function; otherwise // defaults to Judy*PrevEmpty(). // // Compile with -DTRACEJPSE to trace JP traversals. // // This file is separate from JudyPrevNext.c because it differs too greatly for // ifdefs. This might be a bit surprising, but there are two reasons: // // - First, down in the details, searching for an empty index (SearchEmpty) is // remarkably asymmetric with searching for a valid index (SearchValid), // mainly with respect to: No return of a value area for JudyL; partially- // full versus totally-full JPs; and handling of narrow pointers. // // - Second, we chose to implement SearchEmpty without a backtrack stack or // backtrack engine, partly as an experiment, and partly because we think // restarting from the top of the tree is less likely for SearchEmpty than // for SearchValid, because empty indexes are more likely than valid indexes. // // A word about naming: A prior version of this feature (see 4.13) was named // Judy*Free(), but there were concerns about that being read as a verb rather // than an adjective. After prolonged debate and based on user input, we // changed "Free" to "Empty". #if (! (defined(JUDY1) || defined(JUDYL))) #error: One of -DJUDY1 or -DJUDYL must be specified. #endif #ifndef JUDYNEXT #ifndef JUDYPREV #define JUDYPREV 1 // neither set => use default. #endif #endif #ifdef JUDY1 #include "Judy1.h" #else #include "JudyL.h" #endif #include "JudyPrivate1L.h" #ifdef TRACEJPSE #include "JudyPrintJP.c" #endif // **************************************************************************** // J U D Y 1 P R E V E M P T Y // J U D Y 1 N E X T E M P T Y // J U D Y L P R E V E M P T Y // J U D Y L N E X T E M P T Y // // See the manual entry for the API. // // OVERVIEW OF Judy*PrevEmpty() / Judy*NextEmpty(): // // See also for comparison the equivalent comments in JudyPrevNext.c. // // Take the callers *PIndex and subtract/add 1, but watch out for // underflow/overflow, which means "no previous/next empty index found." Use a // reentrant switch statement (state machine, see SMGetRestart and // SMGetContinue) to decode Index, starting with the JRP (PArray), through a // JPM and branches, if any, down to an immediate or a leaf. Look for Index in // that immediate or leaf, and if not found (invalid index), return success // (Index is empty). // // This search can result in a dead end where taking a different path is // required. There are four kinds of dead ends: // // BRANCH PRIMARY dead end: Encountering a fully-populated JP for the // appropriate digit in Index. Search sideways in the branch for the // previous/next absent/null/non-full JP, and if one is found, set Index to the // highest/lowest index possible in that JPs expanse. Then if the JP is an // absent or null JP, return success; otherwise for a non-full JP, traverse // through the partially populated JP. // // BRANCH SECONDARY dead end: Reaching the end of a branch during a sideways // search after a branch primary dead end. Set Index to the lowest/highest // index possible in the whole branchs expanse (one higher/lower than the // previous/next branchs expanse), then restart at the top of the tree, which // includes pre-decrementing/incrementing Index (again) and watching for // underflow/overflow (again). // // LEAF PRIMARY dead end: Finding a valid (non-empty) index in an immediate or // leaf matching Index. Search sideways in the immediate/leaf for the // previous/next empty index; if found, set *PIndex to match and return success. // // LEAF SECONDARY dead end: Reaching the end of an immediate or leaf during a // sideways search after a leaf primary dead end. Just as for a branch // secondary dead end, restart at the top of the tree with Index set to the // lowest/highest index possible in the whole immediate/leafs expanse. // TBD: If leaf secondary dead end occurs, could shortcut and treat it as a // branch primary dead end; but this would require remembering the parent // branchs type and offset (a "one-deep stack"), and also wrestling with // narrow pointers, at least for leaves (but not for immediates). // // Note some ASYMMETRIES between SearchValid and SearchEmpty: // // - The SearchValid code, upon descending through a narrow pointer, if Index // is outside the expanse of the subsidiary node (effectively a secondary // dead end), must decide whether to backtrack or findlimit. But the // SearchEmpty code simply returns success (Index is empty). // // - Similarly, the SearchValid code, upon finding no previous/next index in // the expanse of a narrow pointer (again, a secondary dead end), can simply // start to backtrack at the parent JP. But the SearchEmpty code would have // to first determine whether or not the parent JPs narrow expanse contains // a previous/next empty index outside the subexpanse. Rather than keeping a // parent state stack and backtracking this way, upon a secondary dead end, // the SearchEmpty code simply restarts at the top of the tree, whether or // not a narrow pointer is involved. Again, see the equivalent comments in // JudyPrevNext.c for comparison. // // This function is written iteratively for speed, rather than recursively. // // TBD: Wed like to enhance this function to make successive searches faster. // This would require saving some previous state, including the previous Index // returned, and in which leaf it was found. If the next call is for the same // Index and the array has not been modified, start at the same leaf. This // should be much easier to implement since this is iterative rather than // recursive code. #ifdef JUDY1 #ifdef JUDYPREV FUNCTION int Judy1PrevEmpty #else FUNCTION int Judy1NextEmpty #endif #else #ifdef JUDYPREV FUNCTION int JudyLPrevEmpty #else FUNCTION int JudyLNextEmpty #endif #endif ( Pcvoid_t PArray, // Judy array to search. Word_t * PIndex, // starting point and result. PJError_t PJError // optional, for returning error info. ) { Word_t Index; // fast copy, in a register. Pjp_t Pjp; // current JP. Pjbl_t Pjbl; // Pjp->jp_Addr masked and cast to types: Pjbb_t Pjbb; Pjbu_t Pjbu; Pjlb_t Pjlb; PWord_t Pword; // alternate name for use by GET* macros. Word_t digit; // next digit to decode from Index. Word_t digits; // current state in SM = digits left to decode. Word_t pop0; // in a leaf. Word_t pop0mask; // precalculated to avoid variable shifts. long offset; // within a branch or leaf (can be large). int subexp; // subexpanse in a bitmap branch. BITMAPB_t bitposmaskB; // bit in bitmap for bitmap branch. BITMAPL_t bitposmaskL; // bit in bitmap for bitmap leaf. Word_t possfullJP1; // JP types for possibly full subexpanses: Word_t possfullJP2; Word_t possfullJP3; // ---------------------------------------------------------------------------- // M A C R O S // // These are intended to make the code a bit more readable and less redundant. // CHECK FOR NULL JP: // // TBD: In principle this can be reduced (here and in other *.c files) to just // the latter clause since no Type should ever be below cJU_JPNULL1, but in // fact some root pointer types can be lower, so for safety do both checks. #define JPNULL(Type) (((Type) >= cJU_JPNULL1) && ((Type) <= cJU_JPNULLMAX)) // CHECK FOR A FULL JP: // // Given a JP, indicate if it is fully populated. Use digits, pop0mask, and // possfullJP1..3 in the context. // // This is a difficult problem because it requires checking the Pop0 bits for // all-ones, but the number of bytes depends on the JP type, which is not // directly related to the parent branchs type or level -- the JPs child // could be under a narrow pointer (hence not full). The simple answer // requires switching on or otherwise calculating the JP type, which could be // slow. Instead, in SMPREPB* precalculate pop0mask and also record in // possfullJP1..3 the child JP (branch) types that could possibly be full (one // level down), and use them here. For level-2 branches (with digits == 2), // the test for a full child depends on Judy1/JudyL. // // Note: This cannot be applied to the JP in a JPM because it doesnt have // enough pop0 digits. // // TBD: JPFULL_BRANCH diligently checks for BranchL or BranchB, where neither // of those can ever be full as it turns out. Could just check for a BranchU // at the right level. Also, pop0mask might be overkill, its not used much, // so perhaps just call cJU_POP0MASK(digits - 1) here? // // First, JPFULL_BRANCH checks for a full expanse for a JP whose child can be a // branch, that is, a JP in a branch at level 3 or higher: #define JPFULL_BRANCH(Pjp) \ ((((JU_JPDCDPOP0(Pjp) ^ cJU_ALLONES) & pop0mask) == 0) \ && ((JU_JPTYPE(Pjp) == possfullJP1) \ || (JU_JPTYPE(Pjp) == possfullJP2) \ || (JU_JPTYPE(Pjp) == possfullJP3))) #ifdef JUDY1 #define JPFULL(Pjp) \ ((digits == 2) ? \ (JU_JPTYPE(Pjp) == cJ1_JPFULLPOPU1) : JPFULL_BRANCH(Pjp)) #else #define JPFULL(Pjp) \ ((digits == 2) ? \ (JU_JPTYPE(Pjp) == cJU_JPLEAF_B1) \ && (((JU_JPDCDPOP0(Pjp) & cJU_POP0MASK(1)) == cJU_POP0MASK(1))) : \ JPFULL_BRANCH(Pjp)) #endif // RETURN SUCCESS: // // This hides the need to set *PIndex back to the local value of Index -- use a // local value for faster operation. Note that the callers *PIndex is ALWAYS // modified upon success, at least decremented/incremented. #define RET_SUCCESS { *PIndex = Index; return(1); } // RETURN A CORRUPTION: #define RET_CORRUPT { JU_SET_ERRNO(PJError, JU_ERRNO_CORRUPT); return(JERRI); } // SEARCH A BITMAP BRANCH: // // This is a weak analog of j__udySearchLeaf*() for bitmap branches. Return // the actual or next-left position, base 0, of Digit in a BITMAPB_t bitmap // (subexpanse of a full bitmap), also given a Bitposmask for Digit. The // position is the offset within the set bits. // // Unlike j__udySearchLeaf*(), the offset is not returned bit-complemented if // Digits bit is unset, because the caller can check the bitmap themselves to // determine that. Also, if Digits bit is unset, the returned offset is to // the next-left JP or index (including -1), not to the "ideal" position for // the index = next-right JP or index. // // Shortcut and skip calling j__udyCountBitsB() if the bitmap is full, in which // case (Digit % cJU_BITSPERSUBEXPB) itself is the base-0 offset. #define SEARCHBITMAPB(Bitmap,Digit,Bitposmask) \ (((Bitmap) == cJU_FULLBITMAPB) ? (Digit % cJU_BITSPERSUBEXPB) : \ j__udyCountBitsB((Bitmap) & JU_MASKLOWERINC(Bitposmask)) - 1) #ifdef JUDYPREV // Equivalent to search for the highest offset in Bitmap, that is, one less // than the number of bits set: #define SEARCHBITMAPMAXB(Bitmap) \ (((Bitmap) == cJU_FULLBITMAPB) ? cJU_BITSPERSUBEXPB - 1 : \ j__udyCountBitsB(Bitmap) - 1) #endif // CHECK DECODE BYTES: // // Check Decode bytes in a JP against the equivalent portion of Index. If they // dont match, Index is outside the subexpanse of a narrow pointer, hence is // empty. #define CHECKDCD(cDigits) \ if (JU_DCDNOTMATCHINDEX(Index, Pjp, cDigits)) RET_SUCCESS // REVISE REMAINDER OF INDEX: // // Put one digit in place in Index and clear/set the lower digits, if any, so // the resulting Index is at the start/end of an expanse, or just clear/set the // least digits. // // Actually, to make simple use of JU_LEASTBYTESMASK, first clear/set all least // digits of Index including the digit to be overridden, then set the value of // that one digit. If Digits == 1 the first operation is redundant, but either // very fast or even removed by the optimizer. #define CLEARLEASTDIGITS(Digits) Index &= ~JU_LEASTBYTESMASK(Digits) #define SETLEASTDIGITS( Digits) Index |= JU_LEASTBYTESMASK(Digits) #define CLEARLEASTDIGITS_D(Digit,Digits) \ { \ CLEARLEASTDIGITS(Digits); \ JU_SETDIGIT(Index, Digit, Digits); \ } #define SETLEASTDIGITS_D(Digit,Digits) \ { \ SETLEASTDIGITS(Digits); \ JU_SETDIGIT(Index, Digit, Digits); \ } // SET REMAINDER OF INDEX AND THEN RETURN OR CONTINUE: #define SET_AND_RETURN(OpLeastDigits,Digit,Digits) \ { \ OpLeastDigits(Digit, Digits); \ RET_SUCCESS; \ } #define SET_AND_CONTINUE(OpLeastDigits,Digit,Digits) \ { \ OpLeastDigits(Digit, Digits); \ goto SMGetContinue; \ } // PREPARE TO HANDLE A LEAFW OR JP BRANCH IN THE STATE MACHINE: // // Extract a state-dependent digit from Index in a "constant" way, then jump to // common code for multiple cases. // // TBD: Should this macro do more, such as preparing variable-shift masks for // use in CLEARLEASTDIGITS and SETLEASTDIGITS? #define SMPREPB(cDigits,Next,PossFullJP1,PossFullJP2,PossFullJP3) \ digits = (cDigits); \ digit = JU_DIGITATSTATE(Index, cDigits); \ pop0mask = cJU_POP0MASK((cDigits) - 1); /* for branchs JPs */ \ possfullJP1 = (PossFullJP1); \ possfullJP2 = (PossFullJP2); \ possfullJP3 = (PossFullJP3); \ goto Next // Variations for specific-level branches and for shorthands: // // Note: SMPREPB2 need not initialize possfullJP* because JPFULL does not use // them for digits == 2, but gcc -Wall isnt quite smart enough to see this, so // waste a bit of time and space to get rid of the warning: #define SMPREPB2(Next) \ digits = 2; \ digit = JU_DIGITATSTATE(Index, 2); \ pop0mask = cJU_POP0MASK(1); /* for branchs JPs */ \ possfullJP1 = possfullJP2 = possfullJP3 = 0; \ goto Next #define SMPREPB3(Next) SMPREPB(3, Next, cJU_JPBRANCH_L2, \ cJU_JPBRANCH_B2, \ cJU_JPBRANCH_U2) #ifndef JU_64BIT #define SMPREPBL(Next) SMPREPB(cJU_ROOTSTATE, Next, cJU_JPBRANCH_L3, \ cJU_JPBRANCH_B3, \ cJU_JPBRANCH_U3) #else #define SMPREPB4(Next) SMPREPB(4, Next, cJU_JPBRANCH_L3, \ cJU_JPBRANCH_B3, \ cJU_JPBRANCH_U3) #define SMPREPB5(Next) SMPREPB(5, Next, cJU_JPBRANCH_L4, \ cJU_JPBRANCH_B4, \ cJU_JPBRANCH_U4) #define SMPREPB6(Next) SMPREPB(6, Next, cJU_JPBRANCH_L5, \ cJU_JPBRANCH_B5, \ cJU_JPBRANCH_U5) #define SMPREPB7(Next) SMPREPB(7, Next, cJU_JPBRANCH_L6, \ cJU_JPBRANCH_B6, \ cJU_JPBRANCH_U6) #define SMPREPBL(Next) SMPREPB(cJU_ROOTSTATE, Next, cJU_JPBRANCH_L7, \ cJU_JPBRANCH_B7, \ cJU_JPBRANCH_U7) #endif // RESTART AFTER SECONDARY DEAD END: // // Set Index to the first/last index in the branch or leaf subexpanse and start // over at the top of the tree. #ifdef JUDYPREV #define SMRESTART(Digits) { CLEARLEASTDIGITS(Digits); goto SMGetRestart; } #else #define SMRESTART(Digits) { SETLEASTDIGITS( Digits); goto SMGetRestart; } #endif // CHECK EDGE OF LEAFS EXPANSE: // // Given the LSBs of the lowest/highest valid index in a leaf (or equivalently // in an immediate JP), the level (index size) of the leaf, and the full index // to return (as Index in the context) already set to the full index matching // the lowest/highest one, determine if there is an empty index in the leafs // expanse below/above the lowest/highest index, which is true if the // lowest/highest index is not at the "edge" of the leafs expanse based on its // LSBs. If so, return Index decremented/incremented; otherwise restart at the // top of the tree. // // Note: In many cases Index is already at the right spot and calling // SMRESTART instead of just going directly to SMGetRestart is a bit of // overkill. // // Note: Variable shift occurs if Digits is not a constant. #ifdef JUDYPREV #define LEAF_EDGE(MinIndex,Digits) \ { \ if (MinIndex) { --Index; RET_SUCCESS; } \ SMRESTART(Digits); \ } #else #define LEAF_EDGE(MaxIndex,Digits) \ { \ if ((MaxIndex) != JU_LEASTBYTES(cJU_ALLONES, Digits)) \ { ++Index; RET_SUCCESS; } \ SMRESTART(Digits); \ } #endif // Same as above except Index is not already set to match the lowest/highest // index, so do that before decrementing/incrementing it: #ifdef JUDYPREV #define LEAF_EDGE_SET(MinIndex,Digits) \ { \ if (MinIndex) \ { JU_SETDIGITS(Index, MinIndex, Digits); --Index; RET_SUCCESS; } \ SMRESTART(Digits); \ } #else #define LEAF_EDGE_SET(MaxIndex,Digits) \ { \ if ((MaxIndex) != JU_LEASTBYTES(cJU_ALLONES, Digits)) \ { JU_SETDIGITS(Index, MaxIndex, Digits); ++Index; RET_SUCCESS; } \ SMRESTART(Digits); \ } #endif // FIND A HOLE (EMPTY INDEX) IN AN IMMEDIATE OR LEAF: // // Given an index location in a leaf (or equivalently an immediate JP) known to // contain a usable hole (an empty index less/greater than Index), and the LSBs // of a minimum/maximum index to locate, find the previous/next empty index and // return it. // // Note: "Even" index sizes (1,2,4[,8] bytes) have corresponding native C // types; "odd" index sizes dont, but they are not represented here because // they are handled completely differently; see elsewhere. #ifdef JUDYPREV #define LEAF_HOLE_EVEN(cDigits,Pjll,IndexLSB) \ { \ while (*(Pjll) > (IndexLSB)) --(Pjll); /* too high */ \ if (*(Pjll) < (IndexLSB)) RET_SUCCESS /* Index is empty */ \ while (*(--(Pjll)) == --(IndexLSB)) /* null, find a hole */;\ JU_SETDIGITS(Index, IndexLSB, cDigits); \ RET_SUCCESS; \ } #else #define LEAF_HOLE_EVEN(cDigits,Pjll,IndexLSB) \ { \ while (*(Pjll) < (IndexLSB)) ++(Pjll); /* too low */ \ if (*(Pjll) > (IndexLSB)) RET_SUCCESS /* Index is empty */ \ while (*(++(Pjll)) == ++(IndexLSB)) /* null, find a hole */;\ JU_SETDIGITS(Index, IndexLSB, cDigits); \ RET_SUCCESS; \ } #endif // SEARCH FOR AN EMPTY INDEX IN AN IMMEDIATE OR LEAF: // // Given a pointer to the first index in a leaf (or equivalently an immediate // JP), the population of the leaf, and a first empty Index to find (inclusive, // as Index in the context), where Index is known to fall within the expanse of // the leaf to search, efficiently find the previous/next empty index in the // leaf, if any. For simplicity the following overview is stated in terms of // Judy*NextEmpty() only, but the same concepts apply symmetrically for // Judy*PrevEmpty(). Also, in each case the comparisons are for the LSBs of // Index and leaf indexes, according to the leafs level. // // 1. If Index is GREATER than the last (highest) index in the leaf // (maxindex), return success, Index is empty. (Remember, Index is known // to be in the leafs expanse.) // // 2. If Index is EQUAL to maxindex: If maxindex is not at the edge of the // leafs expanse, increment Index and return success, there is an empty // Index one higher than any in the leaf; otherwise restart with Index // reset to the upper edge of the leafs expanse. Note: This might cause // an extra cache line fill, but this is OK for repeatedly-called search // code, and it saves CPU time. // // 3. If Index is LESS than maxindex, check for "dense to end of leaf": // Subtract Index from maxindex, and back up that many slots in the leaf. // If the resulting offset is not before the start of the leaf then compare // the index at this offset (baseindex) with Index: // // 3a. If GREATER, the leaf must be corrupt, since indexes are sorted and // there are no duplicates. // // 3b. If EQUAL, the leaf is "dense" from Index to maxindex, meaning there is // no reason to search it. "Slide right" to the high end of the leaf // (modify Index to maxindex) and continue with step 2 above. // // 3c. If LESS, continue with step 4. // // 4. If the offset based on maxindex minus Index falls BEFORE the start of // the leaf, or if, per 3c above, baseindex is LESS than Index, the leaf is // guaranteed "not dense to the end" and a usable empty Index must exist. // This supports a more efficient search loop. Start at the FIRST index in // the leaf, or one BEYOND baseindex, respectively, and search the leaf as // follows, comparing each current index (currindex) with Index: // // 4a. If LESS, keep going to next index. Note: This is certain to terminate // because maxindex is known to be greater than Index, hence the loop can // be small and fast. // // 4b. If EQUAL, loop and increment Index until finding currindex greater than // Index, and return success with the modified Index. // // 4c. If GREATER, return success, Index (unmodified) is empty. // // Note: These are macros rather than functions for speed. #ifdef JUDYPREV #define JSLE_EVEN(Addr,Pop0,cDigits,LeafType) \ { \ LeafType * PjllLSB = (LeafType *) (Addr); \ LeafType IndexLSB = Index; /* auto-masking */ \ \ /* Index before or at start of leaf: */ \ \ if (*PjllLSB >= IndexLSB) /* no need to search */ \ { \ if (*PjllLSB > IndexLSB) RET_SUCCESS; /* Index empty */ \ LEAF_EDGE(*PjllLSB, cDigits); \ } \ \ /* Index in or after leaf: */ \ \ offset = IndexLSB - *PjllLSB; /* tentative offset */ \ if (offset <= (Pop0)) /* can check density */ \ { \ PjllLSB += offset; /* move to slot */ \ \ if (*PjllLSB <= IndexLSB) /* dense or corrupt */ \ { \ if (*PjllLSB == IndexLSB) /* dense, check edge */ \ LEAF_EDGE_SET(PjllLSB[-offset], cDigits); \ RET_CORRUPT; \ } \ --PjllLSB; /* not dense, start at previous */ \ } \ else PjllLSB = ((LeafType *) (Addr)) + (Pop0); /* start at max */ \ \ LEAF_HOLE_EVEN(cDigits, PjllLSB, IndexLSB); \ } // JSLE_ODD is completely different from JSLE_EVEN because its important to // minimize copying odd indexes to compare them (see 4.14). Furthermore, a // very complex version (4.17, but abandoned before fully debugged) that // avoided calling j__udySearchLeaf*() ran twice as fast as 4.14, but still // half as fast as SearchValid. Doug suggested that to minimize complexity and // share common code we should use j__udySearchLeaf*() for the initial search // to establish if Index is empty, which should be common. If Index is valid // in a leaf or immediate indexes, odds are good that an empty Index is nearby, // so for simplicity just use a *COPY* function to linearly search the // remainder. // // TBD: Pathological case? Average performance should be good, but worst-case // might suffer. When Search says the initial Index is valid, so a linear // copy-and-compare is begun, if the caller builds fairly large leaves with // dense clusters AND frequently does a SearchEmpty at one end of such a // cluster, performance wont be very good. Might a dense-check help? This // means checking offset against the index at offset, and then against the // first/last index in the leaf. We doubt the pathological case will appear // much in real applications because they will probably alternate SearchValid // and SearchEmpty calls. #define JSLE_ODD(cDigits,Pjll,Pop0,Search,Copy) \ { \ Word_t IndexLSB; /* least bytes only */ \ Word_t IndexFound; /* in leaf */ \ \ if ((offset = Search(Pjll, (Pop0) + 1, Index)) < 0) \ RET_SUCCESS; /* Index is empty */ \ \ IndexLSB = JU_LEASTBYTES(Index, cDigits); \ offset *= (cDigits); \ \ while ((offset -= (cDigits)) >= 0) \ { /* skip until empty or start */ \ Copy(IndexFound, ((uint8_t *) (Pjll)) + offset); \ if (IndexFound != (--IndexLSB)) /* found an empty */ \ { JU_SETDIGITS(Index, IndexLSB, cDigits); RET_SUCCESS; }\ } \ LEAF_EDGE_SET(IndexLSB, cDigits); \ } #else // JUDYNEXT #define JSLE_EVEN(Addr,Pop0,cDigits,LeafType) \ { \ LeafType * PjllLSB = ((LeafType *) (Addr)) + (Pop0); \ LeafType IndexLSB = Index; /* auto-masking */ \ \ /* Index at or after end of leaf: */ \ \ if (*PjllLSB <= IndexLSB) /* no need to search */ \ { \ if (*PjllLSB < IndexLSB) RET_SUCCESS; /* Index empty */\ LEAF_EDGE(*PjllLSB, cDigits); \ } \ \ /* Index before or in leaf: */ \ \ offset = *PjllLSB - IndexLSB; /* tentative offset */ \ if (offset <= (Pop0)) /* can check density */ \ { \ PjllLSB -= offset; /* move to slot */ \ \ if (*PjllLSB >= IndexLSB) /* dense or corrupt */ \ { \ if (*PjllLSB == IndexLSB) /* dense, check edge */ \ LEAF_EDGE_SET(PjllLSB[offset], cDigits); \ RET_CORRUPT; \ } \ ++PjllLSB; /* not dense, start at next */ \ } \ else PjllLSB = (LeafType *) (Addr); /* start at minimum */ \ \ LEAF_HOLE_EVEN(cDigits, PjllLSB, IndexLSB); \ } #define JSLE_ODD(cDigits,Pjll,Pop0,Search,Copy) \ { \ Word_t IndexLSB; /* least bytes only */ \ Word_t IndexFound; /* in leaf */ \ int offsetmax; /* in bytes */ \ \ if ((offset = Search(Pjll, (Pop0) + 1, Index)) < 0) \ RET_SUCCESS; /* Index is empty */ \ \ IndexLSB = JU_LEASTBYTES(Index, cDigits); \ offset *= (cDigits); \ offsetmax = (Pop0) * (cDigits); /* single multiply */ \ \ while ((offset += (cDigits)) <= offsetmax) \ { /* skip until empty or end */ \ Copy(IndexFound, ((uint8_t *) (Pjll)) + offset); \ if (IndexFound != (++IndexLSB)) /* found an empty */ \ { JU_SETDIGITS(Index, IndexLSB, cDigits); RET_SUCCESS; } \ } \ LEAF_EDGE_SET(IndexLSB, cDigits); \ } #endif // JUDYNEXT // Note: Immediate indexes never fill a single index group, so for odd index // sizes, save time by calling JSLE_ODD_IMM instead of JSLE_ODD. #define j__udySearchLeafEmpty1(Addr,Pop0) \ JSLE_EVEN(Addr, Pop0, 1, uint8_t) #define j__udySearchLeafEmpty2(Addr,Pop0) \ JSLE_EVEN(Addr, Pop0, 2, uint16_t) #define j__udySearchLeafEmpty3(Addr,Pop0) \ JSLE_ODD(3, Addr, Pop0, j__udySearchLeaf3, JU_COPY3_PINDEX_TO_LONG) #ifndef JU_64BIT #define j__udySearchLeafEmptyL(Addr,Pop0) \ JSLE_EVEN(Addr, Pop0, 4, Word_t) #else #define j__udySearchLeafEmpty4(Addr,Pop0) \ JSLE_EVEN(Addr, Pop0, 4, uint32_t) #define j__udySearchLeafEmpty5(Addr,Pop0) \ JSLE_ODD(5, Addr, Pop0, j__udySearchLeaf5, JU_COPY5_PINDEX_TO_LONG) #define j__udySearchLeafEmpty6(Addr,Pop0) \ JSLE_ODD(6, Addr, Pop0, j__udySearchLeaf6, JU_COPY6_PINDEX_TO_LONG) #define j__udySearchLeafEmpty7(Addr,Pop0) \ JSLE_ODD(7, Addr, Pop0, j__udySearchLeaf7, JU_COPY7_PINDEX_TO_LONG) #define j__udySearchLeafEmptyL(Addr,Pop0) \ JSLE_EVEN(Addr, Pop0, 8, Word_t) #endif // JU_64BIT // ---------------------------------------------------------------------------- // START OF CODE: // // CHECK FOR SHORTCUTS: // // Error out if PIndex is null. if (PIndex == (PWord_t) NULL) { JU_SET_ERRNO(PJError, JU_ERRNO_NULLPINDEX); return(JERRI); } Index = *PIndex; // fast local copy. // Set and pre-decrement/increment Index, watching for underflow/overflow: // // An out-of-bounds Index means failure: No previous/next empty index. SMGetRestart: // return here with revised Index. #ifdef JUDYPREV if (Index-- == 0) return(0); #else if (++Index == 0) return(0); #endif // An empty array with an in-bounds (not underflowed/overflowed) Index means // success: // // Note: This check is redundant after restarting at SMGetRestart, but should // take insignificant time. if (PArray == (Pvoid_t) NULL) RET_SUCCESS; // ---------------------------------------------------------------------------- // ROOT-LEVEL LEAF that starts with a Pop0 word; just look within the leaf: // // If Index is not in the leaf, return success; otherwise return the first // empty Index, if any, below/above where it would belong. if (JU_LEAFW_POP0(PArray) < cJU_LEAFW_MAXPOP1) // must be a LEAFW { Pjlw_t Pjlw = P_JLW(PArray); // first word of leaf. pop0 = Pjlw[0]; #ifdef JUDY1 if (pop0 == 0) // special case. { #ifdef JUDYPREV if ((Index != Pjlw[1]) || (Index-- != 0)) RET_SUCCESS; #else if ((Index != Pjlw[1]) || (++Index != 0)) RET_SUCCESS; #endif return(0); // no previous/next empty index. } #endif // JUDY1 j__udySearchLeafEmptyL(Pjlw + 1, pop0); // No return -- thanks ALAN } else // ---------------------------------------------------------------------------- // HANDLE JRP Branch: // // For JRP branches, traverse the JPM; handle LEAFW // directly; but look for the most common cases first. { Pjpm_t Pjpm = P_JPM(PArray); Pjp = &(Pjpm->jpm_JP); // goto SMGetContinue; } // ============================================================================ // STATE MACHINE -- GET INDEX: // // Search for Index (already decremented/incremented so as to be an inclusive // search). If not found (empty index), return success. Otherwise do a // previous/next search, and if successful modify Index to the empty index // found. See function header comments. // // ENTRY: Pjp points to next JP to interpret, whose Decode bytes have not yet // been checked. // // Note: Check Decode bytes at the start of each loop, not after looking up a // new JP, so its easy to do constant shifts/masks. // // EXIT: Return, or branch to SMGetRestart with modified Index, or branch to // SMGetContinue with a modified Pjp, as described elsewhere. // // WARNING: For run-time efficiency the following cases replicate code with // varying constants, rather than using common code with variable values! SMGetContinue: // return here for next branch/leaf. #ifdef TRACEJPSE JudyPrintJP(Pjp, "sf", __LINE__); #endif switch (JU_JPTYPE(Pjp)) { // ---------------------------------------------------------------------------- // LINEAR BRANCH: // // Check Decode bytes, if any, in the current JP, then search for a JP for the // next digit in Index. case cJU_JPBRANCH_L2: CHECKDCD(2); SMPREPB2(SMBranchL); case cJU_JPBRANCH_L3: CHECKDCD(3); SMPREPB3(SMBranchL); #ifdef JU_64BIT case cJU_JPBRANCH_L4: CHECKDCD(4); SMPREPB4(SMBranchL); case cJU_JPBRANCH_L5: CHECKDCD(5); SMPREPB5(SMBranchL); case cJU_JPBRANCH_L6: CHECKDCD(6); SMPREPB6(SMBranchL); case cJU_JPBRANCH_L7: CHECKDCD(7); SMPREPB7(SMBranchL); #endif case cJU_JPBRANCH_L: SMPREPBL(SMBranchL); // Common code (state-independent) for all cases of linear branches: SMBranchL: Pjbl = P_JBL(Pjp->jp_Addr); // First, check if Indexs expanse (digit) is below/above the first/last // populated expanse in the BranchL, in which case Index is empty; otherwise // find the offset of the lowest/highest populated expanse at or above/below // digit, if any: // // Note: The for-loop is guaranteed to exit eventually because the first/last // expanse is known to be a terminator. // // Note: Cannot use j__udySearchLeaf*Empty1() here because it only applies to // leaves and does not know about partial versus full JPs, unlike the use of // j__udySearchLeaf1() for BranchLs in SearchValid code. Also, since linear // leaf expanse lists are small, dont waste time calling j__udySearchLeaf1(), // just scan the expanse list. #ifdef JUDYPREV if ((Pjbl->jbl_Expanse[0]) > digit) RET_SUCCESS; for (offset = (Pjbl->jbl_NumJPs) - 1; /* null */; --offset) #else if ((Pjbl->jbl_Expanse[(Pjbl->jbl_NumJPs) - 1]) < digit) RET_SUCCESS; for (offset = 0; /* null */; ++offset) #endif { // Too low/high, keep going; or too high/low, meaning the loop passed a hole // and the initial Index is empty: #ifdef JUDYPREV if ((Pjbl->jbl_Expanse[offset]) > digit) continue; if ((Pjbl->jbl_Expanse[offset]) < digit) RET_SUCCESS; #else if ((Pjbl->jbl_Expanse[offset]) < digit) continue; if ((Pjbl->jbl_Expanse[offset]) > digit) RET_SUCCESS; #endif // Found expanse matching digit; if its not full, traverse through it: if (! JPFULL((Pjbl->jbl_jp) + offset)) { Pjp = (Pjbl->jbl_jp) + offset; goto SMGetContinue; } // Common code: While searching for a lower/higher hole or a non-full JP, upon // finding a lower/higher hole, adjust Index using the revised digit and // return; or upon finding a consecutive lower/higher expanse, if the expanses // JP is non-full, modify Index and traverse through the JP: #define BRANCHL_CHECK(OpIncDec,OpLeastDigits,Digit,Digits) \ { \ if ((Pjbl->jbl_Expanse[offset]) != OpIncDec digit) \ SET_AND_RETURN(OpLeastDigits, Digit, Digits); \ \ if (! JPFULL((Pjbl->jbl_jp) + offset)) \ { \ Pjp = (Pjbl->jbl_jp) + offset; \ SET_AND_CONTINUE(OpLeastDigits, Digit, Digits); \ } \ } // BranchL primary dead end: Expanse matching Index/digit is full (rare except // for dense/sequential indexes): // // Search for a lower/higher hole, a non-full JP, or the end of the expanse // list, while decrementing/incrementing digit. #ifdef JUDYPREV while (--offset >= 0) BRANCHL_CHECK(--, SETLEASTDIGITS_D, digit, digits) #else while (++offset < Pjbl->jbl_NumJPs) BRANCHL_CHECK(++, CLEARLEASTDIGITS_D, digit, digits) #endif // Passed end of BranchL expanse list after finding a matching but full // expanse: // // Digit now matches the lowest/highest expanse, which is a full expanse; if // digit is at the end of BranchLs expanse (no hole before/after), break out // of the loop; otherwise modify Index to the next lower/higher digit and // return success: #ifdef JUDYPREV if (digit == 0) break; --digit; SET_AND_RETURN(SETLEASTDIGITS_D, digit, digits); #else if (digit == JU_LEASTBYTES(cJU_ALLONES, 1)) break; ++digit; SET_AND_RETURN(CLEARLEASTDIGITS_D, digit, digits); #endif } // for-loop // BranchL secondary dead end, no non-full previous/next JP: SMRESTART(digits); // ---------------------------------------------------------------------------- // BITMAP BRANCH: // // Check Decode bytes, if any, in the current JP, then search for a JP for the // next digit in Index. case cJU_JPBRANCH_B2: CHECKDCD(2); SMPREPB2(SMBranchB); case cJU_JPBRANCH_B3: CHECKDCD(3); SMPREPB3(SMBranchB); #ifdef JU_64BIT case cJU_JPBRANCH_B4: CHECKDCD(4); SMPREPB4(SMBranchB); case cJU_JPBRANCH_B5: CHECKDCD(5); SMPREPB5(SMBranchB); case cJU_JPBRANCH_B6: CHECKDCD(6); SMPREPB6(SMBranchB); case cJU_JPBRANCH_B7: CHECKDCD(7); SMPREPB7(SMBranchB); #endif case cJU_JPBRANCH_B: SMPREPBL(SMBranchB); // Common code (state-independent) for all cases of bitmap branches: SMBranchB: Pjbb = P_JBB(Pjp->jp_Addr); // Locate the digits JP in the subexpanse list, if present: subexp = digit / cJU_BITSPERSUBEXPB; assert(subexp < cJU_NUMSUBEXPB); // falls in expected range. bitposmaskB = JU_BITPOSMASKB(digit); // Absent JP = no JP matches current digit in Index: // if (! JU_BITMAPTESTB(Pjbb, digit)) // slower. if (! (JU_JBB_BITMAP(Pjbb, subexp) & bitposmaskB)) // faster. RET_SUCCESS; // Non-full JP matches current digit in Index: // // Iterate to the subsidiary non-full JP. offset = SEARCHBITMAPB(JU_JBB_BITMAP(Pjbb, subexp), digit, bitposmaskB); // not negative since at least one bit is set: assert(offset >= 0); assert(offset < (int) cJU_BITSPERSUBEXPB); // Watch for null JP subarray pointer with non-null bitmap (a corruption): if ((Pjp = P_JP(JU_JBB_PJP(Pjbb, subexp))) == (Pjp_t) NULL) RET_CORRUPT; Pjp += offset; if (! JPFULL(Pjp)) goto SMGetContinue; // BranchB primary dead end: // // Upon hitting a full JP in a BranchB for the next digit in Index, search // sideways for a previous/next absent JP (unset bit) or non-full JP (set bit // with non-full JP); first in the current bitmap subexpanse, then in // lower/higher subexpanses. Upon entry, Pjp points to a known-unusable JP, // ready to decrement/increment. // // Note: The preceding code is separate from this loop because Index does not // need revising (see SET_AND_*()) if the initial index is an empty index. // // TBD: For speed, shift bitposmaskB instead of using JU_BITMAPTESTB or // JU_BITPOSMASKB, but this shift has knowledge of bit order that really should // be encapsulated in a header file. #define BRANCHB_CHECKBIT(OpLeastDigits) \ if (! (JU_JBB_BITMAP(Pjbb, subexp) & bitposmaskB)) /* absent JP */ \ SET_AND_RETURN(OpLeastDigits, digit, digits) #define BRANCHB_CHECKJPFULL(OpLeastDigits) \ if (! JPFULL(Pjp)) \ SET_AND_CONTINUE(OpLeastDigits, digit, digits) #define BRANCHB_STARTSUBEXP(OpLeastDigits) \ if (! JU_JBB_BITMAP(Pjbb, subexp)) /* empty subexpanse, shortcut */ \ SET_AND_RETURN(OpLeastDigits, digit, digits) \ if ((Pjp = P_JP(JU_JBB_PJP(Pjbb, subexp))) == (Pjp_t) NULL) RET_CORRUPT #ifdef JUDYPREV --digit; // skip initial digit. bitposmaskB >>= 1; // see TBD above. BranchBNextSubexp: // return here to check next bitmap subexpanse. while (bitposmaskB) // more bits to check in subexp. { BRANCHB_CHECKBIT(SETLEASTDIGITS_D); --Pjp; // previous in subarray. BRANCHB_CHECKJPFULL(SETLEASTDIGITS_D); assert(digit >= 0); --digit; bitposmaskB >>= 1; } if (subexp-- > 0) // more subexpanses. { BRANCHB_STARTSUBEXP(SETLEASTDIGITS_D); Pjp += SEARCHBITMAPMAXB(JU_JBB_BITMAP(Pjbb, subexp)) + 1; bitposmaskB = (1U << (cJU_BITSPERSUBEXPB - 1)); goto BranchBNextSubexp; } #else // JUDYNEXT ++digit; // skip initial digit. bitposmaskB <<= 1; // note: BITMAPB_t. BranchBNextSubexp: // return here to check next bitmap subexpanse. while (bitposmaskB) // more bits to check in subexp. { BRANCHB_CHECKBIT(CLEARLEASTDIGITS_D); ++Pjp; // previous in subarray. BRANCHB_CHECKJPFULL(CLEARLEASTDIGITS_D); assert(digit < cJU_SUBEXPPERSTATE); ++digit; bitposmaskB <<= 1; // note: BITMAPB_t. } if (++subexp < cJU_NUMSUBEXPB) // more subexpanses. { BRANCHB_STARTSUBEXP(CLEARLEASTDIGITS_D); --Pjp; // pre-decrement. bitposmaskB = 1; goto BranchBNextSubexp; } #endif // JUDYNEXT // BranchB secondary dead end, no non-full previous/next JP: SMRESTART(digits); // ---------------------------------------------------------------------------- // UNCOMPRESSED BRANCH: // // Check Decode bytes, if any, in the current JP, then search for a JP for the // next digit in Index. case cJU_JPBRANCH_U2: CHECKDCD(2); SMPREPB2(SMBranchU); case cJU_JPBRANCH_U3: CHECKDCD(3); SMPREPB3(SMBranchU); #ifdef JU_64BIT case cJU_JPBRANCH_U4: CHECKDCD(4); SMPREPB4(SMBranchU); case cJU_JPBRANCH_U5: CHECKDCD(5); SMPREPB5(SMBranchU); case cJU_JPBRANCH_U6: CHECKDCD(6); SMPREPB6(SMBranchU); case cJU_JPBRANCH_U7: CHECKDCD(7); SMPREPB7(SMBranchU); #endif case cJU_JPBRANCH_U: SMPREPBL(SMBranchU); // Common code (state-independent) for all cases of uncompressed branches: SMBranchU: Pjbu = P_JBU(Pjp->jp_Addr); Pjp = (Pjbu->jbu_jp) + digit; // Absent JP = null JP for current digit in Index: if (JPNULL(JU_JPTYPE(Pjp))) RET_SUCCESS; // Non-full JP matches current digit in Index: // // Iterate to the subsidiary JP. if (! JPFULL(Pjp)) goto SMGetContinue; // BranchU primary dead end: // // Upon hitting a full JP in a BranchU for the next digit in Index, search // sideways for a previous/next null or non-full JP. BRANCHU_CHECKJP() is // shorthand for common code. // // Note: The preceding code is separate from this loop because Index does not // need revising (see SET_AND_*()) if the initial index is an empty index. #define BRANCHU_CHECKJP(OpIncDec,OpLeastDigits) \ { \ OpIncDec Pjp; \ \ if (JPNULL(JU_JPTYPE(Pjp))) \ SET_AND_RETURN(OpLeastDigits, digit, digits) \ \ if (! JPFULL(Pjp)) \ SET_AND_CONTINUE(OpLeastDigits, digit, digits) \ } #ifdef JUDYPREV while (digit-- > 0) BRANCHU_CHECKJP(--, SETLEASTDIGITS_D); #else while (++digit < cJU_BRANCHUNUMJPS) BRANCHU_CHECKJP(++, CLEARLEASTDIGITS_D); #endif // BranchU secondary dead end, no non-full previous/next JP: SMRESTART(digits); // ---------------------------------------------------------------------------- // LINEAR LEAF: // // Check Decode bytes, if any, in the current JP, then search the leaf for the // previous/next empty index starting at Index. Primary leaf dead end is // hidden within j__udySearchLeaf*Empty*(). In case of secondary leaf dead // end, restart at the top of the tree. // // Note: Pword is the name known to GET*; think of it as Pjlw. #define SMLEAFL(cDigits,Func) \ Pword = (PWord_t) P_JLW(Pjp->jp_Addr); \ pop0 = JU_JPLEAF_POP0(Pjp); \ Func(Pword, pop0) #if (defined(JUDYL) || (! defined(JU_64BIT))) case cJU_JPLEAF1: CHECKDCD(1); SMLEAFL(1, j__udySearchLeafEmpty1); #endif case cJU_JPLEAF2: CHECKDCD(2); SMLEAFL(2, j__udySearchLeafEmpty2); case cJU_JPLEAF3: CHECKDCD(3); SMLEAFL(3, j__udySearchLeafEmpty3); #ifdef JU_64BIT case cJU_JPLEAF4: CHECKDCD(4); SMLEAFL(4, j__udySearchLeafEmpty4); case cJU_JPLEAF5: CHECKDCD(5); SMLEAFL(5, j__udySearchLeafEmpty5); case cJU_JPLEAF6: CHECKDCD(6); SMLEAFL(6, j__udySearchLeafEmpty6); case cJU_JPLEAF7: CHECKDCD(7); SMLEAFL(7, j__udySearchLeafEmpty7); #endif // ---------------------------------------------------------------------------- // BITMAP LEAF: // // Check Decode bytes, if any, in the current JP, then search the leaf for the // previous/next empty index starting at Index. case cJU_JPLEAF_B1: CHECKDCD(1); Pjlb = P_JLB(Pjp->jp_Addr); digit = JU_DIGITATSTATE(Index, 1); subexp = digit / cJU_BITSPERSUBEXPL; bitposmaskL = JU_BITPOSMASKL(digit); assert(subexp < cJU_NUMSUBEXPL); // falls in expected range. // Absent index = no index matches current digit in Index: // if (! JU_BITMAPTESTL(Pjlb, digit)) // slower. if (! (JU_JLB_BITMAP(Pjlb, subexp) & bitposmaskL)) // faster. RET_SUCCESS; // LeafB1 primary dead end: // // Upon hitting a valid (non-empty) index in a LeafB1 for the last digit in // Index, search sideways for a previous/next absent index, first in the // current bitmap subexpanse, then in lower/higher subexpanses. // LEAFB1_CHECKBIT() is shorthand for common code to handle one bit in one // bitmap subexpanse. // // Note: The preceding code is separate from this loop because Index does not // need revising (see SET_AND_*()) if the initial index is an empty index. // // TBD: For speed, shift bitposmaskL instead of using JU_BITMAPTESTL or // JU_BITPOSMASKL, but this shift has knowledge of bit order that really should // be encapsulated in a header file. #define LEAFB1_CHECKBIT(OpLeastDigits) \ if (! (JU_JLB_BITMAP(Pjlb, subexp) & bitposmaskL)) \ SET_AND_RETURN(OpLeastDigits, digit, 1) #define LEAFB1_STARTSUBEXP(OpLeastDigits) \ if (! JU_JLB_BITMAP(Pjlb, subexp)) /* empty subexp */ \ SET_AND_RETURN(OpLeastDigits, digit, 1) #ifdef JUDYPREV --digit; // skip initial digit. bitposmaskL >>= 1; // see TBD above. LeafB1NextSubexp: // return here to check next bitmap subexpanse. while (bitposmaskL) // more bits to check in subexp. { LEAFB1_CHECKBIT(SETLEASTDIGITS_D); assert(digit >= 0); --digit; bitposmaskL >>= 1; } if (subexp-- > 0) // more subexpanses. { LEAFB1_STARTSUBEXP(SETLEASTDIGITS_D); bitposmaskL = (1UL << (cJU_BITSPERSUBEXPL - 1)); goto LeafB1NextSubexp; } #else // JUDYNEXT ++digit; // skip initial digit. bitposmaskL <<= 1; // note: BITMAPL_t. LeafB1NextSubexp: // return here to check next bitmap subexpanse. while (bitposmaskL) // more bits to check in subexp. { LEAFB1_CHECKBIT(CLEARLEASTDIGITS_D); assert(digit < cJU_SUBEXPPERSTATE); ++digit; bitposmaskL <<= 1; // note: BITMAPL_t. } if (++subexp < cJU_NUMSUBEXPL) // more subexpanses. { LEAFB1_STARTSUBEXP(CLEARLEASTDIGITS_D); bitposmaskL = 1; goto LeafB1NextSubexp; } #endif // JUDYNEXT // LeafB1 secondary dead end, no empty index: SMRESTART(1); #ifdef JUDY1 // ---------------------------------------------------------------------------- // FULL POPULATION: // // If the Decode bytes do not match, Index is empty (without modification); // otherwise restart. case cJ1_JPFULLPOPU1: CHECKDCD(1); SMRESTART(1); #endif // ---------------------------------------------------------------------------- // IMMEDIATE: // // Pop1 = 1 Immediate JPs: // // If Index is not in the immediate JP, return success; otherwise check if // there is an empty index below/above the immediate JPs index, and if so, // return success with modified Index, else restart. // // Note: Doug says its fast enough to calculate the index size (digits) in // the following; no need to set it separately for each case. case cJU_JPIMMED_1_01: case cJU_JPIMMED_2_01: case cJU_JPIMMED_3_01: #ifdef JU_64BIT case cJU_JPIMMED_4_01: case cJU_JPIMMED_5_01: case cJU_JPIMMED_6_01: case cJU_JPIMMED_7_01: #endif if (JU_JPDCDPOP0(Pjp) != JU_TRIMTODCDSIZE(Index)) RET_SUCCESS; digits = JU_JPTYPE(Pjp) - cJU_JPIMMED_1_01 + 1; LEAF_EDGE(JU_LEASTBYTES(JU_JPDCDPOP0(Pjp), digits), digits); // Immediate JPs with Pop1 > 1: #define IMM_MULTI(Func,BaseJPType) \ JUDY1CODE(Pword = (PWord_t) (Pjp->jp_1Index);) \ JUDYLCODE(Pword = (PWord_t) (Pjp->jp_LIndex);) \ Func(Pword, JU_JPTYPE(Pjp) - (BaseJPType) + 1) case cJU_JPIMMED_1_02: case cJU_JPIMMED_1_03: #if (defined(JUDY1) || defined(JU_64BIT)) case cJU_JPIMMED_1_04: case cJU_JPIMMED_1_05: case cJU_JPIMMED_1_06: case cJU_JPIMMED_1_07: #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_1_08: case cJ1_JPIMMED_1_09: case cJ1_JPIMMED_1_10: case cJ1_JPIMMED_1_11: case cJ1_JPIMMED_1_12: case cJ1_JPIMMED_1_13: case cJ1_JPIMMED_1_14: case cJ1_JPIMMED_1_15: #endif IMM_MULTI(j__udySearchLeafEmpty1, cJU_JPIMMED_1_02); #if (defined(JUDY1) || defined(JU_64BIT)) case cJU_JPIMMED_2_02: case cJU_JPIMMED_2_03: #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_2_04: case cJ1_JPIMMED_2_05: case cJ1_JPIMMED_2_06: case cJ1_JPIMMED_2_07: #endif #if (defined(JUDY1) || defined(JU_64BIT)) IMM_MULTI(j__udySearchLeafEmpty2, cJU_JPIMMED_2_02); #endif #if (defined(JUDY1) || defined(JU_64BIT)) case cJU_JPIMMED_3_02: #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_3_03: case cJ1_JPIMMED_3_04: case cJ1_JPIMMED_3_05: #endif #if (defined(JUDY1) || defined(JU_64BIT)) IMM_MULTI(j__udySearchLeafEmpty3, cJU_JPIMMED_3_02); #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_4_02: case cJ1_JPIMMED_4_03: IMM_MULTI(j__udySearchLeafEmpty4, cJ1_JPIMMED_4_02); case cJ1_JPIMMED_5_02: case cJ1_JPIMMED_5_03: IMM_MULTI(j__udySearchLeafEmpty5, cJ1_JPIMMED_5_02); case cJ1_JPIMMED_6_02: IMM_MULTI(j__udySearchLeafEmpty6, cJ1_JPIMMED_6_02); case cJ1_JPIMMED_7_02: IMM_MULTI(j__udySearchLeafEmpty7, cJ1_JPIMMED_7_02); #endif // ---------------------------------------------------------------------------- // INVALID JP TYPE: default: RET_CORRUPT; } // SMGet switch. } // Judy1PrevEmpty() / Judy1NextEmpty() / JudyLPrevEmpty() / JudyLNextEmpty() judy-1.0.5/src/JudyCommon/JudyDecascade.c0000644000175000017500000007710210204462077020434 0ustar troyhebetroyhebe// Copyright (C) 2000 - 2002 Hewlett-Packard Company // // This program is free software; you can redistribute it and/or modify it // under the term of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License // for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program; if not, write to the Free Software Foundation, // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // _________________ // @(#) $Revision: 4.25 $ $Source: /judy/src/JudyCommon/JudyDecascade.c $ // // "Decascade" support functions for JudyDel.c: These functions convert // smaller-index-size leaves to larger-index-size leaves, and also, bitmap // leaves (LeafB1s) to Leaf1s, and some types of branches to smaller branches // at the same index size. Some "decascading" occurs explicitly in JudyDel.c, // but rare or large subroutines appear as functions here, and the overhead to // call them is negligible. // // Compile with one of -DJUDY1 or -DJUDYL. Note: Function names are converted // to Judy1 or JudyL specific values by external #defines. #if (! (defined(JUDY1) || defined(JUDYL))) #error: One of -DJUDY1 or -DJUDYL must be specified. #endif #ifdef JUDY1 #include "Judy1.h" #endif #ifdef JUDYL #include "JudyL.h" #endif #include "JudyPrivate1L.h" DBGCODE(extern void JudyCheckSorted(Pjll_t Pjll, Word_t Pop1, long IndexSize);) // **************************************************************************** // __ J U D Y C O P Y 2 T O 3 // // Copy one or more 2-byte Indexes to a series of 3-byte Indexes. FUNCTION static void j__udyCopy2to3( uint8_t * PDest, // to where to copy 3-byte Indexes. uint16_t * PSrc, // from where to copy 2-byte indexes. Word_t Pop1, // number of Indexes to copy. Word_t MSByte) // most-significant byte, prefix to each Index. { Word_t Temp; // for building 3-byte Index. assert(Pop1); do { Temp = MSByte | *PSrc++; JU_COPY3_LONG_TO_PINDEX(PDest, Temp); PDest += 3; } while (--Pop1); } // j__udyCopy2to3() #ifdef JU_64BIT // **************************************************************************** // __ J U D Y C O P Y 3 T O 4 // // Copy one or more 3-byte Indexes to a series of 4-byte Indexes. FUNCTION static void j__udyCopy3to4( uint32_t * PDest, // to where to copy 4-byte Indexes. uint8_t * PSrc, // from where to copy 3-byte indexes. Word_t Pop1, // number of Indexes to copy. Word_t MSByte) // most-significant byte, prefix to each Index. { Word_t Temp; // for building 4-byte Index. assert(Pop1); do { JU_COPY3_PINDEX_TO_LONG(Temp, PSrc); Temp |= MSByte; PSrc += 3; *PDest++ = Temp; // truncates to uint32_t. } while (--Pop1); } // j__udyCopy3to4() // **************************************************************************** // __ J U D Y C O P Y 4 T O 5 // // Copy one or more 4-byte Indexes to a series of 5-byte Indexes. FUNCTION static void j__udyCopy4to5( uint8_t * PDest, // to where to copy 4-byte Indexes. uint32_t * PSrc, // from where to copy 4-byte indexes. Word_t Pop1, // number of Indexes to copy. Word_t MSByte) // most-significant byte, prefix to each Index. { Word_t Temp; // for building 5-byte Index. assert(Pop1); do { Temp = MSByte | *PSrc++; JU_COPY5_LONG_TO_PINDEX(PDest, Temp); PDest += 5; } while (--Pop1); } // j__udyCopy4to5() // **************************************************************************** // __ J U D Y C O P Y 5 T O 6 // // Copy one or more 5-byte Indexes to a series of 6-byte Indexes. FUNCTION static void j__udyCopy5to6( uint8_t * PDest, // to where to copy 6-byte Indexes. uint8_t * PSrc, // from where to copy 5-byte indexes. Word_t Pop1, // number of Indexes to copy. Word_t MSByte) // most-significant byte, prefix to each Index. { Word_t Temp; // for building 6-byte Index. assert(Pop1); do { JU_COPY5_PINDEX_TO_LONG(Temp, PSrc); Temp |= MSByte; JU_COPY6_LONG_TO_PINDEX(PDest, Temp); PSrc += 5; PDest += 6; } while (--Pop1); } // j__udyCopy5to6() // **************************************************************************** // __ J U D Y C O P Y 6 T O 7 // // Copy one or more 6-byte Indexes to a series of 7-byte Indexes. FUNCTION static void j__udyCopy6to7( uint8_t * PDest, // to where to copy 6-byte Indexes. uint8_t * PSrc, // from where to copy 5-byte indexes. Word_t Pop1, // number of Indexes to copy. Word_t MSByte) // most-significant byte, prefix to each Index. { Word_t Temp; // for building 6-byte Index. assert(Pop1); do { JU_COPY6_PINDEX_TO_LONG(Temp, PSrc); Temp |= MSByte; JU_COPY7_LONG_TO_PINDEX(PDest, Temp); PSrc += 6; PDest += 7; } while (--Pop1); } // j__udyCopy6to7() #endif // JU_64BIT #ifndef JU_64BIT // 32-bit // **************************************************************************** // __ J U D Y C O P Y 3 T O W // // Copy one or more 3-byte Indexes to a series of longs (words, always 4-byte). FUNCTION static void j__udyCopy3toW( PWord_t PDest, // to where to copy full-word Indexes. uint8_t * PSrc, // from where to copy 3-byte indexes. Word_t Pop1, // number of Indexes to copy. Word_t MSByte) // most-significant byte, prefix to each Index. { assert(Pop1); do { JU_COPY3_PINDEX_TO_LONG(*PDest, PSrc); *PDest++ |= MSByte; PSrc += 3; } while (--Pop1); } // j__udyCopy3toW() #else // JU_64BIT // **************************************************************************** // __ J U D Y C O P Y 7 T O W // // Copy one or more 7-byte Indexes to a series of longs (words, always 8-byte). FUNCTION static void j__udyCopy7toW( PWord_t PDest, // to where to copy full-word Indexes. uint8_t * PSrc, // from where to copy 7-byte indexes. Word_t Pop1, // number of Indexes to copy. Word_t MSByte) // most-significant byte, prefix to each Index. { assert(Pop1); do { JU_COPY7_PINDEX_TO_LONG(*PDest, PSrc); *PDest++ |= MSByte; PSrc += 7; } while (--Pop1); } // j__udyCopy7toW() #endif // JU_64BIT // **************************************************************************** // __ J U D Y B R A N C H B T O B R A N C H L // // When a BranchB shrinks to have few enough JPs, call this function to convert // it to a BranchL. Return 1 for success, or -1 for failure (with details in // Pjpm). FUNCTION int j__udyBranchBToBranchL( Pjp_t Pjp, // points to BranchB to shrink. Pvoid_t Pjpm) // for global accounting. { Pjbb_t PjbbRaw; // old BranchB to shrink. Pjbb_t Pjbb; Pjbl_t PjblRaw; // new BranchL to create. Pjbl_t Pjbl; Word_t Digit; // in BranchB. Word_t NumJPs; // non-null JPs in BranchB. uint8_t Expanse[cJU_BRANCHLMAXJPS]; // for building jbl_Expanse[]. Pjp_t Pjpjbl; // current JP in BranchL. Word_t SubExp; // in BranchB. assert(JU_JPTYPE(Pjp) >= cJU_JPBRANCH_B2); assert(JU_JPTYPE(Pjp) <= cJU_JPBRANCH_B); PjbbRaw = (Pjbb_t) (Pjp->jp_Addr); Pjbb = P_JBB(PjbbRaw); // Copy 1-byte subexpanse digits from BranchB to temporary buffer for BranchL, // for each bit set in the BranchB: // // TBD: The following supports variable-sized linear branches, but they are no // longer variable; this could be simplified to save the copying. // // TBD: Since cJU_BRANCHLMAXJP == 7 now, and cJU_BRANCHUNUMJPS == 256, the // following might be inefficient; is there a faster way to do it? At least // skip wholly empty subexpanses? for (NumJPs = Digit = 0; Digit < cJU_BRANCHUNUMJPS; ++Digit) { if (JU_BITMAPTESTB(Pjbb, Digit)) { Expanse[NumJPs++] = Digit; assert(NumJPs <= cJU_BRANCHLMAXJPS); // required of caller. } } // Allocate and populate the BranchL: if ((PjblRaw = j__udyAllocJBL(Pjpm)) == (Pjbl_t) NULL) return(-1); Pjbl = P_JBL(PjblRaw); JU_COPYMEM(Pjbl->jbl_Expanse, Expanse, NumJPs); Pjbl->jbl_NumJPs = NumJPs; DBGCODE(JudyCheckSorted((Pjll_t) (Pjbl->jbl_Expanse), NumJPs, 1);) // Copy JPs from each BranchB subexpanse subarray: Pjpjbl = P_JP(Pjbl->jbl_jp); // start at first JP in array. for (SubExp = 0; SubExp < cJU_NUMSUBEXPB; ++SubExp) { Pjp_t PjpRaw = JU_JBB_PJP(Pjbb, SubExp); // current Pjp. Pjp_t Pjp; if (PjpRaw == (Pjp_t) NULL) continue; // skip empty subexpanse. Pjp = P_JP(PjpRaw); NumJPs = j__udyCountBitsB(JU_JBB_BITMAP(Pjbb, SubExp)); assert(NumJPs); JU_COPYMEM(Pjpjbl, Pjp, NumJPs); // one subarray at a time. Pjpjbl += NumJPs; j__udyFreeJBBJP(PjpRaw, NumJPs, Pjpm); // subarray. } j__udyFreeJBB(PjbbRaw, Pjpm); // BranchB itself. // Finish up: Calculate new JP type (same index size = level in new class), // and tie new BranchB into parent JP: Pjp->jp_Type += cJU_JPBRANCH_L - cJU_JPBRANCH_B; Pjp->jp_Addr = (Word_t) PjblRaw; return(1); } // j__udyBranchBToBranchL() #ifdef notdef // **************************************************************************** // __ J U D Y B R A N C H U T O B R A N C H B // // When a BranchU shrinks to need little enough memory, call this function to // convert it to a BranchB to save memory (at the cost of some speed). Return // 1 for success, or -1 for failure (with details in Pjpm). // // TBD: Fill out if/when needed. Not currently used in JudyDel.c for reasons // explained there. FUNCTION int j__udyBranchUToBranchB( Pjp_t Pjp, // points to BranchU to shrink. Pvoid_t Pjpm) // for global accounting. { assert(FALSE); return(1); } #endif // notdef #if (defined(JUDYL) || (! defined(JU_64BIT))) // **************************************************************************** // __ J U D Y L E A F B 1 T O L E A F 1 // // Shrink a bitmap leaf (cJU_LEAFB1) to linear leaf (cJU_JPLEAF1). // Return 1 for success, or -1 for failure (with details in Pjpm). // // Note: This function is different than the other JudyLeaf*ToLeaf*() // functions because it receives a Pjp, not just a leaf, and handles its own // allocation and free, in order to allow the caller to continue with a LeafB1 // if allocation fails. FUNCTION int j__udyLeafB1ToLeaf1( Pjp_t Pjp, // points to LeafB1 to shrink. Pvoid_t Pjpm) // for global accounting. { Pjlb_t PjlbRaw; // bitmap in old leaf. Pjlb_t Pjlb; Pjll_t PjllRaw; // new Leaf1. uint8_t * Pleaf1; // Leaf1 pointer type. Word_t Digit; // in LeafB1 bitmap. #ifdef JUDYL Pjv_t PjvNew; // value area in new Leaf1. Word_t Pop1; Word_t SubExp; #endif assert(JU_JPTYPE(Pjp) == cJU_JPLEAF_B1); assert(((JU_JPDCDPOP0(Pjp) & 0xFF) + 1) == cJU_LEAF1_MAXPOP1); // Allocate JPLEAF1 and prepare pointers: if ((PjllRaw = j__udyAllocJLL1(cJU_LEAF1_MAXPOP1, Pjpm)) == 0) return(-1); Pleaf1 = (uint8_t *) P_JLL(PjllRaw); PjlbRaw = (Pjlb_t) (Pjp->jp_Addr); Pjlb = P_JLB(PjlbRaw); JUDYLCODE(PjvNew = JL_LEAF1VALUEAREA(Pleaf1, cJL_LEAF1_MAXPOP1);) // Copy 1-byte indexes from old LeafB1 to new Leaf1: for (Digit = 0; Digit < cJU_BRANCHUNUMJPS; ++Digit) if (JU_BITMAPTESTL(Pjlb, Digit)) *Pleaf1++ = Digit; #ifdef JUDYL // Copy all old-LeafB1 value areas from value subarrays to new Leaf1: for (SubExp = 0; SubExp < cJU_NUMSUBEXPL; ++SubExp) { Pjv_t PjvRaw = JL_JLB_PVALUE(Pjlb, SubExp); Pjv_t Pjv = P_JV(PjvRaw); if (Pjv == (Pjv_t) NULL) continue; // skip empty subarray. Pop1 = j__udyCountBitsL(JU_JLB_BITMAP(Pjlb, SubExp)); // subarray. assert(Pop1); JU_COPYMEM(PjvNew, Pjv, Pop1); // copy value areas. j__udyLFreeJV(PjvRaw, Pop1, Pjpm); PjvNew += Pop1; // advance through new. } assert((((Word_t) Pleaf1) - (Word_t) P_JLL(PjllRaw)) == (PjvNew - JL_LEAF1VALUEAREA(P_JLL(PjllRaw), cJL_LEAF1_MAXPOP1))); #endif // JUDYL DBGCODE(JudyCheckSorted((Pjll_t) P_JLL(PjllRaw), (((Word_t) Pleaf1) - (Word_t) P_JLL(PjllRaw)), 1);) // Finish up: Free the old LeafB1 and plug the new Leaf1 into the JP: // // Note: jp_DcdPopO does not change here. j__udyFreeJLB1(PjlbRaw, Pjpm); Pjp->jp_Addr = (Word_t) PjllRaw; Pjp->jp_Type = cJU_JPLEAF1; return(1); } // j__udyLeafB1ToLeaf1() #endif // (JUDYL || (! JU_64BIT)) // **************************************************************************** // __ J U D Y L E A F 1 T O L E A F 2 // // Copy 1-byte Indexes from a LeafB1 or Leaf1 to 2-byte Indexes in a Leaf2. // Pjp MUST be one of: cJU_JPLEAF_B1, cJU_JPLEAF1, or cJU_JPIMMED_1_*. // Return number of Indexes copied. // // TBD: In this and all following functions, the caller should already be able // to compute the Pop1 return value, so why return it? FUNCTION Word_t j__udyLeaf1ToLeaf2( uint16_t * PLeaf2, // destination uint16_t * Index portion of leaf. #ifdef JUDYL Pjv_t Pjv2, // destination value part of leaf. #endif Pjp_t Pjp, // 1-byte-index object from which to copy. Word_t MSByte, // most-significant byte, prefix to each Index. Pvoid_t Pjpm) // for global accounting. { Word_t Pop1; // Indexes in leaf. Word_t Offset; // in linear leaf list. JUDYLCODE(Pjv_t Pjv1Raw;) // source object value area. JUDYLCODE(Pjv_t Pjv1;) switch (JU_JPTYPE(Pjp)) { // JPLEAF_B1: case cJU_JPLEAF_B1: { Pjlb_t Pjlb = P_JLB(Pjp->jp_Addr); Word_t Digit; // in LeafB1 bitmap. JUDYLCODE(Word_t SubExp;) // in LeafB1. Pop1 = JU_JPBRANCH_POP0(Pjp, 1) + 1; assert(Pop1); // Copy 1-byte indexes from old LeafB1 to new Leaf2, including splicing in // the missing MSByte needed in the Leaf2: for (Digit = 0; Digit < cJU_BRANCHUNUMJPS; ++Digit) if (JU_BITMAPTESTL(Pjlb, Digit)) *PLeaf2++ = MSByte | Digit; #ifdef JUDYL // Copy all old-LeafB1 value areas from value subarrays to new Leaf2: for (SubExp = 0; SubExp < cJU_NUMSUBEXPL; ++SubExp) { Word_t SubExpPop1; Pjv1Raw = JL_JLB_PVALUE(Pjlb, SubExp); if (Pjv1Raw == (Pjv_t) NULL) continue; // skip empty. Pjv1 = P_JV(Pjv1Raw); SubExpPop1 = j__udyCountBitsL(JU_JLB_BITMAP(Pjlb, SubExp)); assert(SubExpPop1); JU_COPYMEM(Pjv2, Pjv1, SubExpPop1); // copy value areas. j__udyLFreeJV(Pjv1Raw, SubExpPop1, Pjpm); Pjv2 += SubExpPop1; // advance through new. } #endif // JUDYL j__udyFreeJLB1((Pjlb_t) (Pjp->jp_Addr), Pjpm); // LeafB1 itself. return(Pop1); } // case cJU_JPLEAF_B1 #if (defined(JUDYL) || (! defined(JU_64BIT))) // JPLEAF1: case cJU_JPLEAF1: { uint8_t * PLeaf1 = (uint8_t *) P_JLL(Pjp->jp_Addr); Pop1 = JU_JPBRANCH_POP0(Pjp, 1) + 1; assert(Pop1); JUDYLCODE(Pjv1 = JL_LEAF1VALUEAREA(PLeaf1, Pop1);) // Copy all Index bytes including splicing in missing MSByte needed in Leaf2 // (plus, for JudyL, value areas): for (Offset = 0; Offset < Pop1; ++Offset) { PLeaf2[Offset] = MSByte | PLeaf1[Offset]; JUDYLCODE(Pjv2[Offset] = Pjv1[Offset];) } j__udyFreeJLL1((Pjll_t) (Pjp->jp_Addr), Pop1, Pjpm); return(Pop1); } #endif // (JUDYL || (! JU_64BIT)) // JPIMMED_1_01: // // Note: jp_DcdPopO has 3 [7] bytes of Index (all but most significant byte), // so the assignment to PLeaf2[] truncates and MSByte is not needed. case cJU_JPIMMED_1_01: { PLeaf2[0] = JU_JPDCDPOP0(Pjp); // see above. JUDYLCODE(Pjv2[0] = Pjp->jp_Addr;) return(1); } // JPIMMED_1_0[2+]: case cJU_JPIMMED_1_02: case cJU_JPIMMED_1_03: #if (defined(JUDY1) || defined(JU_64BIT)) case cJU_JPIMMED_1_04: case cJU_JPIMMED_1_05: case cJU_JPIMMED_1_06: case cJU_JPIMMED_1_07: #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_1_08: case cJ1_JPIMMED_1_09: case cJ1_JPIMMED_1_10: case cJ1_JPIMMED_1_11: case cJ1_JPIMMED_1_12: case cJ1_JPIMMED_1_13: case cJ1_JPIMMED_1_14: case cJ1_JPIMMED_1_15: #endif { Pop1 = JU_JPTYPE(Pjp) - cJU_JPIMMED_1_02 + 2; assert(Pop1); JUDYLCODE(Pjv1Raw = (Pjv_t) (Pjp->jp_Addr);) JUDYLCODE(Pjv1 = P_JV(Pjv1Raw);) for (Offset = 0; Offset < Pop1; ++Offset) { #ifdef JUDY1 PLeaf2[Offset] = MSByte | Pjp->jp_1Index[Offset]; #else PLeaf2[Offset] = MSByte | Pjp->jp_LIndex[Offset]; Pjv2 [Offset] = Pjv1[Offset]; #endif } JUDYLCODE(j__udyLFreeJV(Pjv1Raw, Pop1, Pjpm);) return(Pop1); } // UNEXPECTED CASES, including JPNULL1, should be handled by caller: default: assert(FALSE); break; } // switch return(0); } // j__udyLeaf1ToLeaf2() // ***************************************************************************** // __ J U D Y L E A F 2 T O L E A F 3 // // Copy 2-byte Indexes from a Leaf2 to 3-byte Indexes in a Leaf3. // Pjp MUST be one of: cJU_JPLEAF2 or cJU_JPIMMED_2_*. // Return number of Indexes copied. // // Note: By the time this function is called to compress a level-3 branch to a // Leaf3, the branch has no narrow pointers under it, meaning only level-2 // objects are below it and must be handled here. FUNCTION Word_t j__udyLeaf2ToLeaf3( uint8_t * PLeaf3, // destination "uint24_t *" Index part of leaf. #ifdef JUDYL Pjv_t Pjv3, // destination value part of leaf. #endif Pjp_t Pjp, // 2-byte-index object from which to copy. Word_t MSByte, // most-significant byte, prefix to each Index. Pvoid_t Pjpm) // for global accounting. { Word_t Pop1; // Indexes in leaf. #if (defined(JUDYL) && defined(JU_64BIT)) Pjv_t Pjv2Raw; // source object value area. #endif JUDYLCODE(Pjv_t Pjv2;) switch (JU_JPTYPE(Pjp)) { // JPLEAF2: case cJU_JPLEAF2: { uint16_t * PLeaf2 = (uint16_t *) P_JLL(Pjp->jp_Addr); Pop1 = JU_JPLEAF_POP0(Pjp) + 1; assert(Pop1); j__udyCopy2to3(PLeaf3, PLeaf2, Pop1, MSByte); #ifdef JUDYL Pjv2 = JL_LEAF2VALUEAREA(PLeaf2, Pop1); JU_COPYMEM(Pjv3, Pjv2, Pop1); #endif j__udyFreeJLL2((Pjll_t) (Pjp->jp_Addr), Pop1, Pjpm); return(Pop1); } // JPIMMED_2_01: // // Note: jp_DcdPopO has 3 [7] bytes of Index (all but most significant byte), // so the "assignment" to PLeaf3[] is exact [truncates] and MSByte is not // needed. case cJU_JPIMMED_2_01: { JU_COPY3_LONG_TO_PINDEX(PLeaf3, JU_JPDCDPOP0(Pjp)); // see above. JUDYLCODE(Pjv3[0] = Pjp->jp_Addr;) return(1); } // JPIMMED_2_0[2+]: #if (defined(JUDY1) || defined(JU_64BIT)) case cJU_JPIMMED_2_02: case cJU_JPIMMED_2_03: #endif #if (defined(JUDY1) && defined(JU_64BIT)) case cJ1_JPIMMED_2_04: case cJ1_JPIMMED_2_05: case cJ1_JPIMMED_2_06: case cJ1_JPIMMED_2_07: #endif #if (defined(JUDY1) || defined(JU_64BIT)) { JUDY1CODE(uint16_t * PLeaf2 = (uint16_t *) (Pjp->jp_1Index);) JUDYLCODE(uint16_t * PLeaf2 = (uint16_t *) (Pjp->jp_LIndex);) Pop1 = JU_JPTYPE(Pjp) - cJU_JPIMMED_2_02 + 2; assert(Pop1); j__udyCopy2to3(PLeaf3, PLeaf2, Pop1, MSByte); #ifdef JUDYL Pjv2Raw = (Pjv_t) (Pjp->jp_Addr); Pjv2 = P_JV(Pjv2Raw); JU_COPYMEM(Pjv3, Pjv2, Pop1); j__udyLFreeJV(Pjv2Raw, Pop1, Pjpm); #endif return(Pop1); } #endif // (JUDY1 || JU_64BIT) // UNEXPECTED CASES, including JPNULL2, should be handled by caller: default: assert(FALSE); break; } // switch return(0); } // j__udyLeaf2ToLeaf3() #ifdef JU_64BIT // **************************************************************************** // __ J U D Y L E A F 3 T O L E A F 4 // // Copy 3-byte Indexes from a Leaf3 to 4-byte Indexes in a Leaf4. // Pjp MUST be one of: cJU_JPLEAF3 or cJU_JPIMMED_3_*. // Return number of Indexes copied. // // Note: By the time this function is called to compress a level-4 branch to a // Leaf4, the branch has no narrow pointers under it, meaning only level-3 // objects are below it and must be handled here. FUNCTION Word_t j__udyLeaf3ToLeaf4( uint32_t * PLeaf4, // destination uint32_t * Index part of leaf. #ifdef JUDYL Pjv_t Pjv4, // destination value part of leaf. #endif Pjp_t Pjp, // 3-byte-index object from which to copy. Word_t MSByte, // most-significant byte, prefix to each Index. Pvoid_t Pjpm) // for global accounting. { Word_t Pop1; // Indexes in leaf. JUDYLCODE(Pjv_t Pjv3Raw;) // source object value area. JUDYLCODE(Pjv_t Pjv3;) switch (JU_JPTYPE(Pjp)) { // JPLEAF3: case cJU_JPLEAF3: { uint8_t * PLeaf3 = (uint8_t *) P_JLL(Pjp->jp_Addr); Pop1 = JU_JPLEAF_POP0(Pjp) + 1; assert(Pop1); j__udyCopy3to4(PLeaf4, (uint8_t *) PLeaf3, Pop1, MSByte); #ifdef JUDYL Pjv3 = JL_LEAF3VALUEAREA(PLeaf3, Pop1); JU_COPYMEM(Pjv4, Pjv3, Pop1); #endif j__udyFreeJLL3((Pjll_t) (Pjp->jp_Addr), Pop1, Pjpm); return(Pop1); } // JPIMMED_3_01: // // Note: jp_DcdPopO has 7 bytes of Index (all but most significant byte), so // the assignment to PLeaf4[] truncates and MSByte is not needed. case cJU_JPIMMED_3_01: { PLeaf4[0] = JU_JPDCDPOP0(Pjp); // see above. JUDYLCODE(Pjv4[0] = Pjp->jp_Addr;) return(1); } // JPIMMED_3_0[2+]: case cJU_JPIMMED_3_02: #ifdef JUDY1 case cJ1_JPIMMED_3_03: case cJ1_JPIMMED_3_04: case cJ1_JPIMMED_3_05: #endif { JUDY1CODE(uint8_t * PLeaf3 = (uint8_t *) (Pjp->jp_1Index);) JUDYLCODE(uint8_t * PLeaf3 = (uint8_t *) (Pjp->jp_LIndex);) JUDY1CODE(Pop1 = JU_JPTYPE(Pjp) - cJU_JPIMMED_3_02 + 2;) JUDYLCODE(Pop1 = 2;) j__udyCopy3to4(PLeaf4, PLeaf3, Pop1, MSByte); #ifdef JUDYL Pjv3Raw = (Pjv_t) (Pjp->jp_Addr); Pjv3 = P_JV(Pjv3Raw); JU_COPYMEM(Pjv4, Pjv3, Pop1); j__udyLFreeJV(Pjv3Raw, Pop1, Pjpm); #endif return(Pop1); } // UNEXPECTED CASES, including JPNULL3, should be handled by caller: default: assert(FALSE); break; } // switch return(0); } // j__udyLeaf3ToLeaf4() // Note: In all following j__udyLeaf*ToLeaf*() functions, JPIMMED_*_0[2+] // cases exist for Judy1 (&& 64-bit) only. JudyL has no equivalent Immeds. // ***************************************************************************** // __ J U D Y L E A F 4 T O L E A F 5 // // Copy 4-byte Indexes from a Leaf4 to 5-byte Indexes in a Leaf5. // Pjp MUST be one of: cJU_JPLEAF4 or cJU_JPIMMED_4_*. // Return number of Indexes copied. // // Note: By the time this function is called to compress a level-5 branch to a // Leaf5, the branch has no narrow pointers under it, meaning only level-4 // objects are below it and must be handled here. FUNCTION Word_t j__udyLeaf4ToLeaf5( uint8_t * PLeaf5, // destination "uint40_t *" Index part of leaf. #ifdef JUDYL Pjv_t Pjv5, // destination value part of leaf. #endif Pjp_t Pjp, // 4-byte-index object from which to copy. Word_t MSByte, // most-significant byte, prefix to each Index. Pvoid_t Pjpm) // for global accounting. { Word_t Pop1; // Indexes in leaf. JUDYLCODE(Pjv_t Pjv4;) // source object value area. switch (JU_JPTYPE(Pjp)) { // JPLEAF4: case cJU_JPLEAF4: { uint32_t * PLeaf4 = (uint32_t *) P_JLL(Pjp->jp_Addr); Pop1 = JU_JPLEAF_POP0(Pjp) + 1; assert(Pop1); j__udyCopy4to5(PLeaf5, PLeaf4, Pop1, MSByte); #ifdef JUDYL Pjv4 = JL_LEAF4VALUEAREA(PLeaf4, Pop1); JU_COPYMEM(Pjv5, Pjv4, Pop1); #endif j__udyFreeJLL4((Pjll_t) (Pjp->jp_Addr), Pop1, Pjpm); return(Pop1); } // JPIMMED_4_01: // // Note: jp_DcdPopO has 7 bytes of Index (all but most significant byte), so // the assignment to PLeaf5[] truncates and MSByte is not needed. case cJU_JPIMMED_4_01: { JU_COPY5_LONG_TO_PINDEX(PLeaf5, JU_JPDCDPOP0(Pjp)); // see above. JUDYLCODE(Pjv5[0] = Pjp->jp_Addr;) return(1); } #ifdef JUDY1 // JPIMMED_4_0[4+]: case cJ1_JPIMMED_4_02: case cJ1_JPIMMED_4_03: { uint32_t * PLeaf4 = (uint32_t *) (Pjp->jp_1Index); Pop1 = JU_JPTYPE(Pjp) - cJ1_JPIMMED_4_02 + 2; j__udyCopy4to5(PLeaf5, PLeaf4, Pop1, MSByte); return(Pop1); } #endif // JUDY1 // UNEXPECTED CASES, including JPNULL4, should be handled by caller: default: assert(FALSE); break; } // switch return(0); } // j__udyLeaf4ToLeaf5() // **************************************************************************** // __ J U D Y L E A F 5 T O L E A F 6 // // Copy 5-byte Indexes from a Leaf5 to 6-byte Indexes in a Leaf6. // Pjp MUST be one of: cJU_JPLEAF5 or cJU_JPIMMED_5_*. // Return number of Indexes copied. // // Note: By the time this function is called to compress a level-6 branch to a // Leaf6, the branch has no narrow pointers under it, meaning only level-5 // objects are below it and must be handled here. FUNCTION Word_t j__udyLeaf5ToLeaf6( uint8_t * PLeaf6, // destination uint8_t * Index part of leaf. #ifdef JUDYL Pjv_t Pjv6, // destination value part of leaf. #endif Pjp_t Pjp, // 5-byte-index object from which to copy. Word_t MSByte, // most-significant byte, prefix to each Index. Pvoid_t Pjpm) // for global accounting. { Word_t Pop1; // Indexes in leaf. JUDYLCODE(Pjv_t Pjv5;) // source object value area. switch (JU_JPTYPE(Pjp)) { // JPLEAF5: case cJU_JPLEAF5: { uint8_t * PLeaf5 = (uint8_t *) P_JLL(Pjp->jp_Addr); Pop1 = JU_JPLEAF_POP0(Pjp) + 1; assert(Pop1); j__udyCopy5to6(PLeaf6, PLeaf5, Pop1, MSByte); #ifdef JUDYL Pjv5 = JL_LEAF5VALUEAREA(PLeaf5, Pop1); JU_COPYMEM(Pjv6, Pjv5, Pop1); #endif j__udyFreeJLL5((Pjll_t) (Pjp->jp_Addr), Pop1, Pjpm); return(Pop1); } // JPIMMED_5_01: // // Note: jp_DcdPopO has 7 bytes of Index (all but most significant byte), so // the assignment to PLeaf6[] truncates and MSByte is not needed. case cJU_JPIMMED_5_01: { JU_COPY6_LONG_TO_PINDEX(PLeaf6, JU_JPDCDPOP0(Pjp)); // see above. JUDYLCODE(Pjv6[0] = Pjp->jp_Addr;) return(1); } #ifdef JUDY1 // JPIMMED_5_0[2+]: case cJ1_JPIMMED_5_02: case cJ1_JPIMMED_5_03: { uint8_t * PLeaf5 = (uint8_t *) (Pjp->jp_1Index); Pop1 = JU_JPTYPE(Pjp) - cJ1_JPIMMED_5_02 + 2; j__udyCopy5to6(PLeaf6, PLeaf5, Pop1, MSByte); return(Pop1); } #endif // JUDY1 // UNEXPECTED CASES, including JPNULL5, should be handled by caller: default: assert(FALSE); break; } // switch return(0); } // j__udyLeaf5ToLeaf6() // ***************************************************************************** // __ J U D Y L E A F 6 T O L E A F 7 // // Copy 6-byte Indexes from a Leaf2 to 7-byte Indexes in a Leaf7. // Pjp MUST be one of: cJU_JPLEAF6 or cJU_JPIMMED_6_*. // Return number of Indexes copied. // // Note: By the time this function is called to compress a level-7 branch to a // Leaf7, the branch has no narrow pointers under it, meaning only level-6 // objects are below it and must be handled here. FUNCTION Word_t j__udyLeaf6ToLeaf7( uint8_t * PLeaf7, // destination "uint24_t *" Index part of leaf. #ifdef JUDYL Pjv_t Pjv7, // destination value part of leaf. #endif Pjp_t Pjp, // 6-byte-index object from which to copy. Word_t MSByte, // most-significant byte, prefix to each Index. Pvoid_t Pjpm) // for global accounting. { Word_t Pop1; // Indexes in leaf. JUDYLCODE(Pjv_t Pjv6;) // source object value area. switch (JU_JPTYPE(Pjp)) { // JPLEAF6: case cJU_JPLEAF6: { uint8_t * PLeaf6 = (uint8_t *) P_JLL(Pjp->jp_Addr); Pop1 = JU_JPLEAF_POP0(Pjp) + 1; j__udyCopy6to7(PLeaf7, PLeaf6, Pop1, MSByte); #ifdef JUDYL Pjv6 = JL_LEAF6VALUEAREA(PLeaf6, Pop1); JU_COPYMEM(Pjv7, Pjv6, Pop1); #endif j__udyFreeJLL6((Pjll_t) (Pjp->jp_Addr), Pop1, Pjpm); return(Pop1); } // JPIMMED_6_01: // // Note: jp_DcdPopO has 7 bytes of Index (all but most significant byte), so // the "assignment" to PLeaf7[] is exact and MSByte is not needed. case cJU_JPIMMED_6_01: { JU_COPY7_LONG_TO_PINDEX(PLeaf7, JU_JPDCDPOP0(Pjp)); // see above. JUDYLCODE(Pjv7[0] = Pjp->jp_Addr;) return(1); } #ifdef JUDY1 // JPIMMED_6_02: case cJ1_JPIMMED_6_02: { uint8_t * PLeaf6 = (uint8_t *) (Pjp->jp_1Index); j__udyCopy6to7(PLeaf7, PLeaf6, /* Pop1 = */ 2, MSByte); return(2); } #endif // JUDY1 // UNEXPECTED CASES, including JPNULL6, should be handled by caller: default: assert(FALSE); break; } // switch return(0); } // j__udyLeaf6ToLeaf7() #endif // JU_64BIT #ifndef JU_64BIT // 32-bit version first // **************************************************************************** // __ J U D Y L E A F 3 T O L E A F W // // Copy 3-byte Indexes from a Leaf3 to 4-byte Indexes in a LeafW. Pjp MUST be // one of: cJU_JPLEAF3 or cJU_JPIMMED_3_*. Return number of Indexes copied. // // Note: By the time this function is called to compress a level-L branch to a // LeafW, the branch has no narrow pointers under it, meaning only level-3 // objects are below it and must be handled here. FUNCTION Word_t j__udyLeaf3ToLeafW( Pjlw_t Pjlw, // destination Index part of leaf. #ifdef JUDYL Pjv_t PjvW, // destination value part of leaf. #endif Pjp_t Pjp, // 3-byte-index object from which to copy. Word_t MSByte, // most-significant byte, prefix to each Index. Pvoid_t Pjpm) // for global accounting. { Word_t Pop1; // Indexes in leaf. JUDYLCODE(Pjv_t Pjv3;) // source object value area. switch (JU_JPTYPE(Pjp)) { // JPLEAF3: case cJU_JPLEAF3: { uint8_t * PLeaf3 = (uint8_t *) P_JLL(Pjp->jp_Addr); Pop1 = JU_JPLEAF_POP0(Pjp) + 1; j__udyCopy3toW((PWord_t) Pjlw, PLeaf3, Pop1, MSByte); #ifdef JUDYL Pjv3 = JL_LEAF3VALUEAREA(PLeaf3, Pop1); JU_COPYMEM(PjvW, Pjv3, Pop1); #endif j__udyFreeJLL3((Pjll_t) (Pjp->jp_Addr), Pop1, Pjpm); return(Pop1); } // JPIMMED_3_01: // // Note: jp_DcdPopO has 3 bytes of Index (all but most significant byte), and // MSByte must be ord in. case cJU_JPIMMED_3_01: { Pjlw[0] = MSByte | JU_JPDCDPOP0(Pjp); // see above. JUDYLCODE(PjvW[0] = Pjp->jp_Addr;) return(1); } #ifdef JUDY1 // JPIMMED_3_02: case cJU_JPIMMED_3_02: { uint8_t * PLeaf3 = (uint8_t *) (Pjp->jp_1Index); j__udyCopy3toW((PWord_t) Pjlw, PLeaf3, /* Pop1 = */ 2, MSByte); return(2); } #endif // JUDY1 // UNEXPECTED CASES, including JPNULL3, should be handled by caller: default: assert(FALSE); break; } // switch return(0); } // j__udyLeaf3ToLeafW() #else // JU_64BIT // **************************************************************************** // __ J U D Y L E A F 7 T O L E A F W // // Copy 7-byte Indexes from a Leaf7 to 8-byte Indexes in a LeafW. // Pjp MUST be one of: cJU_JPLEAF7 or cJU_JPIMMED_7_*. // Return number of Indexes copied. // // Note: By the time this function is called to compress a level-L branch to a // LeafW, the branch has no narrow pointers under it, meaning only level-7 // objects are below it and must be handled here. FUNCTION Word_t j__udyLeaf7ToLeafW( Pjlw_t Pjlw, // destination Index part of leaf. #ifdef JUDYL Pjv_t PjvW, // destination value part of leaf. #endif Pjp_t Pjp, // 7-byte-index object from which to copy. Word_t MSByte, // most-significant byte, prefix to each Index. Pvoid_t Pjpm) // for global accounting. { Word_t Pop1; // Indexes in leaf. JUDYLCODE(Pjv_t Pjv7;) // source object value area. switch (JU_JPTYPE(Pjp)) { // JPLEAF7: case cJU_JPLEAF7: { uint8_t * PLeaf7 = (uint8_t *) P_JLL(Pjp->jp_Addr); Pop1 = JU_JPLEAF_POP0(Pjp) + 1; j__udyCopy7toW((PWord_t) Pjlw, PLeaf7, Pop1, MSByte); #ifdef JUDYL Pjv7 = JL_LEAF7VALUEAREA(PLeaf7, Pop1); JU_COPYMEM(PjvW, Pjv7, Pop1); #endif j__udyFreeJLL7((Pjll_t) (Pjp->jp_Addr), Pop1, Pjpm); return(Pop1); } // JPIMMED_7_01: // // Note: jp_DcdPopO has 7 bytes of Index (all but most significant byte), and // MSByte must be ord in. case cJU_JPIMMED_7_01: { Pjlw[0] = MSByte | JU_JPDCDPOP0(Pjp); // see above. JUDYLCODE(PjvW[0] = Pjp->jp_Addr;) return(1); } #ifdef JUDY1 // JPIMMED_7_02: case cJ1_JPIMMED_7_02: { uint8_t * PLeaf7 = (uint8_t *) (Pjp->jp_1Index); j__udyCopy7toW((PWord_t) Pjlw, PLeaf7, /* Pop1 = */ 2, MSByte); return(2); } #endif // UNEXPECTED CASES, including JPNULL7, should be handled by caller: default: assert(FALSE); break; } // switch return(0); } // j__udyLeaf7ToLeafW() #endif // JU_64BIT judy-1.0.5/src/JudyCommon/Makefile.am0000644000175000017500000000025310624600161017617 0ustar troyhebetroyhebeINCLUDES = -I. -I.. AM_CFLAGS = @CFLAGS@ @WARN_CFLAGS@ noinst_LTLIBRARIES = libJudyMalloc.la libJudyMalloc_la_SOURCES = JudyMalloc.c DISTCLEANFILES = .deps Makefile judy-1.0.5/src/JudyCommon/JudyPrivateBranch.h0000644000175000017500000006647610204462077021351 0ustar troyhebetroyhebe#ifndef _JUDY_PRIVATE_BRANCH_INCLUDED #define _JUDY_PRIVATE_BRANCH_INCLUDED // _________________ // // Copyright (C) 2000 - 2002 Hewlett-Packard Company // // This program is free software; you can redistribute it and/or modify it // under the term of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License // for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program; if not, write to the Free Software Foundation, // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // _________________ // @(#) $Revision: 4.57 $ $Source: /judy/src/JudyCommon/JudyPrivateBranch.h $ // // Header file for all Judy sources, for global but private (non-exported) // declarations specific to branch support. // // See also the "Judy Shop Manual" (try judy/doc/int/JudyShopManual.*). // **************************************************************************** // JUDY POINTER (JP) SUPPORT // **************************************************************************** // // This "rich pointer" object is pivotal to Judy execution. // // JP CONTAINING OTHER THAN IMMEDIATE INDEXES: // // If the JP points to a linear or bitmap leaf, jp_DcdPopO contains the // Population-1 in LSbs and Decode (Dcd) bytes in the MSBs. (In practice the // Decode bits are masked off while accessing the Pop0 bits.) // // The Decode Size, the number of Dcd bytes available, is encoded in jpo_Type. // It can also be thought of as the number of states "skipped" in the SM, where // each state decodes 8 bits = 1 byte. // // TBD: Dont need two structures, except possibly to force jp_Type to highest // address! // // Note: The jpo_u union is not required by HP-UX or Linux but Win32 because // the cl.exe compiler otherwise refuses to pack a bitfield (DcdPopO) with // anything else, even with the -Zp option. This is pretty ugly, but // fortunately portable, and its all hide-able by macros (see below). typedef struct J_UDY_POINTER_OTHERS // JPO. { Word_t j_po_Addr; // first word: Pjp_t, Word_t, etc. union { // Word_t j_po_DcdPop0:cJU_BITSPERWORD-cJU_BITSPERBYTE; uint8_t j_po_DcdP0[sizeof(Word_t) - 1]; uint8_t j_po_Bytes[sizeof(Word_t)]; // last byte = jp_Type. } jpo_u; } jpo_t; // JP CONTAINING IMMEDIATE INDEXES: // // j_pi_1Index[] plus j_pi_LIndex[] together hold as many N-byte (1..3-byte // [1..7-byte]) Indexes as will fit in sizeof(jpi_t) less 1 byte for j_pi_Type // (that is, 7..1 [15..1] Indexes). // // For Judy1, j_pi_1Index[] is used and j_pi_LIndex[] is not used. // For JudyL, j_pi_LIndex[] is used and j_pi_1Index[] is not used. // // Note: Actually when Pop1 = 1, jpi_t is not used, and the least bytes of the // single Index are stored in j_po_DcdPopO, for both Judy1 and JudyL, so for // JudyL the j_po_Addr field can hold the target value. // // TBD: Revise this structure to not overload j_po_DcdPopO this way? The // current arrangement works, its just confusing. typedef struct _JUDY_POINTER_IMMED // JPI. { uint8_t j_pi_1Index[sizeof(Word_t)]; // see above. uint8_t j_pi_LIndex[sizeof(Word_t) - 1]; // see above. uint8_t j_pi_Type; // JP type, 1 of cJ*_JPIMMED*. } jpi_t; // UNION OF JP TYPES: // // A branch is an array of cJU_BRANCHUNUMJPS (256) of this object, or an // alternate data type such as: A linear branch which is a list of 2..7 JPs, // or a bitmap branch which contains 8 lists of 0..32 JPs. JPs reside only in // branches of a Judy SM. typedef union J_UDY_POINTER // JP. { jpo_t j_po; // other than immediate indexes. jpi_t j_pi; // immediate indexes. } jp_t, *Pjp_t; // For coding convenience: // // Note, jp_Type has the same bits in jpo_t and jpi_t. #define jp_1Index j_pi.j_pi_1Index // for storing Indexes in first word. #define jp_LIndex j_pi.j_pi_LIndex // for storing Indexes in second word. #define jp_Addr j_po.j_po_Addr //#define jp_DcdPop0 j_po.jpo_u.j_po_DcdPop0 #define jp_Type j_po.jpo_u.j_po_Bytes[sizeof(Word_t) - 1] #define jp_DcdP0 j_po.jpo_u.j_po_DcdP0 // **************************************************************************** // JUDY POINTER (JP) -- RELATED MACROS AND CONSTANTS // **************************************************************************** // EXTRACT VALUES FROM JP: // // Masks for the bytes in the Dcd and Pop0 parts of jp_DcdPopO: // // cJU_DCDMASK() consists of a mask that excludes the (LSb) Pop0 bytes and // also, just to be safe, the top byte of the word, since jp_DcdPopO is 1 byte // less than a full word. // // Note: These are constant macros (cJU) because cPopBytes should be a // constant. Also note cPopBytes == state in the SM. #define cJU_POP0MASK(cPopBytes) JU_LEASTBYTESMASK(cPopBytes) #define cJU_DCDMASK(cPopBytes) \ ((cJU_ALLONES >> cJU_BITSPERBYTE) & (~cJU_POP0MASK(cPopBytes))) // Mask off the high byte from INDEX to it can be compared to DcdPopO: #define JU_TRIMTODCDSIZE(INDEX) ((cJU_ALLONES >> cJU_BITSPERBYTE) & (INDEX)) // Get from jp_DcdPopO the Pop0 for various branch JP Types: // // Note: There are no simple macros for cJU_BRANCH* Types because their // populations must be added up and dont reside in an already-calculated // place. #define JU_JPBRANCH_POP0(PJP,cPopBytes) \ (JU_JPDCDPOP0(PJP) & cJU_POP0MASK(cPopBytes)) // METHOD FOR DETERMINING IF OBJECTS HAVE ROOM TO GROW: // // J__U_GROWCK() is a generic method to determine if an object can grow in // place, based on whether the next population size (one more) would use the // same space. #define J__U_GROWCK(POP1,MAXPOP1,POPTOWORDS) \ (((POP1) != (MAXPOP1)) && (POPTOWORDS[POP1] == POPTOWORDS[(POP1) + 1])) #define JU_BRANCHBJPGROWINPLACE(NumJPs) \ J__U_GROWCK(NumJPs, cJU_BITSPERSUBEXPB, j__U_BranchBJPPopToWords) // DETERMINE IF AN INDEX IS (NOT) IN A JPS EXPANSE: #define JU_DCDNOTMATCHINDEX(INDEX,PJP,POP0BYTES) \ (((INDEX) ^ JU_JPDCDPOP0(PJP)) & cJU_DCDMASK(POP0BYTES)) // NUMBER OF JPs IN AN UNCOMPRESSED BRANCH: // // An uncompressed branch is simply an array of 256 Judy Pointers (JPs). It is // a minimum cacheline fill object. Define it here before its first needed. #define cJU_BRANCHUNUMJPS cJU_SUBEXPPERSTATE // **************************************************************************** // JUDY BRANCH LINEAR (JBL) SUPPORT // **************************************************************************** // // A linear branch is a way of compressing empty expanses (null JPs) out of an // uncompressed 256-way branch, when the number of populated expanses is so // small that even a bitmap branch is excessive. // // The maximum number of JPs in a Judy linear branch: // // Note: This number results in a 1-cacheline sized structure. Previous // versions had a larger struct so a linear branch didnt become a bitmap // branch until the memory consumed was even, but for speed, its better to // switch "sooner" and keep a linear branch fast. #define cJU_BRANCHLMAXJPS 7 // LINEAR BRANCH STRUCT: // // 1-byte count, followed by array of byte-sized expanses, followed by JPs. typedef struct J__UDY_BRANCH_LINEAR { uint8_t jbl_NumJPs; // num of JPs (Pjp_t), 1..N. uint8_t jbl_Expanse[cJU_BRANCHLMAXJPS]; // 1..7 MSbs of pop exps. jp_t jbl_jp [cJU_BRANCHLMAXJPS]; // JPs for populated exps. } jbl_t, * Pjbl_t; // **************************************************************************** // JUDY BRANCH BITMAP (JBB) SUPPORT // **************************************************************************** // // A bitmap branch is a way of compressing empty expanses (null JPs) out of // uncompressed 256-way branch. This costs 1 additional cache line fill, but // can save a lot of memory when it matters most, near the leaves, and // typically there will be only one at most in the path to any Index (leaf). // // The bitmap indicates which of the cJU_BRANCHUNUMJPS (256) JPs in the branch // are NOT null, that is, their expanses are populated. The jbb_t also // contains N pointers to "mini" Judy branches ("subexpanses") of up to M JPs // each (see BITMAP_BRANCHMxN, for example, BITMAP_BRANCH32x8), where M x N = // cJU_BRANCHUNUMJPS. These are dynamically allocated and never contain // cJ*_JPNULL* jp_Types. An empty subexpanse is represented by no bit sets in // the corresponding subexpanse bitmap, in which case the corresponding // jbbs_Pjp pointers value is unused. // // Note that the number of valid JPs in each 1-of-N subexpanses is determined // by POPULATION rather than by EXPANSE -- the desired outcome to save memory // when near the leaves. Note that the memory required for 185 JPs is about as // much as an uncompressed 256-way branch, therefore 184 is set as the maximum. // However, it is expected that a conversion to an uncompressed 256-way branch // will normally take place before this limit is reached for other reasons, // such as improving performance when the "wasted" memory is well amortized by // the population under the branch, preserving an acceptable overall // bytes/Index in the Judy array. // // The number of pointers to arrays of JPs in the Judy bitmap branch: // // Note: The numbers below are the same in both 32 and 64 bit systems. #define cJU_BRANCHBMAXJPS 184 // maximum JPs for bitmap branches. // Convenience wrappers for referencing BranchB bitmaps or JP subarray // pointers: // // Note: JU_JBB_PJP produces a "raw" memory address that must pass through // P_JP before use, except when freeing memory: #define JU_JBB_BITMAP(Pjbb, SubExp) ((Pjbb)->jbb_jbbs[SubExp].jbbs_Bitmap) #define JU_JBB_PJP( Pjbb, SubExp) ((Pjbb)->jbb_jbbs[SubExp].jbbs_Pjp) #define JU_SUBEXPB(Digit) (((Digit) / cJU_BITSPERSUBEXPB) & (cJU_NUMSUBEXPB-1)) #define JU_BITMAPTESTB(Pjbb, Index) \ (JU_JBB_BITMAP(Pjbb, JU_SUBEXPB(Index)) & JU_BITPOSMASKB(Index)) #define JU_BITMAPSETB(Pjbb, Index) \ (JU_JBB_BITMAP(Pjbb, JU_SUBEXPB(Index)) |= JU_BITPOSMASKB(Index)) // Note: JU_BITMAPCLEARB is not defined because the code does it a faster way. typedef struct J__UDY_BRANCH_BITMAP_SUBEXPANSE { BITMAPB_t jbbs_Bitmap; Pjp_t jbbs_Pjp; } jbbs_t; typedef struct J__UDY_BRANCH_BITMAP { jbbs_t jbb_jbbs [cJU_NUMSUBEXPB]; #ifdef SUBEXPCOUNTS Word_t jbb_subPop1[cJU_NUMSUBEXPB]; #endif } jbb_t, * Pjbb_t; #define JU_BRANCHJP_NUMJPSTOWORDS(NumJPs) (j__U_BranchBJPPopToWords[NumJPs]) #ifdef SUBEXPCOUNTS #define cJU_NUMSUBEXPU 16 // number of subexpanse counts. #endif // **************************************************************************** // JUDY BRANCH UNCOMPRESSED (JBU) SUPPORT // **************************************************************************** // Convenience wrapper for referencing BranchU JPs: // // Note: This produces a non-"raw" address already passed through P_JBU(). #define JU_JBU_PJP(Pjp,Index,Level) \ (&((P_JBU((Pjp)->jp_Addr))->jbu_jp[JU_DIGITATSTATE(Index, Level)])) #define JU_JBU_PJP0(Pjp) \ (&((P_JBU((Pjp)->jp_Addr))->jbu_jp[0])) typedef struct J__UDY_BRANCH_UNCOMPRESSED { jp_t jbu_jp [cJU_BRANCHUNUMJPS]; // JPs for populated exp. #ifdef SUBEXPCOUNTS Word_t jbu_subPop1[cJU_NUMSUBEXPU]; #endif } jbu_t, * Pjbu_t; // **************************************************************************** // OTHER SUPPORT FOR JUDY STATE MACHINES (SMs) // **************************************************************************** // OBJECT SIZES IN WORDS: // // Word_ts per various JudyL structures that have constant sizes. // cJU_WORDSPERJP should always be 2; this is fundamental to the Judy // structures. #define cJU_WORDSPERJP (sizeof(jp_t) / cJU_BYTESPERWORD) #define cJU_WORDSPERCL (cJU_BYTESPERCL / cJU_BYTESPERWORD) // OPPORTUNISTIC UNCOMPRESSION: // // Define populations at which a BranchL or BranchB must convert to BranchU. // Earlier conversion is possible with good memory efficiency -- see below. #ifndef NO_BRANCHU // Max population below BranchL, then convert to BranchU: #define JU_BRANCHL_MAX_POP 1000 // Minimum global population increment before next conversion of a BranchB to a // BranchU: // // This is was done to allow malloc() to coalesce memory before the next big // (~512 words) allocation. #define JU_BTOU_POP_INCREMENT 300 // Min/max population below BranchB, then convert to BranchU: #define JU_BRANCHB_MIN_POP 135 #define JU_BRANCHB_MAX_POP 750 #else // NO_BRANCHU // These are set up to have conservative conversion schedules to BranchU: #define JU_BRANCHL_MAX_POP (-1UL) #define JU_BTOU_POP_INCREMENT 300 #define JU_BRANCHB_MIN_POP 1000 #define JU_BRANCHB_MAX_POP (-1UL) #endif // NO_BRANCHU // MISCELLANEOUS MACROS: // Get N most significant bits from the shifted Index word: // // As Index words are decoded, they are shifted left so only relevant, // undecoded Index bits remain. #define JU_BITSFROMSFTIDX(SFTIDX, N) ((SFTIDX) >> (cJU_BITSPERWORD - (N))) // TBD: I have my doubts about the necessity of these macros (dlb): // Produce 1-digit mask at specified state: #define cJU_MASKATSTATE(State) (0xffL << (((State) - 1) * cJU_BITSPERBYTE)) // Get byte (digit) from Index at the specified state, right justified: // // Note: State must be 1..cJU_ROOTSTATE, and Digits must be 1..(cJU_ROOTSTATE // - 1), but theres no way to assert these within an expression. #define JU_DIGITATSTATE(Index,cState) \ ((uint8_t)((Index) >> (((cState) - 1) * cJU_BITSPERBYTE))) // Similarly, place byte (digit) at correct position for the specified state: // // Note: Cast digit to a Word_t first so there are no complaints or problems // about shifting it more than 32 bits on a 64-bit system, say, when it is a // uint8_t from jbl_Expanse[]. (Believe it or not, the C standard says to // promote an unsigned char to a signed int; -Ac does not do this, but -Ae // does.) // // Also, to make lint happy, cast the whole result again because apparently // shifting a Word_t does not result in a Word_t! #define JU_DIGITTOSTATE(Digit,cState) \ ((Word_t) (((Word_t) (Digit)) << (((cState) - 1) * cJU_BITSPERBYTE))) #endif // ! _JUDY_PRIVATE_BRANCH_INCLUDED #ifdef TEST_INSDEL // **************************************************************************** // TEST CODE FOR INSERT/DELETE MACROS // **************************************************************************** // // To use this, compile a temporary *.c file containing: // // #define DEBUG // #define JUDY_ASSERT // #define TEST_INSDEL // #include "JudyPrivate.h" // #include "JudyPrivateBranch.h" // // Use a command like this: cc -Ae +DD64 -I. -I JudyCommon -o t t.c // For best results, include +DD64 on a 64-bit system. // // This test code exercises some tricky macros, but the output must be studied // manually to verify it. Assume that for even-index testing, whole words // (Word_t) suffices. #include #define INDEXES 3 // in each array. // **************************************************************************** // I N I T // // Set up variables for next test. See usage. FUNCTION void Init ( int base, PWord_t PeIndex, PWord_t PoIndex, PWord_t Peleaf, // always whole words. #ifndef JU_64BIT uint8_t * Poleaf3) #else uint8_t * Poleaf3, uint8_t * Poleaf5, uint8_t * Poleaf6, uint8_t * Poleaf7) #endif { int offset; *PeIndex = 99; for (offset = 0; offset <= INDEXES; ++offset) Peleaf[offset] = base + offset; for (offset = 0; offset < (INDEXES + 1) * 3; ++offset) Poleaf3[offset] = base + offset; #ifndef JU_64BIT *PoIndex = (91 << 24) | (92 << 16) | (93 << 8) | 94; #else *PoIndex = (91L << 56) | (92L << 48) | (93L << 40) | (94L << 32) | (95L << 24) | (96L << 16) | (97L << 8) | 98L; for (offset = 0; offset < (INDEXES + 1) * 5; ++offset) Poleaf5[offset] = base + offset; for (offset = 0; offset < (INDEXES + 1) * 6; ++offset) Poleaf6[offset] = base + offset; for (offset = 0; offset < (INDEXES + 1) * 7; ++offset) Poleaf7[offset] = base + offset; #endif } // Init() // **************************************************************************** // P R I N T L E A F // // Print the byte values in a leaf. FUNCTION void PrintLeaf ( char * Label, // for output. int IOffset, // insertion offset in array. int Indsize, // index size in bytes. uint8_t * PLeaf) // array of Index bytes. { int offset; // in PLeaf. int byte; // in one word. (void) printf("%s %u: ", Label, IOffset); for (offset = 0; offset <= INDEXES; ++offset) { for (byte = 0; byte < Indsize; ++byte) (void) printf("%2d", PLeaf[(offset * Indsize) + byte]); (void) printf(" "); } (void) printf("\n"); } // PrintLeaf() // **************************************************************************** // M A I N // // Test program. FUNCTION main() { Word_t eIndex; // even, to insert. Word_t oIndex; // odd, to insert. Word_t eleaf [ INDEXES + 1]; // even leaf, index size 4. uint8_t oleaf3[(INDEXES + 1) * 3]; // odd leaf, index size 3. #ifdef JU_64BIT uint8_t oleaf5[(INDEXES + 1) * 5]; // odd leaf, index size 5. uint8_t oleaf6[(INDEXES + 1) * 6]; // odd leaf, index size 6. uint8_t oleaf7[(INDEXES + 1) * 7]; // odd leaf, index size 7. #endif Word_t eleaf_2 [ INDEXES + 1]; // same, but second arrays: uint8_t oleaf3_2[(INDEXES + 1) * 3]; #ifdef JU_64BIT uint8_t oleaf5_2[(INDEXES + 1) * 5]; uint8_t oleaf6_2[(INDEXES + 1) * 6]; uint8_t oleaf7_2[(INDEXES + 1) * 7]; #endif int ioffset; // index insertion offset. #ifndef JU_64BIT #define INIT Init( 0, & eIndex, & oIndex, eleaf, oleaf3) #define INIT2 INIT; Init(50, & eIndex, & oIndex, eleaf_2, oleaf3_2) #else #define INIT Init( 0, & eIndex, & oIndex, eleaf, oleaf3, \ oleaf5, oleaf6, oleaf7) #define INIT2 INIT; Init(50, & eIndex, & oIndex, eleaf_2, oleaf3_2, \ oleaf5_2, oleaf6_2, oleaf7_2) #endif #define WSIZE sizeof (Word_t) // shorthand. #ifdef PRINTALL // to turn on "noisy" printouts. #define PRINTLEAF(Label,IOffset,Indsize,PLeaf) \ PrintLeaf(Label,IOffset,Indsize,PLeaf) #else #define PRINTLEAF(Label,IOffset,Indsize,PLeaf) \ if (ioffset == 0) \ PrintLeaf(Label,IOffset,Indsize,PLeaf) #endif (void) printf( "In each case, tests operate on an initial array of %d indexes. Even-index\n" "tests set index values to 0,1,2...; odd-index tests set byte values to\n" "0,1,2... Inserted indexes have a value of 99 or else byte values 91,92,...\n", INDEXES); (void) puts("\nJU_INSERTINPLACE():"); for (ioffset = 0; ioffset <= INDEXES; ++ioffset) { INIT; PRINTLEAF("Before", ioffset, WSIZE, (uint8_t *) eleaf); JU_INSERTINPLACE(eleaf, INDEXES, ioffset, eIndex); PrintLeaf("After ", ioffset, WSIZE, (uint8_t *) eleaf); } (void) puts("\nJU_INSERTINPLACE3():"); for (ioffset = 0; ioffset <= INDEXES; ++ioffset) { INIT; PRINTLEAF("Before", ioffset, 3, oleaf3); JU_INSERTINPLACE3(oleaf3, INDEXES, ioffset, oIndex); PrintLeaf("After ", ioffset, 3, oleaf3); } #ifdef JU_64BIT (void) puts("\nJU_INSERTINPLACE5():"); for (ioffset = 0; ioffset <= INDEXES; ++ioffset) { INIT; PRINTLEAF("Before", ioffset, 5, oleaf5); JU_INSERTINPLACE5(oleaf5, INDEXES, ioffset, oIndex); PrintLeaf("After ", ioffset, 5, oleaf5); } (void) puts("\nJU_INSERTINPLACE6():"); for (ioffset = 0; ioffset <= INDEXES; ++ioffset) { INIT; PRINTLEAF("Before", ioffset, 6, oleaf6); JU_INSERTINPLACE6(oleaf6, INDEXES, ioffset, oIndex); PrintLeaf("After ", ioffset, 6, oleaf6); } (void) puts("\nJU_INSERTINPLACE7():"); for (ioffset = 0; ioffset <= INDEXES; ++ioffset) { INIT; PRINTLEAF("Before", ioffset, 7, oleaf7); JU_INSERTINPLACE7(oleaf7, INDEXES, ioffset, oIndex); PrintLeaf("After ", ioffset, 7, oleaf7); } #endif // JU_64BIT (void) puts("\nJU_DELETEINPLACE():"); for (ioffset = 0; ioffset < INDEXES; ++ioffset) { INIT; PRINTLEAF("Before", ioffset, WSIZE, (uint8_t *) eleaf); JU_DELETEINPLACE(eleaf, INDEXES, ioffset); PrintLeaf("After ", ioffset, WSIZE, (uint8_t *) eleaf); } (void) puts("\nJU_DELETEINPLACE_ODD(3):"); for (ioffset = 0; ioffset < INDEXES; ++ioffset) { INIT; PRINTLEAF("Before", ioffset, 3, oleaf3); JU_DELETEINPLACE_ODD(oleaf3, INDEXES, ioffset, 3); PrintLeaf("After ", ioffset, 3, oleaf3); } #ifdef JU_64BIT (void) puts("\nJU_DELETEINPLACE_ODD(5):"); for (ioffset = 0; ioffset < INDEXES; ++ioffset) { INIT; PRINTLEAF("Before", ioffset, 5, oleaf5); JU_DELETEINPLACE_ODD(oleaf5, INDEXES, ioffset, 5); PrintLeaf("After ", ioffset, 5, oleaf5); } (void) puts("\nJU_DELETEINPLACE_ODD(6):"); for (ioffset = 0; ioffset < INDEXES; ++ioffset) { INIT; PRINTLEAF("Before", ioffset, 6, oleaf6); JU_DELETEINPLACE_ODD(oleaf6, INDEXES, ioffset, 6); PrintLeaf("After ", ioffset, 6, oleaf6); } (void) puts("\nJU_DELETEINPLACE_ODD(7):"); for (ioffset = 0; ioffset < INDEXES; ++ioffset) { INIT; PRINTLEAF("Before", ioffset, 7, oleaf7); JU_DELETEINPLACE_ODD(oleaf7, INDEXES, ioffset, 7); PrintLeaf("After ", ioffset, 7, oleaf7); } #endif // JU_64BIT (void) puts("\nJU_INSERTCOPY():"); for (ioffset = 0; ioffset <= INDEXES; ++ioffset) { INIT2; PRINTLEAF("Before, src ", ioffset, WSIZE, (uint8_t *) eleaf); PRINTLEAF("Before, dest", ioffset, WSIZE, (uint8_t *) eleaf_2); JU_INSERTCOPY(eleaf_2, eleaf, INDEXES, ioffset, eIndex); PRINTLEAF("After, src ", ioffset, WSIZE, (uint8_t *) eleaf); PrintLeaf("After, dest", ioffset, WSIZE, (uint8_t *) eleaf_2); } (void) puts("\nJU_INSERTCOPY3():"); for (ioffset = 0; ioffset <= INDEXES; ++ioffset) { INIT2; PRINTLEAF("Before, src ", ioffset, 3, oleaf3); PRINTLEAF("Before, dest", ioffset, 3, oleaf3_2); JU_INSERTCOPY3(oleaf3_2, oleaf3, INDEXES, ioffset, oIndex); PRINTLEAF("After, src ", ioffset, 3, oleaf3); PrintLeaf("After, dest", ioffset, 3, oleaf3_2); } #ifdef JU_64BIT (void) puts("\nJU_INSERTCOPY5():"); for (ioffset = 0; ioffset <= INDEXES; ++ioffset) { INIT2; PRINTLEAF("Before, src ", ioffset, 5, oleaf5); PRINTLEAF("Before, dest", ioffset, 5, oleaf5_2); JU_INSERTCOPY5(oleaf5_2, oleaf5, INDEXES, ioffset, oIndex); PRINTLEAF("After, src ", ioffset, 5, oleaf5); PrintLeaf("After, dest", ioffset, 5, oleaf5_2); } (void) puts("\nJU_INSERTCOPY6():"); for (ioffset = 0; ioffset <= INDEXES; ++ioffset) { INIT2; PRINTLEAF("Before, src ", ioffset, 6, oleaf6); PRINTLEAF("Before, dest", ioffset, 6, oleaf6_2); JU_INSERTCOPY6(oleaf6_2, oleaf6, INDEXES, ioffset, oIndex); PRINTLEAF("After, src ", ioffset, 6, oleaf6); PrintLeaf("After, dest", ioffset, 6, oleaf6_2); } (void) puts("\nJU_INSERTCOPY7():"); for (ioffset = 0; ioffset <= INDEXES; ++ioffset) { INIT2; PRINTLEAF("Before, src ", ioffset, 7, oleaf7); PRINTLEAF("Before, dest", ioffset, 7, oleaf7_2); JU_INSERTCOPY7(oleaf7_2, oleaf7, INDEXES, ioffset, oIndex); PRINTLEAF("After, src ", ioffset, 7, oleaf7); PrintLeaf("After, dest", ioffset, 7, oleaf7_2); } #endif // JU_64BIT (void) puts("\nJU_DELETECOPY():"); for (ioffset = 0; ioffset < INDEXES; ++ioffset) { INIT2; PRINTLEAF("Before, src ", ioffset, WSIZE, (uint8_t *) eleaf); PRINTLEAF("Before, dest", ioffset, WSIZE, (uint8_t *) eleaf_2); JU_DELETECOPY(eleaf_2, eleaf, INDEXES, ioffset, ignore); PRINTLEAF("After, src ", ioffset, WSIZE, (uint8_t *) eleaf); PrintLeaf("After, dest", ioffset, WSIZE, (uint8_t *) eleaf_2); } (void) puts("\nJU_DELETECOPY_ODD(3):"); for (ioffset = 0; ioffset < INDEXES; ++ioffset) { INIT2; PRINTLEAF("Before, src ", ioffset, 3, oleaf3); PRINTLEAF("Before, dest", ioffset, 3, oleaf3_2); JU_DELETECOPY_ODD(oleaf3_2, oleaf3, INDEXES, ioffset, 3); PRINTLEAF("After, src ", ioffset, 3, oleaf3); PrintLeaf("After, dest", ioffset, 3, oleaf3_2); } #ifdef JU_64BIT (void) puts("\nJU_DELETECOPY_ODD(5):"); for (ioffset = 0; ioffset < INDEXES; ++ioffset) { INIT2; PRINTLEAF("Before, src ", ioffset, 5, oleaf5); PRINTLEAF("Before, dest", ioffset, 5, oleaf5_2); JU_DELETECOPY_ODD(oleaf5_2, oleaf5, INDEXES, ioffset, 5); PRINTLEAF("After, src ", ioffset, 5, oleaf5); PrintLeaf("After, dest", ioffset, 5, oleaf5_2); } (void) puts("\nJU_DELETECOPY_ODD(6):"); for (ioffset = 0; ioffset < INDEXES; ++ioffset) { INIT2; PRINTLEAF("Before, src ", ioffset, 6, oleaf6); PRINTLEAF("Before, dest", ioffset, 6, oleaf6_2); JU_DELETECOPY_ODD(oleaf6_2, oleaf6, INDEXES, ioffset, 6); PRINTLEAF("After, src ", ioffset, 6, oleaf6); PrintLeaf("After, dest", ioffset, 6, oleaf6_2); } (void) puts("\nJU_DELETECOPY_ODD(7):"); for (ioffset = 0; ioffset < INDEXES; ++ioffset) { INIT2; PRINTLEAF("Before, src ", ioffset, 7, oleaf7); PRINTLEAF("Before, dest", ioffset, 7, oleaf7_2); JU_DELETECOPY_ODD(oleaf7_2, oleaf7, INDEXES, ioffset, 7); PRINTLEAF("After, src ", ioffset, 7, oleaf7); PrintLeaf("After, dest", ioffset, 7, oleaf7_2); } #endif // JU_64BIT return(0); } // main() #endif // TEST_INSDEL judy-1.0.5/src/JudyCommon/JudyMemUsed.c0000644000175000017500000000341210204462077020130 0ustar troyhebetroyhebe// Copyright (C) 2000 - 2002 Hewlett-Packard Company // // This program is free software; you can redistribute it and/or modify it // under the term of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License // for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program; if not, write to the Free Software Foundation, // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // _________________ // @(#) $Revision: 4.5 $ $Source: /judy/src/JudyCommon/JudyMemUsed.c $ // // Return number of bytes of memory used to support a Judy1/L array. // Compile with one of -DJUDY1 or -DJUDYL. #if (! (defined(JUDY1) || defined(JUDYL))) #error: One of -DJUDY1 or -DJUDYL must be specified. #endif #ifdef JUDY1 #include "Judy1.h" #else #include "JudyL.h" #endif #include "JudyPrivate1L.h" #ifdef JUDY1 FUNCTION Word_t Judy1MemUsed #else // JUDYL FUNCTION Word_t JudyLMemUsed #endif ( Pcvoid_t PArray // from which to retrieve. ) { Word_t Words = 0; if (PArray == (Pcvoid_t) NULL) return(0); if (JU_LEAFW_POP0(PArray) < cJU_LEAFW_MAXPOP1) // must be a LEAFW { Pjlw_t Pjlw = P_JLW(PArray); // first word of leaf. Words = JU_LEAFWPOPTOWORDS(Pjlw[0] + 1); // based on pop1. } else { Pjpm_t Pjpm = P_JPM(PArray); Words = Pjpm->jpm_TotalMemWords; } return(Words * sizeof(Word_t)); // convert to bytes. } // Judy1MemUsed() / JudyLMemUsed() judy-1.0.5/src/JudyHS/0000755000175000017500000000000010624600216014646 5ustar troyhebetroyhebejudy-1.0.5/src/JudyHS/Makefile.am0000644000175000017500000000026010624600161016677 0ustar troyhebetroyhebeINCLUDES = -I. -I.. -I../JudyCommon/ AM_CFLAGS = @CFLAGS@ @WARN_CFLAGS@ noinst_LTLIBRARIES = libJudyHS.la libJudyHS_la_SOURCES = JudyHS.c DISTCLEANFILES = .deps Makefile judy-1.0.5/src/JudyHS/JudyHS.c0000644000175000017500000006776010204462077016205 0ustar troyhebetroyhebe// @(#) $Revision: 4.1 $ $Source: /judy/src/JudyHS/JudyHS.c //======================================================================= // Author Douglas L. Baskins, Dec 2003. // Permission to use this code is freely granted, provided that this // statement is retained. // email - doug@sourcejudy.com -or- dougbaskins@yahoo.com //======================================================================= #include // for memcmp(), memcpy() #include // for JudyL* routines/macros /* This routine is a very fast "string" version of an ADT that stores (JudyHSIns()), retrieves (JudyHSGet()), deletes (JudyHSDel()) and frees the entire ADT (JudyHSFreeArray()) strings. It uses the "Judy arrays" JudyL() API as the main workhorse. The length of the string is included in the calling parameters so that strings with embedded \0s can be used. The string lengths can be from 0 bytes to whatever malloc() can handle (~2GB). Compile: cc -O JudyHS.c -c needs to link with -lJudy (libJudy.a) Note: in gcc version 3.3.1, -O2 generates faster code than -O Note: in gcc version 3.3.2, -O3 generates faster code than -O2 NOTES: 1) There may be some performance issues with 64 bit machines, because I have not characterized that it yet. 2) It appears that a modern CPU (>2Ghz) that the instruction times are much faster that a RAM access, so building up a word from bytes takes no longer that a whole word access. I am taking advantage of this to make this code endian neutral. A side effect of this is strings do not need to be aligned, nor tested to be on to a word boundry. In older and in slow (RISC) machines, this may be a performance issue. I have given up trying to optimize for machines that have very slow mpy, mod, variable shifts and call returns. 3) JudyHS is very scalable from 1 string to billions (with enough RAM). The memory usage is also scales with population. I have attempted to combine the best characteristics of JudyL arrays with Hashing methods and well designed modern processors (such as the 1.3Ghz Intel Centrino this is being written on). HOW JudyHS WORKS: ( 4[8] means 4 bytes in 32 bit machine and 8 in 64) A) A JudyL array is used to separate strings of equal lengths into their own structures (a different hash table is used for each length of string). The additional time overhead is very near zero because of the CPU cache. The space efficiency is improved because the length need not be stored with the string (ls_t). The "JLHash" ADT in the test program "StringCompare" is verification of both these assumptions. B) A 32 bit hash value is produced from the string. Many thanks to the Internet and the author (Bob Jenkins) for coming up with a very good and fast universal string hash. Next the 32 bit hash number is used as an Index to another JudyL array. Notice that one (1) JudyL array is used as a hash table per each string length. If there are no hash collisions (normally) then the string is copied to a structure (ls_t) along with room for storing a Value. A flag is added to the pointer to note it is pointing to a ls_t structure. Since the lengths of the strings are the same, there is no need to stored length of string in the ls_t structure. This saves about a word per string of memory. C) When there is a hashing collision (very rare), a JudyL array is used to decode the next 4[8] bytes of the string. That is, the next 4[8] bytes of the string are used as the Index. This process is repeated until the remaining string is unique. The remaining string (if any) is stored in a (now smaller) ls_t structure. If the remaining string is less or equal to 4[8] bytes, then the ls_t structure is not needed and the Value area in the JudyL array is used. A compile option -DDONOTUSEHASH is available to test this structure without using hashing (only the JudyL tree is used). This is equivalent to having all strings hashed to the same bucket. The speed is still better than all other tree based ADTs I have tested. An added benefit of this is a very fast "hash collision" resolving. It could foil hackers that exploit the slow synonym (linked-list) collision handling property used with most hashing algorithms. If this is not a necessary property, then a simpler ADT "JLHash" that is documented the the test program "StringCompare.c" may be used with a little loss of memory efficiency (because it includes the string length with the ls_t structure). JudyHS was written to be the fastest, very scalable, memory efficient, general purpose string ADT possible. (However, I would like to eat those words someday). (dlb) */ #ifdef EXAMPLE_CODE #include #include #include #include //#include "JudyHS.h" // for Judy.h without JudyHS*() // By Doug Baskins Apr 2004 - for JudyHS man page #define MAXLINE 1000000 /* max length of line */ char Index[MAXLINE]; // string to check int // Usage: CheckDupLines < file main() { Pvoid_t PJArray = (PWord_t)NULL; // Judy array. PWord_t PValue; // ^ Judy array element. Word_t Bytes; // size of JudyHS array. Word_t LineNumb = 0; // current line number Word_t Dups = 0; // number of duplicate lines while (fgets(Index, MAXLINE, stdin) != (char *)NULL) { LineNumb++; // line number // store string into array JHSI(PValue, PJArray, Index, strlen(Index)); if (*PValue) // check if duplicate { Dups++; // count duplicates printf("Duplicate lines %lu:%lu:%s", *PValue, LineNumb, Index); } else { *PValue = LineNumb; // store Line number } } printf("%lu Duplicates, free JudyHS array of %lu Lines\n", Dups, LineNumb - Dups); JHSFA(Bytes, PJArray); // free array printf("The JudyHS array allocated %lu bytes of memory\n", Bytes); return (0); } #endif // EXAMPLE_CODE // Note: Use JLAP_INVALID, which is non-zero, to mark pointers to a ls_t // This makes it compatable with previous versions of JudyL() #define IS_PLS(PLS) (((Word_t) (PLS)) & JLAP_INVALID) #define CLEAR_PLS(PLS) (((Word_t) (PLS)) & (~JLAP_INVALID)) #define SET_PLS(PLS) (((Word_t) (PLS)) | JLAP_INVALID) #define WORDSIZE (sizeof(Word_t)) // this is the struct used for "leaf" strings. Note that // the Value is followed by a "variable" length ls_String array. // typedef struct L_EAFSTRING { Word_t ls_Value; // Value area (cannot change size) uint8_t ls_String[WORDSIZE]; // to fill out to a Word_t size } ls_t , *Pls_t; #define LS_STRUCTOVD (sizeof(ls_t) - WORDSIZE) // Calculate size of ls_t including the string of length of LEN. // #define LS_WORDLEN(LEN) (((LEN) + LS_STRUCTOVD + WORDSIZE - 1) / WORDSIZE) // Copy from 0..4[8] bytes from string to a Word_t // NOTE: the copy in in little-endian order to take advantage of improved // memory efficiency of JudyLIns() with smaller numbers // #define COPYSTRING4toWORD(WORD,STR,LEN) \ { \ WORD = 0; \ switch(LEN) \ { \ default: /* four and greater */ \ case 4: \ WORD += (Word_t)(((uint8_t *)(STR))[3] << 24); \ case 3: \ WORD += (Word_t)(((uint8_t *)(STR))[2] << 16); \ case 2: \ WORD += (Word_t)(((uint8_t *)(STR))[1] << 8); \ case 1: \ WORD += (Word_t)(((uint8_t *)(STR))[0]); \ case 0: break; \ } \ } #ifdef JU_64BIT // copy from 0..8 bytes from string to Word_t // #define COPYSTRING8toWORD(WORD,STR,LEN) \ { \ WORD = 0UL; \ switch(LEN) \ { \ default: /* eight and greater */ \ case 8: \ WORD += ((Word_t)((uint8_t *)(STR))[7] << 56); \ case 7: \ WORD += ((Word_t)((uint8_t *)(STR))[6] << 48); \ case 6: \ WORD += ((Word_t)((uint8_t *)(STR))[5] << 40); \ case 5: \ WORD += ((Word_t)((uint8_t *)(STR))[4] << 32); \ case 4: \ WORD += ((Word_t)((uint8_t *)(STR))[3] << 24); \ case 3: \ WORD += ((Word_t)((uint8_t *)(STR))[2] << 16); \ case 2: \ WORD += ((Word_t)((uint8_t *)(STR))[1] << 8); \ case 1: \ WORD += ((Word_t)((uint8_t *)(STR))[0]); \ case 0: break; \ } \ } #define COPYSTRINGtoWORD COPYSTRING8toWORD #else // JU_32BIT #define COPYSTRINGtoWORD COPYSTRING4toWORD #endif // JU_32BIT // set JError_t locally #define JU_SET_ERRNO(PJERROR, JERRNO) \ { \ if (PJERROR != (PJError_t) NULL) \ { \ if (JERRNO) \ JU_ERRNO(PJError) = (JERRNO); \ JU_ERRID(PJERROR) = __LINE__; \ } \ } //======================================================================= // This routine must hash string to 24..32 bits. The "goodness" of // the hash is not as important as its speed. //======================================================================= // hash to no more than 32 bits // extern Word_t gHmask; for hash bits experiments #define JUDYHASHSTR(HVALUE,STRING,LENGTH) \ { \ uint8_t *p_ = (uint8_t *)(STRING); \ uint8_t *q_ = p_ + (LENGTH); \ uint32_t c_ = 0; \ for (; p_ != q_; ++p_) \ { \ c_ = (c_ * 31) + *p_; \ } \ /* c_ &= gHmask; see above */ \ (HVALUE) = c_; \ } // Find String of Len in JudyHS structure, return pointer to associated Value PPvoid_t JudyHSGet(Pcvoid_t PArray, // pointer (^) to structure void * Str, // pointer to string Word_t Len // length of string ) { uint8_t *String = (uint8_t *)Str; PPvoid_t PPValue; // pointer to Value Word_t Index; // 4[8] bytes of String JLG(PPValue, PArray, Len); // find hash table for strings of Len if (PPValue == (PPvoid_t) NULL) return ((PPvoid_t) NULL); // no strings of this Len // check for caller error (null pointer) // if ((String == (void *) NULL) && (Len != 0)) return ((PPvoid_t) NULL); // avoid null-pointer dereference #ifndef DONOTUSEHASH if (Len > WORDSIZE) // Hash table not necessary with short { uint32_t HValue; // hash of input string JUDYHASHSTR(HValue, String, Len); // hash to no more than 32 bits JLG(PPValue, *PPValue, (Word_t)HValue); // get ^ to hash bucket if (PPValue == (PPvoid_t) NULL) return ((PPvoid_t) NULL); // no entry in Hash table } #endif // DONOTUSEHASH /* Each JudyL array decodes 4[8] bytes of the string. Since the hash collisions occur very infrequently, the performance is not important. However, even if the Hash code is not used this method still is significantly faster than common tree methods (AVL, Red-Black, Splay, b-tree, etc..). You can compare it yourself with #define DONOTUSEHASH 1 or putting -DDONOTUSEHASH in the cc line. Use the "StringCompare.c" code to compare (9Dec2003 dlb). */ while (Len > WORDSIZE) // traverse tree of JudyL arrays { if (IS_PLS(*PPValue)) // ^ to JudyL array or ls_t struct? { Pls_t Pls; // ls_t struct, termination of tree Pls = (Pls_t) CLEAR_PLS(*PPValue); // remove flag from ^ // if remaining string matches, return ^ to Value, else NULL if (memcmp(String, Pls->ls_String, Len) == 0) return ((PPvoid_t) (&(Pls->ls_Value))); else return ((PPvoid_t) NULL); // string does not match } else { COPYSTRINGtoWORD(Index, String, WORDSIZE); JLG(PPValue, *PPValue, Index); // decode next 4[8] bytes if (PPValue == (PPvoid_t) NULL) // if NULL array, bail out return ((PPvoid_t) NULL); // string does not match String += WORDSIZE; // advance Len -= WORDSIZE; } } // Get remaining 1..4[8] bytes left in string COPYSTRINGtoWORD(Index, String, Len); JLG(PPValue, *PPValue, Index); // decode last 1-4[8] bytes return (PPValue); } // Add string to a tree of JudyL arrays (all lengths must be same) static PPvoid_t insStrJudyLTree(uint8_t * String, // string to add to tree of JudyL arrays Word_t Len, // length of string PPvoid_t PPValue, // pointer to root pointer PJError_t PJError // for returning error info ) { Word_t Index; // next 4[8] bytes of String while (Len > WORDSIZE) // add to JudyL tree { // CASE 1, pointer is to a NULL, make a new ls_t leaf if (*PPValue == (Pvoid_t)NULL) { Pls_t Pls; // memory for a ls_t Pls = (Pls_t) JudyMalloc(LS_WORDLEN(Len)); if (Pls == NULL) { JU_SET_ERRNO(PJError, JU_ERRNO_NOMEM); return (PPJERR); } Pls->ls_Value = 0; // clear Value word memcpy(Pls->ls_String, String, Len); // copy to new struct *PPValue = (Pvoid_t)SET_PLS(Pls); // mark pointer return ((PPvoid_t) (&Pls->ls_Value)); // return ^ to Value } // no exit here // CASE 2: is a ls_t, free (and shorten), then decode into JudyL tree if (IS_PLS(*PPValue)) // pointer to a ls_t? (leaf) { Pls_t Pls; // ^ to ls_t uint8_t *String0; // ^ to string in ls_t Word_t Index0; // 4[8] bytes in string Word_t FreeLen; // length of ls_t PPvoid_t PPsplit; FreeLen = LS_WORDLEN(Len); // length of ls_t Pls = (Pls_t) CLEAR_PLS(*PPValue); // demangle ^ to ls_t String0 = Pls->ls_String; if (memcmp(String, String0, Len) == 0) // check if match? { return ((PPvoid_t) (&Pls->ls_Value)); // yes, duplicate } *PPValue = NULL; // clear ^ to ls_t and make JudyL // This do loop is technically not required, saves multiple JudyFree() // when storing already sorted strings into structure do // decode next 4[8] bytes of string { // with a JudyL array // Note: string0 is always aligned COPYSTRINGtoWORD(Index0, String0, WORDSIZE); String0 += WORDSIZE; COPYSTRINGtoWORD(Index, String, WORDSIZE); String += WORDSIZE; Len -= WORDSIZE; PPsplit = PPValue; // save for split below PPValue = JudyLIns(PPValue, Index0, PJError); if (PPValue == PPJERR) { JU_SET_ERRNO(PJError, 0); return (PPJERR); } } while ((Index0 == Index) && (Len > WORDSIZE)); // finish storing remainder of string that was in the ls_t PPValue = insStrJudyLTree(String0, Len, PPValue, PJError); if (PPValue == PPJERR) { return (PPJERR); } // copy old Value to Value in new struct *(PWord_t)PPValue = Pls->ls_Value; // free the string buffer (ls_t) JudyFree((Pvoid_t)Pls, FreeLen); PPValue = JudyLIns(PPsplit, Index, PJError); if (PPValue == PPJERR) { JU_SET_ERRNO(PJError, 0); return (PPValue); } // finish remainder of newly inserted string PPValue = insStrJudyLTree(String, Len, PPValue, PJError); return (PPValue); } // no exit here // CASE 3, more JudyL arrays, decode to next tree COPYSTRINGtoWORD(Index, String, WORDSIZE); Len -= WORDSIZE; String += WORDSIZE; PPValue = JudyLIns(PPValue, Index, PJError); // next 4[8] bytes if (PPValue == PPJERR) { JU_SET_ERRNO(PJError, 0); return (PPValue); } } // this is done outside of loop so "Len" can be an unsigned number COPYSTRINGtoWORD(Index, String, Len); PPValue = JudyLIns(PPValue, Index, PJError); // remaining 4[8] bytes return (PPValue); } // Insert string to JudyHS structure, return pointer to associated Value PPvoid_t JudyHSIns(PPvoid_t PPArray, // ^ to JudyHashArray name void * Str, // pointer to string Word_t Len, // length of string PJError_t PJError // optional, for returning error info ) { uint8_t * String = (uint8_t *)Str; PPvoid_t PPValue; // string can only be NULL if Len is 0. if ((String == (uint8_t *) NULL) && (Len != 0UL)) { JU_SET_ERRNO(PJError, JU_ERRNO_NULLPINDEX); return (PPJERR); } JLG(PPValue, *PPArray, Len); // JudyL hash table for strings of Len if (PPValue == (PPvoid_t) NULL) // make new if missing, (very rare) { PPValue = JudyLIns(PPArray, Len, PJError); if (PPValue == PPJERR) { JU_SET_ERRNO(PJError, 0); return (PPJERR); } } #ifndef DONOTUSEHASH if (Len > WORDSIZE) { uint32_t HValue; // hash of input string JUDYHASHSTR(HValue, String, Len); // hash to no more than 32 bits PPValue = JudyLIns(PPValue, (Word_t)HValue, PJError); if (PPValue == PPJERR) { JU_SET_ERRNO(PJError, 0); return (PPJERR); } } #endif // DONOTUSEHASH PPValue = insStrJudyLTree(String, Len, PPValue, PJError); // add string return (PPValue); // ^ to Value } // Delete string from tree of JudyL arrays (all Lens must be same) static int delStrJudyLTree(uint8_t * String, // delete from tree of JudyL arrays Word_t Len, // length of string PPvoid_t PPValue, // ^ to hash bucket PJError_t PJError // for returning error info ) { PPvoid_t PPValueN; // next pointer Word_t Index; int Ret; // -1=failed, 1=success, 2=quit del if (IS_PLS(*PPValue)) // is pointer to ls_t? { Pls_t Pls; Pls = (Pls_t) CLEAR_PLS(*PPValue); // demangle pointer JudyFree((Pvoid_t)Pls, LS_WORDLEN(Len)); // free the ls_t *PPValue = (Pvoid_t)NULL; // clean pointer return (1); // successfully deleted } if (Len > WORDSIZE) // delete from JudyL tree, not leaf { COPYSTRINGtoWORD(Index, String, WORDSIZE); // get Index JLG(PPValueN, *PPValue, Index); // get pointer to next JudyL array String += WORDSIZE; // advance to next 4[8] bytes Len -= WORDSIZE; Ret = delStrJudyLTree(String, Len, PPValueN, PJError); if (Ret != 1) return(Ret); if (*PPValueN == (PPvoid_t) NULL) { // delete JudyL element from tree Ret = JudyLDel(PPValue, Index, PJError); } } else { COPYSTRINGtoWORD(Index, String, Len); // get leaf element // delete last 1-4[8] bytes from leaf element Ret = JudyLDel(PPValue, Index, PJError); } return (Ret); } // Delete string from JHS structure int JudyHSDel(PPvoid_t PPArray, // ^ to JudyHashArray struct void * Str, // pointer to string Word_t Len, // length of string PJError_t PJError // optional, for returning error info ) { uint8_t * String = (uint8_t *)Str; PPvoid_t PPBucket, PPHtble; int Ret; // return bool from Delete routine #ifndef DONOTUSEHASH uint32_t HValue = 0; // hash value of input string #endif // DONOTUSEHASH if (PPArray == NULL) return (0); // no pointer, return not found // This is a little slower than optimum method, but not much in new CPU // Verify that string is in the structure -- simplifies future assumptions if (JudyHSGet(*PPArray, String, Len) == (PPvoid_t) NULL) return (0); // string not found, return // string is in structure, so testing for absence is not necessary JLG(PPHtble, *PPArray, Len); // JudyL hash table for strings of Len #ifdef DONOTUSEHASH PPBucket = PPHtble; // simulate below code #else // USEHASH if (Len > WORDSIZE) { JUDYHASHSTR(HValue, String, Len); // hash to no more than 32 bits // get pointer to hash bucket JLG(PPBucket, *PPHtble, (Word_t)HValue); } else { PPBucket = PPHtble; // no bucket to JLGet } #endif // USEHASH // delete from JudyL tree // Ret = delStrJudyLTree(String, Len, PPBucket, PJError); if (Ret != 1) { JU_SET_ERRNO(PJError, 0); return(-1); } // handle case of missing JudyL array from hash table and length table if (*PPBucket == (Pvoid_t)NULL) // if JudyL tree gone { #ifndef DONOTUSEHASH if (Len > WORDSIZE) { // delete entry in Hash table Ret = JudyLDel(PPHtble, (Word_t)HValue, PJError); if (Ret != 1) { JU_SET_ERRNO(PJError, 0); return(-1); } } #endif // USEHASH if (*PPHtble == (PPvoid_t) NULL) // if Hash table gone { // delete entry from the String length table Ret = JudyLDel(PPArray, Len, PJError); if (Ret != 1) { JU_SET_ERRNO(PJError, 0); return(-1); } } } return (1); // success } static Word_t delJudyLTree(PPvoid_t PPValue, // ^ to JudyL root pointer Word_t Len, // length of string PJError_t PJError) // for returning error info { Word_t bytes_freed = 0; // bytes freed at point Word_t bytes_total = 0; // accumulated bytes freed PPvoid_t PPValueN; // Pointer is to another tree of JudyL arrays or ls_t struct if (Len > WORDSIZE) // more depth to tree { Word_t NEntry; // Pointer is to a ls_t struct if (IS_PLS(*PPValue)) { Pls_t Pls; Word_t freewords; freewords = LS_WORDLEN(Len); // calculate length Pls = (Pls_t)CLEAR_PLS(*PPValue); // demangle pointer // *PPValue = (Pvoid_t)NULL; // clean pointer JudyFree((Pvoid_t)Pls, freewords); // free the ls_t return(freewords * WORDSIZE); } // else // Walk all the entrys in the JudyL array NEntry = 0; // start at beginning for (PPValueN = JudyLFirst(*PPValue, &NEntry, PJError); (PPValueN != (PPvoid_t) NULL) && (PPValueN != PPJERR); PPValueN = JudyLNext(*PPValue, &NEntry, PJError)) { // recurse to the next level in the tree of arrays bytes_freed = delJudyLTree(PPValueN, Len - WORDSIZE, PJError); if (bytes_freed == JERR) return(JERR); bytes_total += bytes_freed; } if (PPValueN == PPJERR) return(JERR); // now free this JudyL array bytes_freed = JudyLFreeArray(PPValue, PJError); if (bytes_freed == JERR) return(JERR); bytes_total += bytes_freed; return(bytes_total); // return amount freed } // else // Pointer to simple JudyL array bytes_freed = JudyLFreeArray(PPValue, PJError); return(bytes_freed); } Word_t // bytes freed JudyHSFreeArray(PPvoid_t PPArray, // ^ to JudyHashArray struct PJError_t PJError // optional, for returning error info ) { Word_t Len; // start at beginning Word_t bytes_freed; // bytes freed at this level. Word_t bytes_total; // bytes total at all levels. PPvoid_t PPHtble; if (PPArray == NULL) return (0); // no pointer, return none // Walk the string length table for subsidary hash structs // NOTE: This is necessary to determine the depth of the tree bytes_freed = 0; bytes_total = 0; Len = 0; // walk to length table for (PPHtble = JudyLFirst(*PPArray, &Len, PJError); (PPHtble != (PPvoid_t) NULL) && (PPHtble != PPJERR); PPHtble = JudyLNext(*PPArray, &Len, PJError)) { PPvoid_t PPValueH; #ifndef DONOTUSEHASH if (Len > WORDSIZE) { Word_t HEntry = 0; // walk the hash tables for (PPValueH = JudyLFirst(*PPHtble, &HEntry, PJError); (PPValueH != (PPvoid_t) NULL) && (PPValueH != PPJERR); PPValueH = JudyLNext(*PPHtble, &HEntry, PJError)) { bytes_freed = delJudyLTree(PPValueH, Len, PJError); if (bytes_freed == JERR) return(JERR); bytes_total += bytes_freed; } if (PPValueH == PPJERR) return(JERR); // free the Hash table for this length of string bytes_freed = JudyLFreeArray(PPHtble, PJError); if (bytes_freed == JERR) return(JERR); bytes_total += bytes_freed; } else #endif // DONOTUSEHASH { PPValueH = PPHtble; // simulate hash table bytes_freed = delJudyLTree(PPValueH, Len, PJError); if (bytes_freed == JERR) return(JERR); bytes_total += bytes_freed; } } if (PPHtble == PPJERR) return(JERR); // free the length table bytes_freed = JudyLFreeArray(PPArray, PJError); if (bytes_freed == JERR) return(JERR); bytes_total += bytes_freed; return(bytes_total); // return bytes freed } judy-1.0.5/src/JudyHS/Makefile.in0000644000175000017500000003212710624600216016720 0ustar troyhebetroyhebe# Makefile.in generated by automake 1.9.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ top_builddir = ../.. am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd INSTALL = @INSTALL@ install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/JudyHS DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libJudyHS_la_LIBADD = am_libJudyHS_la_OBJECTS = JudyHS.lo libJudyHS_la_OBJECTS = $(am_libJudyHS_la_OBJECTS) DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ SOURCES = $(libJudyHS_la_SOURCES) DIST_SOURCES = $(libJudyHS_la_SOURCES) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMDEP_FALSE = @AMDEP_FALSE@ AMDEP_TRUE = @AMDEP_TRUE@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO = @ECHO@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ F77 = @F77@ FFLAGS = @FFLAGS@ FLAVOR = @FLAVOR@ GREP = @GREP@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ MAKEINFO = @MAKEINFO@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ VERSION_INFO = @VERSION_INFO@ WARN_CFLAGS = @WARN_CFLAGS@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_F77 = @ac_ct_F77@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ INCLUDES = -I. -I.. -I../JudyCommon/ AM_CFLAGS = @CFLAGS@ @WARN_CFLAGS@ noinst_LTLIBRARIES = libJudyHS.la libJudyHS_la_SOURCES = JudyHS.c DISTCLEANFILES = .deps Makefile all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/JudyHS/Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --gnu src/JudyHS/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libJudyHS.la: $(libJudyHS_la_OBJECTS) $(libJudyHS_la_DEPENDENCIES) $(LINK) $(libJudyHS_la_LDFLAGS) $(libJudyHS_la_OBJECTS) $(libJudyHS_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/JudyHS.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs distclean-libtool: -rm -f libtool uninstall-info-am: ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$tags $$unique; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ test -z "$(CTAGS_ARGS)$$tags$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$tags $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && cd $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) $$here distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ list='$(DISTFILES)'; for file in $$list; do \ case $$file in \ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ esac; \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ if test "$$dir" != "$$file" && test "$$dir" != "."; then \ dir="/$$dir"; \ $(mkdir_p) "$(distdir)$$dir"; \ else \ dir=''; \ fi; \ if test -d $$d/$$file; then \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-libtool distclean-tags dvi: dvi-am dvi-am: html: html-am info: info-am info-am: install-data-am: install-exec-am: install-info: install-info-am install-man: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-info-am .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLTLIBRARIES ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-exec \ install-exec-am install-info install-info-am install-man \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags uninstall uninstall-am \ uninstall-info-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: judy-1.0.5/src/JudyHS/JudyHS.h0000644000175000017500000000340210204462077016171 0ustar troyhebetroyhebe// **************************************************************************** // Quick and dirty header file for use with old Judy.h without JudyHS defs // May 2004 (dlb) - No copyright or license -- it is free period. #include // **************************************************************************** // JUDYHSL MACROS: #define JHSI(PV, PArray, PIndex, Count) \ J_2P(PV, (&(PArray)), PIndex, Count, JudyHSIns, "JudyHSIns") #define JHSG(PV, PArray, PIndex, Count) \ (PV) = (Pvoid_t) JudyHSGet(PArray, PIndex, Count) #define JHSD(Rc, PArray, PIndex, Count) \ J_2I(Rc, (&(PArray)), PIndex, Count, JudyHSDel, "JudyHSDel") #define JHSFA(Rc, PArray) \ J_0I(Rc, (&(PArray)), JudyHSFreeArray, "JudyHSFreeArray") // **************************************************************************** // JUDY memory interface to malloc() FUNCTIONS: extern Word_t JudyMalloc(Word_t); // words reqd => words allocd. extern Word_t JudyMallocVirtual(Word_t); // words reqd => words allocd. extern void JudyFree(Pvoid_t, Word_t); // block to free and its size in words. extern void JudyFreeVirtual(Pvoid_t, Word_t); // block to free and its size in words. // **************************************************************************** // JUDYHS FUNCTIONS: extern PPvoid_t JudyHSGet( Pcvoid_t, void *, Word_t); extern PPvoid_t JudyHSIns( PPvoid_t, void *, Word_t, P_JE); extern int JudyHSDel( PPvoid_t, void *, Word_t, P_JE); extern Word_t JudyHSFreeArray( PPvoid_t, P_JE); extern uint32_t JudyHashStr( void *, Word_t); judy-1.0.5/src/JudyHS/README0000644000175000017500000000062110204462077015532 0ustar troyhebetroyhebe# @(#) $Revision: 4.22 $ $Source: /judy/src/JudyHS/README $ # This tree contains sources for the JudyHS*() functions. # # Note: At one time, all of the Judy sources were split between Judy1/ and # JudyL/ variants, but now most of them are merged in JudyCommon/ and this # directory is vestigal. JudyHS.h header for using JudyHS.c with older versions of Judy.h JudyHS.c source of JudyHS functions judy-1.0.5/src/build.bat0000755000175000017500000001733110204462077015304 0ustar troyhebetroyhebe@ECHO OFF echo Set Compiler SET CC=cl echo Set Options SET COPT=-DJU_WIN SET O=-DJUDY1 SET L=-DJUDYL SET INC=-I.. -I..\JudyCommon echo Deleting Old Files del JudyCommon\*.obj JudySL\*.obj JudyHS\*.obj Judy1\*.obj JudyL\*.obj *.dll echo Giving Judy1 the proper Names copy JudyCommon\JudyByCount.c Judy1\Judy1ByCount.c copy JudyCommon\JudyCascade.c Judy1\Judy1Cascade.c copy JudyCommon\JudyCount.c Judy1\Judy1Count.c copy JudyCommon\JudyCreateBranch.c Judy1\Judy1CreateBranch.c copy JudyCommon\JudyDecascade.c Judy1\Judy1Decascade.c copy JudyCommon\JudyDel.c Judy1\Judy1Unset.c copy JudyCommon\JudyFirst.c Judy1\Judy1First.c copy JudyCommon\JudyFreeArray.c Judy1\Judy1FreeArray.c copy JudyCommon\JudyGet.c Judy1\Judy1Test.c copy JudyCommon\JudyGet.c Judy1\j__udy1Test.c copy JudyCommon\JudyInsArray.c Judy1\Judy1SetArray.c copy JudyCommon\JudyIns.c Judy1\Judy1Set.c copy JudyCommon\JudyInsertBranch.c Judy1\Judy1InsertBranch.c copy JudyCommon\JudyMallocIF.c Judy1\Judy1MallocIF.c copy JudyCommon\JudyMemActive.c Judy1\Judy1MemActive.c copy JudyCommon\JudyMemUsed.c Judy1\Judy1MemUsed.c copy JudyCommon\JudyPrevNext.c Judy1\Judy1Next.c copy JudyCommon\JudyPrevNext.c Judy1\Judy1Prev.c copy JudyCommon\JudyPrevNextEmpty.c Judy1\Judy1NextEmpty.c copy JudyCommon\JudyPrevNextEmpty.c Judy1\Judy1PrevEmpty.c copy JudyCommon\JudyTables.c Judy1\Judy1TablesGen.c echo Giving JudyL the proper Names copy JudyCommon\JudyByCount.c JudyL\JudyLByCount.c copy JudyCommon\JudyCascade.c JudyL\JudyLCascade.c copy JudyCommon\JudyCount.c JudyL\JudyLCount.c copy JudyCommon\JudyCreateBranch.c JudyL\JudyLCreateBranch.c copy JudyCommon\JudyDecascade.c JudyL\JudyLDecascade.c copy JudyCommon\JudyDel.c JudyL\JudyLDel.c copy JudyCommon\JudyFirst.c JudyL\JudyLFirst.c copy JudyCommon\JudyFreeArray.c JudyL\JudyLFreeArray.c copy JudyCommon\JudyGet.c JudyL\JudyLGet.c copy JudyCommon\JudyGet.c JudyL\j__udyLGet.c copy JudyCommon\JudyInsArray.c JudyL\JudyLInsArray.c copy JudyCommon\JudyIns.c JudyL\JudyLIns.c copy JudyCommon\JudyInsertBranch.c JudyL\JudyLInsertBranch.c copy JudyCommon\JudyMallocIF.c JudyL\JudyLMallocIF.c copy JudyCommon\JudyMemActive.c JudyL\JudyLMemActive.c copy JudyCommon\JudyMemUsed.c JudyL\JudyLMemUsed.c copy JudyCommon\JudyPrevNext.c JudyL\JudyLNext.c copy JudyCommon\JudyPrevNext.c JudyL\JudyLPrev.c copy JudyCommon\JudyPrevNextEmpty.c JudyL\JudyLNextEmpty.c copy JudyCommon\JudyPrevNextEmpty.c JudyL\JudyLPrevEmpty.c copy JudyCommon\JudyTables.c JudyL\JudyLTablesGen.c echo Compile JudyCommon\JudyMalloc - common to Judy1 and JudyL cd JudyCommon %CC% -I. -I.. -DJU_WIN -c JudyMalloc.c cd .. echo This table is constructed from Juudy1.h data to match malloc(3) needs cd Judy1 %CC% %INC% %COPT% %O% Judy1TablesGen.c -o Judy1TablesGen del Judy1TablesGen.obj Judy1TablesGen %CC% %INC% %COPT% %O% -c Judy1Tables.c echo compile the main line Judy1 modules echo %CC% %INC% %COPT% %O% -c Judy1Test.c %CC% %INC% %COPT% %O% -c Judy1Test.c echo %CC% %INC% %COPT% %O% -c -DJUDYGETINLINE j__udy1Test.c %CC% %INC% %COPT% %O% -c -DJUDYGETINLINE j__udy1Test.c echo %CC% %INC% %COPT% %O% -c Judy1Set.c %CC% %INC% %COPT% %O% -c Judy1Set.c echo %CC% %INC% %COPT% %O% -c Judy1SetArray.c %CC% %INC% %COPT% %O% -c Judy1SetArray.c echo %CC% %INC% %COPT% %O% -c Judy1Unset.c %CC% %INC% %COPT% %O% -c Judy1Unset.c echo %CC% %INC% %COPT% %O% -c Judy1First.c %CC% %INC% %COPT% %O% -c Judy1First.c echo %CC% %INC% %COPT% %O% -DJUDYNEXT -c Judy1Next.c %CC% %INC% %COPT% %O% -DJUDYNEXT -c Judy1Next.c echo %CC% %INC% %COPT% %O% -DJUDYPREV -c Judy1Prev.c %CC% %INC% %COPT% %O% -DJUDYPREV -c Judy1Prev.c echo %CC% %INC% %COPT% %O% -DJUDYNEXT -c Judy1NextEmpty.c %CC% %INC% %COPT% %O% -DJUDYNEXT -c Judy1NextEmpty.c echo %CC% %INC% %COPT% %O% -DJUDYPREV -c Judy1PrevEmpty.c %CC% %INC% %COPT% %O% -DJUDYPREV -c Judy1PrevEmpty.c echo %CC% %INC% %COPT% %O% -c Judy1Count.c %CC% %INC% %COPT% %O% -c Judy1Count.c echo %CC% %INC% %COPT% %O% -c -DNOSMARTJBB -DNOSMARTJBU -DNOSMARTJLB Judy1ByCount.c %CC% %INC% %COPT% %O% -c -DNOSMARTJBB -DNOSMARTJBU -DNOSMARTJLB Judy1ByCount.c echo %CC% %INC% %COPT% %O% -c Judy1FreeArray.c %CC% %INC% %COPT% %O% -c Judy1FreeArray.c echo %CC% %INC% %COPT% %O% -c Judy1MemUsed.c %CC% %INC% %COPT% %O% -c Judy1MemUsed.c echo %CC% %INC% %COPT% %O% -c Judy1MemActive.c %CC% %INC% %COPT% %O% -c Judy1MemActive.c echo %CC% %INC% %COPT% %O% -c Judy1Cascade.c %CC% %INC% %COPT% %O% -c Judy1Cascade.c echo %CC% %INC% %COPT% %O% -c Judy1Decascade.c %CC% %INC% %COPT% %O% -c Judy1Decascade.c echo %CC% %INC% %COPT% %O% -c Judy1CreateBranch.c %CC% %INC% %COPT% %O% -c Judy1CreateBranch.c echo %CC% %INC% %COPT% %O% -c Judy1InsertBranch.C %CC% %INC% %COPT% %O% -c Judy1InsertBranch.C echo %CC% %INC% %COPT% %O% -c Judy1MallocIF.c %CC% %INC% %COPT% %O% -c Judy1MallocIF.c cd .. cd JudyL echo This table is constructed from Juudy1.h data to match malloc(3) needs %CC% %INC% %COPT% JudyLTablesGen.c %L% -o JudyLTablesGen del JudyLTablesGen.obj JudyLTablesGen %CC% %INC% %COPT% %L% -c JudyLTables.c echo compile the main line JudyL modules echo %CC% %INC% %COPT% %L% -c JudyLGet.c %CC% %INC% %COPT% %L% -c JudyLGet.c echo %CC% %INC% %COPT% %L% -c -DJUDYGETINLINE j__udyLGet.c %CC% %INC% %COPT% %L% -c -DJUDYGETINLINE j__udyLGet.c echo %CC% %INC% %COPT% %L% -c JudyLIns.c %CC% %INC% %COPT% %L% -c JudyLIns.c echo %CC% %INC% %COPT% %L% -c JudyLInsArray.c %CC% %INC% %COPT% %L% -c JudyLInsArray.c echo %CC% %INC% %COPT% %L% -c JudyLDel.c %CC% %INC% %COPT% %L% -c JudyLDel.c echo %CC% %INC% %COPT% %L% -c JudyLFirst.c %CC% %INC% %COPT% %L% -c JudyLFirst.c echo %CC% %INC% %COPT% %L% -c -DJUDYNEXT JudyLNext.c %CC% %INC% %COPT% %L% -c -DJUDYNEXT JudyLNext.c echo %CC% %INC% %COPT% %L% -c -DJUDYPREV JudyLPrev.c %CC% %INC% %COPT% %L% -c -DJUDYPREV JudyLPrev.c echo %CC% %INC% %COPT% %L% -c -DJUDYNEXT JudyLNextEmpty.c %CC% %INC% %COPT% %L% -c -DJUDYNEXT JudyLNextEmpty.c echo %CC% %INC% %COPT% %L% -c -DJUDYPREV JudyLPrevEmpty.c %CC% %INC% %COPT% %L% -c -DJUDYPREV JudyLPrevEmpty.c echo %CC% %INC% %COPT% %L% -c JudyLCount.c %CC% %INC% %COPT% %L% -c JudyLCount.c echo %CC% %INC% %COPT% %L% -c -DNOSMARTJBB -DNOSMARTJBU -DNOSMARTJLB JudyLByCount.c %CC% %INC% %COPT% %L% -c -DNOSMARTJBB -DNOSMARTJBU -DNOSMARTJLB JudyLByCount.c echo %CC% %INC% %COPT% %L% -c JudyLFreeArray.c %CC% %INC% %COPT% %L% -c JudyLFreeArray.c echo %CC% %INC% %COPT% %L% -c JudyLMemUsed.c %CC% %INC% %COPT% %L% -c JudyLMemUsed.c echo %CC% %INC% %COPT% %L% -c JudyLMemActive.c %CC% %INC% %COPT% %L% -c JudyLMemActive.c echo %CC% %INC% %COPT% %L% -c JudyLCascade.c %CC% %INC% %COPT% %L% -c JudyLCascade.c echo %CC% %INC% %COPT% %L% -c JudyLDecascade.c %CC% %INC% %COPT% %L% -c JudyLDecascade.c echo %CC% %INC% %COPT% %L% -c JudyLCreateBranch.c %CC% %INC% %COPT% %L% -c JudyLCreateBranch.c echo %CC% %INC% %COPT% %L% -c JudyLInsertBranch.c %CC% %INC% %COPT% %L% -c JudyLInsertBranch.c echo %CC% %INC% %COPT% %L% -c JudyLMallocIF.c %CC% %INC% %COPT% %L% -c JudyLMallocIF.c cd .. cd JudySL echo Compile the JudySL routine echo %CC% %INC% %COPT% -c JudySL.c %CC% %INC% %COPT% -c JudySL.c cd .. cd JudyHS echo Compile the JudyHS routine echo %CC% %INC% %COPT% -c JudyHS.c %CC% %INC% %COPT% -c JudyHS.c cd .. echo Make a Judy dll by linking all the objects togeather link /DLL JudyCommon\*.obj Judy1\*.obj JudyL\*.obj JudySL\*.obj JudyHS\*.obj /OUT:Judy.dll echo Make a Judy archive library by linking all the objects togeather link /LIB JudyCommon\*.obj Judy1\*.obj JudyL\*.obj JudySL\*.obj JudyHS\*.obj /OUT:Judy.lib judy-1.0.5/src/JudyL/0000755000175000017500000000000010624600216014527 5ustar troyhebetroyhebejudy-1.0.5/src/JudyL/Makefile.in0000644000175000017500000006335410624600216016607 0ustar troyhebetroyhebe# Makefile.in generated by automake 1.9.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ top_builddir = ../.. am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd INSTALL = @INSTALL@ install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/JudyL DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libJudyL_la_LIBADD = am_libJudyL_la_OBJECTS = JudyLCascade.lo JudyLTables.lo JudyLCount.lo \ JudyLCreateBranch.lo JudyLDecascade.lo JudyLDel.lo \ JudyLFirst.lo JudyLFreeArray.lo JudyLGet.lo JudyLInsArray.lo \ JudyLIns.lo JudyLInsertBranch.lo JudyLMallocIF.lo \ JudyLMemActive.lo JudyLMemUsed.lo libJudyL_la_OBJECTS = $(am_libJudyL_la_OBJECTS) libcount_la_LIBADD = am_libcount_la_OBJECTS = libcount_la-JudyLByCount.lo libcount_la_OBJECTS = $(am_libcount_la_OBJECTS) libinline_la_LIBADD = am_libinline_la_OBJECTS = libinline_la-j__udyLGet.lo libinline_la_OBJECTS = $(am_libinline_la_OBJECTS) libnext_la_LIBADD = am_libnext_la_OBJECTS = libnext_la-JudyLNext.lo \ libnext_la-JudyLNextEmpty.lo libnext_la_OBJECTS = $(am_libnext_la_OBJECTS) libprev_la_LIBADD = am_libprev_la_OBJECTS = libprev_la-JudyLPrev.lo \ libprev_la-JudyLPrevEmpty.lo libprev_la_OBJECTS = $(am_libprev_la_OBJECTS) DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ SOURCES = $(libJudyL_la_SOURCES) $(libcount_la_SOURCES) \ $(libinline_la_SOURCES) $(libnext_la_SOURCES) \ $(libprev_la_SOURCES) DIST_SOURCES = $(libJudyL_la_SOURCES) $(libcount_la_SOURCES) \ $(libinline_la_SOURCES) $(libnext_la_SOURCES) \ $(libprev_la_SOURCES) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMDEP_FALSE = @AMDEP_FALSE@ AMDEP_TRUE = @AMDEP_TRUE@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO = @ECHO@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ F77 = @F77@ FFLAGS = @FFLAGS@ FLAVOR = @FLAVOR@ GREP = @GREP@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ MAKEINFO = @MAKEINFO@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ VERSION_INFO = @VERSION_INFO@ WARN_CFLAGS = @WARN_CFLAGS@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_F77 = @ac_ct_F77@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ INCLUDES = -I. -I.. -I../JudyCommon/ AM_CFLAGS = -DJUDYL @WARN_CFLAGS@ noinst_LTLIBRARIES = libJudyL.la libnext.la libprev.la libcount.la libinline.la libJudyL_la_SOURCES = JudyLCascade.c JudyLTables.c JudyLCount.c JudyLCreateBranch.c JudyLDecascade.c JudyLDel.c JudyLFirst.c JudyLFreeArray.c JudyLGet.c JudyLInsArray.c JudyLIns.c JudyLInsertBranch.c JudyLMallocIF.c JudyLMemActive.c JudyLMemUsed.c libnext_la_SOURCES = JudyLNext.c JudyLNextEmpty.c libnext_la_CFLAGS = $(AM_CFLAGS) -DJUDYNEXT libprev_la_SOURCES = JudyLPrev.c JudyLPrevEmpty.c libprev_la_CFLAGS = $(AM_CFLAGS) -DJUDYPREV libcount_la_SOURCES = JudyLByCount.c libcount_la_CFLAGS = $(AM_CFLAGS) -DNOSMARTJBB -DNOSMARTJBU -DNOSMARTJLB libinline_la_SOURCES = j__udyLGet.c libinline_la_CFLAGS = $(AM_CFLAGS) -DJUDYGETINLINE DISTCLEANFILES = .deps Makefile CLEANFILES = JudyLByCount.c \ JudyLCascade.c \ JudyLCount.c \ JudyLCreateBranch.c \ JudyLDecascade.c \ JudyLDel.c \ JudyLFirst.c \ JudyLFreeArray.c \ JudyLGet.c \ j__udyLGet.c \ JudyLInsArray.c \ JudyLIns.c \ JudyLInsertBranch.c \ JudyLMallocIF.c \ JudyLMemActive.c \ JudyLMemUsed.c \ JudyLNext.c \ JudyLPrev.c \ JudyLNextEmpty.c \ JudyLPrevEmpty.c \ JudyLTablesGen.c \ JudyLTables.c \ JudyLTablesGen \ .libs \ *.o \ *.lo \ *.la all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/JudyL/Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --gnu src/JudyL/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libJudyL.la: $(libJudyL_la_OBJECTS) $(libJudyL_la_DEPENDENCIES) $(LINK) $(libJudyL_la_LDFLAGS) $(libJudyL_la_OBJECTS) $(libJudyL_la_LIBADD) $(LIBS) libcount.la: $(libcount_la_OBJECTS) $(libcount_la_DEPENDENCIES) $(LINK) $(libcount_la_LDFLAGS) $(libcount_la_OBJECTS) $(libcount_la_LIBADD) $(LIBS) libinline.la: $(libinline_la_OBJECTS) $(libinline_la_DEPENDENCIES) $(LINK) $(libinline_la_LDFLAGS) $(libinline_la_OBJECTS) $(libinline_la_LIBADD) $(LIBS) libnext.la: $(libnext_la_OBJECTS) $(libnext_la_DEPENDENCIES) $(LINK) $(libnext_la_LDFLAGS) $(libnext_la_OBJECTS) $(libnext_la_LIBADD) $(LIBS) libprev.la: $(libprev_la_OBJECTS) $(libprev_la_DEPENDENCIES) $(LINK) $(libprev_la_LDFLAGS) $(libprev_la_OBJECTS) $(libprev_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/JudyLCascade.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/JudyLCount.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/JudyLCreateBranch.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/JudyLDecascade.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/JudyLDel.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/JudyLFirst.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/JudyLFreeArray.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/JudyLGet.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/JudyLIns.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/JudyLInsArray.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/JudyLInsertBranch.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/JudyLMallocIF.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/JudyLMemActive.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/JudyLMemUsed.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/JudyLTables.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcount_la-JudyLByCount.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libinline_la-j__udyLGet.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnext_la-JudyLNext.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnext_la-JudyLNextEmpty.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libprev_la-JudyLPrev.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libprev_la-JudyLPrevEmpty.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< libcount_la-JudyLByCount.lo: JudyLByCount.c @am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcount_la_CFLAGS) $(CFLAGS) -MT libcount_la-JudyLByCount.lo -MD -MP -MF "$(DEPDIR)/libcount_la-JudyLByCount.Tpo" -c -o libcount_la-JudyLByCount.lo `test -f 'JudyLByCount.c' || echo '$(srcdir)/'`JudyLByCount.c; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libcount_la-JudyLByCount.Tpo" "$(DEPDIR)/libcount_la-JudyLByCount.Plo"; else rm -f "$(DEPDIR)/libcount_la-JudyLByCount.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='JudyLByCount.c' object='libcount_la-JudyLByCount.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcount_la_CFLAGS) $(CFLAGS) -c -o libcount_la-JudyLByCount.lo `test -f 'JudyLByCount.c' || echo '$(srcdir)/'`JudyLByCount.c libinline_la-j__udyLGet.lo: j__udyLGet.c @am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libinline_la_CFLAGS) $(CFLAGS) -MT libinline_la-j__udyLGet.lo -MD -MP -MF "$(DEPDIR)/libinline_la-j__udyLGet.Tpo" -c -o libinline_la-j__udyLGet.lo `test -f 'j__udyLGet.c' || echo '$(srcdir)/'`j__udyLGet.c; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libinline_la-j__udyLGet.Tpo" "$(DEPDIR)/libinline_la-j__udyLGet.Plo"; else rm -f "$(DEPDIR)/libinline_la-j__udyLGet.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='j__udyLGet.c' object='libinline_la-j__udyLGet.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libinline_la_CFLAGS) $(CFLAGS) -c -o libinline_la-j__udyLGet.lo `test -f 'j__udyLGet.c' || echo '$(srcdir)/'`j__udyLGet.c libnext_la-JudyLNext.lo: JudyLNext.c @am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnext_la_CFLAGS) $(CFLAGS) -MT libnext_la-JudyLNext.lo -MD -MP -MF "$(DEPDIR)/libnext_la-JudyLNext.Tpo" -c -o libnext_la-JudyLNext.lo `test -f 'JudyLNext.c' || echo '$(srcdir)/'`JudyLNext.c; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libnext_la-JudyLNext.Tpo" "$(DEPDIR)/libnext_la-JudyLNext.Plo"; else rm -f "$(DEPDIR)/libnext_la-JudyLNext.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='JudyLNext.c' object='libnext_la-JudyLNext.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnext_la_CFLAGS) $(CFLAGS) -c -o libnext_la-JudyLNext.lo `test -f 'JudyLNext.c' || echo '$(srcdir)/'`JudyLNext.c libnext_la-JudyLNextEmpty.lo: JudyLNextEmpty.c @am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnext_la_CFLAGS) $(CFLAGS) -MT libnext_la-JudyLNextEmpty.lo -MD -MP -MF "$(DEPDIR)/libnext_la-JudyLNextEmpty.Tpo" -c -o libnext_la-JudyLNextEmpty.lo `test -f 'JudyLNextEmpty.c' || echo '$(srcdir)/'`JudyLNextEmpty.c; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libnext_la-JudyLNextEmpty.Tpo" "$(DEPDIR)/libnext_la-JudyLNextEmpty.Plo"; else rm -f "$(DEPDIR)/libnext_la-JudyLNextEmpty.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='JudyLNextEmpty.c' object='libnext_la-JudyLNextEmpty.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnext_la_CFLAGS) $(CFLAGS) -c -o libnext_la-JudyLNextEmpty.lo `test -f 'JudyLNextEmpty.c' || echo '$(srcdir)/'`JudyLNextEmpty.c libprev_la-JudyLPrev.lo: JudyLPrev.c @am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libprev_la_CFLAGS) $(CFLAGS) -MT libprev_la-JudyLPrev.lo -MD -MP -MF "$(DEPDIR)/libprev_la-JudyLPrev.Tpo" -c -o libprev_la-JudyLPrev.lo `test -f 'JudyLPrev.c' || echo '$(srcdir)/'`JudyLPrev.c; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libprev_la-JudyLPrev.Tpo" "$(DEPDIR)/libprev_la-JudyLPrev.Plo"; else rm -f "$(DEPDIR)/libprev_la-JudyLPrev.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='JudyLPrev.c' object='libprev_la-JudyLPrev.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libprev_la_CFLAGS) $(CFLAGS) -c -o libprev_la-JudyLPrev.lo `test -f 'JudyLPrev.c' || echo '$(srcdir)/'`JudyLPrev.c libprev_la-JudyLPrevEmpty.lo: JudyLPrevEmpty.c @am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libprev_la_CFLAGS) $(CFLAGS) -MT libprev_la-JudyLPrevEmpty.lo -MD -MP -MF "$(DEPDIR)/libprev_la-JudyLPrevEmpty.Tpo" -c -o libprev_la-JudyLPrevEmpty.lo `test -f 'JudyLPrevEmpty.c' || echo '$(srcdir)/'`JudyLPrevEmpty.c; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libprev_la-JudyLPrevEmpty.Tpo" "$(DEPDIR)/libprev_la-JudyLPrevEmpty.Plo"; else rm -f "$(DEPDIR)/libprev_la-JudyLPrevEmpty.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='JudyLPrevEmpty.c' object='libprev_la-JudyLPrevEmpty.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libprev_la_CFLAGS) $(CFLAGS) -c -o libprev_la-JudyLPrevEmpty.lo `test -f 'JudyLPrevEmpty.c' || echo '$(srcdir)/'`JudyLPrevEmpty.c mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs distclean-libtool: -rm -f libtool uninstall-info-am: ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$tags $$unique; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ test -z "$(CTAGS_ARGS)$$tags$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$tags $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && cd $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) $$here distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ list='$(DISTFILES)'; for file in $$list; do \ case $$file in \ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ esac; \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ if test "$$dir" != "$$file" && test "$$dir" != "."; then \ dir="/$$dir"; \ $(mkdir_p) "$(distdir)$$dir"; \ else \ dir=''; \ fi; \ if test -d $$d/$$file; then \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-libtool distclean-tags dvi: dvi-am dvi-am: html: html-am info: info-am info-am: install-data-am: install-exec-am: install-info: install-info-am install-man: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-info-am .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLTLIBRARIES ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-exec \ install-exec-am install-info install-info-am install-man \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags uninstall uninstall-am \ uninstall-info-am JudyLTables.c: JudyLTablesGen.c $(CC) $(INCLUDES) $(AM_CFLAGS) @CFLAGS@ -o JudyLTablesGen JudyLTablesGen.c; ./JudyLTablesGen JudyLByCount.c: ../JudyCommon/JudyByCount.c cp -f ../JudyCommon/JudyByCount.c JudyLByCount.c JudyLCascade.c:../JudyCommon/JudyCascade.c cp -f ../JudyCommon/JudyCascade.c JudyLCascade.c JudyLCount.c:../JudyCommon/JudyCount.c cp -f ../JudyCommon/JudyCount.c JudyLCount.c JudyLCreateBranch.c:../JudyCommon/JudyCreateBranch.c cp -f ../JudyCommon/JudyCreateBranch.c JudyLCreateBranch.c JudyLDecascade.c:../JudyCommon/JudyDecascade.c cp -f ../JudyCommon/JudyDecascade.c JudyLDecascade.c JudyLDel.c:../JudyCommon/JudyDel.c cp -f ../JudyCommon/JudyDel.c JudyLDel.c JudyLFirst.c:../JudyCommon/JudyFirst.c cp -f ../JudyCommon/JudyFirst.c JudyLFirst.c JudyLFreeArray.c:../JudyCommon/JudyFreeArray.c cp -f ../JudyCommon/JudyFreeArray.c JudyLFreeArray.c JudyLGet.c:../JudyCommon/JudyGet.c cp -f ../JudyCommon/JudyGet.c JudyLGet.c j__udyLGet.c:../JudyCommon/JudyGet.c cp -f ../JudyCommon/JudyGet.c j__udyLGet.c JudyLInsArray.c:../JudyCommon/JudyInsArray.c cp -f ../JudyCommon/JudyInsArray.c JudyLInsArray.c JudyLIns.c:../JudyCommon/JudyIns.c cp -f ../JudyCommon/JudyIns.c JudyLIns.c JudyLInsertBranch.c:../JudyCommon/JudyInsertBranch.c cp -f ../JudyCommon/JudyInsertBranch.c JudyLInsertBranch.c JudyLMallocIF.c:../JudyCommon/JudyMallocIF.c cp -f ../JudyCommon/JudyMallocIF.c JudyLMallocIF.c JudyLMemActive.c:../JudyCommon/JudyMemActive.c cp -f ../JudyCommon/JudyMemActive.c JudyLMemActive.c JudyLMemUsed.c:../JudyCommon/JudyMemUsed.c cp -f ../JudyCommon/JudyMemUsed.c JudyLMemUsed.c JudyLNext.c:../JudyCommon/JudyPrevNext.c cp -f ../JudyCommon/JudyPrevNext.c JudyLNext.c JudyLPrev.c:../JudyCommon/JudyPrevNext.c cp -f ../JudyCommon/JudyPrevNext.c JudyLPrev.c JudyLNextEmpty.c:../JudyCommon/JudyPrevNextEmpty.c cp -f ../JudyCommon/JudyPrevNextEmpty.c JudyLNextEmpty.c JudyLPrevEmpty.c:../JudyCommon/JudyPrevNextEmpty.c cp -f ../JudyCommon/JudyPrevNextEmpty.c JudyLPrevEmpty.c JudyLTablesGen.c:../JudyCommon/JudyTables.c cp -f ../JudyCommon/JudyTables.c JudyLTablesGen.c # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: judy-1.0.5/src/JudyL/Makefile.am0000644000175000017500000000721710624600161016571 0ustar troyhebetroyhebeINCLUDES = -I. -I.. -I../JudyCommon/ AM_CFLAGS = -DJUDYL @WARN_CFLAGS@ noinst_LTLIBRARIES = libJudyL.la libnext.la libprev.la libcount.la libinline.la libJudyL_la_SOURCES = JudyLCascade.c JudyLTables.c JudyLCount.c JudyLCreateBranch.c JudyLDecascade.c JudyLDel.c JudyLFirst.c JudyLFreeArray.c JudyLGet.c JudyLInsArray.c JudyLIns.c JudyLInsertBranch.c JudyLMallocIF.c JudyLMemActive.c JudyLMemUsed.c libnext_la_SOURCES = JudyLNext.c JudyLNextEmpty.c libnext_la_CFLAGS = $(AM_CFLAGS) -DJUDYNEXT libprev_la_SOURCES = JudyLPrev.c JudyLPrevEmpty.c libprev_la_CFLAGS = $(AM_CFLAGS) -DJUDYPREV libcount_la_SOURCES = JudyLByCount.c libcount_la_CFLAGS = $(AM_CFLAGS) -DNOSMARTJBB -DNOSMARTJBU -DNOSMARTJLB libinline_la_SOURCES = j__udyLGet.c libinline_la_CFLAGS = $(AM_CFLAGS) -DJUDYGETINLINE JudyLTables.c: JudyLTablesGen.c $(CC) $(INCLUDES) $(AM_CFLAGS) @CFLAGS@ -o JudyLTablesGen JudyLTablesGen.c; ./JudyLTablesGen JudyLByCount.c: ../JudyCommon/JudyByCount.c cp -f ../JudyCommon/JudyByCount.c JudyLByCount.c JudyLCascade.c:../JudyCommon/JudyCascade.c cp -f ../JudyCommon/JudyCascade.c JudyLCascade.c JudyLCount.c:../JudyCommon/JudyCount.c cp -f ../JudyCommon/JudyCount.c JudyLCount.c JudyLCreateBranch.c:../JudyCommon/JudyCreateBranch.c cp -f ../JudyCommon/JudyCreateBranch.c JudyLCreateBranch.c JudyLDecascade.c:../JudyCommon/JudyDecascade.c cp -f ../JudyCommon/JudyDecascade.c JudyLDecascade.c JudyLDel.c:../JudyCommon/JudyDel.c cp -f ../JudyCommon/JudyDel.c JudyLDel.c JudyLFirst.c:../JudyCommon/JudyFirst.c cp -f ../JudyCommon/JudyFirst.c JudyLFirst.c JudyLFreeArray.c:../JudyCommon/JudyFreeArray.c cp -f ../JudyCommon/JudyFreeArray.c JudyLFreeArray.c JudyLGet.c:../JudyCommon/JudyGet.c cp -f ../JudyCommon/JudyGet.c JudyLGet.c j__udyLGet.c:../JudyCommon/JudyGet.c cp -f ../JudyCommon/JudyGet.c j__udyLGet.c JudyLInsArray.c:../JudyCommon/JudyInsArray.c cp -f ../JudyCommon/JudyInsArray.c JudyLInsArray.c JudyLIns.c:../JudyCommon/JudyIns.c cp -f ../JudyCommon/JudyIns.c JudyLIns.c JudyLInsertBranch.c:../JudyCommon/JudyInsertBranch.c cp -f ../JudyCommon/JudyInsertBranch.c JudyLInsertBranch.c JudyLMallocIF.c:../JudyCommon/JudyMallocIF.c cp -f ../JudyCommon/JudyMallocIF.c JudyLMallocIF.c JudyLMemActive.c:../JudyCommon/JudyMemActive.c cp -f ../JudyCommon/JudyMemActive.c JudyLMemActive.c JudyLMemUsed.c:../JudyCommon/JudyMemUsed.c cp -f ../JudyCommon/JudyMemUsed.c JudyLMemUsed.c JudyLNext.c:../JudyCommon/JudyPrevNext.c cp -f ../JudyCommon/JudyPrevNext.c JudyLNext.c JudyLPrev.c:../JudyCommon/JudyPrevNext.c cp -f ../JudyCommon/JudyPrevNext.c JudyLPrev.c JudyLNextEmpty.c:../JudyCommon/JudyPrevNextEmpty.c cp -f ../JudyCommon/JudyPrevNextEmpty.c JudyLNextEmpty.c JudyLPrevEmpty.c:../JudyCommon/JudyPrevNextEmpty.c cp -f ../JudyCommon/JudyPrevNextEmpty.c JudyLPrevEmpty.c JudyLTablesGen.c:../JudyCommon/JudyTables.c cp -f ../JudyCommon/JudyTables.c JudyLTablesGen.c DISTCLEANFILES = .deps Makefile CLEANFILES = JudyLByCount.c \ JudyLCascade.c \ JudyLCount.c \ JudyLCreateBranch.c \ JudyLDecascade.c \ JudyLDel.c \ JudyLFirst.c \ JudyLFreeArray.c \ JudyLGet.c \ j__udyLGet.c \ JudyLInsArray.c \ JudyLIns.c \ JudyLInsertBranch.c \ JudyLMallocIF.c \ JudyLMemActive.c \ JudyLMemUsed.c \ JudyLNext.c \ JudyLPrev.c \ JudyLNextEmpty.c \ JudyLPrevEmpty.c \ JudyLTablesGen.c \ JudyLTables.c \ JudyLTablesGen \ .libs \ *.o \ *.lo \ *.la judy-1.0.5/src/JudyL/JudyL.h0000644000175000017500000005077110204462077015746 0ustar troyhebetroyhebe#ifndef _JUDYL_INCLUDED #define _JUDYL_INCLUDED // _________________ // // Copyright (C) 2000 - 2002 Hewlett-Packard Company // // This program is free software; you can redistribute it and/or modify it // under the term of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License // for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program; if not, write to the Free Software Foundation, // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // _________________ // @(#) $Revision: 4.41 $ $Source: /judy/src/JudyL/JudyL.h $ // **************************************************************************** // JUDYL -- SMALL/LARGE AND/OR CLUSTERED/SPARSE ARRAYS // // -by- // // Douglas L. Baskins // doug@sourcejudy.com // // Judy arrays are designed to be used instead of arrays. The performance // suggests the reason why Judy arrays are thought of as arrays, instead of // trees. They are remarkably memory efficient at all populations. // Implemented as a hybrid digital tree (but really a state machine, see // below), Judy arrays feature fast insert/retrievals, fast near neighbor // searching, and contain a population tree for extremely fast ordinal related // retrievals. // // CONVENTIONS: // // - The comments here refer to 32-bit [64-bit] systems. // // - BranchL, LeafL refer to linear branches and leaves (small populations), // except LeafL does not actually appear as such; rather, Leaf1..3 [Leaf1..7] // is used to represent leaf Index sizes, and LeafW refers to a Leaf with // full (Long) word Indexes, which is also a type of linear leaf. Note that // root-level LeafW (Leaf4 [Leaf8]) leaves are called LEAFW. // // - BranchB, LeafB1 refer to bitmap branches and leaves (intermediate // populations). // // - BranchU refers to uncompressed branches. An uncompressed branch has 256 // JPs, some of which could be null. Note: All leaves are compressed (and // sorted), or else an expanse is full (FullPopu), so there is no LeafU // equivalent to BranchU. // // - "Popu" is short for "Population". // - "Pop1" refers to actual population (base 1). // - "Pop0" refers to Pop1 - 1 (base 0), the way populations are stored in data // structures. // // - Branches and Leaves are both named by the number of bytes in their Pop0 // field. In the case of Leaves, the same number applies to the Index sizes. // // - The representation of many numbers as hex is a relatively safe and // portable way to get desired bitpatterns as unsigned longs. // // - Some preprocessors cant handle single apostrophe characters within // #ifndef code, so here, delete all instead. #include "JudyPrivate.h" // includes Judy.h in turn. #include "JudyPrivateBranch.h" // support for branches. // **************************************************************************** // JUDYL ROOT POINTER (JRP) AND JUDYL POINTER (JP) TYPE FIELDS // **************************************************************************** typedef enum // uint8_t -- but C does not support this type of enum. { // JP NULL TYPES: // // There is a series of cJL_JPNULL* Types because each one pre-records a // different Index Size for when the first Index is inserted in the previously // null JP. They must start >= 8 (three bits). // // Note: These Types must be in sequential order for doing relative // calculations between them. cJL_JPNULL1 = 1, // Index Size 1[1] byte when 1 Index inserted. cJL_JPNULL2, // Index Size 2[2] bytes when 1 Index inserted. cJL_JPNULL3, // Index Size 3[3] bytes when 1 Index inserted. #ifndef JU_64BIT #define cJL_JPNULLMAX cJL_JPNULL3 #else cJL_JPNULL4, // Index Size 4[4] bytes when 1 Index inserted. cJL_JPNULL5, // Index Size 5[5] bytes when 1 Index inserted. cJL_JPNULL6, // Index Size 6[6] bytes when 1 Index inserted. cJL_JPNULL7, // Index Size 7[7] bytes when 1 Index inserted. #define cJL_JPNULLMAX cJL_JPNULL7 #endif // JP BRANCH TYPES: // // Note: There are no state-1 branches; only leaves reside at state 1. // Linear branches: // // Note: These Types must be in sequential order for doing relative // calculations between them. cJL_JPBRANCH_L2, // 2[2] bytes Pop0, 1[5] bytes Dcd. cJL_JPBRANCH_L3, // 3[3] bytes Pop0, 0[4] bytes Dcd. #ifdef JU_64BIT cJL_JPBRANCH_L4, // [4] bytes Pop0, [3] bytes Dcd. cJL_JPBRANCH_L5, // [5] bytes Pop0, [2] bytes Dcd. cJL_JPBRANCH_L6, // [6] bytes Pop0, [1] byte Dcd. cJL_JPBRANCH_L7, // [7] bytes Pop0, [0] bytes Dcd. #endif cJL_JPBRANCH_L, // note: DcdPopO field not used. // Bitmap branches: // // Note: These Types must be in sequential order for doing relative // calculations between them. cJL_JPBRANCH_B2, // 2[2] bytes Pop0, 1[5] bytes Dcd. cJL_JPBRANCH_B3, // 3[3] bytes Pop0, 0[4] bytes Dcd. #ifdef JU_64BIT cJL_JPBRANCH_B4, // [4] bytes Pop0, [3] bytes Dcd. cJL_JPBRANCH_B5, // [5] bytes Pop0, [2] bytes Dcd. cJL_JPBRANCH_B6, // [6] bytes Pop0, [1] byte Dcd. cJL_JPBRANCH_B7, // [7] bytes Pop0, [0] bytes Dcd. #endif cJL_JPBRANCH_B, // note: DcdPopO field not used. // Uncompressed branches: // // Note: These Types must be in sequential order for doing relative // calculations between them. cJL_JPBRANCH_U2, // 2[2] bytes Pop0, 1[5] bytes Dcd. cJL_JPBRANCH_U3, // 3[3] bytes Pop0, 0[4] bytes Dcd. #ifdef JU_64BIT cJL_JPBRANCH_U4, // [4] bytes Pop0, [3] bytes Dcd. cJL_JPBRANCH_U5, // [5] bytes Pop0, [2] bytes Dcd. cJL_JPBRANCH_U6, // [6] bytes Pop0, [1] byte Dcd. cJL_JPBRANCH_U7, // [7] bytes Pop0, [0] bytes Dcd. #endif cJL_JPBRANCH_U, // note: DcdPopO field not used. // JP LEAF TYPES: // Linear leaves: // // Note: These Types must be in sequential order for doing relative // calculations between them. // // Note: There is no full-word (4-byte [8-byte]) Index leaf under a JP because // non-root-state leaves only occur under branches that decode at least one // byte. Full-word, root-state leaves are under a JRP, not a JP. However, in // the code a "fake" JP can be created temporarily above a root-state leaf. cJL_JPLEAF1, // 1[1] byte Pop0, 2 bytes Dcd. cJL_JPLEAF2, // 2[2] bytes Pop0, 1[5] bytes Dcd. cJL_JPLEAF3, // 3[3] bytes Pop0, 0[4] bytes Dcd. #ifdef JU_64BIT cJL_JPLEAF4, // [4] bytes Pop0, [3] bytes Dcd. cJL_JPLEAF5, // [5] bytes Pop0, [2] bytes Dcd. cJL_JPLEAF6, // [6] bytes Pop0, [1] byte Dcd. cJL_JPLEAF7, // [7] bytes Pop0, [0] bytes Dcd. #endif // Bitmap leaf; Index Size == 1: // // Note: These are currently only supported at state 1. At other states the // bitmap would grow from 256 to 256^2, 256^3, ... bits, which would not be // efficient.. cJL_JPLEAF_B1, // 1[1] byte Pop0, 2[6] bytes Dcd. // Full population; Index Size == 1 virtual leaf: // // Note: JudyL has no cJL_JPFULLPOPU1 equivalent to cJ1_JPFULLPOPU1, because // in the JudyL case this could result in a values-only leaf of up to 256 words // (value areas) that would be slow to insert/delete. // JP IMMEDIATES; leaves (Indexes) stored inside a JP: // // The second numeric suffix is the Pop1 for each type. As the Index Size // increases, the maximum possible population decreases. // // Note: These Types must be in sequential order in each group (Index Size), // and the groups in correct order too, for doing relative calculations between // them. For example, since these Types enumerate the Pop1 values (unlike // other JP Types where there is a Pop0 value in the JP), the maximum Pop1 for // each Index Size is computable. // // All enums equal or above this point are cJL_JPIMMEDs. cJL_JPIMMED_1_01, // Index Size = 1, Pop1 = 1. cJL_JPIMMED_2_01, // Index Size = 2, Pop1 = 1. cJL_JPIMMED_3_01, // Index Size = 3, Pop1 = 1. #ifdef JU_64BIT cJL_JPIMMED_4_01, // Index Size = 4, Pop1 = 1. cJL_JPIMMED_5_01, // Index Size = 5, Pop1 = 1. cJL_JPIMMED_6_01, // Index Size = 6, Pop1 = 1. cJL_JPIMMED_7_01, // Index Size = 7, Pop1 = 1. #endif cJL_JPIMMED_1_02, // Index Size = 1, Pop1 = 2. cJL_JPIMMED_1_03, // Index Size = 1, Pop1 = 3. #ifdef JU_64BIT cJL_JPIMMED_1_04, // Index Size = 1, Pop1 = 4. cJL_JPIMMED_1_05, // Index Size = 1, Pop1 = 5. cJL_JPIMMED_1_06, // Index Size = 1, Pop1 = 6. cJL_JPIMMED_1_07, // Index Size = 1, Pop1 = 7. cJL_JPIMMED_2_02, // Index Size = 2, Pop1 = 2. cJL_JPIMMED_2_03, // Index Size = 2, Pop1 = 3. cJL_JPIMMED_3_02, // Index Size = 3, Pop1 = 2. #endif // This special Type is merely a sentinel for doing relative calculations. // This value should not be used in switch statements (to avoid allocating code // for it), which is also why it appears at the end of the enum list. cJL_JPIMMED_CAP } jpL_Type_t; // RELATED VALUES: // Index Size (state) for leaf JP, and JP type based on Index Size (state): #define JL_LEAFINDEXSIZE(jpType) ((jpType) - cJL_JPLEAF1 + 1) #define JL_LEAFTYPE(IndexSize) ((IndexSize) + cJL_JPLEAF1 - 1) // MAXIMUM POPULATIONS OF LINEAR LEAVES: #ifndef JU_64BIT // 32-bit #define J_L_MAXB (sizeof(Word_t) * 64) #define ALLOCSIZES { 3, 5, 7, 11, 15, 23, 32, 47, 64, TERMINATOR } // in words. #define cJL_LEAF1_MAXWORDS (32) // max Leaf1 size in words. // Note: cJL_LEAF1_MAXPOP1 is chosen such that the index portion is less than // 32 bytes -- the number of bytes the index takes in a bitmap leaf. #define cJL_LEAF1_MAXPOP1 \ ((cJL_LEAF1_MAXWORDS * cJU_BYTESPERWORD)/(1 + cJU_BYTESPERWORD)) #define cJL_LEAF2_MAXPOP1 (J_L_MAXB / (2 + cJU_BYTESPERWORD)) #define cJL_LEAF3_MAXPOP1 (J_L_MAXB / (3 + cJU_BYTESPERWORD)) #define cJL_LEAFW_MAXPOP1 \ ((J_L_MAXB - cJU_BYTESPERWORD) / (2 * cJU_BYTESPERWORD)) #else // 64-bit #define J_L_MAXB (sizeof(Word_t) * 64) #define ALLOCSIZES { 3, 5, 7, 11, 15, 23, 32, 47, 64, TERMINATOR } // in words. #define cJL_LEAF1_MAXWORDS (15) // max Leaf1 size in words. #define cJL_LEAF1_MAXPOP1 \ ((cJL_LEAF1_MAXWORDS * cJU_BYTESPERWORD)/(1 + cJU_BYTESPERWORD)) #define cJL_LEAF2_MAXPOP1 (J_L_MAXB / (2 + cJU_BYTESPERWORD)) #define cJL_LEAF3_MAXPOP1 (J_L_MAXB / (3 + cJU_BYTESPERWORD)) #define cJL_LEAF4_MAXPOP1 (J_L_MAXB / (4 + cJU_BYTESPERWORD)) #define cJL_LEAF5_MAXPOP1 (J_L_MAXB / (5 + cJU_BYTESPERWORD)) #define cJL_LEAF6_MAXPOP1 (J_L_MAXB / (6 + cJU_BYTESPERWORD)) #define cJL_LEAF7_MAXPOP1 (J_L_MAXB / (7 + cJU_BYTESPERWORD)) #define cJL_LEAFW_MAXPOP1 \ ((J_L_MAXB - cJU_BYTESPERWORD) / (2 * cJU_BYTESPERWORD)) #endif // 64-bit // MAXIMUM POPULATIONS OF IMMEDIATE JPs: // // These specify the maximum Population of immediate JPs with various Index // Sizes (== sizes of remaining undecoded Index bits). Since the JP Types enum // already lists all the immediates in order by state and size, calculate these // values from it to avoid redundancy. #define cJL_IMMED1_MAXPOP1 ((cJU_BYTESPERWORD - 1) / 1) // 3 [7]. #define cJL_IMMED2_MAXPOP1 ((cJU_BYTESPERWORD - 1) / 2) // 1 [3]. #define cJL_IMMED3_MAXPOP1 ((cJU_BYTESPERWORD - 1) / 3) // 1 [2]. #ifdef JU_64BIT #define cJL_IMMED4_MAXPOP1 ((cJU_BYTESPERWORD - 1) / 4) // [1]. #define cJL_IMMED5_MAXPOP1 ((cJU_BYTESPERWORD - 1) / 5) // [1]. #define cJL_IMMED6_MAXPOP1 ((cJU_BYTESPERWORD - 1) / 6) // [1]. #define cJL_IMMED7_MAXPOP1 ((cJU_BYTESPERWORD - 1) / 7) // [1]. #endif // **************************************************************************** // JUDYL LEAF BITMAP (JLLB) SUPPORT // **************************************************************************** // // Assemble bitmap leaves out of smaller units that put bitmap subexpanses // close to their associated pointers. Why not just use a bitmap followed by a // series of pointers? (See 4.27.) Turns out this wastes a cache fill on // systems with smaller cache lines than the assumed value cJU_WORDSPERCL. #define JL_JLB_BITMAP(Pjlb, Subexp) ((Pjlb)->jLlb_jLlbs[Subexp].jLlbs_Bitmap) #define JL_JLB_PVALUE(Pjlb, Subexp) ((Pjlb)->jLlb_jLlbs[Subexp].jLlbs_PValue) typedef struct J__UDYL_LEAF_BITMAP_SUBEXPANSE { BITMAPL_t jLlbs_Bitmap; Pjv_t jLlbs_PValue; } jLlbs_t; typedef struct J__UDYL_LEAF_BITMAP { jLlbs_t jLlb_jLlbs[cJU_NUMSUBEXPL]; } jLlb_t, * PjLlb_t; // Words per bitmap leaf: #define cJL_WORDSPERLEAFB1 (sizeof(jLlb_t) / cJU_BYTESPERWORD) // **************************************************************************** // MEMORY ALLOCATION SUPPORT // **************************************************************************** // ARRAY-GLOBAL INFORMATION: // // At the cost of an occasional additional cache fill, this object, which is // pointed at by a JRP and in turn points to a JP_BRANCH*, carries array-global // information about a JudyL array that has sufficient population to amortize // the cost. The jpm_Pop0 field prevents having to add up the total population // for the array in insert, delete, and count code. The jpm_JP field prevents // having to build a fake JP for entry to a state machine; however, the // jp_DcdPopO field in jpm_JP, being one byte too small, is not used. // // Note: Struct fields are ordered to keep "hot" data in the first 8 words // (see left-margin comments) for machines with 8-word cache lines, and to keep // sub-word fields together for efficient packing. typedef struct J_UDYL_POPULATION_AND_MEMORY { /* 1 */ Word_t jpm_Pop0; // total population-1 in array. /* 2 */ jp_t jpm_JP; // JP to first branch; see above. /* 4 */ Word_t jpm_LastUPop0; // last jpm_Pop0 when convert to BranchU /* 7 */ Pjv_t jpm_PValue; // pointer to value to return. // Note: Field names match PJError_t for convenience in macros: /* 8 */ char je_Errno; // one of the enums in Judy.h. /* 8/9 */ int je_ErrID; // often an internal source line number. /* 9/10 */ Word_t jpm_TotalMemWords; // words allocated in array. } jLpm_t, *PjLpm_t; // TABLES FOR DETERMINING IF LEAVES HAVE ROOM TO GROW: // // These tables indicate if a given memory chunk can support growth of a given // object into wasted (rounded-up) memory in the chunk. Note: This violates // the hiddenness of the JudyMalloc code. extern const uint8_t j__L_Leaf1PopToWords[cJL_LEAF1_MAXPOP1 + 1]; extern const uint8_t j__L_Leaf2PopToWords[cJL_LEAF2_MAXPOP1 + 1]; extern const uint8_t j__L_Leaf3PopToWords[cJL_LEAF3_MAXPOP1 + 1]; #ifdef JU_64BIT extern const uint8_t j__L_Leaf4PopToWords[cJL_LEAF4_MAXPOP1 + 1]; extern const uint8_t j__L_Leaf5PopToWords[cJL_LEAF5_MAXPOP1 + 1]; extern const uint8_t j__L_Leaf6PopToWords[cJL_LEAF6_MAXPOP1 + 1]; extern const uint8_t j__L_Leaf7PopToWords[cJL_LEAF7_MAXPOP1 + 1]; #endif extern const uint8_t j__L_LeafWPopToWords[cJL_LEAFW_MAXPOP1 + 1]; extern const uint8_t j__L_LeafVPopToWords[]; // These tables indicate where value areas start: extern const uint8_t j__L_Leaf1Offset [cJL_LEAF1_MAXPOP1 + 1]; extern const uint8_t j__L_Leaf2Offset [cJL_LEAF2_MAXPOP1 + 1]; extern const uint8_t j__L_Leaf3Offset [cJL_LEAF3_MAXPOP1 + 1]; #ifdef JU_64BIT extern const uint8_t j__L_Leaf4Offset [cJL_LEAF4_MAXPOP1 + 1]; extern const uint8_t j__L_Leaf5Offset [cJL_LEAF5_MAXPOP1 + 1]; extern const uint8_t j__L_Leaf6Offset [cJL_LEAF6_MAXPOP1 + 1]; extern const uint8_t j__L_Leaf7Offset [cJL_LEAF7_MAXPOP1 + 1]; #endif extern const uint8_t j__L_LeafWOffset [cJL_LEAFW_MAXPOP1 + 1]; // Also define macros to hide the details in the code using these tables. #define JL_LEAF1GROWINPLACE(Pop1) \ J__U_GROWCK(Pop1, cJL_LEAF1_MAXPOP1, j__L_Leaf1PopToWords) #define JL_LEAF2GROWINPLACE(Pop1) \ J__U_GROWCK(Pop1, cJL_LEAF2_MAXPOP1, j__L_Leaf2PopToWords) #define JL_LEAF3GROWINPLACE(Pop1) \ J__U_GROWCK(Pop1, cJL_LEAF3_MAXPOP1, j__L_Leaf3PopToWords) #ifdef JU_64BIT #define JL_LEAF4GROWINPLACE(Pop1) \ J__U_GROWCK(Pop1, cJL_LEAF4_MAXPOP1, j__L_Leaf4PopToWords) #define JL_LEAF5GROWINPLACE(Pop1) \ J__U_GROWCK(Pop1, cJL_LEAF5_MAXPOP1, j__L_Leaf5PopToWords) #define JL_LEAF6GROWINPLACE(Pop1) \ J__U_GROWCK(Pop1, cJL_LEAF6_MAXPOP1, j__L_Leaf6PopToWords) #define JL_LEAF7GROWINPLACE(Pop1) \ J__U_GROWCK(Pop1, cJL_LEAF7_MAXPOP1, j__L_Leaf7PopToWords) #endif #define JL_LEAFWGROWINPLACE(Pop1) \ J__U_GROWCK(Pop1, cJL_LEAFW_MAXPOP1, j__L_LeafWPopToWords) #define JL_LEAFVGROWINPLACE(Pop1) \ J__U_GROWCK(Pop1, cJU_BITSPERSUBEXPL, j__L_LeafVPopToWords) #define JL_LEAF1VALUEAREA(Pjv,Pop1) (((PWord_t)(Pjv)) + j__L_Leaf1Offset[Pop1]) #define JL_LEAF2VALUEAREA(Pjv,Pop1) (((PWord_t)(Pjv)) + j__L_Leaf2Offset[Pop1]) #define JL_LEAF3VALUEAREA(Pjv,Pop1) (((PWord_t)(Pjv)) + j__L_Leaf3Offset[Pop1]) #ifdef JU_64BIT #define JL_LEAF4VALUEAREA(Pjv,Pop1) (((PWord_t)(Pjv)) + j__L_Leaf4Offset[Pop1]) #define JL_LEAF5VALUEAREA(Pjv,Pop1) (((PWord_t)(Pjv)) + j__L_Leaf5Offset[Pop1]) #define JL_LEAF6VALUEAREA(Pjv,Pop1) (((PWord_t)(Pjv)) + j__L_Leaf6Offset[Pop1]) #define JL_LEAF7VALUEAREA(Pjv,Pop1) (((PWord_t)(Pjv)) + j__L_Leaf7Offset[Pop1]) #endif #define JL_LEAFWVALUEAREA(Pjv,Pop1) (((PWord_t)(Pjv)) + j__L_LeafWOffset[Pop1]) #define JL_LEAF1POPTOWORDS(Pop1) (j__L_Leaf1PopToWords[Pop1]) #define JL_LEAF2POPTOWORDS(Pop1) (j__L_Leaf2PopToWords[Pop1]) #define JL_LEAF3POPTOWORDS(Pop1) (j__L_Leaf3PopToWords[Pop1]) #ifdef JU_64BIT #define JL_LEAF4POPTOWORDS(Pop1) (j__L_Leaf4PopToWords[Pop1]) #define JL_LEAF5POPTOWORDS(Pop1) (j__L_Leaf5PopToWords[Pop1]) #define JL_LEAF6POPTOWORDS(Pop1) (j__L_Leaf6PopToWords[Pop1]) #define JL_LEAF7POPTOWORDS(Pop1) (j__L_Leaf7PopToWords[Pop1]) #endif #define JL_LEAFWPOPTOWORDS(Pop1) (j__L_LeafWPopToWords[Pop1]) #define JL_LEAFVPOPTOWORDS(Pop1) (j__L_LeafVPopToWords[Pop1]) // FUNCTIONS TO ALLOCATE OBJECTS: PjLpm_t j__udyLAllocJLPM(void); // constant size. Pjbl_t j__udyLAllocJBL( PjLpm_t); // constant size. Pjbb_t j__udyLAllocJBB( PjLpm_t); // constant size. Pjp_t j__udyLAllocJBBJP(Word_t, PjLpm_t); Pjbu_t j__udyLAllocJBU( PjLpm_t); // constant size. Pjll_t j__udyLAllocJLL1( Word_t, PjLpm_t); Pjll_t j__udyLAllocJLL2( Word_t, PjLpm_t); Pjll_t j__udyLAllocJLL3( Word_t, PjLpm_t); #ifdef JU_64BIT Pjll_t j__udyLAllocJLL4( Word_t, PjLpm_t); Pjll_t j__udyLAllocJLL5( Word_t, PjLpm_t); Pjll_t j__udyLAllocJLL6( Word_t, PjLpm_t); Pjll_t j__udyLAllocJLL7( Word_t, PjLpm_t); #endif Pjlw_t j__udyLAllocJLW( Word_t ); // no PjLpm_t needed. PjLlb_t j__udyLAllocJLB1( PjLpm_t); // constant size. Pjv_t j__udyLAllocJV( Word_t, PjLpm_t); // FUNCTIONS TO FREE OBJECTS: void j__udyLFreeJLPM( PjLpm_t, PjLpm_t); // constant size. void j__udyLFreeJBL( Pjbl_t, PjLpm_t); // constant size. void j__udyLFreeJBB( Pjbb_t, PjLpm_t); // constant size. void j__udyLFreeJBBJP(Pjp_t, Word_t, PjLpm_t); void j__udyLFreeJBU( Pjbu_t, PjLpm_t); // constant size. void j__udyLFreeJLL1( Pjll_t, Word_t, PjLpm_t); void j__udyLFreeJLL2( Pjll_t, Word_t, PjLpm_t); void j__udyLFreeJLL3( Pjll_t, Word_t, PjLpm_t); #ifdef JU_64BIT void j__udyLFreeJLL4( Pjll_t, Word_t, PjLpm_t); void j__udyLFreeJLL5( Pjll_t, Word_t, PjLpm_t); void j__udyLFreeJLL6( Pjll_t, Word_t, PjLpm_t); void j__udyLFreeJLL7( Pjll_t, Word_t, PjLpm_t); #endif void j__udyLFreeJLW( Pjlw_t, Word_t, PjLpm_t); void j__udyLFreeJLB1( PjLlb_t, PjLpm_t); // constant size. void j__udyLFreeJV( Pjv_t, Word_t, PjLpm_t); void j__udyLFreeSM( Pjp_t, PjLpm_t); // everything below Pjp. #endif // ! _JUDYL_INCLUDED judy-1.0.5/src/JudyL/README0000644000175000017500000000024610204462077015416 0ustar troyhebetroyhebe# @(#) $Revision: 4.19 $ $Source: /judy/src/JudyL/README $ # # This tree contains sources for the JudyL*() functions. # JudyL.h lint.waivers see usage in makefile judy-1.0.5/src/JudySL/0000755000175000017500000000000010624600216014652 5ustar troyhebetroyhebejudy-1.0.5/src/JudySL/Makefile.in0000644000175000017500000003212710624600216016724 0ustar troyhebetroyhebe# Makefile.in generated by automake 1.9.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ top_builddir = ../.. am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd INSTALL = @INSTALL@ install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/JudySL DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libJudySL_la_LIBADD = am_libJudySL_la_OBJECTS = JudySL.lo libJudySL_la_OBJECTS = $(am_libJudySL_la_OBJECTS) DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ SOURCES = $(libJudySL_la_SOURCES) DIST_SOURCES = $(libJudySL_la_SOURCES) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMDEP_FALSE = @AMDEP_FALSE@ AMDEP_TRUE = @AMDEP_TRUE@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO = @ECHO@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ F77 = @F77@ FFLAGS = @FFLAGS@ FLAVOR = @FLAVOR@ GREP = @GREP@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ MAKEINFO = @MAKEINFO@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ VERSION_INFO = @VERSION_INFO@ WARN_CFLAGS = @WARN_CFLAGS@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_F77 = @ac_ct_F77@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ INCLUDES = -I. -I.. -I../JudyCommon/ AM_CFLAGS = @CFLAGS@ @WARN_CFLAGS@ noinst_LTLIBRARIES = libJudySL.la libJudySL_la_SOURCES = JudySL.c DISTCLEANFILES = .deps Makefile all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/JudySL/Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --gnu src/JudySL/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libJudySL.la: $(libJudySL_la_OBJECTS) $(libJudySL_la_DEPENDENCIES) $(LINK) $(libJudySL_la_LDFLAGS) $(libJudySL_la_OBJECTS) $(libJudySL_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/JudySL.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs distclean-libtool: -rm -f libtool uninstall-info-am: ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$tags $$unique; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ test -z "$(CTAGS_ARGS)$$tags$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$tags $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && cd $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) $$here distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ list='$(DISTFILES)'; for file in $$list; do \ case $$file in \ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ esac; \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ if test "$$dir" != "$$file" && test "$$dir" != "."; then \ dir="/$$dir"; \ $(mkdir_p) "$(distdir)$$dir"; \ else \ dir=''; \ fi; \ if test -d $$d/$$file; then \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-libtool distclean-tags dvi: dvi-am dvi-am: html: html-am info: info-am info-am: install-data-am: install-exec-am: install-info: install-info-am install-man: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-info-am .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLTLIBRARIES ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-exec \ install-exec-am install-info install-info-am install-man \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags uninstall uninstall-am \ uninstall-info-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: judy-1.0.5/src/JudySL/Makefile.am0000644000175000017500000000026010624600161016703 0ustar troyhebetroyhebeINCLUDES = -I. -I.. -I../JudyCommon/ AM_CFLAGS = @CFLAGS@ @WARN_CFLAGS@ noinst_LTLIBRARIES = libJudySL.la libJudySL_la_SOURCES = JudySL.c DISTCLEANFILES = .deps Makefile judy-1.0.5/src/JudySL/JudySL.c0000644000175000017500000012757710204462077016220 0ustar troyhebetroyhebe// // This program is free software; you can redistribute it and/or modify it // under the term of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License // for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program; if not, write to the Free Software Foundation, // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // _________________ // @(#) $Revision: 4.38 $ $Source: /judy/src/JudySL/JudySL.c $ // // JUDY FUNCTIONS FOR STRING INDEXES, where associated values are longs. One // JudySL*() corresponds to each JudyL*() function (with exceptions). // // See the manual entry for details. // // METHOD: Break up each null-terminated Index (string) into chunks of W // bytes, where W is the machines word size, with null-padding in the last // word if necessary. Store strings as a tree of JudyL arrays, that is, array // of array of array... where each level consumes W bytes (one word) as an // index to the JudyL array at that level. Since strings can begin on // arbitrary byte boundaries, copy each chunk of W bytes from Index into a // word-aligned object before using it as a Judy index. // // The JudySL tree also supports "single-index shortcut leaves". A simple // JudySL array (tree of JudyL arrays) would go as many levels deep as the // Index (string) is long, which wastes time and memory when an Index is unique // beyond a certain point. When theres just one Index under a pointer, given // a reliable way to tell that the pointer is not a root pointer to another // JudyL array, it should save a lot of time to instead point to a "leaf" // object, similar to leaves in JudyL arrays. // // TBD: Multi-index leaves, like those in JudyL, are also worth considering, // but their payback for JudySL is less certain. Likewise, shortcut branches // are worth considering too. // // This code uses the Judy.h definitions and Doug Baskins convention of a "P" // prefix for pointers, except no "P" for the first level of char * (strings). // IMPORTS: #include // for strcmp(), strlen(), strcpy() #include #ifndef NDEDUG #define NDEBUG 1 #endif #include //======================================================================= // Compile: // // cc -O JudyHS.c -c // // Notes: // 1) use -DJU_64BIT for 64 bit compiles (HP, Sun, IPF, Motorola/IBM? etc..) // 2) In gcc version 3.3.1 for a Centrino, -O2 is faster than -O // 3) In gcc version 3.3.2 for a Centrino, -O3 is faster than -O2 //======================================================================= #define JU_SET_ERRNO(PJERROR, JERRNO) \ { \ if (PJERROR != (PJError_t)NULL) \ { \ JU_ERRNO(PJERROR) = (JERRNO); \ JU_ERRID(PJERROR) = __LINE__; \ } \ } #define JU_SET_ERRNO_NONNULL(PJERROR, JERRNO) \ { \ JU_ERRNO(PJERROR) = (JERRNO); \ JU_ERRID(PJERROR) = __LINE__; \ } // SUPPORT FOR HANDLING WORDS: #define WORDSIZE (sizeof (Word_t)) // bytes in word = JudyL index. #define WORDS(BYTES) (((BYTES) + WORDSIZE - 1) / WORDSIZE) // round up. // To mark a pointer is to a "short cut leaf", set least bit #define IS_PSCL(PSCL) (((Word_t) (PSCL)) & JLAP_INVALID) #define CLEAR_PSCL(PSCL) ((Pscl_t)(((Word_t) (PSCL)) & (~JLAP_INVALID))) #define SET_PSCL(PSCL) (((Word_t) (PSCL)) | JLAP_INVALID) // MISCELLANEOUS GLOBALS: // Get the Index (string) length in bytes, including the trailing \0, which // is an integral part of the string: // A string is "in the last word" if a previously-set byte count is at or below // the system word size, or in some cases if the last byte in the (null-padded) // word is null (assume big-endian, including in a register on a little-endian // machine): #define LASTWORD_BY_VALUE(WORD) (! ((WORD) & 0xffL)) #ifdef JU_64BIT // copy from 1..7 bytes from string to Word_t and test if \0 bytes // #define COPYSTRINGtoWORD(WORD,STR) \ { \ do \ { \ uint8_t chr; \ WORD = (Word_t)(STR)[0] << 56; \ if (!(WORD)) break; \ if (!(chr = (STR)[1])) break; \ WORD += ((Word_t)(chr) << 48); \ if (!(chr = (STR)[2])) break; \ WORD += ((Word_t)(chr) << 40); \ if (!(chr = (STR)[3])) break; \ WORD += ((Word_t)(chr) << 32); \ if (!(chr = (STR)[4])) break; \ WORD += ((Word_t)(chr) << 24); \ if (!(chr = (STR)[5])) break; \ WORD += ((Word_t)(chr) << 16); \ if (!(chr = (STR)[6])) break; \ WORD += ((Word_t)(chr) << 8) + (STR)[7]; \ } while(0); \ } // copy Word_t from 1..8 bytes to string and test of \0 bytes // #define COPYWORDtoSTRING(STR,WORD) \ { \ do \ { \ if (!((STR)[0] = (uint8_t)((WORD) >> 56))) break; \ if (!((STR)[1] = (uint8_t)((WORD) >> 48))) break; \ if (!((STR)[2] = (uint8_t)((WORD) >> 40))) break; \ if (!((STR)[3] = (uint8_t)((WORD) >> 32))) break; \ if (!((STR)[4] = (uint8_t)((WORD) >> 24))) break; \ if (!((STR)[5] = (uint8_t)((WORD) >> 16))) break; \ if (!((STR)[6] = (uint8_t)((WORD) >> 8))) break; \ (STR)[7] = (uint8_t)(WORD); \ } while(0); \ } #else // JU_32BIT // copy from 1..4 bytes from string to Word_t and test if \0 bytes #define COPYSTRINGtoWORD(WORD,STR) \ { \ do \ { \ uint8_t chr; \ WORD = (STR)[0] << 24; \ if (WORD == 0) break; \ if (!(chr = (STR)[1])) break; \ WORD += (Word_t)(chr << 16); \ if (!(chr = (STR)[2])) break; \ WORD += (Word_t)(chr << 8) + (STR)[3]; \ } while(0); \ } // copy Word_t from 1..4 bytes to string and test of \0 bytes #define COPYWORDtoSTRING(STR,WORD) \ { \ do \ { \ if (!((STR)[0] = (uint8_t)((WORD) >> 24))) break; \ if (!((STR)[1] = (uint8_t)((WORD) >> 16))) break; \ if (!((STR)[2] = (uint8_t)((WORD) >> 8))) break; \ (STR)[3] = (uint8_t)(WORD); \ } while(0); \ } #endif // JU_32BIT // SUPPORT FOR SINGLE-INDEX SHORTCUT LEAVES: typedef struct SHORCUTLEAF { Pvoid_t scl_Pvalue; // callers value area. uint8_t scl_Index[WORDSIZE]; // base Index string. } scl_t , *Pscl_t; // overhead of the scl_Pvalue only, the scl_Index is calculate elsewhere #define STRUCTOVD (sizeof(scl_t) - WORDSIZE) // How big to malloc a shortcut leaf; stringlen should already include the // trailing null char: #define SCLSIZE(LEN) (((LEN) + STRUCTOVD + WORDSIZE - 1) / WORDSIZE) // string routines, may replace with your own // #define STRCMP(S1,S2) strcmp((void *)(S1), (void *)(S2)) #define STRCPY(S1,S2) strcpy((void *)(S1), (void *)(S2)) #define STRLEN(S1) (strlen((void *)(S1)) + 1) // Index and value area for a shortcut leaf, depending on how it matches the // undecoded remainder of the Index, given a Pscl_t that includes type bits // that must be cleared: // // PSCLINDEX() and PSCLVALUE() are also useful when Pscl contains uncleared // TYPE bits. // // Note: SCLCMP() cannot take advantage of knowing the Index length because // the scl_Index length is not pre-known when these macros are used. #define PSCLINDEX(PSCL) ((CLEAR_PSCL(PSCL))->scl_Index) #define PSCLVALUE(PSCL) ((CLEAR_PSCL(PSCL))->scl_Pvalue) #define SCLCMP(INDEX,PSCL) STRCMP(INDEX, PSCLINDEX(PSCL)) #define PPSCLVALUE_EQ(INDEX,PSCL) \ ((SCLCMP(INDEX, PSCL) == 0) ? &PSCLVALUE(PSCL) : (PPvoid_t)NULL) #define PPSCLVALUE_LT(INDEX,PSCL) \ ((SCLCMP(INDEX, PSCL) < 0) ? &PSCLVALUE(PSCL) : (PPvoid_t)NULL) #define PPSCLVALUE_GT(INDEX,PSCL) \ ((SCLCMP(INDEX, PSCL) > 0) ? &PSCLVALUE(PSCL) : (PPvoid_t)NULL) // Common in-lined code to append or free a shortcut leaf: // // See header comments about premature return(). Note that malloc() does not // pre-zero the memory, so ensure scl_Pvalue is zeroed, just like a value area // in a JudyL array. Hope strcpy() is fast enough in this context. #define APPEND_SCL(PSCL,PPARRAY,INDEX,LEN,PJERROR) \ { \ if (((PSCL) = (Pscl_t) JudyMalloc(SCLSIZE(LEN))) == (Pscl_t)NULL) \ { \ JU_SET_ERRNO(PJERROR, JU_ERRNO_NOMEM); \ return (PPJERR); \ } \ *(PPARRAY) = (Pvoid_t)SET_PSCL(PSCL); \ ((PSCL)->scl_Pvalue) = (Pvoid_t)NULL; \ (void)STRCPY((PSCL)->scl_Index, INDEX); \ } // "FORWARD" DECLARATIONS: static void JudySLModifyErrno(PJError_t PJError, Pcvoid_t PArray, Pcvoid_t PArrayOrig); static int JudySLDelSub(PPvoid_t PPArray, PPvoid_t PPArrayOrig, const uint8_t * Index, Word_t len, PJError_t PJError); static PPvoid_t JudySLPrevSub(Pcvoid_t PArray, uint8_t * Index, int orig, Word_t len, PJError_t PJError); static PPvoid_t JudySLNextSub(Pcvoid_t PArray, uint8_t * Index, int orig, Word_t len, PJError_t PJError); // **************************************************************************** // J U D Y S L M O D I F Y E R R N O // // Common code for error translation: When a caller passes an invalid JAP // ("not a JudyL pointer"), OR if the JudySL array is corrupted at a lower // level, various JudyL*() calls return JU_ERRNO_NOTJUDYL. If the caller wants // detailed error info, convert this particular error to JU_ERRNO_NOTJUDYSL if // at the top of the tree, otherwise convert it to JU_ERRNO_CORRUPT, meaning // there was a corruption (the only one even detectable outside JudyL) in the // JudySL tree; but pass through any other errors unaltered. static void JudySLModifyErrno(PJError_t PJError, // to modify if non-null. Pcvoid_t PArray, // current JudyL array. Pcvoid_t PArrayOrig // top-of-tree JudyL array. ) { // map this Judy errno. if ((PJError != PJE0) && (JU_ERRNO(PJError) == JU_ERRNO_NOTJUDYL)) { if (PArray == PArrayOrig) // callers fault. { JU_SET_ERRNO_NONNULL(PJError, JU_ERRNO_NOTJUDYSL); } else // lower level. { JU_SET_ERRNO_NONNULL(PJError, JU_ERRNO_CORRUPT); } } } // JudySLModifyErrno() // **************************************************************************** // J U D Y S L G E T // // See comments in file header and below. PPvoid_t JudySLGet(Pcvoid_t PArray, const uint8_t * Index, PJError_t PJError) { const uint8_t *pos = Index; // place in Index. Word_t indexword; // buffer for aligned copy. PPvoid_t PPValue; // from JudyL array. // CHECK FOR CALLER ERROR (NULL POINTER): if (Index == (uint8_t *) NULL) { JU_SET_ERRNO(PJError, JU_ERRNO_NULLPINDEX); return (PPJERR); } // SEARCH NEXT LEVEL JUDYL ARRAY IN TREE: // // Use or copy each word from the Index string and check for it in the next // level JudyL array in the array tree, but first watch for shortcut leaves. // Upon invalid Index or end of Index (string) in current word, return. do // until return. { if (IS_PSCL(PArray)) // a shortcut leaf. return (PPSCLVALUE_EQ(pos, PArray)); COPYSTRINGtoWORD(indexword, pos); // copy next 4[8] bytes. JLG(PPValue, PArray, indexword); if ((PPValue == (PPvoid_t) NULL) || LASTWORD_BY_VALUE(indexword)) return (PPValue); // CONTINUE TO NEXT LEVEL DOWN JUDYL ARRAY TREE: // // If a previous JudySLIns() ran out of memory partway down the tree, it left a // null *PPValue; this is automatically treated here as a dead-end (not a core // dump or assertion; see version 1.25). pos += WORDSIZE; PArray = *PPValue; // each value -> next array. } while(1); // forever // NOTREACHED JudySLGet() } // **************************************************************************** // J U D Y S L I N S // // See also the comments in JudySLGet(), which is somewhat similar, though // simpler. // // Theory of operation: // // Upon encountering a null pointer in the tree of JudyL arrays, insert a // shortcut leaf -- including directly under a null root pointer for the first // Index in the JudySL array. // // Upon encountering a pre-existing shortcut leaf, if the old Index is equal to // the new one, return the old value area. Otherwise, "carry down" the old // Index until the old and new Indexes diverge, at which point each Index // either terminates in the last JudyL array or a new shortcut leaf is inserted // under it for the Indexs remainder. // // TBD: Running out of memory below the starting point causes a premature // return below (in several places) and leaves a dead-end in the JudySL tree. // Ideally the code here would back this out rather than wasting a little // memory, but in lieu of that, the get, delete, and search functions // understand dead-ends and handle them appropriately. PPvoid_t JudySLIns(PPvoid_t PPArray, const uint8_t * Index, PJError_t PJError) { PPvoid_t PPArrayOrig = PPArray; // for error reporting. const uint8_t *pos = Index; // place in Index. const uint8_t *pos2 = (uint8_t *) NULL; // old Index (SCL being moved). Word_t len; // bytes remaining. // Note: len2 is set when needed and only used when valid, but this is not // clear to gcc -Wall, so initialize it here to avoid a warning: Word_t len2 = 0; // for old Index (SCL being moved). Word_t scl2 = 0; // size in words of SCL Word_t indexword; // buffer for aligned copy. Word_t indexword2; // for old Index (SCL being moved). PPvoid_t PPValue; // from JudyL array. PPvoid_t PPValue2; // for old Index (SCL being moved). Pscl_t Pscl = (Pscl_t) NULL; // shortcut leaf. Pscl_t Pscl2; // for old Index (SCL being moved). // CHECK FOR CALLER ERROR (NULL POINTERS): if (PPArray == (PPvoid_t) NULL) { JU_SET_ERRNO(PJError, JU_ERRNO_NULLPPARRAY); return (PPJERR); } if (Index == (uint8_t *) NULL) { JU_SET_ERRNO(PJError, JU_ERRNO_NULLPINDEX); return (PPJERR); } len = STRLEN(Index); // bytes remaining. // APPEND SHORTCUT LEAF: // // If PPArray, which is the root pointer to the first or next JudyL array in // the tree, points to null (no next JudyL array), AND there is no shortcut // leaf being carried down, append a shortcut leaf here for the new Index, no // matter how much of the Index string remains (one or more bytes, including // the trailing \0). while (1) // until return. { if (*PPArray == (Pvoid_t)NULL) // no next JudyL array. { if (Pscl == (Pscl_t) NULL) // no SCL being carried down. { APPEND_SCL(Pscl, PPArray, pos, len, PJError); // returns if error. return (&(Pscl->scl_Pvalue)); } // else do nothing here; see below. } // CARRY DOWN PRE-EXISTING SHORTCUT LEAF: // // When PPArray points to a pre-existing shortcut leaf, if its Index is equal // to the Index to be inserted, meaning no insertion is required, return its // value area; otherwise, "move it aside" and "carry it down" -- replace it // (see below) with one or more levels of JudyL arrays. Moving it aside // initially just means setting Pscl non-null, both as a flag and for later // use, and clearing the pointer to the SCL in the JudyL array. else if (IS_PSCL(*PPArray)) { assert(Pscl == (Pscl_t) NULL); // no nested SCLs. Pscl = CLEAR_PSCL(*PPArray); pos2 = Pscl->scl_Index; // note: pos2 is always word-aligned. len2 = STRLEN(pos2); // bytes remaining. // first check if string is already inserted if ((len == len2) && (STRCMP(pos, pos2) == 0)) return (&(Pscl->scl_Pvalue)); *PPArray = (Pvoid_t)NULL; // disconnect SCL. scl2 = SCLSIZE(len2); // save for JudyFree // continue with *PPArray now clear, and Pscl, pos2, len2 set. } // CHECK IF OLD AND NEW INDEXES DIVERGE IN THE CURRENT INDEX WORD: // // If a shortcut leaf is being carried down and its remaining Index chars now // diverge from the remaining chars of the Index being inserted, that is, if // the next words of each Index differ, "plug in" the old Index here, in a new // JudyL array, before proceeding. // // Note: Call JudyLIns() for the SCL Index word before calling it for the new // Index word, so PPValue remains correct for the latter. (JudyLIns() return // values are not stable across multiple calls.) // // Note: Although pos2 is word-aligned, and a Pscl_t is a whole number of // words in size, pos2 is not certain to be null-padded through a whole word, // so copy it first to an index word for later use. // // See header comments about premature return(). COPYSTRINGtoWORD(indexword, pos); // copy next 4[8] bytes. if (Pscl != (Pscl_t) NULL) { COPYSTRINGtoWORD(indexword2, pos2); // copy next 4[8] bytes. if (indexword != indexword2) // SCL and new Indexes diverge. { assert(*PPArray == (Pvoid_t)NULL); // should be new JudyL array. // Note: If JudyLIns() returns JU_ERRNO_NOTJUDYL here, *PPArray should not be // modified, so JudySLModifyErrno() can do the right thing. if ((PPValue2 = JudyLIns(PPArray, indexword2, PJError)) == PPJERR) { JudySLModifyErrno(PJError, *PPArray, *PPArrayOrig); return (PPJERR); } assert(PPValue2 != (PPvoid_t) NULL); // If the old (SCL) Index terminates here, copy its value directly into the // JudyL value area; otherwise create a new shortcut leaf for it, under // *PPValue2 (skipping the word just inserted), and copy its value to the new // SCL: if (len2 <= WORDSIZE) { *((PWord_t)PPValue2) = (Word_t)(Pscl->scl_Pvalue); } else { APPEND_SCL(Pscl2, PPValue2, pos2 + WORDSIZE, len2 - WORDSIZE, PJError); (Pscl2->scl_Pvalue) = Pscl->scl_Pvalue; } // old SCL no longer needed. JudyFree((void *)Pscl, scl2); Pscl = (Pscl_t) NULL; } } // APPEND NEXT LEVEL JUDYL ARRAY TO TREE: // // If a shortcut leaf was carried down and diverged at this level, the code // above already appended the new JudyL array, but the next word of the new // Index still must be inserted in it. // // See header comments about premature return(). // // Note: If JudyLIns() returns JU_ERRNO_NOTJUDYL here, *PPArray should not be // modified, so JudySLModifyErrno() can do the right thing. if ((PPValue = JudyLIns(PPArray, indexword, PJError)) == PPJERR) { JudySLModifyErrno(PJError, *PPArray, *PPArrayOrig); return (PPJERR); } assert(PPValue != (PPvoid_t) NULL); // CHECK IF NEW INDEX TERMINATES: // // Note that if it does, and an old SCL was being carried down, it must have // diverged by this point, and is already handled. if (len <= WORDSIZE) { assert(Pscl == (Pscl_t) NULL); return (PPValue); // is value for whole Index string. } pos += WORDSIZE; len -= WORDSIZE; pos2 += WORDSIZE; // useless unless Pscl is set. len2 -= WORDSIZE; PPArray = PPValue; // each value -> next array. } // while. } // NOTREACHED, JudySLIns() // **************************************************************************** // J U D Y S L D E L // // See the comments in JudySLGet(), which is somewhat similar. // // Unlike JudySLGet() and JudySLIns(), recurse downward through the tree of // JudyL arrays to find and delete the given Index, if present, and then on the // way back up, any of its parent arrays which ends up empty. // // TECHNICAL NOTES: // // Recursion seems bad, but this allows for an arbitrary-length Index. Also, a // more clever iterative solution that used JudyLCount() (see below) would // still require a function call per tree level, so why not just recurse? // // An earlier version (1.20) used a fixed-size stack, which limited the Index // size. We were going to replace this with using JudyLCount(), in order to // note and return to (read this carefully) the highest level JudyL array with // a count of 1, all of whose descendant JudyL arrays also have a count of 1, // and delete from that point downwards. This solution would traverse the // array tree downward looking to see if the given Index is in the tree, then // if so, delete layers downwards starting below the last one that contains // other Indexes than the one being deleted. // // TBD: To save time coding, and to very likely save time overall during // execution, this function does "lazy deletions", or putting it more nicely, // it allows "hysteresis" in the JudySL tree, when shortcut leafs are present. // It only removes the specified Index, and recursively any empty JudyL arrays // above it, without fully reversing the effects of JudySLIns(). This is // probably OK because any application that calls JudySLDel() is likely to call // JudySLIns() again with the same or a neighbor Index. int JudySLDel(PPvoid_t PPArray, const uint8_t * Index, PJError_t PJError) // optional, for returning error info. { // Check for caller error (null pointer): if (PPArray == (PPvoid_t) NULL) { JU_SET_ERRNO(PJError, JU_ERRNO_NULLPPARRAY); return (JERR); } if (Index == (uint8_t *) NULL) { JU_SET_ERRNO(PJError, JU_ERRNO_NULLPINDEX); return (JERR); } // Do the deletion: return (JudySLDelSub(PPArray, PPArray, Index, STRLEN(Index), PJError)); } // JudySLDel() // **************************************************************************** // J U D Y S L D E L S U B // // This is the "engine" for JudySLDel() that expects aligned and len to already // be computed (only once). See the header comments for JudySLDel(). static int JudySLDelSub(PPvoid_t PPArray, // in which to delete. PPvoid_t PPArrayOrig, // for error reporting. const uint8_t * Index, // to delete. Word_t len, // bytes remaining. PJError_t PJError) // optional, for returning error info. { Word_t indexword; // next word to find. PPvoid_t PPValue; // from JudyL array. int retcode; // from lower-level call. assert(PPArray != (PPvoid_t) NULL); assert(Index != (uint8_t *) NULL); // DELETE SHORTCUT LEAF: // // As described above, this can leave an empty JudyL array, or one containing // only a single other Index word -- which could be, but is not, condensed into // a higher-level shortcut leaf. More precisely, at this level it leaves a // temporary "dead end" in the JudySL tree, similar to when running out of // memory during JudySLIns(), and this is somewhat cleaned up by higher // recursions of the same function (see below); but remaining shortcut leaves // for other Indexes are not coalesced. if (IS_PSCL(*PPArray)) { Pscl_t Pscll = CLEAR_PSCL(*PPArray); Word_t words; if (STRCMP(Index, Pscll->scl_Index)) return (0); // incorrect index. words = SCLSIZE(STRLEN(Pscll->scl_Index)); JudyFree((void *)Pscll, words); *PPArray = (Pvoid_t)NULL; return (1); // correct index deleted. } // DELETE LAST INDEX WORD, FROM CURRENT JUDYL ARRAY: // // When at the end of the full Index, delete the last word, if present, from // the current JudyL array, and return the result all the way up. COPYSTRINGtoWORD(indexword, Index); // copy next 4[8] bytes. if (len <= WORDSIZE) { if ((retcode = JudyLDel(PPArray, indexword, PJError)) == JERR) { JudySLModifyErrno(PJError, *PPArray, *PPArrayOrig); return (JERR); } return (retcode); } // DELETE BELOW NON-LAST INDEX WORD IN CURRENT JUDYL ARRAY: // // If a word before the end of the full Index is present in the current JudyL // array, recurse through its value, which must be a pointer to another JudyL // array, to continue the deletion at the next level. Return the JudyLGet() // return if the Indexs current word is not in the JudyL array, or if no // delete occurs below this level, both of which mean the whole Index is not // currently valid. // JLG(PPValue, *PPArray, indexword); if (PPValue == (PPvoid_t) NULL) return (0); // Index not in JudySL array. // If a previous JudySLIns() ran out of memory partway down the tree, it left a // null *PPValue; this is automatically treated as a dead-end (not a core dump // or assertion; see version 1.25). if ((retcode = JudySLDelSub(PPValue, PPArrayOrig, Index + WORDSIZE, len - WORDSIZE, PJError)) != 1) { return (retcode); // no lower-level delete, or error. } // DELETE EMPTY JUDYL ARRAY: // // A delete occurred below in the tree. If the child JudyL array became empty, // delete the current Index word from the current JudyL array, which could // empty the current array and null out *PPArray in turn (or pass through an // error). Otherwise simply indicate that a deletion did occur. if (*PPValue == (Pvoid_t)NULL) { if ((retcode = JudyLDel(PPArray, indexword, PJError)) == JERR) { JudySLModifyErrno(PJError, *PPArray, *PPArrayOrig); return (JERR); } return (retcode); } return (1); } // JudySLDelSub() // **************************************************************************** // J U D Y S L P R E V // // Recursively traverse the JudySL tree downward using JudyLGet() to look for // each successive index word from Index in the JudyL array at each level. At // the last level for the Index (LASTWORD_BY_LEN()), use JudyLPrev() instead of // JudyLGet(), to exclude the initial Index. If this doesnt result in finding // a previous Index, work back up the tree using JudyLPrev() at each higher // level to search for a previous index word. Upon finding a previous index // word, descend again if/as necessary, this time inclusively, to find and // return the full previous Index. // // Also support shortcut leaves. // // Since this function is recursive and it also needs to know if its still // looking for the original Index (to exclude it at the LASTWORD_BY_LEN() // level) or for the remaining words of the previous Index (inclusive), // actually call a subroutine that takes an additional parameter. // // See also the technical notes in JudySLDel() regarding the use of recursion // rather than iteration. PPvoid_t JudySLPrev(Pcvoid_t PArray, uint8_t * Index, PJError_t PJError) // optional, for returning error info. { // Check for caller error (null pointer), or empty JudySL array: if (Index == (uint8_t *) NULL) { JU_SET_ERRNO(PJError, JU_ERRNO_NULLPINDEX); return (PPJERR); } if (PArray == (Pvoid_t)NULL) return ((PPvoid_t) NULL); // Do the search: return (JudySLPrevSub(PArray, Index, /* original = */ 1, STRLEN(Index), PJError)); } // JudySLPrev() // **************************************************************************** // J U D Y S L P R E V S U B // // This is the "engine" for JudySLPrev() that knows whether its still looking // for the original Index (exclusive) or a neighbor index (inclusive), and that // expects aligned and len to already be computed (only once). See the header // comments for JudySLPrev(). static PPvoid_t JudySLPrevSub(Pcvoid_t PArray, uint8_t * Index, int orig, Word_t len, // bytes remaining. PJError_t PJError) // optional, for returning error info. { Word_t indexword; // next word to find. PPvoid_t PPValue; // from JudyL array. // ORIGINAL SEARCH: // // When at a shortcut leaf, copy its remaining Index (string) chars into Index // and return its value area if the current Index is after (greater than) the // SCLs index; otherwise return null. if (orig) { if (IS_PSCL(PArray)) { if ((PPValue = PPSCLVALUE_GT(Index, PArray)) != (PPvoid_t) NULL) (void)STRCPY(Index, PSCLINDEX(PArray)); return (PPValue); } // If the current Index word: // - is not the last word in Index (end of string), // - exists in the current JudyL array, and, // - a previous Index is found below it, return that Indexs value area. COPYSTRINGtoWORD(indexword, Index); // copy next 4[8] bytes. if (len > WORDSIZE) // not at end of Index. { JLG(PPValue, PArray, indexword); if (PPValue != (PPvoid_t) NULL) { // If a previous JudySLIns() ran out of memory partway down the tree, it left a // null *PPValue; this is automatically treated as a dead-end (not a core dump // or assertion; see version 1.25): PPValue = JudySLPrevSub(*PPValue, Index + WORDSIZE, /* original = */ 1, len - WORDSIZE, PJError); if (PPValue == PPJERR) return (PPJERR); // propagate error. if (PPValue != (PPvoid_t) NULL) return (PPValue); // see above. } } // Search for previous index word: // // One of the above conditions is false. Search the current JudyL array for // the Index word, if any, prior to the current index word. If none is found, // return null; otherwise fall through to common later code. if ((PPValue = JudyLPrev(PArray, &indexword, PJError)) == PPJERR) { JudySLModifyErrno(PJError, PArray, orig ? PArray : (Pvoid_t)NULL); return (PPJERR); } if (PPValue == (PPvoid_t) NULL) return ((PPvoid_t) NULL); // no previous index word. } // if. // SUBSEQUENT SEARCH: // // A higher level search already excluded the initial Index, then found a // previous index word, and is now traversing down to determine the rest of the // Index and to obtain its value area. If at a shortcut leaf, return its value // area. Otherwise search the current JudyL array backward from the upper // limit for its last index word. If no index word is found, return null -- // should never happen unless the JudySL tree is corrupt; otherwise fall // through to common later code. else { if (IS_PSCL(PArray)) // at shortcut leaf. { (void)STRCPY(Index, PSCLINDEX(PArray)); return (&PSCLVALUE(PArray)); } indexword = ~0UL; if ((PPValue = JudyLLast(PArray, &indexword, PJError)) == PPJERR) { JudySLModifyErrno(PJError, PArray, orig ? PArray : (Pvoid_t)NULL); return (PPJERR); } // If a previous JudySLIns() ran out of memory partway down the tree, it left a // null *PPValue; this is automatically treated as a dead-end (not a core dump // or assertion; see version 1.25): if (PPValue == (PPvoid_t) NULL) return ((PPvoid_t) NULL); // no previous index word. } // FOUND PREVIOUS INDEX WORD: // // A previous (if original) or last (if subsequent) index word was located in // the current JudyL array. Store it into the callers Index (string). Then // if the found (previous) Index ends here, return its value area; otherwise do // a subsequent search below this point, which should never fail unless the // JudySL tree is corrupt, but this is detected at a lower level by the above // assertion. // // Note: Treat Index as unaligned, even if it is aligned, to avoid writing // past the end of allocated memory (in case its less than a whole number of // words). COPYWORDtoSTRING(Index, indexword); // copy next 4[8] bytes. if (LASTWORD_BY_VALUE(indexword)) return (PPValue); // If a previous JudySLIns() ran out of memory partway down the tree, it left a // null *PPValue; this is automatically treated as a dead-end (not a core dump // or assertion; see version 1.25): return (JudySLPrevSub(*PPValue, Index + WORDSIZE, /* original = */ 0, len - WORDSIZE, PJError)); } // JudySLPrevSub() // **************************************************************************** // J U D Y S L N E X T // // See the comments in JudySLPrev(), which is very similar. // // TBD: Could the two functions call a common engine function with various // subfunctions and other constants specified? PPvoid_t JudySLNext(Pcvoid_t PArray, uint8_t * Index, PJError_t PJError) // optional, for returning error info. { // Check for caller error (null pointer), or empty JudySL array: if (Index == (uint8_t *) NULL) { JU_SET_ERRNO(PJError, JU_ERRNO_NULLPINDEX); return (PPJERR); } if (PArray == (Pvoid_t)NULL) return ((PPvoid_t) NULL); // Do the search: return (JudySLNextSub(PArray, Index, /* original = */ 1, STRLEN(Index), PJError)); } // JudySLNext() // **************************************************************************** // J U D Y S L N E X T S U B // // See the comments in JudySLPrevSub(), which is very similar. static PPvoid_t JudySLNextSub(Pcvoid_t PArray, uint8_t * Index, int orig, Word_t len, // bytes remaining. PJError_t PJError) // optional, for returning error info. { Word_t indexword; // next word to find. PPvoid_t PPValue; // from JudyL array. if (orig) { if (IS_PSCL(PArray)) { if ((PPValue = PPSCLVALUE_LT(Index, PArray)) != (PPvoid_t) NULL) (void)STRCPY(Index, PSCLINDEX(PArray)); return (PPValue); } COPYSTRINGtoWORD(indexword, Index); // copy next 4[8] bytes. if (len > WORDSIZE) // not at end of Index. { JLG(PPValue, PArray, indexword); if (PPValue != (PPvoid_t) NULL) { // If a previous JudySLIns() ran out of memory partway down the tree, it left a // null *PPValue; this is automatically treated as a dead-end (not a core dump // or assertion; see version 1.25): PPValue = JudySLNextSub(*PPValue, Index + WORDSIZE, /* original = */ 1, len - WORDSIZE, PJError); if (PPValue == PPJERR) return (PPJERR); // propagate error. if (PPValue != (PPvoid_t) NULL) return (PPValue); // see above. } } if ((PPValue = JudyLNext(PArray, &indexword, PJError)) == PPJERR) { JudySLModifyErrno(PJError, PArray, orig ? PArray : (Pvoid_t)NULL); return (PPJERR); } if (PPValue == (PPvoid_t) NULL) return ((PPvoid_t) NULL); // no next index word. } else { if (IS_PSCL(PArray)) // at shortcut leaf. { (void)STRCPY(Index, PSCLINDEX(PArray)); return (&PSCLVALUE(PArray)); } indexword = 0; if ((PPValue = JudyLFirst(PArray, &indexword, PJError)) == PPJERR) { JudySLModifyErrno(PJError, PArray, orig ? PArray : (Pvoid_t)NULL); return (PPJERR); } // If a previous JudySLIns() ran out of memory partway down the tree, it left a // null *PPValue; this is automatically treated as a dead-end (not a core dump // or assertion; see version 1.25): if (PPValue == (PPvoid_t) NULL) return ((PPvoid_t) NULL); // no next index word. } COPYWORDtoSTRING(Index, indexword); // copy next 4[8] bytes if (LASTWORD_BY_VALUE(indexword)) return (PPValue); // If a previous JudySLIns() ran out of memory partway down the tree, it left a // null *PPValue; this is automatically treated as a dead-end (not a core dump // or assertion; see version 1.25): return (JudySLNextSub(*PPValue, Index + WORDSIZE, /* original = */ 0, len - WORDSIZE, PJError)); } // JudySLNextSub() // **************************************************************************** // J U D Y S L F I R S T // // Like JudyLFirst(), do a JudySLGet(), then if necessary a JudySLNext(). PPvoid_t JudySLFirst(Pcvoid_t PArray, uint8_t * Index, PJError_t PJError) // optional, for returning error info. { PPvoid_t PPValue; // from JudyL array. if (Index == (uint8_t *) NULL) { JU_SET_ERRNO(PJError, JU_ERRNO_NULLPINDEX); return (PPJERR); } if ((PPValue = JudySLGet(PArray, Index, PJError)) == PPJERR) return (PPJERR); // propagate serious error. if ((PPValue == (PPvoid_t) NULL) // first try failed. && ((PPValue = JudySLNext(PArray, Index, PJError)) == PPJERR)) { return (PPJERR); // propagate serious error. } return (PPValue); } // JudySLFirst() // **************************************************************************** // J U D Y S L L A S T // // Like JudyLLast(), do a JudySLGet(), then if necessary a JudySLPrev(). PPvoid_t JudySLLast(Pcvoid_t PArray, uint8_t * Index, PJError_t PJError) // optional, for returning error info. { PPvoid_t PPValue; // from JudyL array. if (Index == (uint8_t *) NULL) { JU_SET_ERRNO(PJError, JU_ERRNO_NULLPINDEX); return (PPJERR); } if ((PPValue = JudySLGet(PArray, Index, PJError)) == PPJERR) return (PPJERR); // propagate serious error. if ((PPValue == (PPvoid_t) NULL) // first try failed. && ((PPValue = JudySLPrev(PArray, Index, PJError)) == PPJERR)) { return (PPJERR); // propagate serious error. } return (PPValue); } // JudySLLast() // **************************************************************************** // J U D Y S L F R E E A R R A Y // // Walk the JudySL tree of JudyL arrays to free each JudyL array, depth-first. // During the walk, ignore indexes (strings) that end in the current JudyL // array to be freed. Just recurse through those indexes which do not end, // that is, those whose associated value areas point to subsidiary JudyL // arrays, except for those which point to shortcut leaves. Return the total // bytes freed in all of the JudyL arrays at or below the current level. // // Like the JudyLFreeArray() and Judy1FreeArray() code, this is written // recursively, which is probably fast enough, to allow indexes (strings) of // arbitrary size. If recursion turns out to be a problem, consider instead // doing some large, fixed number of iterative descents (like 100) using a // fixed-size "stack" (array), then recursing upon overflow (relatively // rarely). Word_t JudySLFreeArray(PPvoid_t PPArray, PJError_t PJError) // optional, for returning error info. { PPvoid_t PPArrayOrig = PPArray; // for error reporting. Word_t indexword = 0; // word just found. PPvoid_t PPValue; // from Judy array. Word_t bytes_freed = 0; // bytes freed at this level. Word_t bytes_total = 0; // bytes freed at all levels. if (PPArray == (PPvoid_t) NULL) { JU_SET_ERRNO(PJError, JU_ERRNO_NULLPPARRAY); return (JERR); } // FREE SHORTCUT LEAF: if (IS_PSCL(*PPArray)) { Word_t freewords; Pscl_t Pscl; Pscl = CLEAR_PSCL(*PPArray); freewords = SCLSIZE(STRLEN(Pscl->scl_Index)); JudyFree((void *)Pscl, freewords); *PPArray = (Pvoid_t)NULL; return (freewords * WORDSIZE); } // FREE EACH SUB-ARRAY (DEPTH-FIRST): // // If a previous JudySLIns() ran out of memory partway down the tree, it left a // null *PPValue. This is automatically treated correctly here as a dead-end. // // An Index (string) ends in the current word iff the last byte of the // (null-padded) word is null. for (PPValue = JudyLFirst(*PPArray, &indexword, PJError); (PPValue != (PPvoid_t) NULL) && (PPValue != PPJERR); PPValue = JudyLNext(*PPArray, &indexword, PJError)) { if (!LASTWORD_BY_VALUE(indexword)) { if ((bytes_freed = JudySLFreeArray(PPValue, PJError)) == JERR) return (JERR); // propagate serious error. bytes_total += bytes_freed; } } // Check for a serious error in a JudyL*() call: if (PPValue == PPJERR) { JudySLModifyErrno(PJError, *PPArray, *PPArrayOrig); return (JERR); } // Now free the current array, which also nulls the pointer: // // Note: *PPArray can be null here for a totally null JudySL array => // JudyLFreeArray() returns zero. if ((bytes_freed = JudyLFreeArray(PPArray, PJError)) == JERR) { JudySLModifyErrno(PJError, *PPArray, *PPArrayOrig); return (JERR); } return (bytes_total + bytes_freed); } // JudySLFreeArray() judy-1.0.5/src/JudySL/README0000644000175000017500000000027310204462077015541 0ustar troyhebetroyhebe# @(#) $Revision: 4.3 $ $Source: /judy/src/JudySL/README $ # # This tree contains sources for the JudySL*() functions. JudySL.c source file Note: JudySL.h is no longer needed (May 2004) judy-1.0.5/src/Makefile.am0000644000175000017500000000012610624600161015532 0ustar troyhebetroyhebeSUBDIRS = . JudyCommon JudyL Judy1 JudySL JudyHS obj DISTCLEANFILES = .deps Makefile judy-1.0.5/src/sh_build0000755000175000017500000002537310204462077015236 0ustar troyhebetroyhebeecho "--- This is a compile kit to suggest how to port to your machine" echo "--- This script runs in 7 seconds on a 3.2Ghz Pentium P4C" echo "--- Must be in the 'src' directory to execute this script" echo "--- I normally run it like: COPT='-O3 -march=i686' sh_build" echo "--- Set Compiler" CC='cc' echo "--- Set Optimization" # COPT='-O' echo "--- Set Shared library option" # CPIC='-fPIC CPIC='' echo "--- Compile JudyMalloc - common to Judy1 and JudyL" echo "--- cd JudyCommon" cd JudyCommon rm -f *.o $CC $COPT $CPIC -I. -I.. -c JudyMalloc.c echo "--- cd .." cd .. echo "--- Give Judy1 the proper names" echo "--- cd Judy1" cd Judy1 rm -f *.o ln -sf ../JudyCommon/JudyByCount.c Judy1ByCount.c ln -sf ../JudyCommon/JudyCascade.c Judy1Cascade.c ln -sf ../JudyCommon/JudyCount.c Judy1Count.c ln -sf ../JudyCommon/JudyCreateBranch.c Judy1CreateBranch.c ln -sf ../JudyCommon/JudyDecascade.c Judy1Decascade.c ln -sf ../JudyCommon/JudyDel.c Judy1Unset.c ln -sf ../JudyCommon/JudyFirst.c Judy1First.c ln -sf ../JudyCommon/JudyFreeArray.c Judy1FreeArray.c ln -sf ../JudyCommon/JudyGet.c Judy1Test.c ln -sf ../JudyCommon/JudyGet.c j__udy1Test.c ln -sf ../JudyCommon/JudyInsArray.c Judy1SetArray.c ln -sf ../JudyCommon/JudyIns.c Judy1Set.c ln -sf ../JudyCommon/JudyInsertBranch.c Judy1InsertBranch.c ln -sf ../JudyCommon/JudyMallocIF.c Judy1MallocIF.c ln -sf ../JudyCommon/JudyMemActive.c Judy1MemActive.c ln -sf ../JudyCommon/JudyMemUsed.c Judy1MemUsed.c ln -sf ../JudyCommon/JudyPrevNext.c Judy1Next.c ln -sf ../JudyCommon/JudyPrevNext.c Judy1Prev.c ln -sf ../JudyCommon/JudyPrevNextEmpty.c Judy1NextEmpty.c ln -sf ../JudyCommon/JudyPrevNextEmpty.c Judy1PrevEmpty.c ln -sf ../JudyCommon/JudyTables.c Judy1TablesGen.c echo "--- This table is constructed from Judy1.h data to match malloc(3) needs" echo "--- $CC $COPT -I. -I.. -I../JudyCommon -DJUDY1 Judy1TablesGen.c -o Judy1TablesGen" $CC $COPT -I. -I.. -I../JudyCommon -DJUDY1 Judy1TablesGen.c -o Judy1TablesGen rm -f *.o ./Judy1TablesGen echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 Judy1Tables.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 Judy1Tables.c echo "--- Compile the main line Judy1 modules" echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 Judy1Test.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 Judy1Test.c echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 -DJUDYGETINLINE j__udy1Test.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 -DJUDYGETINLINE j__udy1Test.c echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 Judy1Set.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 Judy1Set.c echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 Judy1SetArray.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 Judy1SetArray.c echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 Judy1Unset.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 Judy1Unset.c echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 Judy1First.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 Judy1First.c echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 -DJUDYNEXT Judy1Next.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 -DJUDYNEXT Judy1Next.c echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 -DJUDYPREV Judy1Prev.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 -DJUDYPREV Judy1Prev.c echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 -DJUDYNEXT Judy1NextEmpty.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 -DJUDYNEXT Judy1NextEmpty.c echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 -DJUDYPREV Judy1PrevEmpty.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 -DJUDYPREV Judy1PrevEmpty.c echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 Judy1Count.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 Judy1Count.c echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 -DNOSMARTJBB -DNOSMARTJBU -DNOSMARTJLB Judy1ByCount.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 -DNOSMARTJBB -DNOSMARTJBU -DNOSMARTJLB Judy1ByCount.c echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 Judy1FreeArray.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 Judy1FreeArray.c echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 Judy1MemUsed.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 Judy1MemUsed.c echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 Judy1MemActive.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 Judy1MemActive.c echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 Judy1Cascade.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 Judy1Cascade.c echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 Judy1Decascade.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 Judy1Decascade.c echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 Judy1CreateBranch.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 Judy1CreateBranch.c echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 Judy1InsertBranch.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 Judy1InsertBranch.c echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 Judy1MallocIF.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDY1 Judy1MallocIF.c echo "--- cd .." cd .. echo "--- Give JudyL the proper names" echo "--- cd JudyL" cd JudyL rm -f *.o ln -sf ../JudyCommon/JudyByCount.c JudyLByCount.c ln -sf ../JudyCommon/JudyCascade.c JudyLCascade.c ln -sf ../JudyCommon/JudyCount.c JudyLCount.c ln -sf ../JudyCommon/JudyCreateBranch.c JudyLCreateBranch.c ln -sf ../JudyCommon/JudyDecascade.c JudyLDecascade.c ln -sf ../JudyCommon/JudyDel.c JudyLDel.c ln -sf ../JudyCommon/JudyFirst.c JudyLFirst.c ln -sf ../JudyCommon/JudyFreeArray.c JudyLFreeArray.c ln -sf ../JudyCommon/JudyGet.c JudyLGet.c ln -sf ../JudyCommon/JudyGet.c j__udyLGet.c ln -sf ../JudyCommon/JudyInsArray.c JudyLInsArray.c ln -sf ../JudyCommon/JudyIns.c JudyLIns.c ln -sf ../JudyCommon/JudyInsertBranch.c JudyLInsertBranch.c ln -sf ../JudyCommon/JudyMallocIF.c JudyLMallocIF.c ln -sf ../JudyCommon/JudyMemActive.c JudyLMemActive.c ln -sf ../JudyCommon/JudyMemUsed.c JudyLMemUsed.c ln -sf ../JudyCommon/JudyPrevNext.c JudyLNext.c ln -sf ../JudyCommon/JudyPrevNext.c JudyLPrev.c ln -sf ../JudyCommon/JudyPrevNextEmpty.c JudyLNextEmpty.c ln -sf ../JudyCommon/JudyPrevNextEmpty.c JudyLPrevEmpty.c ln -sf ../JudyCommon/JudyTables.c JudyLTablesGen.c echo "--- This table is constructed from JudyL.h data to match malloc(3) needs" echo "--- $CC $COPT -I. -I.. -I../JudyCommon -DJUDYL JudyLTablesGen.c -o JudyLTablesGen" $CC $COPT -I. -I.. -I../JudyCommon -DJUDYL JudyLTablesGen.c -o JudyLTablesGen rm -f *.o ./JudyLTablesGen echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL JudyLTables.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL JudyLTables.c echo "--- Compile the main line JudyL modules" echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL JudyLGet.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL JudyLGet.c echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL -DJUDYGETINLINE j__udyLGet.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL -DJUDYGETINLINE j__udyLGet.c echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL JudyLIns.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL JudyLIns.c echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL JudyLIns.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL JudyLInsArray.c echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL JudyLDel.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL JudyLDel.c echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL JudyLFirst.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL JudyLFirst.c echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL -DJUDYNEXT JudyLNext.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL -DJUDYNEXT JudyLNext.c echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL -DJUDYPREV JudyLPrev.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL -DJUDYPREV JudyLPrev.c echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL -DJUDYNEXT JudyLNextEmpty.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL -DJUDYNEXT JudyLNextEmpty.c echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL -DJUDYPREV JudyLPrevEmpty.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL -DJUDYPREV JudyLPrevEmpty.c echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL JudyLCount.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL JudyLCount.c echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL -DNOSMARTJBB -DNOSMARTJBU -DNOSMARTJLB JudyLByCount.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL -DNOSMARTJBB -DNOSMARTJBU -DNOSMARTJLB JudyLByCount.c echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL JudyLFreeArray.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL JudyLFreeArray.c echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL JudyLMemUsed.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL JudyLMemUsed.c echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL JudyLMemActive.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL JudyLMemActive.c echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL JudyLCascade.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL JudyLCascade.c echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL JudyLDecascade.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL JudyLDecascade.c echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL JudyLCreateBranch.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL JudyLCreateBranch.c echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL JudyLInsertBranch.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL JudyLInsertBranch.c echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL JudyLMallocIF.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c -DJUDYL JudyLMallocIF.c echo "--- cd .." cd .. echo "--- Compile the JudySL routine" echo "--- cd JudySL" cd JudySL rm -f *.o echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c JudySL.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c JudySL.c echo "--- cd .." cd .. echo "--- Compile the JudyHS routine" echo "--- cd JudyHS" cd JudyHS rm -f *.o echo "--- $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c JudyHS.c" $CC $COPT $CPIC -I. -I.. -I../JudyCommon -c JudyHS.c echo "--- cd .." cd .. # Make a Judy shared library with CPIC='-fPIC' above #ld -shared -o libJudy.so Judy*/*.o # # -OR- # echo "--- Make a Judy static library" ar -r libJudy.a Judy*/*.o echo "--- Done" judy-1.0.5/src/obj/0000755000175000017500000000000010624600217014253 5ustar troyhebetroyhebejudy-1.0.5/src/obj/Makefile.in0000644000175000017500000003366010624600217016330 0ustar troyhebetroyhebe# Makefile.in generated by automake 1.9.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ top_builddir = ../.. am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd INSTALL = @INSTALL@ install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/obj DIST_COMMON = $(include_HEADERS) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)" libLTLIBRARIES_INSTALL = $(INSTALL) LTLIBRARIES = $(lib_LTLIBRARIES) libJudy_la_DEPENDENCIES = ../JudyCommon/*.lo ../JudyL/*.lo \ ../Judy1/*.lo ../JudyHS/*.lo ../JudySL/*.lo am_libJudy_la_OBJECTS = libJudy_la_OBJECTS = $(am_libJudy_la_OBJECTS) DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ SOURCES = $(libJudy_la_SOURCES) DIST_SOURCES = $(libJudy_la_SOURCES) includeHEADERS_INSTALL = $(INSTALL_HEADER) HEADERS = $(include_HEADERS) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMDEP_FALSE = @AMDEP_FALSE@ AMDEP_TRUE = @AMDEP_TRUE@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO = @ECHO@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ F77 = @F77@ FFLAGS = @FFLAGS@ FLAVOR = @FLAVOR@ GREP = @GREP@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ MAKEINFO = @MAKEINFO@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ VERSION_INFO = @VERSION_INFO@ WARN_CFLAGS = @WARN_CFLAGS@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_F77 = @ac_ct_F77@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ AM_CFLAGS = @WARN_CFLAGS@ CLEANFILES = libJudy.la include_HEADERS = ../Judy.h lib_LTLIBRARIES = libJudy.la libJudy_la_SOURCES = libJudy_la_LIBADD = ../JudyCommon/*.lo ../JudyL/*.lo ../Judy1/*.lo ../JudyHS/*.lo ../JudySL/*.lo libJudy_la_LDFLAGS = @VERSION_INFO@ DISTCLEANFILES = .deps Makefile all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/obj/Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --gnu src/obj/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(mkdir_p) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ if test -f $$p; then \ f=$(am__strip_dir) \ echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \ else :; fi; \ done uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @set -x; list='$(lib_LTLIBRARIES)'; for p in $$list; do \ p=$(am__strip_dir) \ echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \ $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libJudy.la: $(libJudy_la_OBJECTS) $(libJudy_la_DEPENDENCIES) $(LINK) -rpath $(libdir) $(libJudy_la_LDFLAGS) $(libJudy_la_OBJECTS) $(libJudy_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs distclean-libtool: -rm -f libtool uninstall-info-am: install-includeHEADERS: $(include_HEADERS) @$(NORMAL_INSTALL) test -z "$(includedir)" || $(mkdir_p) "$(DESTDIR)$(includedir)" @list='$(include_HEADERS)'; for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ f=$(am__strip_dir) \ echo " $(includeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(includedir)/$$f'"; \ $(includeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(includedir)/$$f"; \ done uninstall-includeHEADERS: @$(NORMAL_UNINSTALL) @list='$(include_HEADERS)'; for p in $$list; do \ f=$(am__strip_dir) \ echo " rm -f '$(DESTDIR)$(includedir)/$$f'"; \ rm -f "$(DESTDIR)$(includedir)/$$f"; \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$tags $$unique; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ test -z "$(CTAGS_ARGS)$$tags$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$tags $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && cd $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) $$here distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) $(mkdir_p) $(distdir)/.. @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ list='$(DISTFILES)'; for file in $$list; do \ case $$file in \ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ esac; \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ if test "$$dir" != "$$file" && test "$$dir" != "."; then \ dir="/$$dir"; \ $(mkdir_p) "$(distdir)$$dir"; \ else \ dir=''; \ fi; \ if test -d $$d/$$file; then \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) $(HEADERS) installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"; do \ test -z "$$dir" || $(mkdir_p) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-libtool distclean-tags dvi: dvi-am dvi-am: html: html-am info: info-am info-am: install-data-am: install-includeHEADERS install-exec-am: install-libLTLIBRARIES install-info: install-info-am install-man: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-includeHEADERS uninstall-info-am \ uninstall-libLTLIBRARIES .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-libLTLIBRARIES clean-libtool ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-exec \ install-exec-am install-includeHEADERS install-info \ install-info-am install-libLTLIBRARIES install-man \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags uninstall uninstall-am \ uninstall-includeHEADERS uninstall-info-am \ uninstall-libLTLIBRARIES # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: judy-1.0.5/src/obj/Makefile.am0000644000175000017500000000045510624600161016311 0ustar troyhebetroyhebeAM_CFLAGS = @WARN_CFLAGS@ CLEANFILES = libJudy.la include_HEADERS = ../Judy.h lib_LTLIBRARIES = libJudy.la libJudy_la_SOURCES = libJudy_la_LIBADD = ../JudyCommon/*.lo ../JudyL/*.lo ../Judy1/*.lo ../JudyHS/*.lo ../JudySL/*.lo libJudy_la_LDFLAGS = @VERSION_INFO@ DISTCLEANFILES = .deps Makefile judy-1.0.5/src/Judy1/0000755000175000017500000000000010624600216014474 5ustar troyhebetroyhebejudy-1.0.5/src/Judy1/Makefile.am0000644000175000017500000000715610624600161016540 0ustar troyhebetroyhebeINCLUDES = -I. -I.. -I../JudyCommon/ AM_CFLAGS = -DJUDY1 @WARN_CFLAGS@ noinst_LTLIBRARIES = libJudy1.la libnext.la libprev.la libcount.la libinline.la libJudy1_la_SOURCES = Judy1Test.c Judy1Tables.c Judy1Set.c Judy1SetArray.c Judy1Unset.c Judy1Cascade.c Judy1Count.c Judy1CreateBranch.c Judy1Decascade.c Judy1First.c Judy1FreeArray.c Judy1InsertBranch.c Judy1MallocIF.c Judy1MemActive.c Judy1MemUsed.c libnext_la_SOURCES = Judy1Next.c Judy1NextEmpty.c libnext_la_CFLAGS = $(AM_CFLAGS) -DJUDYNEXT libprev_la_SOURCES = Judy1Prev.c Judy1PrevEmpty.c libprev_la_CFLAGS = $(AM_CFLAGS) -DJUDYPREV libcount_la_SOURCES = Judy1ByCount.c libcount_la_CFLAGS = $(AM_CFLAGS) -DNOSMARTJBB -DNOSMARTJBU -DNOSMARTJLB libinline_la_SOURCES = j__udy1Test.c libinline_la_CFLAGS = $(AM_CFLAGS) -DJUDYGETINLINE Judy1Tables.c: Judy1TablesGen.c $(CC) $(INCLUDES) $(AM_CFLAGS) @CFLAGS@ -o Judy1TablesGen Judy1TablesGen.c; ./Judy1TablesGen Judy1ByCount.c:../JudyCommon/JudyByCount.c cp -f ../JudyCommon/JudyByCount.c Judy1ByCount.c Judy1Cascade.c:../JudyCommon/JudyCascade.c cp -f ../JudyCommon/JudyCascade.c Judy1Cascade.c Judy1Count.c:../JudyCommon/JudyCount.c cp -f ../JudyCommon/JudyCount.c Judy1Count.c Judy1CreateBranch.c:../JudyCommon/JudyCreateBranch.c cp -f ../JudyCommon/JudyCreateBranch.c Judy1CreateBranch.c Judy1Decascade.c:../JudyCommon/JudyDecascade.c cp -f ../JudyCommon/JudyDecascade.c Judy1Decascade.c Judy1Unset.c:../JudyCommon/JudyDel.c cp -f ../JudyCommon/JudyDel.c Judy1Unset.c Judy1First.c:../JudyCommon/JudyFirst.c cp -f ../JudyCommon/JudyFirst.c Judy1First.c Judy1FreeArray.c:../JudyCommon/JudyFreeArray.c cp -f ../JudyCommon/JudyFreeArray.c Judy1FreeArray.c Judy1Test.c:../JudyCommon/JudyGet.c cp -f ../JudyCommon/JudyGet.c Judy1Test.c j__udy1Test.c:../JudyCommon/JudyGet.c cp -f ../JudyCommon/JudyGet.c j__udy1Test.c Judy1SetArray.c:../JudyCommon/JudyInsArray.c cp -f ../JudyCommon/JudyInsArray.c Judy1SetArray.c Judy1Set.c:../JudyCommon/JudyIns.c cp -f ../JudyCommon/JudyIns.c Judy1Set.c Judy1InsertBranch.c:../JudyCommon/JudyInsertBranch.c cp -f ../JudyCommon/JudyInsertBranch.c Judy1InsertBranch.c Judy1MallocIF.c:../JudyCommon/JudyMallocIF.c cp -f ../JudyCommon/JudyMallocIF.c Judy1MallocIF.c Judy1MemActive.c:../JudyCommon/JudyMemActive.c cp -f ../JudyCommon/JudyMemActive.c Judy1MemActive.c Judy1MemUsed.c:../JudyCommon/JudyMemUsed.c cp -f ../JudyCommon/JudyMemUsed.c Judy1MemUsed.c Judy1Next.c:../JudyCommon/JudyPrevNext.c cp -f ../JudyCommon/JudyPrevNext.c Judy1Next.c Judy1Prev.c:../JudyCommon/JudyPrevNext.c cp -f ../JudyCommon/JudyPrevNext.c Judy1Prev.c Judy1NextEmpty.c:../JudyCommon/JudyPrevNextEmpty.c cp -f ../JudyCommon/JudyPrevNextEmpty.c Judy1NextEmpty.c Judy1PrevEmpty.c:../JudyCommon/JudyPrevNextEmpty.c cp -f ../JudyCommon/JudyPrevNextEmpty.c Judy1PrevEmpty.c Judy1TablesGen.c:../JudyCommon/JudyTables.c cp -f ../JudyCommon/JudyTables.c Judy1TablesGen.c DISTCLEANFILES = .deps Makefile CLEANFILES = Judy1ByCount.c \ Judy1Cascade.c \ Judy1Count.c \ Judy1CreateBranch.c \ Judy1Decascade.c \ Judy1Unset.c \ Judy1First.c \ Judy1FreeArray.c \ Judy1Test.c \ j__udy1Test.c \ Judy1SetArray.c \ Judy1Set.c \ Judy1InsertBranch.c \ Judy1MallocIF.c \ Judy1MemActive.c \ Judy1MemUsed.c \ Judy1Next.c \ Judy1Prev.c \ Judy1NextEmpty.c \ Judy1PrevEmpty.c \ Judy1TablesGen.c \ Judy1Tables.c \ .libs \ Judy1TablesGen \ *.o \ *.lo \ *.la judy-1.0.5/src/Judy1/Judy1.h0000644000175000017500000005337410204462077015662 0ustar troyhebetroyhebe#ifndef _JUDY1_INCLUDED #define _JUDY1_INCLUDED // _________________ // // Copyright (C) 2000 - 2002 Hewlett-Packard Company // // This program is free software; you can redistribute it and/or modify it // under the term of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License // for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program; if not, write to the Free Software Foundation, // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // _________________ // @(#) $Revision: 4.76 $ $Source: /judy/src/Judy1/Judy1.h $ // **************************************************************************** // JUDY1 -- SMALL/LARGE AND/OR CLUSTERED/SPARSE BIT ARRAYS // // -by- // // Douglas L. Baskins // doug@sourcejudy.com // // Judy arrays are designed to be used instead of arrays. The performance // suggests the reason why Judy arrays are thought of as arrays, instead of // trees. They are remarkably memory efficient at all populations. // Implemented as a hybrid digital tree (but really a state machine, see // below), Judy arrays feature fast insert/retrievals, fast near neighbor // searching, and contain a population tree for extremely fast ordinal related // retrievals. // // CONVENTIONS: // // - The comments here refer to 32-bit [64-bit] systems. // // - BranchL, LeafL refer to linear branches and leaves (small populations), // except LeafL does not actually appear as such; rather, Leaf1..3 [Leaf1..7] // is used to represent leaf Index sizes, and LeafW refers to a Leaf with // full (long) word Indexes, which is also a type of linear leaf. Note that // root-level LeafW (Leaf4 [Leaf8]) leaves are also called LEAFW. // // - BranchB, LeafB1 refer to bitmap branches and leaves (intermediate // populations). // // - BranchU refers to uncompressed branches. An uncompressed branch has 256 // JPs, some of which could be null. Note: All leaves are compressed (and // sorted), or else an expanse is full (FullPopu), so there is no LeafU // equivalent to BranchU. // // - "Popu" is short for "Population". // - "Pop1" refers to actual population (base 1). // - "Pop0" refers to Pop1 - 1 (base 0), the way populations are stored in data // structures. // // - Branches and Leaves are both named by the number of bytes in their Pop0 // field. In the case of Leaves, the same number applies to the Index sizes. // // - The representation of many numbers as hex is a relatively safe and // portable way to get desired bitpatterns as unsigned longs. // // - Some preprocessors cant handle single apostrophe characters within // #ifndef code, so here, use delete all instead. #include "JudyPrivate.h" // includes Judy.h in turn. #include "JudyPrivateBranch.h" // **************************************************************************** // JUDY1 ROOT POINTER (JRP) AND JUDY1 POINTER (JP) TYPE FIELDS // **************************************************************************** // // The following enum lists all possible JP Type fields. typedef enum // uint8_t -- but C does not support this type of enum. { // JP NULL TYPES: // // There is a series of cJ1_JPNULL* Types because each one pre-records a // different Index Size for when the first Index is inserted in the previously // null JP. They must start >= 8 (three bits). // // Note: These Types must be in sequential order for doing relative // calculations between them. cJ1_JPNULL1 = 1, // Index Size 1[1] byte when 1 Index inserted. cJ1_JPNULL2, // Index Size 2[2] bytes when 1 Index inserted. cJ1_JPNULL3, // Index Size 3[3] bytes when 1 Index inserted. #ifndef JU_64BIT #define cJ1_JPNULLMAX cJ1_JPNULL3 #else cJ1_JPNULL4, // Index Size 4[4] bytes when 1 Index inserted. cJ1_JPNULL5, // Index Size 5[5] bytes when 1 Index inserted. cJ1_JPNULL6, // Index Size 6[6] bytes when 1 Index inserted. cJ1_JPNULL7, // Index Size 7[7] bytes when 1 Index inserted. #define cJ1_JPNULLMAX cJ1_JPNULL7 #endif // JP BRANCH TYPES: // // Note: There are no state-1 branches; only leaves reside at state 1. // Linear branches: // // Note: These Types must be in sequential order for doing relative // calculations between them. cJ1_JPBRANCH_L2, // 2[2] bytes Pop0, 1[5] bytes Dcd. cJ1_JPBRANCH_L3, // 3[3] bytes Pop0, 0[4] bytes Dcd. #ifdef JU_64BIT cJ1_JPBRANCH_L4, // [4] bytes Pop0, [3] bytes Dcd. cJ1_JPBRANCH_L5, // [5] bytes Pop0, [2] bytes Dcd. cJ1_JPBRANCH_L6, // [6] bytes Pop0, [1] byte Dcd. cJ1_JPBRANCH_L7, // [7] bytes Pop0, [0] bytes Dcd. #endif cJ1_JPBRANCH_L, // note: DcdPopO field not used. // Bitmap branches: // // Note: These Types must be in sequential order for doing relative // calculations between them. cJ1_JPBRANCH_B2, // 2[2] bytes Pop0, 1[5] bytes Dcd. cJ1_JPBRANCH_B3, // 3[3] bytes Pop0, 0[4] bytes Dcd. #ifdef JU_64BIT cJ1_JPBRANCH_B4, // [4] bytes Pop0, [3] bytes Dcd. cJ1_JPBRANCH_B5, // [5] bytes Pop0, [2] bytes Dcd. cJ1_JPBRANCH_B6, // [6] bytes Pop0, [1] byte Dcd. cJ1_JPBRANCH_B7, // [7] bytes Pop0, [0] bytes Dcd. #endif cJ1_JPBRANCH_B, // note: DcdPopO field not used. // Uncompressed branches: // // Note: These Types must be in sequential order for doing relative // calculations between them. cJ1_JPBRANCH_U2, // 2[2] bytes Pop0, 1[5] bytes Dcd. cJ1_JPBRANCH_U3, // 3[3] bytes Pop0, 0[4] bytes Dcd. #ifdef JU_64BIT cJ1_JPBRANCH_U4, // [4] bytes Pop0, [3] bytes Dcd. cJ1_JPBRANCH_U5, // [5] bytes Pop0, [2] bytes Dcd. cJ1_JPBRANCH_U6, // [6] bytes Pop0, [1] byte Dcd. cJ1_JPBRANCH_U7, // [7] bytes Pop0, [0] bytes Dcd. #endif cJ1_JPBRANCH_U, // note: DcdPopO field not used. // JP LEAF TYPES: // Linear leaves: // // Note: These Types must be in sequential order for doing relative // calculations between them. // // Note: There is no cJ1_JPLEAF1 for 64-bit for a subtle reason. An immediate // JP can hold 15 1-byte Indexes, and a bitmap leaf would be used for 17 // Indexes, so rather than support a linear leaf for only the case of exactly // 16 Indexes, a bitmap leaf is used in that case. See also below regarding // cJ1_LEAF1_MAXPOP1 on 64-bit systems. // // Note: There is no full-word (4-byte [8-byte]) Index leaf under a JP because // non-root-state leaves only occur under branches that decode at least one // byte. Full-word, root-state leaves are under a JRP, not a JP. However, in // the code a "fake" JP can be created temporarily above a root-state leaf. #ifndef JU_64BIT // 32-bit only; see above. cJ1_JPLEAF1, // 1 byte Pop0, 2 bytes Dcd. #endif cJ1_JPLEAF2, // 2[2] bytes Pop0, 1[5] bytes Dcd. cJ1_JPLEAF3, // 3[3] bytes Pop0, 0[4] bytes Dcd. #ifdef JU_64BIT cJ1_JPLEAF4, // [4] bytes Pop0, [3] bytes Dcd. cJ1_JPLEAF5, // [5] bytes Pop0, [2] bytes Dcd. cJ1_JPLEAF6, // [6] bytes Pop0, [1] byte Dcd. cJ1_JPLEAF7, // [7] bytes Pop0, [0] bytes Dcd. #endif // Bitmap leaf; Index Size == 1: // // Note: These are currently only supported at state 1. At other states the // bitmap would grow from 256 to 256^2, 256^3, ... bits, which would not be // efficient.. cJ1_JPLEAF_B1, // 1[1] byte Pop0, 2[6] bytes Dcd. // Full population; Index Size == 1 virtual leaf: // // Note: These are currently only supported at state 1. At other states they // could be used, but they would be rare and the savings are dubious. cJ1_JPFULLPOPU1, // 1[1] byte Pop0, 2[6] bytes Dcd. #ifdef notdef // for future enhancements cJ1_JPFULLPOPU1m1, // Full Population - 1 cJ1_JPFULLPOPU1m2, // Full Population - 2 cJ1_JPFULLPOPU1m3, // Full Population - 3 cJ1_JPFULLPOPU1m4, // Full Population - 4 cJ1_JPFULLPOPU1m5, // Full Population - 5 cJ1_JPFULLPOPU1m6, // Full Population - 6 cJ1_JPFULLPOPU1m7, // Full Population - 7 #ifdef JU_64BIT cJ1_JPFULLPOPU1m8, // Full Population - 8 cJ1_JPFULLPOPU1m9, // Full Population - 9 cJ1_JPFULLPOPU1m10, // Full Population - 10 cJ1_JPFULLPOPU1m11, // Full Population - 11 cJ1_JPFULLPOPU1m12, // Full Population - 12 cJ1_JPFULLPOPU1m13, // Full Population - 13 cJ1_JPFULLPOPU1m14, // Full Population - 14 cJ1_JPFULLPOPU1m15, // Full Population - 15 #endif #endif // notdef -- for future enhancements // JP IMMEDIATES; leaves (Indexes) stored inside a JP: // // The second numeric suffix is the Pop1 for each type. As the Index Size // increases, the maximum possible population decreases. // // Note: These Types must be in sequential order in each group (Index Size), // and the groups in correct order too, for doing relative calculations between // them. For example, since these Types enumerate the Pop1 values (unlike // other JP Types where there is a Pop0 value in the JP), the maximum Pop1 for // each Index Size is computable. cJ1_JPIMMED_1_01, // Index Size = 1, Pop1 = 1. cJ1_JPIMMED_2_01, // Index Size = 2, Pop1 = 1. cJ1_JPIMMED_3_01, // Index Size = 3, Pop1 = 1. #ifdef JU_64BIT cJ1_JPIMMED_4_01, // Index Size = 4, Pop1 = 1. cJ1_JPIMMED_5_01, // Index Size = 5, Pop1 = 1. cJ1_JPIMMED_6_01, // Index Size = 6, Pop1 = 1. cJ1_JPIMMED_7_01, // Index Size = 7, Pop1 = 1. #endif cJ1_JPIMMED_1_02, // Index Size = 1, Pop1 = 2. cJ1_JPIMMED_1_03, // Index Size = 1, Pop1 = 3. cJ1_JPIMMED_1_04, // Index Size = 1, Pop1 = 4. cJ1_JPIMMED_1_05, // Index Size = 1, Pop1 = 5. cJ1_JPIMMED_1_06, // Index Size = 1, Pop1 = 6. cJ1_JPIMMED_1_07, // Index Size = 1, Pop1 = 7. #ifdef JU_64BIT cJ1_JPIMMED_1_08, // Index Size = 1, Pop1 = 8. cJ1_JPIMMED_1_09, // Index Size = 1, Pop1 = 9. cJ1_JPIMMED_1_10, // Index Size = 1, Pop1 = 10. cJ1_JPIMMED_1_11, // Index Size = 1, Pop1 = 11. cJ1_JPIMMED_1_12, // Index Size = 1, Pop1 = 12. cJ1_JPIMMED_1_13, // Index Size = 1, Pop1 = 13. cJ1_JPIMMED_1_14, // Index Size = 1, Pop1 = 14. cJ1_JPIMMED_1_15, // Index Size = 1, Pop1 = 15. #endif cJ1_JPIMMED_2_02, // Index Size = 2, Pop1 = 2. cJ1_JPIMMED_2_03, // Index Size = 2, Pop1 = 3. #ifdef JU_64BIT cJ1_JPIMMED_2_04, // Index Size = 2, Pop1 = 4. cJ1_JPIMMED_2_05, // Index Size = 2, Pop1 = 5. cJ1_JPIMMED_2_06, // Index Size = 2, Pop1 = 6. cJ1_JPIMMED_2_07, // Index Size = 2, Pop1 = 7. #endif cJ1_JPIMMED_3_02, // Index Size = 3, Pop1 = 2. #ifdef JU_64BIT cJ1_JPIMMED_3_03, // Index Size = 3, Pop1 = 3. cJ1_JPIMMED_3_04, // Index Size = 3, Pop1 = 4. cJ1_JPIMMED_3_05, // Index Size = 3, Pop1 = 5. cJ1_JPIMMED_4_02, // Index Size = 4, Pop1 = 2. cJ1_JPIMMED_4_03, // Index Size = 4, Pop1 = 3. cJ1_JPIMMED_5_02, // Index Size = 5, Pop1 = 2. cJ1_JPIMMED_5_03, // Index Size = 3, Pop1 = 3. cJ1_JPIMMED_6_02, // Index Size = 6, Pop1 = 2. cJ1_JPIMMED_7_02, // Index Size = 7, Pop1 = 2. #endif // This special Type is merely a sentinel for doing relative calculations. // This value should not be used in switch statements (to avoid allocating code // for it), which is also why it appears at the end of the enum list. cJ1_JPIMMED_CAP } jp1_Type_t; // RELATED VALUES: // // Index Size (state) for leaf JP, and JP type based on Index Size (state): #ifndef JU_64BIT // 32-bit #define J1_LEAFINDEXSIZE(jpType) ((jpType) - cJ1_JPLEAF1 + 1) #define J1_LEAFTYPE(IndexSize) ((IndexSize) + cJ1_JPLEAF1 - 1) #else #define J1_LEAFINDEXSIZE(jpType) ((jpType) - cJ1_JPLEAF2 + 2) #define J1_LEAFTYPE(IndexSize) ((IndexSize) + cJ1_JPLEAF2 - 2) #endif // **************************************************************************** // JUDY1 POINTER (JP) -- RELATED MACROS AND CONSTANTS // **************************************************************************** // MAXIMUM POPULATIONS OF LINEAR LEAVES: // // Allow up to 2 cache lines per leaf, with N bytes per index. // // J_1_MAXB is the maximum number of bytes (sort of) to allocate per leaf. // ALLOCSIZES is defined here, not there, for single-point control of these key // definitions. See JudyTables.c for "TERMINATOR". #define J_1_MAXB (sizeof(Word_t) * 32) #define ALLOCSIZES { 3, 5, 7, 11, 15, 23, 32, 47, 64, TERMINATOR } // in words. #define cJ1_LEAF1_MAXWORDS 5 // Leaf1 max alloc size in words. // Under JRP (root-state leaves): // // Includes a count (Population) word. // // Under JP (non-root-state leaves), which have no count (Population) words: // // When a 1-byte index leaf grows above cJ1_LEAF1_MAXPOP1 Indexes (bytes), // the memory chunk required grows to a size where a bitmap is just as // efficient, so use a bitmap instead for all greater Populations, on both // 32-bit and 64-bit systems. However, on a 32-bit system this occurs upon // going from 6 to 8 words (24 to 32 bytes) in the memory chunk, but on a // 64-bit system this occurs upon going from 2 to 4 words (16 to 32 bytes). It // would be silly to go from a 15-Index Immediate JP to a 16-Index linear leaf // to a 17-Index bitmap leaf, so just use a bitmap leaf for 16+ Indexes, which // means set cJ1_LEAF1_MAXPOP1 to cJ1_IMMED1_MAXPOP1 (15) to cause the // transition at that point. // // Note: cJ1_LEAF1_MAXPOP1 is not used on 64-bit systems. #ifndef JU_64BIT // 32-bit #define cJ1_LEAF1_MAXPOP1 (cJ1_LEAF1_MAXWORDS * cJU_BYTESPERWORD) #define cJ1_LEAF2_MAXPOP1 (J_1_MAXB / 2) #define cJ1_LEAF3_MAXPOP1 (J_1_MAXB / 3) #define cJ1_LEAFW_MAXPOP1 ((J_1_MAXB - cJU_BYTESPERWORD) / cJU_BYTESPERWORD) #else // 64-bit // #define cJ1_LEAF1_MAXPOP1 // no LEAF1 in 64-bit. #define cJ1_LEAF2_MAXPOP1 (J_1_MAXB / 2) #define cJ1_LEAF3_MAXPOP1 (J_1_MAXB / 3) #define cJ1_LEAF4_MAXPOP1 (J_1_MAXB / 4) #define cJ1_LEAF5_MAXPOP1 (J_1_MAXB / 5) #define cJ1_LEAF6_MAXPOP1 (J_1_MAXB / 6) #define cJ1_LEAF7_MAXPOP1 (J_1_MAXB / 7) #define cJ1_LEAFW_MAXPOP1 ((J_1_MAXB - cJU_BYTESPERWORD) / cJU_BYTESPERWORD) #endif // MAXIMUM POPULATIONS OF IMMEDIATE JPs: // // These specify the maximum Population of immediate JPs with various Index // Sizes (== sizes of remaining undecoded Index bits). #define cJ1_IMMED1_MAXPOP1 ((sizeof(jp_t) - 1) / 1) // 7 [15]. #define cJ1_IMMED2_MAXPOP1 ((sizeof(jp_t) - 1) / 2) // 3 [7]. #define cJ1_IMMED3_MAXPOP1 ((sizeof(jp_t) - 1) / 3) // 2 [5]. #ifdef JU_64BIT #define cJ1_IMMED4_MAXPOP1 ((sizeof(jp_t) - 1) / 4) // [3]. #define cJ1_IMMED5_MAXPOP1 ((sizeof(jp_t) - 1) / 5) // [3]. #define cJ1_IMMED6_MAXPOP1 ((sizeof(jp_t) - 1) / 6) // [2]. #define cJ1_IMMED7_MAXPOP1 ((sizeof(jp_t) - 1) / 7) // [2]. #endif // **************************************************************************** // JUDY1 BITMAP LEAF (J1LB) SUPPORT // **************************************************************************** #define J1_JLB_BITMAP(Pjlb,Subexp) ((Pjlb)->j1lb_Bitmap[Subexp]) typedef struct J__UDY1_BITMAP_LEAF { BITMAPL_t j1lb_Bitmap[cJU_NUMSUBEXPL]; } j1lb_t, * Pj1lb_t; // **************************************************************************** // MEMORY ALLOCATION SUPPORT // **************************************************************************** // ARRAY-GLOBAL INFORMATION: // // At the cost of an occasional additional cache fill, this object, which is // pointed at by a JRP and in turn points to a JP_BRANCH*, carries array-global // information about a Judy1 array that has sufficient population to amortize // the cost. The jpm_Pop0 field prevents having to add up the total population // for the array in insert, delete, and count code. The jpm_JP field prevents // having to build a fake JP for entry to a state machine; however, the // jp_DcdPopO field in jpm_JP, being one byte too small, is not used. // // Note: Struct fields are ordered to keep "hot" data in the first 8 words // (see left-margin comments) for machines with 8-word cache lines, and to keep // sub-word fields together for efficient packing. typedef struct J_UDY1_POPULATION_AND_MEMORY { /* 1 */ Word_t jpm_Pop0; // total population-1 in array. /* 2 */ jp_t jpm_JP; // JP to first branch; see above. /* 4 */ Word_t jpm_LastUPop0; // last jpm_Pop0 when convert to BranchU // Note: Field names match PJError_t for convenience in macros: /* 7 */ char je_Errno; // one of the enums in Judy.h. /* 7/8 */ int je_ErrID; // often an internal source line number. /* 8/9 */ Word_t jpm_TotalMemWords; // words allocated in array. } j1pm_t, *Pj1pm_t; // TABLES FOR DETERMINING IF LEAVES HAVE ROOM TO GROW: // // These tables indicate if a given memory chunk can support growth of a given // object into wasted (rounded-up) memory in the chunk. This violates the // hiddenness of the JudyMalloc code. // // Also define macros to hide the details in the code using these tables. #ifndef JU_64BIT extern const uint8_t j__1_Leaf1PopToWords[cJ1_LEAF1_MAXPOP1 + 1]; #endif extern const uint8_t j__1_Leaf2PopToWords[cJ1_LEAF2_MAXPOP1 + 1]; extern const uint8_t j__1_Leaf3PopToWords[cJ1_LEAF3_MAXPOP1 + 1]; #ifdef JU_64BIT extern const uint8_t j__1_Leaf4PopToWords[cJ1_LEAF4_MAXPOP1 + 1]; extern const uint8_t j__1_Leaf5PopToWords[cJ1_LEAF5_MAXPOP1 + 1]; extern const uint8_t j__1_Leaf6PopToWords[cJ1_LEAF6_MAXPOP1 + 1]; extern const uint8_t j__1_Leaf7PopToWords[cJ1_LEAF7_MAXPOP1 + 1]; #endif extern const uint8_t j__1_LeafWPopToWords[cJ1_LEAFW_MAXPOP1 + 1]; // Check if increase of population will fit in same leaf: #ifndef JU_64BIT #define J1_LEAF1GROWINPLACE(Pop1) \ J__U_GROWCK(Pop1, cJ1_LEAF1_MAXPOP1, j__1_Leaf1PopToWords) #endif #define J1_LEAF2GROWINPLACE(Pop1) \ J__U_GROWCK(Pop1, cJ1_LEAF2_MAXPOP1, j__1_Leaf2PopToWords) #define J1_LEAF3GROWINPLACE(Pop1) \ J__U_GROWCK(Pop1, cJ1_LEAF3_MAXPOP1, j__1_Leaf3PopToWords) #ifdef JU_64BIT #define J1_LEAF4GROWINPLACE(Pop1) \ J__U_GROWCK(Pop1, cJ1_LEAF4_MAXPOP1, j__1_Leaf4PopToWords) #define J1_LEAF5GROWINPLACE(Pop1) \ J__U_GROWCK(Pop1, cJ1_LEAF5_MAXPOP1, j__1_Leaf5PopToWords) #define J1_LEAF6GROWINPLACE(Pop1) \ J__U_GROWCK(Pop1, cJ1_LEAF6_MAXPOP1, j__1_Leaf6PopToWords) #define J1_LEAF7GROWINPLACE(Pop1) \ J__U_GROWCK(Pop1, cJ1_LEAF7_MAXPOP1, j__1_Leaf7PopToWords) #endif #define J1_LEAFWGROWINPLACE(Pop1) \ J__U_GROWCK(Pop1, cJ1_LEAFW_MAXPOP1, j__1_LeafWPopToWords) #ifndef JU_64BIT #define J1_LEAF1POPTOWORDS(Pop1) (j__1_Leaf1PopToWords[Pop1]) #endif #define J1_LEAF2POPTOWORDS(Pop1) (j__1_Leaf2PopToWords[Pop1]) #define J1_LEAF3POPTOWORDS(Pop1) (j__1_Leaf3PopToWords[Pop1]) #ifdef JU_64BIT #define J1_LEAF4POPTOWORDS(Pop1) (j__1_Leaf4PopToWords[Pop1]) #define J1_LEAF5POPTOWORDS(Pop1) (j__1_Leaf5PopToWords[Pop1]) #define J1_LEAF6POPTOWORDS(Pop1) (j__1_Leaf6PopToWords[Pop1]) #define J1_LEAF7POPTOWORDS(Pop1) (j__1_Leaf7PopToWords[Pop1]) #endif #define J1_LEAFWPOPTOWORDS(Pop1) (j__1_LeafWPopToWords[Pop1]) // FUNCTIONS TO ALLOCATE OBJECTS: Pj1pm_t j__udy1AllocJ1PM(void); // constant size. Pjbl_t j__udy1AllocJBL( Pj1pm_t); // constant size. Pjbb_t j__udy1AllocJBB( Pj1pm_t); // constant size. Pjp_t j__udy1AllocJBBJP(Word_t, Pj1pm_t); Pjbu_t j__udy1AllocJBU( Pj1pm_t); // constant size. #ifndef JU_64BIT Pjll_t j__udy1AllocJLL1( Word_t, Pj1pm_t); #endif Pjll_t j__udy1AllocJLL2( Word_t, Pj1pm_t); Pjll_t j__udy1AllocJLL3( Word_t, Pj1pm_t); #ifdef JU_64BIT Pjll_t j__udy1AllocJLL4( Word_t, Pj1pm_t); Pjll_t j__udy1AllocJLL5( Word_t, Pj1pm_t); Pjll_t j__udy1AllocJLL6( Word_t, Pj1pm_t); Pjll_t j__udy1AllocJLL7( Word_t, Pj1pm_t); #endif Pjlw_t j__udy1AllocJLW( Word_t ); // no Pj1pm needed. Pj1lb_t j__udy1AllocJLB1( Pj1pm_t); // constant size. // FUNCTIONS TO FREE OBJECTS: void j__udy1FreeJ1PM( Pj1pm_t, Pj1pm_t); // constant size. void j__udy1FreeJBL( Pjbl_t, Pj1pm_t); // constant size. void j__udy1FreeJBB( Pjbb_t, Pj1pm_t); // constant size. void j__udy1FreeJBBJP(Pjp_t, Word_t, Pj1pm_t); void j__udy1FreeJBU( Pjbu_t, Pj1pm_t); // constant size. #ifndef JU_64BIT void j__udy1FreeJLL1( Pjll_t, Word_t, Pj1pm_t); #endif void j__udy1FreeJLL2( Pjll_t, Word_t, Pj1pm_t); void j__udy1FreeJLL3( Pjll_t, Word_t, Pj1pm_t); #ifdef JU_64BIT void j__udy1FreeJLL4( Pjll_t, Word_t, Pj1pm_t); void j__udy1FreeJLL5( Pjll_t, Word_t, Pj1pm_t); void j__udy1FreeJLL6( Pjll_t, Word_t, Pj1pm_t); void j__udy1FreeJLL7( Pjll_t, Word_t, Pj1pm_t); #endif void j__udy1FreeJLW( Pjlw_t, Word_t, Pj1pm_t); void j__udy1FreeJLB1( Pj1lb_t, Pj1pm_t); // constant size. void j__udy1FreeSM( Pjp_t, Pj1pm_t); // everything below Pjp. #endif // ! _JUDY1_INCLUDED judy-1.0.5/src/Judy1/Makefile.in0000644000175000017500000006334310624600216016552 0ustar troyhebetroyhebe# Makefile.in generated by automake 1.9.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ top_builddir = ../.. am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd INSTALL = @INSTALL@ install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/Judy1 DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libJudy1_la_LIBADD = am_libJudy1_la_OBJECTS = Judy1Test.lo Judy1Tables.lo Judy1Set.lo \ Judy1SetArray.lo Judy1Unset.lo Judy1Cascade.lo Judy1Count.lo \ Judy1CreateBranch.lo Judy1Decascade.lo Judy1First.lo \ Judy1FreeArray.lo Judy1InsertBranch.lo Judy1MallocIF.lo \ Judy1MemActive.lo Judy1MemUsed.lo libJudy1_la_OBJECTS = $(am_libJudy1_la_OBJECTS) libcount_la_LIBADD = am_libcount_la_OBJECTS = libcount_la-Judy1ByCount.lo libcount_la_OBJECTS = $(am_libcount_la_OBJECTS) libinline_la_LIBADD = am_libinline_la_OBJECTS = libinline_la-j__udy1Test.lo libinline_la_OBJECTS = $(am_libinline_la_OBJECTS) libnext_la_LIBADD = am_libnext_la_OBJECTS = libnext_la-Judy1Next.lo \ libnext_la-Judy1NextEmpty.lo libnext_la_OBJECTS = $(am_libnext_la_OBJECTS) libprev_la_LIBADD = am_libprev_la_OBJECTS = libprev_la-Judy1Prev.lo \ libprev_la-Judy1PrevEmpty.lo libprev_la_OBJECTS = $(am_libprev_la_OBJECTS) DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ SOURCES = $(libJudy1_la_SOURCES) $(libcount_la_SOURCES) \ $(libinline_la_SOURCES) $(libnext_la_SOURCES) \ $(libprev_la_SOURCES) DIST_SOURCES = $(libJudy1_la_SOURCES) $(libcount_la_SOURCES) \ $(libinline_la_SOURCES) $(libnext_la_SOURCES) \ $(libprev_la_SOURCES) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMDEP_FALSE = @AMDEP_FALSE@ AMDEP_TRUE = @AMDEP_TRUE@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO = @ECHO@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ F77 = @F77@ FFLAGS = @FFLAGS@ FLAVOR = @FLAVOR@ GREP = @GREP@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ MAKEINFO = @MAKEINFO@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ VERSION_INFO = @VERSION_INFO@ WARN_CFLAGS = @WARN_CFLAGS@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_F77 = @ac_ct_F77@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ INCLUDES = -I. -I.. -I../JudyCommon/ AM_CFLAGS = -DJUDY1 @WARN_CFLAGS@ noinst_LTLIBRARIES = libJudy1.la libnext.la libprev.la libcount.la libinline.la libJudy1_la_SOURCES = Judy1Test.c Judy1Tables.c Judy1Set.c Judy1SetArray.c Judy1Unset.c Judy1Cascade.c Judy1Count.c Judy1CreateBranch.c Judy1Decascade.c Judy1First.c Judy1FreeArray.c Judy1InsertBranch.c Judy1MallocIF.c Judy1MemActive.c Judy1MemUsed.c libnext_la_SOURCES = Judy1Next.c Judy1NextEmpty.c libnext_la_CFLAGS = $(AM_CFLAGS) -DJUDYNEXT libprev_la_SOURCES = Judy1Prev.c Judy1PrevEmpty.c libprev_la_CFLAGS = $(AM_CFLAGS) -DJUDYPREV libcount_la_SOURCES = Judy1ByCount.c libcount_la_CFLAGS = $(AM_CFLAGS) -DNOSMARTJBB -DNOSMARTJBU -DNOSMARTJLB libinline_la_SOURCES = j__udy1Test.c libinline_la_CFLAGS = $(AM_CFLAGS) -DJUDYGETINLINE DISTCLEANFILES = .deps Makefile CLEANFILES = Judy1ByCount.c \ Judy1Cascade.c \ Judy1Count.c \ Judy1CreateBranch.c \ Judy1Decascade.c \ Judy1Unset.c \ Judy1First.c \ Judy1FreeArray.c \ Judy1Test.c \ j__udy1Test.c \ Judy1SetArray.c \ Judy1Set.c \ Judy1InsertBranch.c \ Judy1MallocIF.c \ Judy1MemActive.c \ Judy1MemUsed.c \ Judy1Next.c \ Judy1Prev.c \ Judy1NextEmpty.c \ Judy1PrevEmpty.c \ Judy1TablesGen.c \ Judy1Tables.c \ .libs \ Judy1TablesGen \ *.o \ *.lo \ *.la all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Judy1/Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --gnu src/Judy1/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libJudy1.la: $(libJudy1_la_OBJECTS) $(libJudy1_la_DEPENDENCIES) $(LINK) $(libJudy1_la_LDFLAGS) $(libJudy1_la_OBJECTS) $(libJudy1_la_LIBADD) $(LIBS) libcount.la: $(libcount_la_OBJECTS) $(libcount_la_DEPENDENCIES) $(LINK) $(libcount_la_LDFLAGS) $(libcount_la_OBJECTS) $(libcount_la_LIBADD) $(LIBS) libinline.la: $(libinline_la_OBJECTS) $(libinline_la_DEPENDENCIES) $(LINK) $(libinline_la_LDFLAGS) $(libinline_la_OBJECTS) $(libinline_la_LIBADD) $(LIBS) libnext.la: $(libnext_la_OBJECTS) $(libnext_la_DEPENDENCIES) $(LINK) $(libnext_la_LDFLAGS) $(libnext_la_OBJECTS) $(libnext_la_LIBADD) $(LIBS) libprev.la: $(libprev_la_OBJECTS) $(libprev_la_DEPENDENCIES) $(LINK) $(libprev_la_LDFLAGS) $(libprev_la_OBJECTS) $(libprev_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Judy1Cascade.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Judy1Count.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Judy1CreateBranch.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Judy1Decascade.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Judy1First.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Judy1FreeArray.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Judy1InsertBranch.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Judy1MallocIF.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Judy1MemActive.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Judy1MemUsed.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Judy1Set.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Judy1SetArray.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Judy1Tables.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Judy1Test.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Judy1Unset.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcount_la-Judy1ByCount.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libinline_la-j__udy1Test.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnext_la-Judy1Next.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnext_la-Judy1NextEmpty.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libprev_la-Judy1Prev.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libprev_la-Judy1PrevEmpty.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< libcount_la-Judy1ByCount.lo: Judy1ByCount.c @am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcount_la_CFLAGS) $(CFLAGS) -MT libcount_la-Judy1ByCount.lo -MD -MP -MF "$(DEPDIR)/libcount_la-Judy1ByCount.Tpo" -c -o libcount_la-Judy1ByCount.lo `test -f 'Judy1ByCount.c' || echo '$(srcdir)/'`Judy1ByCount.c; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libcount_la-Judy1ByCount.Tpo" "$(DEPDIR)/libcount_la-Judy1ByCount.Plo"; else rm -f "$(DEPDIR)/libcount_la-Judy1ByCount.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='Judy1ByCount.c' object='libcount_la-Judy1ByCount.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcount_la_CFLAGS) $(CFLAGS) -c -o libcount_la-Judy1ByCount.lo `test -f 'Judy1ByCount.c' || echo '$(srcdir)/'`Judy1ByCount.c libinline_la-j__udy1Test.lo: j__udy1Test.c @am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libinline_la_CFLAGS) $(CFLAGS) -MT libinline_la-j__udy1Test.lo -MD -MP -MF "$(DEPDIR)/libinline_la-j__udy1Test.Tpo" -c -o libinline_la-j__udy1Test.lo `test -f 'j__udy1Test.c' || echo '$(srcdir)/'`j__udy1Test.c; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libinline_la-j__udy1Test.Tpo" "$(DEPDIR)/libinline_la-j__udy1Test.Plo"; else rm -f "$(DEPDIR)/libinline_la-j__udy1Test.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='j__udy1Test.c' object='libinline_la-j__udy1Test.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libinline_la_CFLAGS) $(CFLAGS) -c -o libinline_la-j__udy1Test.lo `test -f 'j__udy1Test.c' || echo '$(srcdir)/'`j__udy1Test.c libnext_la-Judy1Next.lo: Judy1Next.c @am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnext_la_CFLAGS) $(CFLAGS) -MT libnext_la-Judy1Next.lo -MD -MP -MF "$(DEPDIR)/libnext_la-Judy1Next.Tpo" -c -o libnext_la-Judy1Next.lo `test -f 'Judy1Next.c' || echo '$(srcdir)/'`Judy1Next.c; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libnext_la-Judy1Next.Tpo" "$(DEPDIR)/libnext_la-Judy1Next.Plo"; else rm -f "$(DEPDIR)/libnext_la-Judy1Next.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='Judy1Next.c' object='libnext_la-Judy1Next.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnext_la_CFLAGS) $(CFLAGS) -c -o libnext_la-Judy1Next.lo `test -f 'Judy1Next.c' || echo '$(srcdir)/'`Judy1Next.c libnext_la-Judy1NextEmpty.lo: Judy1NextEmpty.c @am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnext_la_CFLAGS) $(CFLAGS) -MT libnext_la-Judy1NextEmpty.lo -MD -MP -MF "$(DEPDIR)/libnext_la-Judy1NextEmpty.Tpo" -c -o libnext_la-Judy1NextEmpty.lo `test -f 'Judy1NextEmpty.c' || echo '$(srcdir)/'`Judy1NextEmpty.c; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libnext_la-Judy1NextEmpty.Tpo" "$(DEPDIR)/libnext_la-Judy1NextEmpty.Plo"; else rm -f "$(DEPDIR)/libnext_la-Judy1NextEmpty.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='Judy1NextEmpty.c' object='libnext_la-Judy1NextEmpty.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnext_la_CFLAGS) $(CFLAGS) -c -o libnext_la-Judy1NextEmpty.lo `test -f 'Judy1NextEmpty.c' || echo '$(srcdir)/'`Judy1NextEmpty.c libprev_la-Judy1Prev.lo: Judy1Prev.c @am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libprev_la_CFLAGS) $(CFLAGS) -MT libprev_la-Judy1Prev.lo -MD -MP -MF "$(DEPDIR)/libprev_la-Judy1Prev.Tpo" -c -o libprev_la-Judy1Prev.lo `test -f 'Judy1Prev.c' || echo '$(srcdir)/'`Judy1Prev.c; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libprev_la-Judy1Prev.Tpo" "$(DEPDIR)/libprev_la-Judy1Prev.Plo"; else rm -f "$(DEPDIR)/libprev_la-Judy1Prev.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='Judy1Prev.c' object='libprev_la-Judy1Prev.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libprev_la_CFLAGS) $(CFLAGS) -c -o libprev_la-Judy1Prev.lo `test -f 'Judy1Prev.c' || echo '$(srcdir)/'`Judy1Prev.c libprev_la-Judy1PrevEmpty.lo: Judy1PrevEmpty.c @am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libprev_la_CFLAGS) $(CFLAGS) -MT libprev_la-Judy1PrevEmpty.lo -MD -MP -MF "$(DEPDIR)/libprev_la-Judy1PrevEmpty.Tpo" -c -o libprev_la-Judy1PrevEmpty.lo `test -f 'Judy1PrevEmpty.c' || echo '$(srcdir)/'`Judy1PrevEmpty.c; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libprev_la-Judy1PrevEmpty.Tpo" "$(DEPDIR)/libprev_la-Judy1PrevEmpty.Plo"; else rm -f "$(DEPDIR)/libprev_la-Judy1PrevEmpty.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='Judy1PrevEmpty.c' object='libprev_la-Judy1PrevEmpty.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libprev_la_CFLAGS) $(CFLAGS) -c -o libprev_la-Judy1PrevEmpty.lo `test -f 'Judy1PrevEmpty.c' || echo '$(srcdir)/'`Judy1PrevEmpty.c mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs distclean-libtool: -rm -f libtool uninstall-info-am: ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$tags $$unique; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ test -z "$(CTAGS_ARGS)$$tags$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$tags $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && cd $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) $$here distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ list='$(DISTFILES)'; for file in $$list; do \ case $$file in \ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ esac; \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ if test "$$dir" != "$$file" && test "$$dir" != "."; then \ dir="/$$dir"; \ $(mkdir_p) "$(distdir)$$dir"; \ else \ dir=''; \ fi; \ if test -d $$d/$$file; then \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-libtool distclean-tags dvi: dvi-am dvi-am: html: html-am info: info-am info-am: install-data-am: install-exec-am: install-info: install-info-am install-man: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-info-am .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLTLIBRARIES ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-exec \ install-exec-am install-info install-info-am install-man \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags uninstall uninstall-am \ uninstall-info-am Judy1Tables.c: Judy1TablesGen.c $(CC) $(INCLUDES) $(AM_CFLAGS) @CFLAGS@ -o Judy1TablesGen Judy1TablesGen.c; ./Judy1TablesGen Judy1ByCount.c:../JudyCommon/JudyByCount.c cp -f ../JudyCommon/JudyByCount.c Judy1ByCount.c Judy1Cascade.c:../JudyCommon/JudyCascade.c cp -f ../JudyCommon/JudyCascade.c Judy1Cascade.c Judy1Count.c:../JudyCommon/JudyCount.c cp -f ../JudyCommon/JudyCount.c Judy1Count.c Judy1CreateBranch.c:../JudyCommon/JudyCreateBranch.c cp -f ../JudyCommon/JudyCreateBranch.c Judy1CreateBranch.c Judy1Decascade.c:../JudyCommon/JudyDecascade.c cp -f ../JudyCommon/JudyDecascade.c Judy1Decascade.c Judy1Unset.c:../JudyCommon/JudyDel.c cp -f ../JudyCommon/JudyDel.c Judy1Unset.c Judy1First.c:../JudyCommon/JudyFirst.c cp -f ../JudyCommon/JudyFirst.c Judy1First.c Judy1FreeArray.c:../JudyCommon/JudyFreeArray.c cp -f ../JudyCommon/JudyFreeArray.c Judy1FreeArray.c Judy1Test.c:../JudyCommon/JudyGet.c cp -f ../JudyCommon/JudyGet.c Judy1Test.c j__udy1Test.c:../JudyCommon/JudyGet.c cp -f ../JudyCommon/JudyGet.c j__udy1Test.c Judy1SetArray.c:../JudyCommon/JudyInsArray.c cp -f ../JudyCommon/JudyInsArray.c Judy1SetArray.c Judy1Set.c:../JudyCommon/JudyIns.c cp -f ../JudyCommon/JudyIns.c Judy1Set.c Judy1InsertBranch.c:../JudyCommon/JudyInsertBranch.c cp -f ../JudyCommon/JudyInsertBranch.c Judy1InsertBranch.c Judy1MallocIF.c:../JudyCommon/JudyMallocIF.c cp -f ../JudyCommon/JudyMallocIF.c Judy1MallocIF.c Judy1MemActive.c:../JudyCommon/JudyMemActive.c cp -f ../JudyCommon/JudyMemActive.c Judy1MemActive.c Judy1MemUsed.c:../JudyCommon/JudyMemUsed.c cp -f ../JudyCommon/JudyMemUsed.c Judy1MemUsed.c Judy1Next.c:../JudyCommon/JudyPrevNext.c cp -f ../JudyCommon/JudyPrevNext.c Judy1Next.c Judy1Prev.c:../JudyCommon/JudyPrevNext.c cp -f ../JudyCommon/JudyPrevNext.c Judy1Prev.c Judy1NextEmpty.c:../JudyCommon/JudyPrevNextEmpty.c cp -f ../JudyCommon/JudyPrevNextEmpty.c Judy1NextEmpty.c Judy1PrevEmpty.c:../JudyCommon/JudyPrevNextEmpty.c cp -f ../JudyCommon/JudyPrevNextEmpty.c Judy1PrevEmpty.c Judy1TablesGen.c:../JudyCommon/JudyTables.c cp -f ../JudyCommon/JudyTables.c Judy1TablesGen.c # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: judy-1.0.5/src/Judy1/README0000644000175000017500000000056610204462077015370 0ustar troyhebetroyhebe# @(#) $Revision: 4.22 $ $Source: /judy/src/Judy1/README $ # This tree contains sources for the Judy1*() functions. # # Note: At one time, all of the Judy sources were split between Judy1/ and # JudyL/ variants, but now most of them are merged in JudyCommon/ and this # directory is vestigal. Judy1.h header for following functions lint.waivers see usage in makefile judy-1.0.5/src/Makefile.in0000644000175000017500000003367410624600217015563 0ustar troyhebetroyhebe# Makefile.in generated by automake 1.9.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ top_builddir = .. am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd INSTALL = @INSTALL@ install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ html-recursive info-recursive install-data-recursive \ install-exec-recursive install-info-recursive \ install-recursive installcheck-recursive installdirs-recursive \ pdf-recursive ps-recursive uninstall-info-recursive \ uninstall-recursive ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMDEP_FALSE = @AMDEP_FALSE@ AMDEP_TRUE = @AMDEP_TRUE@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO = @ECHO@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ F77 = @F77@ FFLAGS = @FFLAGS@ FLAVOR = @FLAVOR@ GREP = @GREP@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ MAKEINFO = @MAKEINFO@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ VERSION_INFO = @VERSION_INFO@ WARN_CFLAGS = @WARN_CFLAGS@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_F77 = @ac_ct_F77@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ SUBDIRS = . JudyCommon JudyL Judy1 JudySL JudyHS obj DISTCLEANFILES = .deps Makefile all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --gnu src/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs distclean-libtool: -rm -f libtool uninstall-info-am: # This directory's subdirectories are mostly independent; you can cd # into them and run `make' without going through this Makefile. # To change the values of `make' variables: instead of editing Makefiles, # (1) if the variable is set in `config.status', edit `config.status' # (which will cause the Makefiles to be regenerated when you run `make'); # (2) otherwise, pass the desired values on the `make' command line. $(RECURSIVE_TARGETS): @failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ list='$(SUBDIRS)'; for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" mostlyclean-recursive clean-recursive distclean-recursive \ maintainer-clean-recursive: @failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ rev=''; for subdir in $$list; do \ if test "$$subdir" = "."; then :; else \ rev="$$subdir $$rev"; \ fi; \ done; \ rev="$$rev ."; \ target=`echo $@ | sed s/-recursive//`; \ for subdir in $$rev; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done && test -z "$$fail" tags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ done ctags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ mkid -fID $$unique tags: TAGS TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$tags $$unique; \ fi ctags: CTAGS CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ test -z "$(CTAGS_ARGS)$$tags$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$tags $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && cd $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) $$here distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ list='$(DISTFILES)'; for file in $$list; do \ case $$file in \ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ esac; \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ if test "$$dir" != "$$file" && test "$$dir" != "."; then \ dir="/$$dir"; \ $(mkdir_p) "$(distdir)$$dir"; \ else \ dir=''; \ fi; \ if test -d $$d/$$file; then \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test -d "$(distdir)/$$subdir" \ || $(mkdir_p) "$(distdir)/$$subdir" \ || exit 1; \ distdir=`$(am__cd) $(distdir) && pwd`; \ top_distdir=`$(am__cd) $(top_distdir) && pwd`; \ (cd $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$top_distdir" \ distdir="$$distdir/$$subdir" \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-libtool \ distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive info: info-recursive info-am: install-data-am: install-exec-am: install-info: install-info-recursive install-man: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-info-am uninstall-info: uninstall-info-recursive .PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am check check-am \ clean clean-generic clean-libtool clean-recursive ctags \ ctags-recursive distclean distclean-generic distclean-libtool \ distclean-recursive distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-exec install-exec-am install-info \ install-info-am install-man install-strip installcheck \ installcheck-am installdirs installdirs-am maintainer-clean \ maintainer-clean-generic maintainer-clean-recursive \ mostlyclean mostlyclean-generic mostlyclean-libtool \ mostlyclean-recursive pdf pdf-am ps ps-am tags tags-recursive \ uninstall uninstall-am uninstall-info-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: judy-1.0.5/src/README0000644000175000017500000000102210204462077014360 0ustar troyhebetroyhebe# @(#) $Revision: 4.10 $ $Source: /judy/src/README $ # This tree contains sources for the Judy project. # For more on how to build Judy files, see make_includes/README. The 'sh_build' script to compiling Judy manually for other platforms # Current stuff: Judy.h exported header file for libJudy.a Judy.h.check.c test program for Judy.h JudyCommon/ shared utility functions and common source files Judy1/ Judy1.h JudyL/ JudyL.h JudySL/ JudySL*() JudyHS/ JudyHS*() apps/ applications done or redone using Judy judy-1.0.5/src/Judy.h.check.c0000644000175000017500000001162010204462077016066 0ustar troyhebetroyhebe// Copyright (C) 2000 - 2002 Hewlett-Packard Company // // This program is free software; you can redistribute it and/or modify it // under the term of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License // for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program; if not, write to the Free Software Foundation, // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // _________________ // @(#) $Revision: 4.17 $ $Source: /judy/src/Judy.h.check.c $ // // Fake "program" to test the exports in Judy.h by exercising each one. This // program should compile OK (with libJudy.a) but does not run OK. #include "Judy.h" int main() { Pvoid_t PArray = (Pvoid_t) NULL; PPvoid_t PPArray = &PArray; Word_t Index = 0; PWord_t PIndex = &Index; uint8_t *CIndex = NULL; PPvoid_t PPvoid; Word_t myword; Word_t Length; int myint; // JUDY FUNCTIONS: myint = Judy1Test ( PArray, Index, PJE0); myint = Judy1Set (PPArray, Index, PJE0); myint = Judy1SetArray (PPArray, Index, &Index, PJE0); myint = Judy1Unset (PPArray, Index, PJE0); myword = Judy1Count ( PArray, Index, Index, PJE0); myint = Judy1ByCount ( PArray, Index, PIndex, PJE0); myword = Judy1FreeArray (PPArray, PJE0); myword = Judy1MemUsed ( PArray ); myword = Judy1MemActive ( PArray ); myint = Judy1First ( PArray, PIndex, PJE0); myint = Judy1Next ( PArray, PIndex, PJE0); myint = Judy1Last ( PArray, PIndex, PJE0); myint = Judy1Prev ( PArray, PIndex, PJE0); myint = Judy1FirstEmpty ( PArray, PIndex, PJE0); myint = Judy1NextEmpty ( PArray, PIndex, PJE0); myint = Judy1LastEmpty ( PArray, PIndex, PJE0); myint = Judy1PrevEmpty ( PArray, PIndex, PJE0); PPvoid = JudyLGet ( PArray, Index, PJE0); PPvoid = JudyLIns (PPArray, Index, PJE0); myint = JudyLInsArray (PPArray, Index, &Index, &Index, PJE0); myint = JudyLDel (PPArray, Index, PJE0); myword = JudyLCount ( PArray, Index, Index, PJE0); PPvoid = JudyLByCount ( PArray, Index, PIndex, PJE0); myword = JudyLFreeArray (PPArray, PJE0); myword = JudyLMemUsed ( PArray ); myword = JudyLMemActive ( PArray ); PPvoid = JudyLFirst ( PArray, PIndex, PJE0); PPvoid = JudyLNext ( PArray, PIndex, PJE0); PPvoid = JudyLLast ( PArray, PIndex, PJE0); PPvoid = JudyLPrev ( PArray, PIndex, PJE0); myint = JudyLFirstEmpty ( PArray, PIndex, PJE0); myint = JudyLNextEmpty ( PArray, PIndex, PJE0); myint = JudyLLastEmpty ( PArray, PIndex, PJE0); myint = JudyLPrevEmpty ( PArray, PIndex, PJE0); PPvoid = JudySLGet ( PArray, CIndex, PJE0); PPvoid = JudySLIns (PPArray, CIndex, PJE0); myint = JudySLDel (PPArray, CIndex, PJE0); myword = JudySLFreeArray (PPArray, PJE0); PPvoid = JudySLFirst ( PArray, CIndex, PJE0); PPvoid = JudySLNext ( PArray, CIndex, PJE0); PPvoid = JudySLLast ( PArray, CIndex, PJE0); PPvoid = JudySLPrev ( PArray, CIndex, PJE0); PPvoid = JudyHSGet ( PArray, CIndex, Length); PPvoid = JudyHSIns (PPArray, CIndex, Length, PJE0); myint = JudyHSDel (PPArray, CIndex, Length, PJE0); // MACRO EQUIVALENTS: J1T (myint, PArray, Index); J1S (myint, PArray, Index); J1SA (myint, PArray, Index, &Index); J1U (myint, PArray, Index); J1F (myint, PArray, Index); J1N (myint, PArray, Index); J1L (myint, PArray, Index); J1P (myint, PArray, Index); J1FE (myint, PArray, Index); J1NE (myint, PArray, Index); J1LE (myint, PArray, Index); J1PE (myint, PArray, Index); J1C (myword, PArray, Index, Index); J1BC (myint, PArray, Index, Index); J1FA (myword, PArray); JLG (PPvoid, PArray, Index); JLI (PPvoid, PArray, Index); JLIA (myint, PArray, Index, &Index, &Index); JLD (myint, PArray, Index); JLF (PPvoid, PArray, Index); JLN (PPvoid, PArray, Index); JLL (PPvoid, PArray, Index); JLP (PPvoid, PArray, Index); JLFE (myint, PArray, Index); JLNE (myint, PArray, Index); JLLE (myint, PArray, Index); JLPE (myint, PArray, Index); JLC (myword, PArray, Index, Index); JLBC (PPvoid, PArray, myword, Index); JLFA (myword, PArray); JSLG (PPvoid, PArray, CIndex); JSLI (PPvoid, PArray, CIndex); JSLD (myint, PArray, CIndex); JSLF (PPvoid, PArray, CIndex); JSLN (PPvoid, PArray, CIndex); JSLL (PPvoid, PArray, CIndex); JSLP (PPvoid, PArray, CIndex); JSLFA (myword, PArray); JHSI (PPvoid, PArray, CIndex, Length); JHSG (PPvoid, PArray, CIndex, Length); JHSD (myint, PArray, CIndex, Length); return(0); } // main() judy-1.0.5/configure.ac0000644000175000017500000002371110624600161015202 0ustar troyhebetroyhebeAC_PREREQ(2.57) AC_INIT(Judy, 1.0.5, dougbaskins@yahoo.com) AM_MAINTAINER_MODE dnl Turn on automake, and pass it the PACKAGE_NAME and PACKAGE_VERSION, too. AM_INIT_AUTOMAKE($PACKAGE_NAME, $PACKAGE_VERSION) dnl Tell autoconf we want to keep our preprocessor defines in a header named dnl config.h. This keeps automake from passing a zillion -D directives to dnl the C compiler. AM_CONFIG_HEADER([config.h]) dnl========================================================================== dnl WARNING - WARNING - Shared Library Versioning - WARNING - WARNING dnl========================================================================== dnl This is the most dangerous part of this file--making a mistake here can dnl cause massively painful chaos for libJudy developers, and potentially dnl even end users. So PLEASE pay attention, and read up on the theory of dnl shared library versioning. Tens of thousands of Linux users (and several dnl QA departments) may thank you someday. dnl dnl There are two major concerns: dnl dnl 1) When changing the libJudy ABI (application binary interface), dnl VERSION_INFO *must* be updated according to libtool's rules. Failure dnl to do this will make applications using libJudy dump core, typically dnl under obscure conditions on user systems. I won't attempt to dnl explain these rules here; please see 'info libtool' for details. dnl dnl 2) When changing the libJudy ABI, it is also desirable to make libJudy dnl "parallel installable". This means that it should be possible to dnl install development headers and libraries for more than one version dnl of libJudy at once. Failure to do this may cause problems for dnl Linux distributions which include libJudy. (For example, it's dnl impossible to switch between libpng2-dev and libpng3-dev on a dnl Debian system without uninstalling and reinstalling both the Gnome dnl and KDE SDKs.) For more information, do a Google search for dnl "parallel installable". dnl dnl Right now, this package only provides the mechanisms to handle concern dnl (1). Concern (2) is slightly more complicated, and will require some dnl careful thinking. Fortunately, concern (2) doesn't become important dnl until other SDKs rely on the libJudy SDK. dnl dnl Of course, it's safe to avoid changing the libJudy ABI. :-) dnl dnl The version scheme used by Libtool tracks interfaces, where an interface is dnl the set of exported entry points into the library. All Libtool libraries dnl start with -version-info set to 0:0:0 - this will be the default version dnl number if you don't explicitly set it on the Libtool link command line. The dnl meaning of these numbers (from left to right) is as follows: dnl dnl current: dnl The number of the current interface exported by the library. A current dnl value of 0, means that you are calling the interface exported by this dnl library interface 0. dnl dnl revision: dnl The implementation number of the most recent interface exported by this dnl library. In this case, a revision value of 0 means that this is the dnl first implementation of the interface. dnl dnl If the next release of this library exports the same interface, but has dnl different implementation (perhaps some bugs have been fixed), the dnl revision number will be higher, but current number will be the same. In dnl that case, when given a choice, the library with the highest revision dnl will always be used by the runtime loader. dnl dnl age: dnl The number of previous additional interfaces supported by this library. dnl If age were 2, then this library can be linked into executables which dnl were built with a release of this library that exported the current dnl interface number, current, or any of the previous two interfaces. dnl dnl By definition age must be less than or equal to current. At the outset, only dnl the first ever interface is implemented, so age can only be 0. dnl VERSION_INFO="-version-info 1:3:0" AC_SUBST(VERSION_INFO) dnl========================================================================== dnl Flavors dnl========================================================================== dnl Judy can be compiled in one of three flavors: "product" (the default), dnl "debug", or "cov". We allow the user to select flavors using dnl --enable-debug and --enable-ccover arguments to automake, which is dnl the typical way of doing things. dnl dnl Note how we perform string comparison: dnl dnl if test "x$enable_debug" = xyes; then dnl dnl We do several odd things here: dnl dnl 1) We use 'test' instead of '[ ]' for shell portability. dnl 2) We prefix strings with 'x' when comparing them, to protect against dnl empty strings. dnl 3) We ALWAYS quote user-supplied shell variables, to protect against dnl embedded spaces. dnl dnl The results of this test aren't used anywhere yet. dnl Keep the user entertained. AC_MSG_CHECKING(which flavor to build) dnl Process our --enable-debug argument. AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug], [enable debugging features]), , enable_debug=no) if test "x$enable_debug" != xyes -a "x$enable_debug" != xno; then AC_MSG_ERROR(You may not pass an argument to --enable-debug) fi dnl Process our --enable-ccover argument. AC_ARG_ENABLE(ccover, AC_HELP_STRING([--enable-ccover], [enable use of ccover code coverage tools]), , enable_ccover=no) if test "x$enable_ccover" != xyes -a "x$enable_ccover" != xno; then AC_MSG_ERROR(You may not pass an argument to --enable-ccover) fi dnl Determine our flavor. if test "x$enable_debug" = xyes -a "x$enable_ccover" = xyes; then AC_MSG_ERROR(You may not use --enable-debug and --enable-ccover together) elif test "x$enable_debug" = xyes; then FLAVOR=debug elif test "x$enable_ccover" = xyes; then FLAVOR=cov else FLAVOR=product fi dnl Define FLAVOR in our makefiles. AC_SUBST(FLAVOR) dnl Tell the user what flavor we've decided to build. AC_MSG_RESULT($FLAVOR) dnl========================================================================== dnl Checks for Programs dnl========================================================================== AC_PROG_CC AC_PROG_CPP AC_PROG_INSTALL AC_PROG_LN_S AC_PROG_MAKE_SET dnl========================================================================== dnl Checks for Header Files dnl========================================================================== AC_HEADER_STDC AC_CHECK_HEADERS([fcntl.h inttypes.h limits.h malloc.h stddef.h stdint.h stdlib.h string.h strings.h sys/param.h sys/time.h unistd.h]) dnl========================================================================== dnl Checks for Typedefs, Structures, and Compiler Characteristics dnl========================================================================== dnl Standard, boring stuff. AC_HEADER_STDBOOL AC_C_CONST AC_C_INLINE AC_TYPE_SIZE_T AC_HEADER_TIME AC_STRUCT_TM AC_C_VOLATILE AC_CHECK_TYPES([ptrdiff_t]) dnl If we're compiling for a little-endian system, define JU_LITTLE_ENDIAN. dnl If we can't tell what kind of system we're compling for, alert the dnl user as described in 'info autoconf'. AC_C_BIGENDIAN(, AC_DEFINE(JU_LITTLE_ENDIAN, 1, [Define to 1 on little-endian systems.])) dnl Figure out if we are 32-bit or 64-bit (LP64) AC_CHECK_SIZEOF(void *) if test "$ac_cv_sizeof_void_p" = 8; then AC_MSG_RESULT(Detected 64-bit Build Environment) CFLAGS="-DJU_64BIT $CFLAGS" else AC_MSG_RESULT(Detected 32-bit Build Environment) CFLAGS="-UJU_64BIT $CFLAGS" fi AC_ARG_ENABLE(32-bit, [ --enable-32-bit Generate code for a 32-bit environment], b32="$enableval", b32="no") if test x"$b32" != "xno"; then AC_MSG_RESULT(Configured to Build 32-bit) if test x"$GCC" = xyes; then CFLAGS="-UJU_64BIT -m32 $CFLAGS" else CFLAGS="-UJU_64BIT $CFLAGS" fi fi AC_ARG_ENABLE(64-bit, [ --enable-64-bit Generate code for a 64-bit environment], b64="$enableval", b64="no") if test x"$b64" != "xno"; then AC_MSG_RESULT(Configured to Building 64-bit) if test x"$GCC" = xyes; then CFLAGS="-DJU_64BIT -m64 $CFLAGS" else CFLAGS="-DJU_64BIT $CFLAGS" fi fi # dnl Determine whether or not we're compiling for a 64-bit system by looking # dnl at the size of a 'long'. This will define SIZEOF_LONG in config.h. We # dnl append some text to the bottom of config.h to set JU_64BIT appropriately. # dnl we try to do the correct thing if the user doesn't chose for us. # AC_CHECK_SIZEOF(long) # AH_BOTTOM([/* Define JU_64BIT to 1 if we're on a 64-bit system. */ # if SIZEOF_LONG == 8 # define JU_64BIT 1 # endif]) #fi dnl========================================================================== dnl Checks for Libraries dnl========================================================================== AC_FUNC_ERROR_AT_LINE AC_FUNC_MALLOC AC_FUNC_MEMCMP AC_FUNC_MMAP AC_FUNC_STAT AC_FUNC_VPRINTF AC_CHECK_FUNCS([getpagesize gettimeofday memset munmap pow strchr strcspn strerror strstr strtoul uname]) dnl These must be called before AM_PROG_LIBTOOL, because it may want dnl to call AC_CHECK_PROG. AC_CHECK_TOOL(AR, ar) AC_CHECK_TOOL(LD, ld) AC_CHECK_TOOL(RANLIB, ranlib, :) dnl Checks for libtool - this must be done after we set cflags (abi issues) dnl AM_PROG_LIBTOOL WARN_CFLAGS="" build_warnings="-W -Wall -Wstrict-prototypes -Wmissing-prototypes" AC_ARG_ENABLE([build-warnings], [ --enable-build-warnings Enable build-time compiler warnings for gcc]) if test x"$build_warnings" = xyes; then if test x"$GCC" = xyes; then WARN_CFLAGS="${build_warnings}" fi fi AC_SUBST(WARN_CFLAGS) AC_CONFIG_FILES([Makefile src/Judy1/Makefile src/JudyCommon/Makefile src/JudyHS/Makefile src/JudyL/Makefile src/JudySL/Makefile src/Makefile src/obj/Makefile tool/Makefile doc/Makefile test/Makefile]) AC_OUTPUT judy-1.0.5/AUTHORS0000644000175000017500000000016710204462077013772 0ustar troyhebetroyhebeDoug Baskinks Owner and Main Author Contributors: Troy Heber: Repackaging Project Administration judy-1.0.5/ChangeLog0000644000175000017500000000454610624600161014473 0ustar troyhebetroyhebe1.0.5 Version (May 2007) by (twh) o added proper clean targets to enable multiple builds o added examples directory o Correctly Detects 32/64-bit build environment o Allow explicit configure for 32/64-bit environment 1.0.4 Version (May 2007) by (twh) o fixed the Checkit problem "error Judy1PrevEmpty Rcode != 1 = 0" o Fixed memory allignment in JudyMallocIF.c (doug) o Fixed messages from "make check" (doug). 1.0.3 Version (Feb 2006 ) by (twh) o fixed make files to break out each copy element to be a unique target, this also seems to have resolved the issue where running make check rebuilds the entire library again. 1.0.2 Version (Jan 2006 ) by (twh) o fixed assumption of signed char in test programs. o updated sh_build o fixed generation of man pages from html o fixed 32-bit and 64-bit configure 1.0.1 Version (Dec 2004) by (twh) o fixed bootstrap to use later versions o fixed manpage naming from (3X) to (3) o Code changes to support Microsoft __inline directive o Move away from using symlinks to using copies o Added build.bat to support building on Windows 1.0.0 Version (Sept 2004) by (twh) o Complete Autoconfisication of Judy o Removed previous build environment o Change INSTALL_IT back to INSTALL o Moving to 1.0.0 to denote API change. 0.1.6 Version (1June2004) by (dlb) o See src/sh_build in case of 'make' failures o The is an endian-neutral version I.E. (jp_DcdPop0 deleted) o Should not require any special platform specific compile flags o Includes JudyHS*() -- very fast, scalable string version o JudyHS*() is still preliminary and may need additional functionality. o See test/manual/StringCompare.c for comparing different 'string' ADT's o Deleted files: JudyMalloc.h, JudySL.h, JudySearch* o All malloc() and free() is done thru interface routines in JudyMalloc.c o Judy.h should work on all platforms that conform to ISO standards. o After trying on many platforms, was changed to o jbgraph has some 'bash/ksh' isms that need to be removed. o See test/manual/testjbgraph for plotting performance graphs o 'libtools' stuff is in unknown shape. o Does not "mangle" the root pointer (so old valgrind is not confused) o Conform to standard "C" o Change INSTALL to INSTALL_IT because it confused "make install" o To he man pages need work to clean up the .html to be portable o Plus hundreds of changes to make the source more portable. judy-1.0.5/INSTALL0000644000175000017500000000140110204462077013743 0ustar troyhebetroyhebe=== QUICK INSTALLATION OF JUDY LIBRARY AND MANUAL ENTRIES === 1. ./configure #NOTE: you must do configure with either --enable-32-bit or --enable-64-bit depending on your system. Also note if you are doing a non-native compile you are responsiable for setting the appropriate CFLAGS. See README for more information. 2. make 3. make check 4. make install # NOTE: must be SUPERUSER for make install # This installs /opt/Judy/* and symlinks to # files there from /usr/include/, /usr/lib/, # /usr/share/man/, and /usr/share/doc/Judy/. (Installation done! The rest is optional but recommended.) 5) man Judy # nroff -man version, or... 6) file:/opt/Judy/usr/share/doc/Judy/Judy_3x.htm # from LOCAL Web browser. judy-1.0.5/Makefile.am0000644000175000017500000000144710624600161014752 0ustar troyhebetroyhebe# Tell automake we don't want to comply with every last clause in the # GNU Maintainer's Manual. AUTOMAKE_OPTIONS = foreign # We need to build the following subdirectories in this order. Note that # we put a Makefile.am in every subdirectory, even if there's nothing to # compile, so that we can support 'make dist' gracefully. # # Dependencies: src <- tool (for libJudy), tool <- doc (for jhton), src <- # test (for libJudy). #SUBDIRS = src tool doc test make_includes #SUBDIRS = src/JudyCommon src/JudyL src/Judy1 src/JudySL src/JudyHS src/obj SUBDIRS = src tool doc test # These files will be included in our tarballs, even though automake knows # nothing else about them. #EXTRA_DIST = Makefile.multi original_configure .cvsignore DISTCLEANFILES = config.log config.status Makefile libtool make.out judy-1.0.5/COPYING0000644000175000017500000006461610204462077013766 0ustar troyhebetroyhebeJudy - C library functions for creating and accessing dynamic arrays Copyright (C) 2004 Doug Baskins This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! judy-1.0.5/bootstrap0000755000175000017500000000045510622150133014654 0ustar troyhebetroyhebe#! /bin/sh set -x libtoolize --force --copy #aclocal-1.9 aclocal #autoheader2.50 autoheader #add --include-deps if you want to bootstrap with any other compiler than gcc #automake --add-missing --copy --include-deps automake-1.9 --add-missing --force --copy #autoconf2.50 autoconf rm -f config.cache judy-1.0.5/README0000644000175000017500000001157610624600161013602 0ustar troyhebetroyhebe Judy - C library creating and accessing dynamic arrays ============================================================== Content --------- 1. Introduction 2. Directory Contents 3. How to install 4. License 5. Change History 6. Reporting Bugs 7. Known Issues 1. INTRODUCTION ----------------- This tree contains sources, documents, tests, and tools for the Judy package. This file is in a form that can be validated using the tool/readme script. NOTE: The README files here describe some files that are not included in every Judy source package. WHAT IS JUDY? (see below for list of top-level directories and files) Judy is a C library that implements a dynamic array. Empty Judy arrays are declared with null pointers. A Judy array consumes memory only when populated yet can grow to take advantage of all available memory. Judy's key benefits are: scalability, performance, memory efficiency, and ease of use. Judy arrays are designed to grow without tuning into the peta-element range, scaling near O(log-base-256) -- 1 more RAM access at 256 X population. Judy arrays are accessed with insert, retrieve, and delete calls for number or string indexes. Configuration and tuning are not required -- in fact not possible. Judy offers sorting, counting, and neighbor/empty searching. Indexes can be sequential, clustered, periodic, or random -- it doesn't matter to the algorithm. Judy arrays can be arranged hierarchically to handle any bit patterns -- large indexes, sets of keys, etc. Judy is often an improvement over common data structures such as: arrays, sparse arrays, hash tables, B-trees, binary trees, linear lists, skiplists, other sort and search algorithms, and counting functions. 2. JUDY TOP DIRECTORY CONTENTS: -------------------------------- AUTHORS Judy authors and contributors README This file. INSTALL Summary instructions to build, check and install Judy. COPYING Judy deliverable license notice (the LGPL). ChangeLog List of changes per version of Judy. configure Autoconf configure script to allow a portable build e environment. src/ Header and source files used to build the package. doc/ Documents, both external (to the package) and internal. test/ Test support and some timing programs. tool/ Primitive tool (jhton) to convert *.html files to "man" pages. and build tables used by Judy to malloc() sizes of memory. 3. HOW TO INSTALL ----------------- For a quick description see the INSTALL file. Judy is now based on the GNU Auto tools. This means that you can do the standard configure, make, make check and make install and everything should work, with one minor difference and a little caveat. Judy is capable of being built as a 32-bit or a 64-bit library. Configure will test to detect the native environment and default to that. Therefor if you explicitly want to to compile for the non-native environment you need to tell Judy what you want. You can run ./configure with one of the following flags: --enable-32-bit --enable-64-bit The caveat comes in on machines that support both at 32-bit and 64-bit runtime environments such as RISC platforms and x86-64. In this case your compiler will either use 32-bit or 64-bit as default. If you plan to use the default you can follow the above instructions and be finished. However, if you wish to compile for the non-default target type. YOU ARE RESPONSIBLE FOR SETTING THE CORRECT FLAGS! Such as CFLAGS to make your compiler switch modes LDFLAGS to make your linker behave, etc. For example: On HP-UX PA-RISC the compiler generates 32-bit code by default. If I wish to stick with the defaults I can simply build Judy by: ./configure make make check make install If I want to build Judy as a 64-bit library on HP-UX PA-RISC I have to do: CFLAGS=+DD64 ./configure --enable-64-bit make make check make install If I want to build Judy native (64-bit) on Linux AMD64 I have to do: ./configure make make check make install If I want to build Judy 32-bit on Linux AMD64 I have to do: ./configure --enable-32-bit make make check make install 4. LICENSE ---------- The user library is licensed under the GNU Lesser Public License (LGPL) Version 2.1, February 1999. The full text of the LGPL is located at: COPYING 5. CHAGE HISTORY ---------------- See the ChangeLog file. 6. REPORTING BUGS ----------------- If you encounter a bug, please submit it to the project bug list, located on the project page: https://sourceforge.net/projects/judy/ 7. KNOWN ISSUES --------------- When compiling on HP-UX, you may get a message like: error 1000: Unexpected symbol: This is a problem with the HP's compiler in that it doesn't like a typedef'ed type following a static inline. You can work around it by running this command from the Judy directory. find ./ -name \*.[ch] | xargs perl -i.BAK -pe 's/static inline/static/g' judy-1.0.5/tool/0000755000175000017500000000000010624600217013667 5ustar troyhebetroyhebejudy-1.0.5/tool/listJPtype.c0000644000175000017500000002044110204462077016147 0ustar troyhebetroyhebe// Copyright (C) 2000 - 2002 Hewlett-Packard Company // // This program is free software; you can redistribute it and/or modify it // under the term of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License // for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program; if not, write to the Free Software Foundation, // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // _________________ // @(#) $Revision: 4.9 $ $Date: 2002/06/25 00:35:37 $ // @(#) $Source: /cvsroot/judy/tool/listJPtype.c,v $ // Print JP values. // // Compile with one of -DJUDY1 or -DJUDYL; defaults to JUDY1: // // IOPTS='-I ../src -I ../src/Judy1 -I ../src/JudyL -I ../src/JudyCommon' // cc -Ae -DJUDY1 $IOPTS listJPtype.c -o listJPtype1 // cc -Ae -DJUDYL $IOPTS listJPtype.c -o listJPtypeL // cc +DD64 -Ae -DJUDY1 -DJU_64BIT $IOPTS listJPtype.c -o listJPtype1_64 // cc +DD64 -Ae -DJUDYL -DJU_64BIT $IOPTS listJPtype.c -o listJPtypeL_64 #ifndef JUDYL #ifndef JUDY1 #define JUDY1 1 // neither set => use default. #endif #endif #ifdef JUDY1 #include "Judy1.h" #else #include "JudyL.h" #endif // Lists of all JP types; must agree with header files: struct list { char * name; int value; } *Plist, list[] = { #ifdef JUDY1 { "cJ1_JAPNULL", cJ1_JAPNULL, }, { "cJ1_JAPLEAF", cJ1_JAPLEAF, }, { "cJ1_JAPBRANCH", cJ1_JAPBRANCH, }, { "cJ1_JPNULL1", cJ1_JPNULL1, }, { "cJ1_JPNULL2", cJ1_JPNULL2, }, { "cJ1_JPNULL3", cJ1_JPNULL3, }, #ifdef JU_64BIT { "cJ1_JPNULL4", cJ1_JPNULL4, }, { "cJ1_JPNULL5", cJ1_JPNULL5, }, { "cJ1_JPNULL6", cJ1_JPNULL6, }, { "cJ1_JPNULL7", cJ1_JPNULL7, }, #endif { "cJ1_JPNULLMAX", cJ1_JPNULLMAX, }, { "cJ1_JPBRANCH_L2", cJ1_JPBRANCH_L2, }, { "cJ1_JPBRANCH_L3", cJ1_JPBRANCH_L3, }, #ifdef JU_64BIT { "cJ1_JPBRANCH_L4", cJ1_JPBRANCH_L4, }, { "cJ1_JPBRANCH_L5", cJ1_JPBRANCH_L5, }, { "cJ1_JPBRANCH_L6", cJ1_JPBRANCH_L6, }, { "cJ1_JPBRANCH_L7", cJ1_JPBRANCH_L7, }, #endif { "cJ1_JPBRANCH_L", cJ1_JPBRANCH_L, }, { "cJ1_JPBRANCH_B2", cJ1_JPBRANCH_B2, }, { "cJ1_JPBRANCH_B3", cJ1_JPBRANCH_B3, }, #ifdef JU_64BIT { "cJ1_JPBRANCH_B4", cJ1_JPBRANCH_B4, }, { "cJ1_JPBRANCH_B5", cJ1_JPBRANCH_B5, }, { "cJ1_JPBRANCH_B6", cJ1_JPBRANCH_B6, }, { "cJ1_JPBRANCH_B7", cJ1_JPBRANCH_B7, }, #endif { "cJ1_JPBRANCH_B", cJ1_JPBRANCH_B, }, { "cJ1_JPBRANCH_U2", cJ1_JPBRANCH_U2, }, { "cJ1_JPBRANCH_U3", cJ1_JPBRANCH_U3, }, #ifdef JU_64BIT { "cJ1_JPBRANCH_U4", cJ1_JPBRANCH_U4, }, { "cJ1_JPBRANCH_U5", cJ1_JPBRANCH_U5, }, { "cJ1_JPBRANCH_U6", cJ1_JPBRANCH_U6, }, { "cJ1_JPBRANCH_U7", cJ1_JPBRANCH_U7, }, #endif { "cJ1_JPBRANCH_U", cJ1_JPBRANCH_U, }, #ifndef JU_64BIT { "cJ1_JPLEAF1", cJ1_JPLEAF1, }, #endif { "cJ1_JPLEAF2", cJ1_JPLEAF2, }, { "cJ1_JPLEAF3", cJ1_JPLEAF3, }, #ifdef JU_64BIT { "cJ1_JPLEAF4", cJ1_JPLEAF4, }, { "cJ1_JPLEAF5", cJ1_JPLEAF5, }, { "cJ1_JPLEAF6", cJ1_JPLEAF6, }, { "cJ1_JPLEAF7", cJ1_JPLEAF7, }, #endif { "cJ1_JPLEAF_B1", cJ1_JPLEAF_B1, }, { "cJ1_JPFULLPOPU1", cJ1_JPFULLPOPU1, }, { "cJ1_JPIMMED_1_01", cJ1_JPIMMED_1_01, }, { "cJ1_JPIMMED_2_01", cJ1_JPIMMED_2_01, }, { "cJ1_JPIMMED_3_01", cJ1_JPIMMED_3_01, }, #ifdef JU_64BIT { "cJ1_JPIMMED_4_01", cJ1_JPIMMED_4_01, }, { "cJ1_JPIMMED_5_01", cJ1_JPIMMED_5_01, }, { "cJ1_JPIMMED_6_01", cJ1_JPIMMED_6_01, }, { "cJ1_JPIMMED_7_01", cJ1_JPIMMED_7_01, }, #endif { "cJ1_JPIMMED_1_02", cJ1_JPIMMED_1_02, }, { "cJ1_JPIMMED_1_03", cJ1_JPIMMED_1_03, }, { "cJ1_JPIMMED_1_04", cJ1_JPIMMED_1_04, }, { "cJ1_JPIMMED_1_05", cJ1_JPIMMED_1_05, }, { "cJ1_JPIMMED_1_06", cJ1_JPIMMED_1_06, }, { "cJ1_JPIMMED_1_07", cJ1_JPIMMED_1_07, }, #ifdef JU_64BIT { "cJ1_JPIMMED_1_08", cJ1_JPIMMED_1_08, }, { "cJ1_JPIMMED_1_09", cJ1_JPIMMED_1_09, }, { "cJ1_JPIMMED_1_10", cJ1_JPIMMED_1_10, }, { "cJ1_JPIMMED_1_11", cJ1_JPIMMED_1_11, }, { "cJ1_JPIMMED_1_12", cJ1_JPIMMED_1_12, }, { "cJ1_JPIMMED_1_13", cJ1_JPIMMED_1_13, }, { "cJ1_JPIMMED_1_14", cJ1_JPIMMED_1_14, }, { "cJ1_JPIMMED_1_15", cJ1_JPIMMED_1_15, }, #endif { "cJ1_JPIMMED_2_02", cJ1_JPIMMED_2_02, }, { "cJ1_JPIMMED_2_03", cJ1_JPIMMED_2_03, }, #ifdef JU_64BIT { "cJ1_JPIMMED_2_04", cJ1_JPIMMED_2_04, }, { "cJ1_JPIMMED_2_05", cJ1_JPIMMED_2_05, }, { "cJ1_JPIMMED_2_06", cJ1_JPIMMED_2_06, }, { "cJ1_JPIMMED_2_07", cJ1_JPIMMED_2_07, }, #endif { "cJ1_JPIMMED_3_02", cJ1_JPIMMED_3_02, }, #ifdef JU_64BIT { "cJ1_JPIMMED_3_03", cJ1_JPIMMED_3_03, }, { "cJ1_JPIMMED_3_04", cJ1_JPIMMED_3_04, }, { "cJ1_JPIMMED_3_05", cJ1_JPIMMED_3_05, }, { "cJ1_JPIMMED_4_02", cJ1_JPIMMED_4_02, }, { "cJ1_JPIMMED_4_03", cJ1_JPIMMED_4_03, }, { "cJ1_JPIMMED_5_02", cJ1_JPIMMED_5_02, }, { "cJ1_JPIMMED_5_03", cJ1_JPIMMED_5_03, }, { "cJ1_JPIMMED_6_02", cJ1_JPIMMED_6_02, }, { "cJ1_JPIMMED_7_02", cJ1_JPIMMED_7_02, }, #endif { "cJ1_JPIMMED_CAP", cJ1_JPIMMED_CAP, }, #else // JUDYL ------------------------------------------------------------- { "cJL_JAPNULL", cJL_JAPNULL, }, { "cJL_JAPLEAF", cJL_JAPLEAF, }, { "cJL_JAPLEAF_POPU2", cJL_JAPLEAF_POPU2, }, { "cJL_JAPBRANCH", cJL_JAPBRANCH, }, { "cJL_JAPINVALID", cJL_JAPINVALID, }, { "cJL_JAPLEAF_POPU1", cJL_JAPLEAF_POPU1, }, { "cJL_JPNULL1", cJL_JPNULL1, }, { "cJL_JPNULL2", cJL_JPNULL2, }, { "cJL_JPNULL3", cJL_JPNULL3, }, #ifdef JU_64BIT { "cJL_JPNULL4", cJL_JPNULL4, }, { "cJL_JPNULL5", cJL_JPNULL5, }, { "cJL_JPNULL6", cJL_JPNULL6, }, { "cJL_JPNULL7", cJL_JPNULL7, }, #endif { "cJL_JPNULLMAX", cJL_JPNULLMAX, }, { "cJL_JPBRANCH_L2", cJL_JPBRANCH_L2, }, { "cJL_JPBRANCH_L3", cJL_JPBRANCH_L3, }, #ifdef JU_64BIT { "cJL_JPBRANCH_L4", cJL_JPBRANCH_L4, }, { "cJL_JPBRANCH_L5", cJL_JPBRANCH_L5, }, { "cJL_JPBRANCH_L6", cJL_JPBRANCH_L6, }, { "cJL_JPBRANCH_L7", cJL_JPBRANCH_L7, }, #endif { "cJL_JPBRANCH_L", cJL_JPBRANCH_L, }, { "cJL_JPBRANCH_B2", cJL_JPBRANCH_B2, }, { "cJL_JPBRANCH_B3", cJL_JPBRANCH_B3, }, #ifdef JU_64BIT { "cJL_JPBRANCH_B4", cJL_JPBRANCH_B4, }, { "cJL_JPBRANCH_B5", cJL_JPBRANCH_B5, }, { "cJL_JPBRANCH_B6", cJL_JPBRANCH_B6, }, { "cJL_JPBRANCH_B7", cJL_JPBRANCH_B7, }, #endif { "cJL_JPBRANCH_B", cJL_JPBRANCH_B, }, { "cJL_JPBRANCH_U2", cJL_JPBRANCH_U2, }, { "cJL_JPBRANCH_U3", cJL_JPBRANCH_U3, }, #ifdef JU_64BIT { "cJL_JPBRANCH_U4", cJL_JPBRANCH_U4, }, { "cJL_JPBRANCH_U5", cJL_JPBRANCH_U5, }, { "cJL_JPBRANCH_U6", cJL_JPBRANCH_U6, }, { "cJL_JPBRANCH_U7", cJL_JPBRANCH_U7, }, #endif { "cJL_JPBRANCH_U", cJL_JPBRANCH_U, }, { "cJL_JPLEAF1", cJL_JPLEAF1, }, { "cJL_JPLEAF2", cJL_JPLEAF2, }, { "cJL_JPLEAF3", cJL_JPLEAF3, }, #ifdef JU_64BIT { "cJL_JPLEAF4", cJL_JPLEAF4, }, { "cJL_JPLEAF5", cJL_JPLEAF5, }, { "cJL_JPLEAF6", cJL_JPLEAF6, }, { "cJL_JPLEAF7", cJL_JPLEAF7, }, #endif { "cJL_JPLEAF_B1", cJL_JPLEAF_B1, }, { "cJL_JPIMMED_1_01", cJL_JPIMMED_1_01, }, { "cJL_JPIMMED_2_01", cJL_JPIMMED_2_01, }, { "cJL_JPIMMED_3_01", cJL_JPIMMED_3_01, }, #ifdef JU_64BIT { "cJL_JPIMMED_4_01", cJL_JPIMMED_4_01, }, { "cJL_JPIMMED_5_01", cJL_JPIMMED_5_01, }, { "cJL_JPIMMED_6_01", cJL_JPIMMED_6_01, }, { "cJL_JPIMMED_7_01", cJL_JPIMMED_7_01, }, #endif { "cJL_JPIMMED_1_02", cJL_JPIMMED_1_02, }, { "cJL_JPIMMED_1_03", cJL_JPIMMED_1_03, }, #ifdef JU_64BIT { "cJL_JPIMMED_1_04", cJL_JPIMMED_1_04, }, { "cJL_JPIMMED_1_05", cJL_JPIMMED_1_05, }, { "cJL_JPIMMED_1_06", cJL_JPIMMED_1_06, }, { "cJL_JPIMMED_1_07", cJL_JPIMMED_1_07, }, { "cJL_JPIMMED_2_02", cJL_JPIMMED_2_02, }, { "cJL_JPIMMED_2_03", cJL_JPIMMED_2_03, }, { "cJL_JPIMMED_3_02", cJL_JPIMMED_3_02, }, #endif { "cJL_JPIMMED_CAP", cJL_JPIMMED_CAP, }, #endif // JUDYL { (char *) 0, 0, }, }; FUNCTION main() { for (Plist = list; (Plist -> name) != (char *) 0; ++Plist) (void) printf ("%-20s %2d\n", Plist -> name, Plist -> value); } // main judy-1.0.5/tool/jhton.c0000644000175000017500000015356410204462077015177 0ustar troyhebetroyhebe// Copyright (C) 2000 - 2002 Hewlett-Packard Company // // This program is free software; you can redistribute it and/or modify it // under the term of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License // for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program; if not, write to the Free Software Foundation, // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // _________________ // @(#) $Revision: 4.22 $ $Source: /cvsroot/judy/tool/jhton.c,v $ // // JUDY HTML MANUAL ENTRY TO NROFF TRANSLATOR. // // USAGE: filename.htm[l] // Writes nroff -man output to stdout. // Suggestion: Pipe output through rmnl to delete extraneous newlines that // this program cannot easily avoid. // // Compile with -DDEBUG for assertions and other checks. // If so, run with DUMP set in the env to dump the docnodes tree. // // CONCEPT: This program was written out of necessity for the 11.11 OEUR // release of Judy. Ideally our manual entries would be written in an abstract // XML format with an XSLT-based means to translate them to any other format, // such as HTML or nroff. In lieu of that, this program knows how to translate // a limited subset of HTML, as used in our manual entries, to equivalent // nroff, as described below preceding EmitNroffHeader(). // // The translation is still complex enough to merit writing a parser that first // builds a tree representation of the structured (HTML) document. I would use // yacc and lex if I knew them... // // This program is written for simplicity, cleanliness, and robustness, and not // necessarily for speed. // // FLEXIBILITY: It should be possible to teach this program new HTML tags; see // data structures below. The program might also be useful for other HTML // manual entries, so long as they follow the simple conventions used in the // Judy entries; see the comments before EmitNroffHeader(). You can also // discover the format by trial and error -- this program issues verbose error // messages. // // CONVENTIONS: // // - Global variables start with "g_" except option_*. // - Global constants start with "gc_". // // - Pointer variable names start with one "P" per level of indirection. // // - Exception: (char *) and (char[]) types, that is, strings, do not // necessarily start with "P". A generic char pointer is named "Pch". // Variables of type (char **) start with a single P. // // - Exception: the well known name "char ** argv". // // - Pointers to first elements of serial linked lists of structures have names // ending in "Phead". // // - Line lengths are less than 80 columns. Message parameters to Error() // begin on the same line for easy finding. // // - Error messages might exceed one line when emitted, but no effort is made // to wrap them nicely. #include #include #include // for varargs. #include // for str*(). #include #include // for isspace(), etc. #include #include #define ISSPACE(Char) isspace((int) (Char)) // for convenience with lint. #define ISDIGIT(Char) isdigit((int) (Char)) #define ISUPPER(Char) isupper((int) (Char)) #define PUTS(String) (void) fputs(String, stdout) // for convenience. #define PUTC(Char) (void) putc((int) (Char), stdout) #ifndef DEBUG #define NDEBUG // turn off assertions by default. #endif // Shorthand notation to avoid #ifdefs for single-line conditional statement: // // Warning: This cannot be used around compiler directives, such as // "#include", nor in the case where Code contains a comma other than nested // within parentheses or quotes. #ifndef DEBUG #define DBGCODE(Code) // null. #else #define DBGCODE(Code) Code #endif // **************************************************************************** // MISCELLANEOUS GLOBAL VALUES: #define FUNCTION // null; easy to find functions. #define FALSE 0 #define TRUE 1 #define CHNULL ('\0') #define PCNULL ((char *) NULL) typedef int bool_t; // for clarity with Boolean values. char * gc_usage[] = { "usage: %s filename.htm[l]", "", "Reads restricted (Judy-specific) HTML from filename.htm[l] and emits", "equivalent nroff -man to stdout.", PCNULL, }; char * gc_myname; // how program was invoked. #define OKEXIT 0 #define NOEXIT 0 // values for Error(). #define ERREXIT 1 #define USAGE 2 #define NOERRNO 0 // Prefix for printf formats: #define FILELINE "File \"%s\", line %d: " // Common error string: char * FmtErrLineEnds = FILELINE "Input line ends within an HTML tag; for this " "translator, all tags must be on a single input line"; // Macros for skipping whitespace or non-whitespace; in the latter case, // stopping at end of line or end of tag: #define SKIPSPACE(Pch) { while (ISSPACE(*(Pch))) ++(Pch); } #define SKIPNONSPACE(Pch) { while ((! ISSPACE(*(Pch))) \ && (*(Pch) != CHNULL) \ && (*(Pch) != '>')) ++(Pch); } // Highest line number + 1, and last input line number that caused output: int g_linenumlim; int g_prevlinenum = 0; //
 block equivalents in nroff need some special handling for bold font
// and for continuing a tagged paragraph; these are bit flags:

#define	INPRE_BLOCK  0x1	// came from 
.
#define	INPRE_BOLD   0x2	// came from 
.
#define	INPRE_INDENT 0x4	// under 
below top level. // **************************************************************************** // DOCUMENT NODE TYPES: // // If an HTML tag is not in this list, it's unrecognized and causes a fatal // error. Otherwise the tag type (dn_type) is one of DN_TYPE_*, which are // defined so the code can use them, but they MUST match the order of // initialization of g_dntype[]. // // Note: The default node type is DN_TYPE_TEXT, that is, text outside of any // tag. enum { DN_TYPE_TEXT = 0, DN_TYPE_HTML, DN_TYPE_HEAD, DN_TYPE_TITLE, DN_TYPE_BODY, DN_TYPE_COMM, DN_TYPE_TABLE, DN_TYPE_TR, DN_TYPE_TD, DN_TYPE_DL, DN_TYPE_DT, DN_TYPE_DD, DN_TYPE_A, DN_TYPE_B, DN_TYPE_I, DN_TYPE_PRE, DN_TYPE_P, DN_TYPE_BR }; // Regarding dnt_nest: If an HTML tag type is marked as nesting, that means // it is required not to be a singleton in this context; it must have a closing // tag, and when the tree is built, the intervening text is nested as a child. // Otherwise, intervening text is a sibling; a closing tag is allowed (whether // or not this makes sense), but is not required; however, if present, it must // match. struct docnode_type { char * dnt_tag; // HTML tag. bool_t dnt_savetag; // flag: save HTML tag. bool_t dnt_nest; // flag: see comments above. int dnt_type; // corresponding number. } g_dntype[] = { // Note: HTML is case-insensitive, but for expediency this program is // case-sensitive. Tags must be as shown below. { "", FALSE, FALSE, DN_TYPE_TEXT, }, // special, see above. { "HTML", FALSE, TRUE, DN_TYPE_HTML, }, { "HEAD", FALSE, TRUE, DN_TYPE_HEAD, }, { "TITLE", FALSE, TRUE, DN_TYPE_TITLE, }, { "BODY", FALSE, TRUE, DN_TYPE_BODY, }, { "!--", TRUE, FALSE, DN_TYPE_COMM, }, // comments are singleton tags. { "TABLE", FALSE, TRUE, DN_TYPE_TABLE, }, // limited understanding! { "TR", FALSE, TRUE, DN_TYPE_TR, }, { "TD", TRUE, TRUE, DN_TYPE_TD, }, { "DL", FALSE, TRUE, DN_TYPE_DL, }, { "DT", FALSE, TRUE, DN_TYPE_DT, }, { "DD", FALSE, FALSE, DN_TYPE_DD, }, //
not req in our manuals. { "A", TRUE, TRUE, DN_TYPE_A, }, // either "name" or "href" type. { "B", FALSE, TRUE, DN_TYPE_B, }, { "I", FALSE, TRUE, DN_TYPE_I, }, { "PRE", FALSE, TRUE, DN_TYPE_PRE, }, { "P", FALSE, FALSE, DN_TYPE_P, }, //

not req in our manuals. { "BR", FALSE, FALSE, DN_TYPE_BR, }, //
not req in our manuals. { PCNULL, FALSE, FALSE, 0, }, // end of list. }; // Convenience macros: #define TAG(DN_Type) (g_dntype[DN_Type].dnt_tag) #define SAVETAG(DN_Type) (g_dntype[DN_Type].dnt_savetag) #define NEST(DN_Type) (g_dntype[DN_Type].dnt_nest) // **************************************************************************** // DOCUMENT NODE DATA STRUCTURES: // // Document nodes are saved in a doubly-linked tree of docnodes. Each docnode // points sideways to a doubly-linked list of sibling docnodes for // previous/successive unnested document objects, plus points to its parent and // to the first of a sideways doubly-linked child list of nested objects. All // data lives in malloc'd memory. // // The dn_text field is null for a tag node unless the tag text is worth // saving. The field is non-null for non-tag (document) text. typedef struct docnode * Pdn_t; struct docnode { int dn_type; // node type, index in g_dntype[]. int dn_linenum; // where introduced, for reconstructing. bool_t dn_closed; // flag: closing tag was seen. bool_t dn_noemit; // flag: skip on output, for marking ahead. bool_t dn_bold; // flag: for
, whole section is bold.

	char *	dn_text;	// node text; see above.

	Pdn_t	dn_Pprev;	// previous node in sibling list.
	Pdn_t	dn_Pnext;	// next     node in sibling list.
	Pdn_t	dn_Pparent;	// up-link to parent node, if any.
	Pdn_t	dn_Pchild;	// down-link to first node in child subtree.
};

#define	PDNNULL	((Pdn_t) NULL)

Pdn_t g_Pdnhead = PDNNULL;	// head of docnode tree.


// ****************************************************************************
// FUNCTION SIGNATURES (forward declarations):

int	main(int argc, char ** argv);

void	ReadInputFile( char * Filename, FILE * PFile);
void	CheckNesting(Pdn_t Pdn);
void	EmitNroffHeader(char * Filename, char ** PPageName);
void	EmitNroffBody(Pdn_t Pdn, int DLLevel, int InPRE, char * PageName);

void	ExtractHeader(  Pdn_t Pdn, char ** PFileRev,
		        char ** PPageName, char ** PPageSection,
			char *  PLcLetter, char ** PRevision);
char *	ExtractText(    Pdn_t Pdn);
void	ExtractPageInfo(Pdn_t Pdn, char * Pch,
			char ** PPageName, char ** PPageSection,
			char *  PLcLetter);

int	TagType(char * Tag, bool_t * isclosing, char * Filename, int Linenum);
Pdn_t	AppDocNode( Pdn_t Pdn,	     int linenum);
Pdn_t	NewDocNode( Pdn_t dn_Pparent, int linenum);
char *	SaveDocNode(Pdn_t Pdn, int DN_Type, char * Pch,
		    char * Filename, int Linenum);
bool_t	ParentPre(Pdn_t Pdn, bool_t BoldOnly);

void	MarkNoEmit(   Pdn_t Pdn, bool_t Font);
void	EmitText(     char * Pch, int InPRE, int Linenum);
void	EmitTextPRE(  char * Pch, int InPRE);
void	EmitTextBS(   char * Pch);
bool_t	NoWhiteSpace( char * Pch);
int	CountNewlines(char * Pch);

char *	StrSave(  char * String);
char *	StrSaveN( char * String, ...);
void *	Malloc(	  size_t Size);

void	Usage(void);
void    Error(int Exitvalue, int MyErrno, char * Message, ...);

DBGCODE(void DumpTree(Pdn_t Pdn, int Depth, bool_t Separator);)


// ****************************************************************************
// M A I N

FUNCTION int main(
	int	argc,
	char **	argv)
{
	char *	filename;	// input file.
	FILE *	Pfile;		// open input file.
	char *	pagename;	// such as "Judy1".

	gc_myname = argv[0];
	if (argc != 2) Usage();
	filename = argv[1];

#ifdef DEBUG
// Assert that each dnt_type matches its index in the table, since the code
// depends on this:

	{
	    int dn_type;

	    for (dn_type = 0; TAG(dn_type) != PCNULL; ++dn_type)
		assert(g_dntype[dn_type].dnt_type == dn_type);
	}
#endif


// READ FROM LIST OF FILES OR STDIN; BUILD TREE:

	if ((Pfile = fopen(filename, "r")) == (FILE *) NULL)
	{
	    Error(ERREXIT, errno, "Cannot open file \"%s\" to read it",
		  filename);
	}

	ReadInputFile(filename, Pfile);

	if (ferror(Pfile))
	    Error(ERREXIT, errno, "Cannot read from file \"%s\"", filename);

	DBGCODE(DumpTree(g_Pdnhead, /* Depth = */ 0, /* Separator = */ TRUE);)

	if (g_Pdnhead == PDNNULL)
	{
	    Error(ERREXIT, NOERRNO, "No HTML tags found in file \"%s\"",
		  filename);
	}

	CheckNesting(g_Pdnhead);


// EMIT NROFF VERSION OF TEXT:

	EmitNroffHeader(filename, &pagename);
	EmitNroffBody(g_Pdnhead, /* DLLevel = */ 0, /* InPRE = */ 0, pagename);
	PUTC('\n');			// ensure last line is terminated.

	return(0);

} // main()


// ****************************************************************************
// R E A D   I N P U T   F I L E
//
// Given a filename and stream pointer for reading, read and parse
// Judy-specific HTML and build a structure representing the document, under
// g_Pdnhead.  Set g_linenumlim.
//
// Note:  Ideally this would be a shorter function with helper subroutines, but
// I wrote this fast.  :-)
//
// Note:  This used be called just ReadFile(), but on win_ipf, at least the
// cross-compile environment, this resulted in a duplicate symbol error, as if
// ReadFile() is in a library somewhere.

FUNCTION void ReadInputFile(
	char *	Filename,
	FILE *	PFile)
{
	int	linenum = 0;		// input line number.
	char	line[BUFSIZ];		// read from file.
	char *	Pch;			// place in line.
	char *	Pch2;			// place in line.
	char *	Pchp;			// prior to skipped whitespace.
	char *	tagname;		// for error reporting.
	char	chold;			// old char.
	int	dn_type;		// docnode type.
	bool_t	isclosing;		// is a closing tag.
	Pdn_t	Pdn = PDNNULL;		// current docnode.
	Pdn_t	Pdnprev;		// previous in sibling list.


// READ LINE, TRIM AT ANY NEWLINE, AND SKIP LEADING WHITESPACE:

	while (fgets(line, BUFSIZ, PFile) != PCNULL)
	{
	    line[strcspn(line, "\n")] = CHNULL;
	    ++linenum;

	    Pch = Pchp = line;
	    SKIPSPACE(Pch);		// skip any leading whitespace.

	    if (! ParentPre(Pdn, /* BoldOnly = */ FALSE))
		Pchp = Pch;		// skip for storing, too.


// HANDLE EMPTY LINE:
//
// If within an "already open" DN_TYPE_TEXT, append a newline to the existing
// text in case it turns out to be significant later (mainly in a 
// section).

	    if (*Pch == CHNULL)
	    {
		if ((Pdn->dn_type) == DN_TYPE_TEXT)
		{
		    assert((Pdn->dn_text) != PCNULL);
		    (Pdn->dn_text) = StrSaveN(Pdn->dn_text, "\n", PCNULL);
		}
		continue;
	    }


// HANDLE DATA LINE:
//
// Look for a "<" that starts an HTML tag.

	    while (*Pch != CHNULL)		// more on line.
	    {
		Pch2 = strchr(Pch, '<');	// look for next tag start.


// SAVE DOCUMENT TEXT:
//
// Save any text preceding a tag (or through end of line) in a document text
// (DN_TYPE_TEXT) docnode; either the existing node if there is one, else a new
// node as a sibling or child of the previous, as appropriate.
//
// This builds one docnode for any inter-tag text, whether it's a portion of
// one line, or many lines long.  In some ways that's simplest and most
// efficient, and in other ways it's weird.
//
// Note:  Use Pchp here, not Pch, so as not to ignore leading whitespace on
// 
 lines.

		if (! ((Pch2 == PCNULL) ? strlen(Pchp) : Pch2 - Pchp))
		{
		    assert((Pch == Pch2) || (Pch2 == PCNULL));
		}
		else
		{
		    if (g_Pdnhead == PDNNULL)	// no current tree.
		    {
			Error(ERREXIT, NOERRNO, FILELINE "For this "
			      "translator, the HTML file must start with an "
			      "HTML tag in \"<>\", and no other text",
			      Filename, linenum);
		    }

// Current docnode is not DN_TYPE_TEXT, so append a new docnode child or
// sibling, as appropriate, to the tree:

		    assert(Pdn != PDNNULL);	// should already be assigned.

		    if ((Pdn->dn_type) != DN_TYPE_TEXT)
		    {
			Pdn = AppDocNode(Pdn, linenum);
			(Pdn->dn_type) = DN_TYPE_TEXT;
		    }

// Save current text in current docnode, appending to any existing text:
//
// Note:  To avoid messing up alignments in 
 text, use Pchp, not Pch,
// which can skip whitespace.

		    if (Pch2 != PCNULL) *Pch2 = CHNULL;	 // terminate briefly.

		    if ((Pdn->dn_text) == PCNULL)	// no existing text.
			(Pdn->dn_text) = StrSave(Pchp);
		    else
			(Pdn->dn_text) = StrSaveN(Pdn->dn_text, Pchp, PCNULL);

		    assert((Pdn->dn_text) != PCNULL);

// If there's still a tag on the line, unterminate Pch2; otherwise append a
// newline to the saved text in case more document text follows:

		    if (Pch2 != PCNULL)
			*Pch2 = '<';			// unterminate.
		    else
			(Pdn->dn_text) = StrSaveN(Pdn->dn_text, "\n", PCNULL);

		} // if text preceding tag.


// ANALYZE HTML TAG (if any):

		if (Pch2 == PCNULL) break;	// no tag on line; line is done.

		Pch = Pch2 + 1;		// skip "<".
		SKIPSPACE(Pch);		// skip any whitespace.

		if (*Pch == CHNULL)
		    Error(ERREXIT, NOERRNO, FmtErrLineEnds, Filename, linenum);

		Pch2 = Pch;
		SKIPNONSPACE(Pch2);  // find whitespace or end of line or tag.

		if (*Pch2 == CHNULL)
		    Error(ERREXIT, NOERRNO, FmtErrLineEnds, Filename, linenum);

		chold = *Pch2;
		*Pch2 = CHNULL;		// temporarily terminate.
		dn_type = TagType(Pch, &isclosing, Filename, linenum);
		*Pch2 = chold;


// HANDLE CLOSING TAG:
//
// First ensure the tag checks out OK.

		if (isclosing)
		{
		    if (*Pch2 != '>')
		    {
			Error(ERREXIT, NOERRNO, FILELINE "Closing HTML tag "
			      "\"%s\" must be followed immediately by \">\"; "
			      "this translator does not even allow whitespace",
			      Filename, linenum, Pch);
		    }

		    if (g_Pdnhead == PDNNULL)
		    {
			Error(ERREXIT, NOERRNO, FILELINE "Closing HTML tag "
			      "\"%s\" found before any opening tag in the file",
			      Filename, linenum, Pch);
		    }

		    tagname = Pch;		// for error reporting.
		    Pch = Pchp = Pch2 + 1;	// skip ">" in line.

// Check if the closing tag is an optional closing for the last unclosed,
// non-DN_TYPE_TEXT docnode in the current sibling list, if any:

		    for (Pdnprev  = Pdn;
			 Pdnprev != PDNNULL;
			 Pdnprev  = Pdnprev->dn_Pprev)
		    {
			if (((Pdnprev->dn_type) == DN_TYPE_TEXT)
			 || (Pdnprev->dn_closed))
			{
			    continue;		// skip text or closed tag.
			}

			if ((Pdnprev->dn_type) == dn_type)
			{
			    (Pdnprev->dn_closed) = TRUE;  // optional closing.
			    break;
			}
		    }

		    if (Pdnprev != PDNNULL) continue;	// matched closing.

// Otherwise check that the closing tag is the (required) closing tag for the
// (required) parent node (which must not have been closed yet):

		    if ((Pdn->dn_Pparent) == PDNNULL)
		    {
			Error(ERREXIT, NOERRNO, FILELINE "Closing HTML tag "
			      "\"%s\" does not match an opening tag",
			      Filename, linenum, tagname);
		    }

		    assert(! (Pdn->dn_Pparent->dn_closed));

		    if ((Pdn->dn_Pparent->dn_type) != dn_type)
		    {
			Error(ERREXIT, NOERRNO, FILELINE "Parent HTML tag "
			      "\"%s\" found on line %d requires a closing tag, "
			      "but \"%s\" does not match it; check for out-of-"
			      "order HTML tags", Filename, linenum,
			      TAG(Pdn->dn_Pparent->dn_type),
			      Pdn->dn_Pparent->dn_linenum, tagname);
		    }

// Go uplevel in the tree to the parent node:

		    Pdn = Pdn->dn_Pparent;
		    (Pdn->dn_closed) = TRUE;
		    continue;

		} // closing tag.


// NEW HTML TAG:  ADD SIBLING OR CHILD NODE TO TREE:
//
// Save appropriate information about the tag and move beyond its closing point
// in the input line.

		Pdn = AppDocNode(Pdn, linenum);
		Pch = Pch2;
		assert( Pch != PCNULL);
		assert(*Pch != CHNULL);
		Pch = Pchp = SaveDocNode(Pdn, dn_type, Pch, Filename, linenum);

	    } // while more on input line.
	} // while more in input file.

	g_linenumlim = linenum + 1;

} // ReadInputFile()


// ****************************************************************************
// C H E C K   N E S T I N G
//
// Given a docnode, recursively check that all nested HTML tags were closed.
// If not, error out.

FUNCTION void CheckNesting(
	Pdn_t Pdn)	// current docnode.
{
	if (NEST(Pdn->dn_type) && (! (Pdn->dn_closed)))
	{
	    Error(ERREXIT, NOERRNO, "No closing tag found for HTML tag \"%s\" "
		  "from input line %d", TAG(Pdn->dn_type), Pdn->dn_linenum);
	}

	if ((Pdn->dn_Pchild) != PDNNULL) CheckNesting(Pdn->dn_Pchild);
	if ((Pdn->dn_Pnext)  != PDNNULL) CheckNesting(Pdn->dn_Pnext);

} // CheckNesting()




// ****************************************************************************
// E M I T   N R O F F   H E A D E R
//
// Given the input filename, a pointer to a page name string to return, and the
// docnode tree under g_Pdnhead, extract header info and emit nroff header
// lines.

FUNCTION void EmitNroffHeader(
	char *	Filename,		// input file.
	char **	PPageName)		// such as "Judy1", to return.
{
	char *	filerev = PCNULL;	// from first comment in input.
	char *	pagesection;		// such as "3X".
	char	lcletter;		// manual tab section, such as "j".
	char *	revision;		// from centered table datum.
	time_t	currtime;		// for ctime().

// Extract "weird" header values:
//
// These must be found in the docnodes tree and prepared for emitting nroff.

	ExtractHeader(g_Pdnhead, &filerev,
		      PPageName, &pagesection, &lcletter, &revision);

	if (filerev == PCNULL)
	{
	    Error(ERREXIT, NOERRNO, "HTML file lacks comment lines; it must "
		  "contain at least one comment line, and the first one must "
		  "contain revision information");
	}

// Emit file header; note, ctime() output already contains a newline:

	(void) time(&currtime);
	(void) printf(".\\\" Auto-translated to nroff -man from %s by %s at %s",
		      Filename, gc_myname, ctime(&currtime));

	(void) printf(".\\\" %s\n",  filerev);
	(void) printf(".TA %c\n",    lcletter);
	(void) printf(".TH %s %s\n", *PPageName, pagesection);
	(void) puts(  ".ds )H Hewlett-Packard Company");
	(void) printf(".ds ]W %s\n", revision);

} // EmitNroffHeader()


// ****************************************************************************
// E M I T   N R O F F   B O D Y
//
// Given a current node in the docnodes tree, the current 
level, a flag // whether below a
 node, the manual entry page name, and in
// g_prevlinenum, the previous input line number that resulted in output,
// recursively emit nroff body text.  Translate the HTML docnodes as described
// in the comments prior to EmitNroffHeader(), and also translate certain HTML
// escaped chars back to literal form.  Hope the results are legal nroff
// without spurious unintended nroff commands embedded.
//
// Note:  This function recurses two ways; first, to the child subtree, and
// second, to the next sibling at the current level.

FUNCTION void EmitNroffBody(
	Pdn_t	Pdn,		// current top of subtree.
	int	DLLevel,	// 
level, top = 0. int InPRE, // bit flags for
 handling.
	char *	PageName)	// such as "Judy1".
{
	int	DLcount = 0;	   // set to 1 if hit 
here. char * suffix = PCNULL; // to print after children, before siblings. // When about to emit text, if the previous output came from a lower input line // number, start with a newline; otherwise do not, and let the text // concatenate: // // Use CHECKPREV except when the text to be emitted is forced to a new line. #ifdef CPPRINT // for special debugging: #define CHECKPREVPRINT printf("\ncp %d %d\n", g_prevlinenum, Pdn->dn_linenum) #else #define CHECKPREVPRINT // null #endif #define CHECKPREV \ CHECKPREVPRINT; \ { if (g_prevlinenum && (g_prevlinenum < (Pdn->dn_linenum))) PUTC('\n');} // To support CHECKPREV, call SETPREV() after emitting text that might need a // line break to a new line, or SETPREVNONL to ensure NO newline, that is, the // next text concatenates on the same line: // // Note: For a correct line number, SETPREV() must account for any newlines in // the text just emitted. #define SETPREV(Text) g_prevlinenum = (Pdn->dn_linenum) + CountNewlines(Text) #define SETPREVNONL g_prevlinenum = g_linenumlim // no newline. // Check if under a lower-level
, for continuing an indented paragraph: #define UNDER_DL ((DLLevel > 1) \ && ((Pdn->dn_Pparent) != PDNNULL) \ && ((Pdn->dn_Pparent->dn_type) == DN_TYPE_DL)) // SWITCH ON DOCNODE TYPE: if (Pdn->dn_noemit) // upstream node said to skip this one. goto NextNode; switch (Pdn->dn_type) { // DOCUMENT TEXT: // // Just emit it with HTML escaped chars modified, with backslashes doubled, // with no trailing newline, and if not within
 text, with any leading
// whitespace deleted, so that, for example, something like "\fI text\fP" does
// not result.

	case DN_TYPE_TEXT:

	    assert((Pdn->dn_text) != PCNULL);
	    CHECKPREV;
	    EmitText(Pdn->dn_text, InPRE, Pdn->dn_linenum);
	    SETPREV(Pdn->dn_text);
	    break;


// IGNORE THESE TYPES:
//
// See EmitNroffHeader() for nroff equivalents already emitted in some cases.
// In some cases, mark all child nodes no-emit to ignore them.

	case DN_TYPE_HTML:
	case DN_TYPE_HEAD:
	case DN_TYPE_BODY:
	case DN_TYPE_COMM:	break;

	case DN_TYPE_TITLE:
	case DN_TYPE_TABLE:
	case DN_TYPE_TR:
	case DN_TYPE_TD:

	    MarkNoEmit(Pdn->dn_Pchild, /* Font = */ FALSE);
	    break;


// DESCRIPTIVE LIST:
//
// At the top level these represent manual entry sections, and any bold markers
// around the text are ignored.  Below the top level these translate to tagged
// paragraphs.  Here, just note the increment and continue the walk.

	case DN_TYPE_DL:

	    DLcount = 1;
	    break;


// DESCRIPTIVE LIST TAG:

	case DN_TYPE_DT:

	    assert(NEST(DN_TYPE_DT));		// tag text must be child.

	    if ((Pdn->dn_Pchild) == PDNNULL)	// no child exists.
	    {
		Error(ERREXIT, NOERRNO, "HTML tag \"%s\" found at input line "
		      "%d lacks text, which is required by this translator",
		      TAG(DN_TYPE_DT), Pdn->dn_linenum);
	    }

// Further handling depends on DLLevel as explained above:

	    if (DLLevel <= 1)		// major manual section.
	    {
		PUTS("\n.SH ");

		if ((Pdn->dn_Pchild->dn_type) == DN_TYPE_B)
		    (Pdn->dn_Pchild->dn_noemit) = TRUE;	 // skip ....
	    }

// If a 
immediately follows a previous
, use .PD 0 for the successive // .TP to join lines: else { if (((Pdn->dn_Pprev) != PDNNULL) && ((Pdn->dn_Pprev->dn_type) == DN_TYPE_DT)) { PUTS("\n.PD 0\n"); suffix = "\n.PD\n"; } PUTS("\n.TP 15\n.C "); } SETPREVNONL; break; // DESCRIPTIVE LIST DATUM: // // Just proceed to dump the embedded text. case DN_TYPE_DD: break; // ANCHOR: // // Ignore inbound ("name") anchors and process outbound ("href") anchor labels // into appropriately highlighted text. case DN_TYPE_A: { size_t len; // of substring. Pdn_t Pdn2; // child node. char * Pch; // place in text. assert((Pdn->dn_text) != PCNULL); if (strstr(Pdn->dn_text, "name=") != PCNULL) break; if (strstr(Pdn->dn_text, "href=") == PCNULL) { Error(NOEXIT, NOERRNO, "Unrecognized HTML anchor type \"%s\" " "at input line %d ignored; only \"name=\" and \"href=\" " "are allowed by this translator", Pdn->dn_text, Pdn->dn_linenum); break; } // Check for nested text (anchor label): // // TBD: The error message lies a little. If the text is something like, // "foobar", it passes this test; and later, all font tags in the anchor // label are marked no-emit; and any other embedded tags, who knows what // happens? if (((Pdn2 = Pdn->dn_Pchild)->dn_type) != DN_TYPE_TEXT) { Error(ERREXIT, NOERRNO, "HTML \"href\" anchor at input line " "%d lacks a directly nested anchor label, with no " "further nested tags; this translator cannot support " "nested tags in anchor labels", Pdn->dn_linenum); } assert((Pdn2->dn_text) != PCNULL); // If the anchor is within a
, do nothing special with fonts, as
// explained earlier:

	    if (ParentPre(Pdn, /* BoldOnly = */ TRUE)) break;

// Since anchor label text font will be forced in a moment, ignore any nested
// font directives so they don't mess up nroff:

	    MarkNoEmit(Pdn->dn_Pchild, /* Font = */ TRUE);

// See if anchor label appears to be a reference to the current page, to some
// other page, or else just make it italicized text:
//
// TBD:  This is pretty shaky, hope it's close enough.

	    len = strlen(PageName);

	    if (strncmp(Pdn2->dn_text, PageName, len) == 0)  // self-reference.
	    {
		CHECKPREV;
		PUTS("\\fB");			// bold font.
		SETPREVNONL;
		suffix = "\\fP";		// revert to previous font.
		break;
	    }

// Contains '(' and no whitespace => appears to reference some other page:
//
// Emit revised, tagged anchor label text immediately.

	    if (((Pch = strchr(Pdn2->dn_text, '(')) != PCNULL)
	     && NoWhiteSpace(Pdn2->dn_text))
	    {
		CHECKPREV;
		PUTS("\\fI");			// italic font.
		*Pch = CHNULL;			// terminate briefly.
		PUTS(Pdn2->dn_text);
		*Pch = '(';
		PUTS("\\fP");			// revert to previous font.
		PUTS(Pch);
		SETPREV(Pdn2->dn_text);

		(Pdn2->dn_noemit) = TRUE;	// skip later.
		break;
	    }

// Just make the anchor label italicized text:

	    CHECKPREV;
	    PUTS("\\fI");			// italic font.
	    SETPREVNONL;
	    suffix = "\\fP";			// revert to previous font.
	    break;

	} // case DN_TYPE_A


// BOLD TEXT:
//
// If the first child is 
, use a "hard" font change; otherwise an in-line
// change.
//
// Note:  For 
, this node is already marked dn_noemit and not seen here. // // Note: For
, nroff seems to reset font upon .PP, so mark the bold
// for later emission.

	case DN_TYPE_B:

	    if (((Pdn->dn_Pchild) != PDNNULL)
	     && ((Pdn->dn_Pchild->dn_type) == DN_TYPE_PRE))
	    {
		(Pdn->dn_Pchild->dn_bold) = TRUE;	// see above.
		break;
	    }

	    CHECKPREV;
	    PUTS("\\fB");			// bold font.
	    SETPREVNONL;
	    suffix = "\\fP";			// revert to previous font.
	    break;


// ITALIC TEXT:

	case DN_TYPE_I:

	    CHECKPREV;
	    PUTS("\\fI");			// italic font.
	    SETPREVNONL;
	    suffix = "\\fP";			// revert to previous font.
	    break;


// PREFORMATTED TEXT:
//
// Emit prefix/suffix directives based on example in strchr(3C).

	case DN_TYPE_PRE:

	    PUTS(UNDER_DL ? "\n.IP\n.nf\n.ps +1\n" : "\n.PP\n.nf\n.ps +1\n");
	    if (Pdn->dn_bold) PUTS(".ft B\n");	// deferred bold.
	    SETPREVNONL;
	    suffix = ((Pdn->dn_bold) ? "\n.ft P\n.ps\n.fi\n" : "\n.ps\n.fi\n");

	    // set for all children:
	    InPRE = INPRE_BLOCK
		  | ((Pdn->dn_bold) ? INPRE_BOLD   : 0)
		  | (UNDER_DL ?	      INPRE_INDENT : 0);
	    break;


// PARAGRAPH BREAK:
//
// If the parent is a 
below the top level, use .IP to continue a .TP // (tagged paragraph); otherwise emit a standard .PP. case DN_TYPE_P: PUTS(UNDER_DL ? "\n.IP\n" : "\n.PP\n"); SETPREVNONL; break; // LINE BREAK: case DN_TYPE_BR: PUTS("\n.br\n"); SETPREVNONL; break; // UNRECOGNIZED DOCNODE TYPE: default: Error(ERREXIT, NOERRNO, "Internal error: Unexpected docnode type " "%d in docnodes tree", Pdn->dn_type); } // end switch on dn_type // VISIT CHILD AND SIBLING DOCNODES: // // If this was a
here, pass an incremented value to child nodes, but not // to sibling nodes. NextNode: if ((Pdn->dn_Pchild) != PDNNULL) EmitNroffBody(Pdn->dn_Pchild, DLLevel + DLcount, InPRE, PageName); if (suffix != PCNULL) PUTS(suffix); if ((Pdn->dn_Pnext) != PDNNULL) EmitNroffBody(Pdn->dn_Pnext, DLLevel, InPRE, PageName); } // EmitNroffBody() // **************************************************************************** // E X T R A C T H E A D E R // // Given a current docnode and pointers to values to return, walk the entire // docnode tree once, recursively, in-order (parent then child then sibling) to // extract nroff header information. Find the first comment line, insist it // contain "@\(#)", and put this in *PFileRev. Also find exactly one // DN_TYPE_TABLE, containing exactly one DN_TYPE_TR, containing one DN_TYPE_TD // containing "align=\"left\"" and one DN_TYPE_TD containing // "align=\"center\"", and extract from these the nroff .TH pagename, // pagesection, and lcletter, and nroff ]W variable revision string, // respectively. Error out if anything goes wrong. // // Note: Some of the returned strings are in separate malloc'd memory and // others are not; treat them as read-only. FUNCTION void ExtractHeader( Pdn_t Pdn, // current docnode. char ** PFileRev, // from first comment in input. char ** PPageName, // such as "Judy1". char ** PPageSection, // such as "3X". char * PLcLetter, // manual tab section, such as "j". char ** PRevision) // from centered table datum. { static bool_t found_filerev = FALSE; static bool_t found_table = FALSE; static bool_t found_tr = FALSE; static bool_t found_tdleft = FALSE; static bool_t found_tdcenter = FALSE; char * text; // from text node. // Note: The following are used for both 0 and >= 2 instances, so they don't // include a line number because there is none for the 0 case: #define ERR_TABLE "This translator expects exactly one HTML table " \ "(\"TABLE\" tag) in the input file" #define ERR_TR "This translator expects exactly one HTML table row " \ "(\"TR\" tag) in the input file" #define ERR_TDLEFT "This translator expects exactly one HTML table row " \ "datum (\"TD\" tag) in the input containing " \ "'align=\"left\"'" #define ERR_TDCENTER "This translator expects exactly one HTML table row " \ "datum (\"TD\" tag) in the input containing " \ "'align=\"center\"'" // CHECK CURRENT DOCNODE TYPE: switch (Pdn->dn_type) { case DN_TYPE_COMM: if (found_filerev) break; // already done. found_filerev = TRUE; // Hide the whatstring markers here from what(1) itself: if (strstr(Pdn->dn_text, "@" "(#)") == PCNULL) { Error(ERREXIT, NOERRNO, "First HTML comment line in input, " "found at line %d, must contain a whatstring, marked by " "\"@" "(#)\"", Pdn->dn_linenum); } *PFileRev = Pdn->dn_text; break; case DN_TYPE_TABLE: if (found_table) Error(ERREXIT, NOERRNO, ERR_TABLE); found_table = TRUE; if (((Pdn->dn_Pchild) == PDNNULL) || ((Pdn->dn_Pchild->dn_type) != DN_TYPE_TR)) { Error(ERREXIT, NOERRNO, "The HTML \"%s\" tag at line %d must " "be followed by a \"%s\" tag, but it is not", TAG(DN_TYPE_TABLE), Pdn->dn_linenum, TAG(DN_TYPE_TR)); } break; case DN_TYPE_TR: if (found_tr) Error(ERREXIT, NOERRNO, ERR_TR); found_tr = TRUE; if (((Pdn->dn_Pchild) == PDNNULL) || ((Pdn->dn_Pchild->dn_type) != DN_TYPE_TD)) { Error(ERREXIT, NOERRNO, "The HTML \"%s\" tag at line %d must " "be followed by a \"%s\" tag, but it is not", TAG(DN_TYPE_TR), Pdn->dn_linenum, TAG(DN_TYPE_TD)); } break; case DN_TYPE_TD: if (strstr(Pdn->dn_text, "align=\"left\"") != PCNULL) { if (found_tdleft) Error(ERREXIT, NOERRNO, ERR_TDLEFT); found_tdleft = TRUE; text = StrSave(ExtractText(Pdn)); ExtractPageInfo(Pdn, text, PPageName, PPageSection, PLcLetter); } else if (strstr(Pdn->dn_text, "align=\"center\"") != PCNULL) { if (found_tdcenter) Error(ERREXIT, NOERRNO, ERR_TDCENTER); found_tdcenter = TRUE; *PRevision = ExtractText(Pdn); } // else ignore line. } // switch on dn_type // VISIT CHILD AND SIBLING DOCNODES: // // Note: Do this even though it seems redundant, to ensure no duplicates. if ((Pdn->dn_Pchild) != PDNNULL) { ExtractHeader(Pdn->dn_Pchild, PFileRev, PPageName, PPageSection, PLcLetter, PRevision); } if ((Pdn->dn_Pnext) != PDNNULL) { ExtractHeader(Pdn->dn_Pnext, PFileRev, PPageName, PPageSection, PLcLetter, PRevision); } // AT TOP OF TREE, CHECK FOR SUCCESS: // // Note: If you read the fine print, it's clear the ERR_TR here is impossible // to hit. if (Pdn != g_Pdnhead) return; if (! found_table) Error(ERREXIT, NOERRNO, ERR_TABLE); if (! found_tr) Error(ERREXIT, NOERRNO, ERR_TR); if (! found_tdleft) Error(ERREXIT, NOERRNO, ERR_TDLEFT); if (! found_tdcenter) Error(ERREXIT, NOERRNO, ERR_TDCENTER); } // ExtractHeader() // **************************************************************************** // E X T R A C T T E X T // // Given a non-null docnode, return the non-null dn_text field from its first // child (directly, not a copy). Error out if anything goes wrong. FUNCTION char * ExtractText( Pdn_t Pdn) // parent node. { assert(Pdn != PDNNULL); #define ERR_NULLTEXT "Node for HTML tag \"%s\", found at line %d, lacks a " \ "child \"text\" node containing a non-null text string " \ "as required" // TBD: This does not report a case of a text string containing only // whitespace, but some callers do that themselves: if (((Pdn->dn_Pchild) == PDNNULL) || ((Pdn->dn_Pchild->dn_type) != DN_TYPE_TEXT) || ((Pdn->dn_Pchild->dn_text) == PCNULL) || ((Pdn->dn_Pchild->dn_text[0]) == CHNULL)) { Error(ERREXIT, NOERRNO, ERR_NULLTEXT, TAG(Pdn->dn_type), Pdn->dn_linenum); } return(Pdn->dn_Pchild->dn_text); } // ExtractText() // **************************************************************************** // E X T R A C T P A G E I N F O // // Given a docnode, a non-null, modifiable string alleged to contain an nroff // -man header, such as "Judy(3X)", and pointers to return values, break out // and return the pieces. Error out if anything goes wrong. // // Note: Returned strings are in separate malloc'd memory. FUNCTION void ExtractPageInfo( Pdn_t Pdn, // for error reporting. char * Pch, // string to decipher. char ** PPageName, // such as "Judy1". char ** PPageSection, // such as "3X". char * PLcLetter) // manual tab section, such as "j". { char * Pch2; // second place in string. char * Pch3 = PCNULL; // third place in string; init for gcc -Wall. // Find start of string: assert(Pch != PCNULL); SKIPSPACE(Pch); if (*Pch == CHNULL) // nothing but whitepace. { Error(ERREXIT, NOERRNO, ERR_NULLTEXT, TAG(Pdn->dn_type), Pdn->dn_linenum); } // Find "(": if ((Pch2 = strchr(Pch, '(')) == PCNULL) { Error(ERREXIT, NOERRNO, "Node for HTML tag \"%s\", found at " "line %d, has a child \"text\" node whose text lacks a '('", TAG(Pdn->dn_type), Pdn->dn_linenum); } if (Pch == Pch2) { Error(ERREXIT, NOERRNO, "Node for HTML tag \"%s\", found at " "line %d, has a child \"text\" node whose text starts with " "'(' and lacks a leading pagename", TAG(Pdn->dn_type), Pdn->dn_linenum); } // Validate the "()" suffix, such as "(1)" or "(3X)": if ((! ISDIGIT(Pch2[1])) // not "(". || ((Pch3 = strchr(Pch2, ')')) == PCNULL) // no ")". || (Pch2 + 3 < Pch3) // too far away. || ((Pch2 + 3 == Pch3) // . && (! ISUPPER(Pch2[2])))) // not . { Error(ERREXIT, NOERRNO, "Node for HTML tag \"%s\", found at " "line %d, has a child \"text\" node whose text lacks a " "standard UNIX manual entry suffix in the form " "\"([])\", such as \"(1)\" or \"(3X)\"", TAG(Pdn->dn_type), Pdn->dn_linenum); } // Break out parts: *Pch2 = *Pch3 = CHNULL; // terminate at '(' and ')'. *PPageName = StrSave(Pch); *PPageSection = StrSave(Pch2 + 1); // Look for *PLcLetter: if (! ISUPPER(**PPageName)) { Error(ERREXIT, NOERRNO, "Node for HTML tag \"%s\", found at " "line %d, has a child \"text\" node whose text does not " "start with an uppercase letter", TAG(Pdn->dn_type), Pdn->dn_linenum); } *PLcLetter = tolower((int) (**PPageName)); } // ExtractPageInfo() // **************************************************************************** // T A G T Y P E // // Given a non-null string that should be an HTML tag type, a pointer to a // bool_t to return whether this is a closing tag, and a filename and line // number for error reporting, look up the tag type in g_dntype[] and return // its index. Error out if not found. // // As a special case, if presented with "!---" with any number of dashes, look // for "!--". FUNCTION int TagType( char * Tag, // to look up. bool_t * Pisclosing, // return flag: is a closing tag. char * Filename, // for error reporting. int Linenum) // for error reporting. { int dn_type; // to return. char * mytag; // local variation. assert( Tag != PCNULL); assert(*Tag != CHNULL); // Check for closing tag (yes, even for types that don't really allow it): if ((*Pisclosing = (*Tag == '/'))) // (()) for gcc. { ++Tag; SKIPSPACE(Tag); if (*Tag == CHNULL) Error(ERREXIT, NOERRNO, FmtErrLineEnds, Filename, Linenum); } // Translate comment tag to known type: mytag = (strncmp(Tag, "!--", 3) ? Tag : "!--"); // see above. // Look up tag: // // Note: Main code already asserted dnt_type == dn_type for each entry. for (dn_type = 0; TAG(dn_type) != PCNULL; ++dn_type) if (strcmp(mytag, TAG(dn_type)) == 0) return(dn_type); Error(ERREXIT, NOERRNO, FILELINE "Unrecognized HTML tag \"%s\"; " "see program source file for recognized types; this is a " "limited, special-purpose translator", Filename, Linenum, Tag); /*NOTREACHED*/ return(0); // make some compilers happy. } // TagType() // **************************************************************************** // A P P D O C N O D E // // Given a current docnode tree node, the input file line number, and // g_Pdnhead, create a new docnode, append it to the tree in the right place, // and return a pointer to it, with g_Pdnhead updated if required: // // * If empty tree, insert new as head of tree. // // * Otherwise if current node nests and is not closed, insert as its child. // // * Otherwise insert as a sibling of the current node. // // Note: Most HTML tags are non-singletons and hence nest, but if the nesting // doesn't make sense, too bad, it's not detected, at least not here. FUNCTION Pdn_t AppDocNode( Pdn_t Pdn, // current docnode tree node. int Linenum) // in input file. { // No current tree, insert first node: if (g_Pdnhead == PDNNULL) return(g_Pdnhead = NewDocNode(PDNNULL, Linenum)); // Insert new node as child, with parent set to current node: if (NEST(Pdn->dn_type) && (! (Pdn->dn_closed))) return((Pdn->dn_Pchild) = NewDocNode(Pdn, Linenum)); // Insert new node as sibling with same parent: (Pdn->dn_Pnext) = NewDocNode(Pdn->dn_Pparent, Linenum); (Pdn->dn_Pnext->dn_Pprev) = Pdn; return(Pdn->dn_Pnext); } // AppDocNode() // **************************************************************************** // N E W D O C N O D E // // Malloc() a new docnode and initialize its fields except dn_type, with error // checking. Set its parent to the given value. FUNCTION Pdn_t NewDocNode( Pdn_t dn_Pparent, // parent to record. int Linenum) // in input file. { Pdn_t Pdn = (Pdn_t) Malloc(sizeof(struct docnode)); (Pdn -> dn_linenum) = Linenum; (Pdn -> dn_closed) = FALSE; (Pdn -> dn_noemit) = FALSE; (Pdn -> dn_bold) = FALSE; (Pdn -> dn_text) = PCNULL; (Pdn -> dn_Pprev) = PDNNULL; (Pdn -> dn_Pnext) = PDNNULL; (Pdn -> dn_Pparent) = dn_Pparent; (Pdn -> dn_Pchild) = PDNNULL; return(Pdn); } // NewDocNode() // **************************************************************************** // S A V E D O C N O D E // // Given a pointer to a docnode, the docnode type, a string for the current // location (past tag name at whitespace or ">"), and a filename and line // number for error reporting, save the docnode type in the node, and also save // the tag text if appropriate; then find the end of the tag (">") and return // past that location (possibly before more whitespace). Error out in case of // syntax error. FUNCTION char * SaveDocNode( Pdn_t Pdn, // docnode to modify. int DN_Type, // new type to save. char * Pch, // current location past tagname. char * Filename, // for error reporting. int Linenum) // for error reporting. { char * Pch2 = PCNULL; // second location; init for gcc -Wall. assert( Pch != PCNULL); assert(*Pch != CHNULL); // Save type: (Pdn->dn_type) = DN_Type; // Pass whitespace and then find the end of the tag: SKIPSPACE(Pch); if ((*Pch == CHNULL) || ((Pch2 = strchr(Pch, '>')) == PCNULL)) Error(ERREXIT, NOERRNO, FmtErrLineEnds, Filename, Linenum); // Optionally save tag text: if (SAVETAG(DN_Type)) { *Pch2 = CHNULL; // temporarily terminate. (Pdn->dn_text) = StrSave(Pch); *Pch2 = '>'; } return(Pch2 + 1); } // SaveDocNode() // **************************************************************************** // P A R E N T P R E // // Given a docnode (can be null) and a flag whether only bold
 is of
// interest, return TRUE if any of its parents is a 
 (marked for bold
// text), that is, DN_TYPE_PRE (with dn_bold set); otherwise return FALSE.

FUNCTION bool_t ParentPre(
	Pdn_t  Pdn,		// starting node.
	bool_t BoldOnly)	// flag: only care about bold 
.
{
	if (Pdn == PDNNULL) return (FALSE);	// no parent.

	for (Pdn = Pdn->dn_Pparent; Pdn != PDNNULL; Pdn = Pdn->dn_Pparent)
	{
	    if (((Pdn->dn_type) == DN_TYPE_PRE)
	     && ((! BoldOnly) || (Pdn->dn_bold)))
	    {
		return(TRUE);
	    }
	}

	return(FALSE);

} // ParentPre()


// ****************************************************************************
// M A R K   N O   E M I T
//
// Given a docnode (can be null), and a flag, recursively mark the node and all
// children and siblings as do-not-emit, unless the flag is set, only mark font
// docnodes.

FUNCTION void MarkNoEmit(
	Pdn_t  Pdn,	// top node to mark.
	bool_t Font)	// flag: only mark font docnodes.
{
	if (Pdn == PDNNULL) return;

	if ((! Font)
	 || ((Pdn->dn_type) == DN_TYPE_B)
	 || ((Pdn->dn_type) == DN_TYPE_I))
	{
	    (Pdn->dn_noemit) = TRUE;
	}

	if ((Pdn->dn_Pchild) != PDNNULL) MarkNoEmit(Pdn->dn_Pchild, Font);
	if ((Pdn->dn_Pnext)  != PDNNULL) MarkNoEmit(Pdn->dn_Pnext,  Font);

} // MarkNoEmit()


// ****************************************************************************
// E M I T   T E X T
//
// Given a text string, a bitflag for 
 status, and an input line number
// for error reporting, copy the text string to stdout with no added newlines,
// but translating selected HTML escape codes to simple characters, doubling
// any backslashes, and if InPRE, inserting .IP (if INPRE_INDENT) or .PP at
// blank lines (between successive newlines), and if INPRE_BOLD, putting back
// bold font since .IP/.PP seems to reset the font.  Warn about unrecognized
// escape codes.

struct et_list {
	char * et_escape;	// expected text.
	size_t et_len;		// of expected text.
	char   et_emit;		// equivalent char.
} et_list[] = {
	{ "amp;", 4, '&', },
	{ "gt;",  3, '>', },
	{ "lt;",  3, '<', },
	{ PCNULL, 0, ' ', },	// end of list.
};

FUNCTION void EmitText(
	char * Pch,		// text to emit.
	int    InPRE,		// bitflag for 
 status.
	int    Linenum)		// for error reporting.
{
	char * Pch2;		// place in text.
	struct et_list * Pet;	// place in et_list[].

	while ((Pch2 = strchr(Pch, '&')) != PCNULL)	// another escape code.
	{
	    *Pch2 = CHNULL;		// briefly terminate.
	    EmitTextPRE(Pch, InPRE);	// emit preceding part.
	    *Pch2 = '&';
	    Pch = Pch2 + 1;			// past '&'.

	    for (Pet = et_list; Pet->et_escape != PCNULL; ++Pet)
	    {
		if (strncmp(Pch, Pet->et_escape, Pet->et_len) == 0)
		{
		    PUTC(Pet->et_emit);		// translate.
		    Pch += Pet->et_len;		// skip escapecode.
		    break;
		}
	    }

	    if (Pet->et_escape == PCNULL)	// no match found.
	    {
		Error(NOEXIT, NOERRNO, "Unrecognized HTML escape code in "
		      "line %d (or text beginning on that line): \"%.4s...\", "
		      "passed through unaltered", Linenum, Pch2);

		PUTC('&');		// emit start of escape code.
		// continue with Pch is just after the '&'.
	    }
	}

	EmitTextPRE(Pch, InPRE);	// emit remaining part.

} // EmitText()


// ****************************************************************************
// E M I T   T E X T   P R E
//
// Given a text string with no HTML escape codes in it and a bitflag for 
// status (see EmitText()), emit the string with 
 handling, and with any
// backslashes doubled.

FUNCTION void EmitTextPRE(
	char * Pch,		// string to emit.
	int    InPRE)		// bitflag for 
 status.
{
	char * Pch2;		// place in string.

	if (! InPRE) { EmitTextBS(Pch); return; }

	while ((Pch2 = strchr(Pch, '\n')) != PCNULL)	// another newline.
	{
	    *Pch2 = CHNULL;		// briefly terminate.
	    EmitTextBS(Pch);		// emit preceding part.
	    *Pch2 = '\n';
	    PUTC('\n');			// emit current newline.

	    if (*(Pch = Pch2 + 1) == '\n')	// successive newline.
	    {
		// emit before next newline:
		PUTS((InPRE & INPRE_INDENT) ? ".IP" : ".PP");

		// also reset font:
		if (InPRE & INPRE_BOLD) PUTS("\n.ft B");
	    }
	}

	EmitTextBS(Pch);		// emit trailing part.

} // EmitTextPRE()


// ****************************************************************************
// E M I T   T E X T   B S
//
// Given a text string with no HTML escape codes in it, emit the string with
// any backslashes doubled.

FUNCTION void EmitTextBS(
	char * Pch)		// string to emit.
{
	while (*Pch != CHNULL)
	{
	    PUTC(*Pch); if (*Pch == '\\') PUTC('\\');
	    ++Pch;
	}

} // EmitTextBS()


// ****************************************************************************
// N O   W H I T E   S P A C E
//
// Given a string, return TRUE if it contains no whitespace, otherwise FALSE.

FUNCTION bool_t NoWhiteSpace(
	char * Pch)	// string to check.
{
	assert(Pch != PCNULL);

	while (*Pch != CHNULL) { if (ISSPACE(*Pch)) return(FALSE); ++Pch; }
	return(TRUE);

} // NoWhiteSpace()


// ****************************************************************************
// C O U N T   N E W L I N E S
//
// Return the number of newline chars in a string.

FUNCTION int CountNewlines(
	char * Pch)	// in which to count newlines.
{
	int    count = 0;

	assert(Pch != PCNULL);

	while (*Pch != CHNULL) count += ((*Pch++) == '\n');
	return(count);

} // CountNewlines()


// ****************************************************************************
// S T R   S A V E
//
// Given a string, copy the string into malloc'd space and return a pointer to
// the new copy.  Error out if malloc() fails.

FUNCTION char * StrSave(
	char * string)
{
	return(strcpy((char *) Malloc((size_t) (strlen(string) + 1)), string));

} // StrSave()


// ****************************************************************************
// S T R   S A V E   N
//
// Given one or more strings, terminated by a null pointer, allocate space for
// the concatenation of the strings, concatenate them, and return a pointer to
// the result.  Also free() all but the last string.

FUNCTION char * StrSaveN(
	char *	String, ...)
{
	va_list Parg;			// place in arg list.
	char *	stringN;		// string from arg list.
	char *	stringN1 = PCNULL;	// previous string.
	size_t	size = 0;		// total bytes needed.
	char *	result;			// string to return.


// DETERMINE SPACE NEEDED:

	va_start(Parg, String);

	for (stringN  = String;
	     stringN != PCNULL;
	     stringN  = va_arg(Parg, char *))
	{
	    size += strlen(stringN);
	}

	va_end(Parg);


// ALLOCATE SPACE, CONCATENATE STRINGS:

	*(result = (char *) Malloc((size_t) (size + 1))) = CHNULL;

	va_start(Parg, String);

	for (stringN  = String;
	     stringN != PCNULL;
	     stringN  = va_arg(Parg, char *))
	{
	    if (stringN1 != PCNULL) free((void *) stringN1);
	    stringN1 = stringN;			// all but last string.
	    (void) strcat(result, stringN);
	}

	va_end(Parg);
	return(result);

} // StrSaveN()


// ****************************************************************************
// M A L L O C
//
// Do a malloc() with error checking.

FUNCTION void * Malloc(
	size_t	Size)	// bytes to get.
{
	void *	Pm;	// pointer to memory.

	if ((Pm = malloc(Size)) == (void *) NULL)
	    Error(ERREXIT, errno, "Cannot malloc %d bytes", Size);

	return(Pm);

} // Malloc()


// ****************************************************************************
// U S A G E
//
// Print usage messages (char *gc_usage[]) to stderr and exit with ERREXIT.
// Follow each message line by a newline.

FUNCTION void Usage(void)
{
	int which = 0;		// current line.

	while (gc_usage[which] != PCNULL)
	{
	    (void) fprintf(stderr, gc_usage[which++], gc_myname);
	    (void) putc('\n', stderr);
	}

	exit(ERREXIT);

} // Usage()


// ****************************************************************************
// E R R O R
//
// Given an exit value (NOEXIT, ERREXIT, or USAGE), an errno value (NOERRNO if
// none), a message (printf) string, and zero or more argument strings, print
// an error message to stderr and, if exitvalue is NOEXIT, return; if USAGE,
// print a pointer to the program's usage message; otherwise exit with the
// value.
//
// Message is preceded by ": " using global gc_myname, and by
// "Warning: " for NOEXIT, and followed by a period and newline.  If myerrno
// (system error number) is not NOERRNO, a relevant message is appended before
// the period.

FUNCTION void Error(
	int	Exitvalue,	// or NOEXIT for warning.
	int	MyErrno,	// system errno if relevant.
	char *	Message, ...)
{
	va_list Parg;		// place in arg list.

	(void) fprintf(stderr, "%s: ", gc_myname);
	if (Exitvalue == NOEXIT) (void) fputs("Warning: ", stderr);

	va_start(Parg, Message);
	(void) vfprintf(stderr, Message, Parg);
	va_end(Parg);

	if (MyErrno != NOERRNO)
	{
	    (void) fprintf(stderr, ": %s (errno = %d)", strerror(MyErrno),
			   MyErrno);
	}

	(void) putc('.',  stderr);
	(void) putc('\n', stderr);

	if (Exitvalue == USAGE)
	{
	    (void) fprintf(stderr, "For a usage summary, run %s -?\n",
			   gc_myname);
	}

	DBGCODE(DumpTree(g_Pdnhead, /* Depth = */ 0, /* Separator = */ FALSE);)

	if (Exitvalue != NOEXIT)
	    exit(Exitvalue);

} // Error()


#ifdef DEBUG

// ****************************************************************************
// D U M P   T R E E
//
// Dump to stdout a representation of the docnode tree under g_Pdnhead.
// Recursively traverse the tree in-order (parent then child then sibling).

FUNCTION void DumpTree(
	Pdn_t  Pdn,		// first node of current sibling list.
	int    Depth,		// current depth.
	bool_t Separator)	// print a separator line after a long dump.
{
	int   indent;		// for counting to Depth.

// Check if enabled:

	if (getenv("DUMP") == PCNULL)
	{
	    PUTS(".\\\" $DUMP not set; DumpTree() disabled.\n");
	    return;
	}

// Check for empty tree:

	if ((Depth == 0) && (Pdn == PDNNULL))
	{
	    PUTS("Head pointer is null.\n");
	    return;
	}

// Print siblings and each of their children, indented to Depth after the node
// address:

	while (Pdn != PDNNULL)
	{
	    (void) printf("%lx ", (unsigned long) Pdn);

	    for (indent = 0; indent <= Depth; ++indent) PUTC('.');

	    (void) printf(" %-5s %3d %c %lx %lx \"%s\"\n",
			  ((Pdn -> dn_type) == DN_TYPE_TEXT) ?
			      "text" : TAG(Pdn -> dn_type),
			  Pdn -> dn_linenum,
			  (Pdn->dn_closed) ? 'c' : 'o',
			  Pdn -> dn_Pparent,
			  Pdn -> dn_Pprev,
			  Pdn -> dn_text);

	    if ((Pdn -> dn_Pchild) != PDNNULL)
		DumpTree(Pdn -> dn_Pchild, Depth + 1, Separator);

	    Pdn = Pdn -> dn_Pnext;
	}

// Print separator line:

	if ((Depth == 0) && Separator)
	    PUTS("=======================================================\n");

} // DumpTree()

#endif // DEBUG
judy-1.0.5/tool/Makefile.in0000644000175000017500000003153110624600217015737 0ustar  troyhebetroyhebe# Makefile.in generated by automake 1.9.6 from Makefile.am.
# @configure_input@

# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
# 2003, 2004, 2005  Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.

@SET_MAKE@

srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
top_builddir = ..
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
INSTALL = @INSTALL@
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
noinst_PROGRAMS = jhton$(EXEEXT)
subdir = tool
DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
PROGRAMS = $(noinst_PROGRAMS)
am_jhton_OBJECTS = jhton.$(OBJEXT)
jhton_OBJECTS = $(am_jhton_OBJECTS)
jhton_LDADD = $(LDADD)
DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \
	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
	$(AM_CFLAGS) $(CFLAGS)
CCLD = $(CC)
LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
	$(AM_LDFLAGS) $(LDFLAGS) -o $@
SOURCES = $(jhton_SOURCES)
DIST_SOURCES = $(jhton_SOURCES)
ETAGS = etags
CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMDEP_FALSE = @AMDEP_FALSE@
AMDEP_TRUE = @AMDEP_TRUE@
AMTAR = @AMTAR@
AR = @AR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
ECHO = @ECHO@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
F77 = @F77@
FFLAGS = @FFLAGS@
FLAVOR = @FLAVOR@
GREP = @GREP@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
MAINT = @MAINT@
MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
MAKEINFO = @MAKEINFO@
OBJEXT = @OBJEXT@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
RANLIB = @RANLIB@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
VERSION = @VERSION@
VERSION_INFO = @VERSION_INFO@
WARN_CFLAGS = @WARN_CFLAGS@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_F77 = @ac_ct_F77@
am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
datadir = @datadir@
datarootdir = @datarootdir@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
sysconfdir = @sysconfdir@
target_alias = @target_alias@
INCLUDES = -I. 
AM_CFLAGS = @CFLAGS@ @WARN_CFLAGS@
jhton_SOURCES = jhton.c
DISTCLEANFILES = .deps Makefile
all: all-am

.SUFFIXES:
.SUFFIXES: .c .lo .o .obj
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
	@for dep in $?; do \
	  case '$(am__configure_deps)' in \
	    *$$dep*) \
	      cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
		&& exit 0; \
	      exit 1;; \
	  esac; \
	done; \
	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu  tool/Makefile'; \
	cd $(top_srcdir) && \
	  $(AUTOMAKE) --gnu  tool/Makefile
.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
	@case '$?' in \
	  *config.status*) \
	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
	  *) \
	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
	esac;

$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh

$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh

clean-noinstPROGRAMS:
	@list='$(noinst_PROGRAMS)'; for p in $$list; do \
	  f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
	  echo " rm -f $$p $$f"; \
	  rm -f $$p $$f ; \
	done
jhton$(EXEEXT): $(jhton_OBJECTS) $(jhton_DEPENDENCIES) 
	@rm -f jhton$(EXEEXT)
	$(LINK) $(jhton_LDFLAGS) $(jhton_OBJECTS) $(jhton_LDADD) $(LIBS)

mostlyclean-compile:
	-rm -f *.$(OBJEXT)

distclean-compile:
	-rm -f *.tab.c

@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jhton.Po@am__quote@

.c.o:
@am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@	$(COMPILE) -c $<

.c.obj:
@am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`

.c.lo:
@am__fastdepCC_TRUE@	if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<

mostlyclean-libtool:
	-rm -f *.lo

clean-libtool:
	-rm -rf .libs _libs

distclean-libtool:
	-rm -f libtool
uninstall-info-am:

ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
	unique=`for i in $$list; do \
	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
	  done | \
	  $(AWK) '    { files[$$0] = 1; } \
	       END { for (i in files) print i; }'`; \
	mkid -fID $$unique
tags: TAGS

TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
		$(TAGS_FILES) $(LISP)
	tags=; \
	here=`pwd`; \
	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
	unique=`for i in $$list; do \
	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
	  done | \
	  $(AWK) '    { files[$$0] = 1; } \
	       END { for (i in files) print i; }'`; \
	if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
	  test -n "$$unique" || unique=$$empty_fix; \
	  $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
	    $$tags $$unique; \
	fi
ctags: CTAGS
CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
		$(TAGS_FILES) $(LISP)
	tags=; \
	here=`pwd`; \
	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
	unique=`for i in $$list; do \
	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
	  done | \
	  $(AWK) '    { files[$$0] = 1; } \
	       END { for (i in files) print i; }'`; \
	test -z "$(CTAGS_ARGS)$$tags$$unique" \
	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
	     $$tags $$unique

GTAGS:
	here=`$(am__cd) $(top_builddir) && pwd` \
	  && cd $(top_srcdir) \
	  && gtags -i $(GTAGS_ARGS) $$here

distclean-tags:
	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags

distdir: $(DISTFILES)
	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
	list='$(DISTFILES)'; for file in $$list; do \
	  case $$file in \
	    $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
	    $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
	  esac; \
	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
	    dir="/$$dir"; \
	    $(mkdir_p) "$(distdir)$$dir"; \
	  else \
	    dir=''; \
	  fi; \
	  if test -d $$d/$$file; then \
	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
	    fi; \
	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
	  else \
	    test -f $(distdir)/$$file \
	    || cp -p $$d/$$file $(distdir)/$$file \
	    || exit 1; \
	  fi; \
	done
check-am: all-am
check: check-am
all-am: Makefile $(PROGRAMS)
installdirs:
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am

install-am: all-am
	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am

installcheck: installcheck-am
install-strip:
	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
	  `test -z '$(STRIP)' || \
	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
mostlyclean-generic:

clean-generic:

distclean-generic:
	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
	-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)

maintainer-clean-generic:
	@echo "This command is intended for maintainers to use"
	@echo "it deletes files that may require special tools to rebuild."
clean: clean-am

clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \
	mostlyclean-am

distclean: distclean-am
	-rm -rf ./$(DEPDIR)
	-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
	distclean-libtool distclean-tags

dvi: dvi-am

dvi-am:

html: html-am

info: info-am

info-am:

install-data-am:

install-exec-am:

install-info: install-info-am

install-man:

installcheck-am:

maintainer-clean: maintainer-clean-am
	-rm -rf ./$(DEPDIR)
	-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic

mostlyclean: mostlyclean-am

mostlyclean-am: mostlyclean-compile mostlyclean-generic \
	mostlyclean-libtool

pdf: pdf-am

pdf-am:

ps: ps-am

ps-am:

uninstall-am: uninstall-info-am

.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
	clean-libtool clean-noinstPROGRAMS ctags distclean \
	distclean-compile distclean-generic distclean-libtool \
	distclean-tags distdir dvi dvi-am html html-am info info-am \
	install install-am install-data install-data-am install-exec \
	install-exec-am install-info install-info-am install-man \
	install-strip installcheck installcheck-am installdirs \
	maintainer-clean maintainer-clean-generic mostlyclean \
	mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
	pdf pdf-am ps ps-am tags uninstall uninstall-am \
	uninstall-info-am

# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
judy-1.0.5/tool/Makefile.am0000644000175000017500000000020710624600161015720 0ustar  troyhebetroyhebeINCLUDES =  -I. 
AM_CFLAGS = @CFLAGS@ @WARN_CFLAGS@

noinst_PROGRAMS = jhton

jhton_SOURCES = jhton.c

DISTCLEANFILES = .deps Makefile
judy-1.0.5/tool/README0000644000175000017500000000664710204462077014570 0ustar  troyhebetroyhebe
# @(#) $Revision: 4.2 $

# CHECK README FILES AGAINST DIRECTORIES.

# Usage: