2147 lines
92 KiB
C
2147 lines
92 KiB
C
// 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$ $Source$
|
|
//
|
|
// 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()
|