judy-1.0.5/ 0000755 0001750 0001750 00000000000 10624600220 012704 5 ustar troyhebe troyhebe judy-1.0.5/test/ 0000755 0001750 0001750 00000000000 10624600217 013671 5 ustar troyhebe troyhebe judy-1.0.5/test/Makefile.in 0000644 0001750 0001750 00000025711 10624600217 015744 0 ustar troyhebe troyhebe # 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.c 0000644 0001750 0001750 00000170045 10622113030 016071 0 ustar troyhebe troyhebe // @(#) $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.h 0000644 0001750 0001750 00000015562 10204462077 015352 0 ustar troyhebe troyhebe #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.c 0000644 0001750 0001750 00000005252 10204462077 016147 0 ustar troyhebe troyhebe #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.c 0000644 0001750 0001750 00000052434 10204462077 016117 0 ustar troyhebe troyhebe // @(#) $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/README 0000644 0001750 0001750 00000002404 10204462077 014555 0 ustar troyhebe troyhebe StringCompare.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.c 0000644 0001750 0001750 00000236060 10204462077 016625 0 ustar troyhebe troyhebe // @(#) $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.c 0000644 0001750 0001750 00000060735 10622113030 016214 0 ustar troyhebe troyhebe // @(#) $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.c 0000644 0001750 0001750 00000002366 10204462077 016531 0 ustar troyhebe troyhebe #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/ 0000755 0001750 0001750 00000000000 10624600177 017700 5 ustar troyhebe troyhebe judy-1.0.5/test/Centrino_1.3Mhz_Plots/JudyHS_CO.plot 0000644 0001750 0001750 00000105131 10204462077 022327 0 ustar troyhebe troyhebe # 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.plot 0000644 0001750 0001750 00000105643 10204462077 022054 0 ustar troyhebe troyhebe # 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.plot 0000644 0001750 0001750 00000104575 10204462077 022305 0 ustar troyhebe troyhebe # 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.plot 0000644 0001750 0001750 00000105535 10204462077 022343 0 ustar troyhebe troyhebe # 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.c 0000644 0001750 0001750 00000517365 10204462077 016506 0 ustar troyhebe troyhebe /*
[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.c 0000644 0001750 0001750 00000076030 10204462077 015734 0 ustar troyhebe troyhebe // @(#) $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.c 0000644 0001750 0001750 00000130066 10204462077 015776 0 ustar troyhebe troyhebe // @(#) $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.am 0000644 0001750 0001750 00000000317 10624600161 015724 0 ustar troyhebe troyhebe 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
judy-1.0.5/test/simple.c 0000644 0001750 0001750 00000000576 10204462077 015342 0 ustar troyhebe troyhebe #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/Checkit 0000755 0001750 0001750 00000006500 10622113030 015160 0 ustar troyhebe troyhebe #!/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.c 0000644 0001750 0001750 00000017631 10204462077 015344 0 ustar troyhebe troyhebe // @(#) $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/testjbgraph 0000755 0001750 0001750 00000001726 10204462077 016146 0 ustar troyhebe troyhebe # 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/jbgraph 0000755 0001750 0001750 00000100327 10204462077 015243 0 ustar troyhebe troyhebe #!/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/ 0000755 0001750 0001750 00000000000 10624600215 013455 5 ustar troyhebe troyhebe judy-1.0.5/doc/ext/ 0000755 0001750 0001750 00000000000 10624600177 014264 5 ustar troyhebe troyhebe judy-1.0.5/doc/ext/README_deliver 0000644 0001750 0001750 00000001436 10204462077 016661 0 ustar troyhebe troyhebe # @(#) $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.htm 0000644 0001750 0001750 00000016560 10204462077 016375 0 ustar troyhebe troyhebe
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.
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()).
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.
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.
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.
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.
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.
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.
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.
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.)
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.)
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.
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/LICENSE 0000644 0001750 0001750 00000000000 10204462077 015256 0 ustar troyhebe troyhebe judy-1.0.5/doc/ext/README 0000644 0001750 0001750 00000001436 10204462077 015147 0 ustar troyhebe troyhebe # @(#) $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.htm 0000644 0001750 0001750 00000013760 10204462077 017576 0 ustar troyhebe troyhebe
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)
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.
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.
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).
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.
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.
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.
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.
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.
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.
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.
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;
}
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.
Judy arrays -
C library functions for creating and accessing dynamic arrays
SYNOPSIS
Judy1 - maps an Index (word) to a bitJudyL - maps an Index (word) to a Value (word/pointer)
JudySL - maps an Index (null terminated string) to a ValueJudyHS - 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).
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.)
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).
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.
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.
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.
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).
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.
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.
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.
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.
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.
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.)
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.)
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.
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.
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.
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.
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.
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.
judy-1.0.5/doc/int/ 0000755 0001750 0001750 00000000000 10624600177 014256 5 ustar troyhebe troyhebe judy-1.0.5/doc/int/10minutes.htm 0000644 0001750 0001750 00000031453 10204462077 016622 0 ustar troyhebe troyhebe
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/ 0000755 0001750 0001750 00000000000 10624600177 014237 5 ustar troyhebe troyhebe judy-1.0.5/doc/man/man3/ 0000755 0001750 0001750 00000000000 10624600177 015075 5 ustar troyhebe troyhebe judy-1.0.5/doc/Makefile.am 0000644 0001750 0001750 00000014552 10624600161 015520 0 ustar troyhebe troyhebe 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
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.in 0000644 0001750 0001750 00000041202 10624600215 015521 0 ustar troyhebe troyhebe # 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/ 0000755 0001750 0001750 00000000000 10624600217 013501 5 ustar troyhebe troyhebe judy-1.0.5/src/apps/ 0000755 0001750 0001750 00000000000 10624600177 014451 5 ustar troyhebe troyhebe judy-1.0.5/src/apps/demo/ 0000755 0001750 0001750 00000000000 10624600177 015375 5 ustar troyhebe troyhebe judy-1.0.5/src/apps/demo/Makefile_deliver 0000644 0001750 0001750 00000002711 10204462077 020547 0 ustar troyhebe troyhebe # @(#) $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.c 0000644 0001750 0001750 00000017203 10204462077 017223 0 ustar troyhebe troyhebe // @(#) $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.c 0000644 0001750 0001750 00000007723 10204462077 017131 0 ustar troyhebe troyhebe // 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.c 0000644 0001750 0001750 00000002122 10204462077 017320 0 ustar troyhebe troyhebe #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_deliver 0000644 0001750 0001750 00000001001 10204462077 017756 0 ustar troyhebe troyhebe # @(#) $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_demo 0000755 0001750 0001750 00000002457 10204462077 017142 0 ustar troyhebe troyhebe # @(#) $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/README 0000644 0001750 0001750 00000001501 10204462077 016251 0 ustar troyhebe troyhebe # @(#) $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.c 0000644 0001750 0001750 00000001750 10204462077 017000 0 ustar troyhebe troyhebe #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/README 0000644 0001750 0001750 00000001600 10204462077 015325 0 ustar troyhebe troyhebe # @(#) $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.h 0000644 0001750 0001750 00000066577 10622113030 014600 0 ustar troyhebe troyhebe #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/ 0000755 0001750 0001750 00000000000 10624600216 015564 5 ustar troyhebe troyhebe judy-1.0.5/src/JudyCommon/JudyMemActive.c 0000644 0001750 0001750 00000015225 10204462077 020450 0 ustar troyhebe troyhebe // 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.c 0000644 0001750 0001750 00000267636 10204462077 017321 0 ustar troyhebe troyhebe // 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.c 0000644 0001750 0001750 00000005151 10204462077 020002 0 ustar troyhebe troyhebe // 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.c 0000644 0001750 0001750 00000165655 10204462077 020366 0 ustar troyhebe troyhebe // 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.c 0000644 0001750 0001750 00000021527 10204462077 020012 0 ustar troyhebe troyhebe // 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.c 0000644 0001750 0001750 00000020170 10204462077 021112 0 ustar troyhebe troyhebe // 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.h 0000644 0001750 0001750 00000040270 10204462077 020410 0 ustar troyhebe troyhebe #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.c 0000644 0001750 0001750 00000105634 10204462077 017321 0 ustar troyhebe troyhebe // 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.h 0000644 0001750 0001750 00000210305 10204462077 020211 0 ustar troyhebe troyhebe #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.c 0000644 0001750 0001750 00000022162 10204462077 020454 0 ustar troyhebe troyhebe // 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/README 0000644 0001750 0001750 00000004300 10204462077 016446 0 ustar troyhebe troyhebe # @(#) $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.in 0000644 0001750 0001750 00000032226 10624600216 017636 0 ustar troyhebe troyhebe # 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.c 0000644 0001750 0001750 00000010722 10204462077 021155 0 ustar troyhebe troyhebe // 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.c 0000644 0001750 0001750 00000156414 10204462077 020127 0 ustar troyhebe troyhebe // 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.c 0000644 0001750 0001750 00000067245 10204462077 020172 0 ustar troyhebe troyhebe // 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.c 0000644 0001750 0001750 00000056630 10622113030 020213 0 ustar troyhebe troyhebe // 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.c 0000644 0001750 0001750 00000046112 10204462077 020123 0 ustar troyhebe troyhebe // 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.c 0000644 0001750 0001750 00000012577 10204462077 017674 0 ustar troyhebe troyhebe // 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.c 0000644 0001750 0001750 00000125060 10204462077 020325 0 ustar troyhebe troyhebe // 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.c 0000644 0001750 0001750 00000113411 10204462077 017662 0 ustar troyhebe troyhebe // 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.c 0000644 0001750 0001750 00000215505 10204462077 017332 0 ustar troyhebe troyhebe // 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.c 0000644 0001750 0001750 00000136044 10204462077 021373 0 ustar troyhebe troyhebe // 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.c 0000644 0001750 0001750 00000077102 10204462077 020434 0 ustar troyhebe troyhebe // 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.am 0000644 0001750 0001750 00000000253 10624600161 017617 0 ustar troyhebe troyhebe INCLUDES = -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.h 0000644 0001750 0001750 00000066476 10204462077 021351 0 ustar troyhebe troyhebe #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.c 0000644 0001750 0001750 00000003412 10204462077 020130 0 ustar troyhebe troyhebe // 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/ 0000755 0001750 0001750 00000000000 10624600216 014646 5 ustar troyhebe troyhebe judy-1.0.5/src/JudyHS/Makefile.am 0000644 0001750 0001750 00000000260 10624600161 016677 0 ustar troyhebe troyhebe INCLUDES = -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.c 0000644 0001750 0001750 00000067760 10204462077 016205 0 ustar troyhebe troyhebe // @(#) $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.in 0000644 0001750 0001750 00000032127 10624600216 016720 0 ustar troyhebe troyhebe # 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.h 0000644 0001750 0001750 00000003402 10204462077 016171 0 ustar troyhebe troyhebe // ****************************************************************************
// 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/README 0000644 0001750 0001750 00000000621 10204462077 015532 0 ustar troyhebe troyhebe # @(#) $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.bat 0000755 0001750 0001750 00000017331 10204462077 015304 0 ustar troyhebe troyhebe @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/ 0000755 0001750 0001750 00000000000 10624600216 014527 5 ustar troyhebe troyhebe judy-1.0.5/src/JudyL/Makefile.in 0000644 0001750 0001750 00000063354 10624600216 016607 0 ustar troyhebe troyhebe # 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.am 0000644 0001750 0001750 00000007217 10624600161 016571 0 ustar troyhebe troyhebe 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
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.h 0000644 0001750 0001750 00000050771 10204462077 015746 0 ustar troyhebe troyhebe #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/README 0000644 0001750 0001750 00000000246 10204462077 015416 0 ustar troyhebe troyhebe # @(#) $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/ 0000755 0001750 0001750 00000000000 10624600216 014652 5 ustar troyhebe troyhebe judy-1.0.5/src/JudySL/Makefile.in 0000644 0001750 0001750 00000032127 10624600216 016724 0 ustar troyhebe troyhebe # 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.am 0000644 0001750 0001750 00000000260 10624600161 016703 0 ustar troyhebe troyhebe INCLUDES = -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.c 0000644 0001750 0001750 00000127577 10204462077 016220 0 ustar troyhebe troyhebe //
// 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/README 0000644 0001750 0001750 00000000273 10204462077 015541 0 ustar troyhebe troyhebe # @(#) $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.am 0000644 0001750 0001750 00000000126 10624600161 015532 0 ustar troyhebe troyhebe SUBDIRS = . JudyCommon JudyL Judy1 JudySL JudyHS obj
DISTCLEANFILES = .deps Makefile
judy-1.0.5/src/sh_build 0000755 0001750 0001750 00000025373 10204462077 015236 0 ustar troyhebe troyhebe echo "--- 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/ 0000755 0001750 0001750 00000000000 10624600217 014253 5 ustar troyhebe troyhebe judy-1.0.5/src/obj/Makefile.in 0000644 0001750 0001750 00000033660 10624600217 016330 0 ustar troyhebe troyhebe # 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.am 0000644 0001750 0001750 00000000455 10624600161 016311 0 ustar troyhebe troyhebe 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
judy-1.0.5/src/Judy1/ 0000755 0001750 0001750 00000000000 10624600216 014474 5 ustar troyhebe troyhebe judy-1.0.5/src/Judy1/Makefile.am 0000644 0001750 0001750 00000007156 10624600161 016540 0 ustar troyhebe troyhebe 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
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.h 0000644 0001750 0001750 00000053374 10204462077 015662 0 ustar troyhebe troyhebe #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.in 0000644 0001750 0001750 00000063343 10624600216 016552 0 ustar troyhebe troyhebe # 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/README 0000644 0001750 0001750 00000000566 10204462077 015370 0 ustar troyhebe troyhebe # @(#) $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.in 0000644 0001750 0001750 00000033674 10624600217 015563 0 ustar troyhebe troyhebe # 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/README 0000644 0001750 0001750 00000001022 10204462077 014360 0 ustar troyhebe troyhebe # @(#) $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.c 0000644 0001750 0001750 00000011620 10204462077 016066 0 ustar troyhebe troyhebe // 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.ac 0000644 0001750 0001750 00000023711 10624600161 015202 0 ustar troyhebe troyhebe AC_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/AUTHORS 0000644 0001750 0001750 00000000167 10204462077 013772 0 ustar troyhebe troyhebe Doug Baskinks
Owner and Main Author
Contributors:
Troy Heber:
Repackaging
Project Administration
judy-1.0.5/ChangeLog 0000644 0001750 0001750 00000004546 10624600161 014473 0 ustar troyhebe troyhebe 1.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/INSTALL 0000644 0001750 0001750 00000001401 10204462077 013743 0 ustar troyhebe troyhebe === 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.am 0000644 0001750 0001750 00000001447 10624600161 014752 0 ustar troyhebe troyhebe # 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/COPYING 0000644 0001750 0001750 00000064616 10204462077 013766 0 ustar troyhebe troyhebe Judy - 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/bootstrap 0000755 0001750 0001750 00000000455 10622150133 014654 0 ustar troyhebe troyhebe #! /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/README 0000644 0001750 0001750 00000011576 10624600161 013602 0 ustar troyhebe troyhebe
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/ 0000755 0001750 0001750 00000000000 10624600217 013667 5 ustar troyhebe troyhebe judy-1.0.5/tool/listJPtype.c 0000644 0001750 0001750 00000020441 10204462077 016147 0 ustar troyhebe troyhebe // 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.c 0000644 0001750 0001750 00000153564 10204462077 015177 0 ustar troyhebe troyhebe // 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.
{ "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.in 0000644 0001750 0001750 00000031531 10624600217 015737 0 ustar troyhebe troyhebe # 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.am 0000644 0001750 0001750 00000000207 10624600161 015720 0 ustar troyhebe troyhebe INCLUDES = -I.
AM_CFLAGS = @CFLAGS@ @WARN_CFLAGS@
noinst_PROGRAMS = jhton
jhton_SOURCES = jhton.c
DISTCLEANFILES = .deps Makefile
judy-1.0.5/tool/README 0000644 0001750 0001750 00000006647 10204462077 014570 0 ustar troyhebe troyhebe
# @(#) $Revision: 4.2 $
# CHECK README FILES AGAINST DIRECTORIES.
# Usage: