1874 lines
71 KiB
C
1874 lines
71 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$
|
|
//
|
|
// 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()
|