The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#ifndef _JUDY_PRIVATE_BRANCH_INCLUDED
#define _JUDY_PRIVATE_BRANCH_INCLUDED
// _________________
//
// Copyright (C) 2000 - 2002 Hewlett-Packard Company
//
// This program is free software; you can redistribute it and/or modify it
// under the term of the GNU Lesser General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
// for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program; if not, write to the Free Software Foundation,
// Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
// _________________

// @(#) $Revision: 4.57 $ $Source: /judy/src/JudyCommon/JudyPrivateBranch.h $
//
// Header file for all Judy sources, for global but private (non-exported)
// declarations specific to branch support.
//
// See also the "Judy Shop Manual" (try judy/doc/int/JudyShopManual.*).


// ****************************************************************************
// JUDY POINTER (JP) SUPPORT
// ****************************************************************************
//
// This "rich pointer" object is pivotal to Judy execution.
//
// JP CONTAINING OTHER THAN IMMEDIATE INDEXES:
//
// If the JP points to a linear or bitmap leaf, jp_DcdPopO contains the
// Population-1 in LSbs and Decode (Dcd) bytes in the MSBs.  (In practice the
// Decode bits are masked off while accessing the Pop0 bits.)
//
// The Decode Size, the number of Dcd bytes available, is encoded in jpo_Type.
// It can also be thought of as the number of states "skipped" in the SM, where
// each state decodes 8 bits = 1 byte.
//
// TBD:  Dont need two structures, except possibly to force jp_Type to highest
// address!
//
// Note:  The jpo_u union is not required by HP-UX or Linux but Win32 because
// the cl.exe compiler otherwise refuses to pack a bitfield (DcdPopO) with
// anything else, even with the -Zp option.  This is pretty ugly, but
// fortunately portable, and its all hide-able by macros (see below).

typedef struct J_UDY_POINTER_OTHERS      // JPO.
        {
            Word_t      j_po_Addr;       // first word:  Pjp_t, Word_t, etc.
            union {
//              Word_t  j_po_DcdPop0:cJU_BITSPERWORD-cJU_BITSPERBYTE;
                uint8_t j_po_DcdP0[sizeof(Word_t) - 1];
                uint8_t j_po_Bytes[sizeof(Word_t)];     // last byte = jp_Type.
            } jpo_u;
        } jpo_t;


// JP CONTAINING IMMEDIATE INDEXES:
//
// j_pi_1Index[] plus j_pi_LIndex[] together hold as many N-byte (1..3-byte
// [1..7-byte]) Indexes as will fit in sizeof(jpi_t) less 1 byte for j_pi_Type
// (that is, 7..1 [15..1] Indexes).
//
// For Judy1, j_pi_1Index[] is used and j_pi_LIndex[] is not used.
// For JudyL, j_pi_LIndex[] is used and j_pi_1Index[] is not used.
//
// Note:  Actually when Pop1 = 1, jpi_t is not used, and the least bytes of the
// single Index are stored in j_po_DcdPopO, for both Judy1 and JudyL, so for
// JudyL the j_po_Addr field can hold the target value.
//
// TBD:  Revise this structure to not overload j_po_DcdPopO this way?  The
// current arrangement works, its just confusing.

typedef struct _JUDY_POINTER_IMMED      // JPI.
        {
            uint8_t j_pi_1Index[sizeof(Word_t)];        // see above.
            uint8_t j_pi_LIndex[sizeof(Word_t) - 1];    // see above.
            uint8_t j_pi_Type;                  // JP type, 1 of cJ*_JPIMMED*.
        } jpi_t;


// UNION OF JP TYPES:
//
// A branch is an array of cJU_BRANCHUNUMJPS (256) of this object, or an
// alternate data type such as:  A linear branch which is a list of 2..7 JPs,
// or a bitmap branch which contains 8 lists of 0..32 JPs.  JPs reside only in
// branches of a Judy SM.

typedef union J_UDY_POINTER             // JP.
        {
            jpo_t j_po;                 // other than immediate indexes.
            jpi_t j_pi;                 // immediate indexes.
        } jp_t, *Pjp_t;

// For coding convenience:
//
// Note, jp_Type has the same bits in jpo_t and jpi_t.

#define jp_1Index  j_pi.j_pi_1Index     // for storing Indexes in first  word.
#define jp_LIndex  j_pi.j_pi_LIndex     // for storing Indexes in second word.
#define jp_Addr    j_po.j_po_Addr
//#define       jp_DcdPop0 j_po.jpo_u.j_po_DcdPop0
#define jp_Type    j_po.jpo_u.j_po_Bytes[sizeof(Word_t) - 1]
#define jp_DcdP0   j_po.jpo_u.j_po_DcdP0


// ****************************************************************************
// JUDY POINTER (JP) -- RELATED MACROS AND CONSTANTS
// ****************************************************************************

// EXTRACT VALUES FROM JP:
//
// Masks for the bytes in the Dcd and Pop0 parts of jp_DcdPopO:
//
// cJU_DCDMASK() consists of a mask that excludes the (LSb) Pop0 bytes and
// also, just to be safe, the top byte of the word, since jp_DcdPopO is 1 byte
// less than a full word.
//
// Note:  These are constant macros (cJU) because cPopBytes should be a
// constant.  Also note cPopBytes == state in the SM.

#define cJU_POP0MASK(cPopBytes) JU_LEASTBYTESMASK(cPopBytes)

#define cJU_DCDMASK(cPopBytes) \
        ((cJU_ALLONES >> cJU_BITSPERBYTE) & (~cJU_POP0MASK(cPopBytes)))

// Mask off the high byte from INDEX to it can be compared to DcdPopO:

#define JU_TRIMTODCDSIZE(INDEX) ((cJU_ALLONES >> cJU_BITSPERBYTE) & (INDEX))

// Get from jp_DcdPopO the Pop0 for various branch JP Types:
//
// Note:  There are no simple macros for cJU_BRANCH* Types because their
// populations must be added up and dont reside in an already-calculated
// place.

#define JU_JPBRANCH_POP0(PJP,cPopBytes) \
        (JU_JPDCDPOP0(PJP) & cJU_POP0MASK(cPopBytes))

// METHOD FOR DETERMINING IF OBJECTS HAVE ROOM TO GROW:
//
// J__U_GROWCK() is a generic method to determine if an object can grow in
// place, based on whether the next population size (one more) would use the
// same space.

#define J__U_GROWCK(POP1,MAXPOP1,POPTOWORDS) \
        (((POP1) != (MAXPOP1)) && (POPTOWORDS[POP1] == POPTOWORDS[(POP1) + 1]))

#define JU_BRANCHBJPGROWINPLACE(NumJPs) \
        J__U_GROWCK(NumJPs, cJU_BITSPERSUBEXPB, j__U_BranchBJPPopToWords)


// DETERMINE IF AN INDEX IS (NOT) IN A JPS EXPANSE:

#define JU_DCDNOTMATCHINDEX(INDEX,PJP,POP0BYTES) \
        (((INDEX) ^ JU_JPDCDPOP0(PJP)) & cJU_DCDMASK(POP0BYTES))


// NUMBER OF JPs IN AN UNCOMPRESSED BRANCH:
//
// An uncompressed branch is simply an array of 256 Judy Pointers (JPs).  It is
// a minimum cacheline fill object.  Define it here before its first needed.

#define cJU_BRANCHUNUMJPS  cJU_SUBEXPPERSTATE


// ****************************************************************************
// JUDY BRANCH LINEAR (JBL) SUPPORT
// ****************************************************************************
//
// A linear branch is a way of compressing empty expanses (null JPs) out of an
// uncompressed 256-way branch, when the number of populated expanses is so
// small that even a bitmap branch is excessive.
//
// The maximum number of JPs in a Judy linear branch:
//
// Note:  This number results in a 1-cacheline sized structure.  Previous
// versions had a larger struct so a linear branch didnt become a bitmap
// branch until the memory consumed was even, but for speed, its better to
// switch "sooner" and keep a linear branch fast.

#define cJU_BRANCHLMAXJPS 7


// LINEAR BRANCH STRUCT:
//
// 1-byte count, followed by array of byte-sized expanses, followed by JPs.

typedef struct J__UDY_BRANCH_LINEAR
        {
            uint8_t jbl_NumJPs;                     // num of JPs (Pjp_t), 1..N.
            uint8_t jbl_Expanse[cJU_BRANCHLMAXJPS]; // 1..7 MSbs of pop exps.
            jp_t    jbl_jp     [cJU_BRANCHLMAXJPS]; // JPs for populated exps.
        } jbl_t, * Pjbl_t;


// ****************************************************************************
// JUDY BRANCH BITMAP (JBB) SUPPORT
// ****************************************************************************
//
// A bitmap branch is a way of compressing empty expanses (null JPs) out of
// uncompressed 256-way branch.  This costs 1 additional cache line fill, but
// can save a lot of memory when it matters most, near the leaves, and
// typically there will be only one at most in the path to any Index (leaf).
//
// The bitmap indicates which of the cJU_BRANCHUNUMJPS (256) JPs in the branch
// are NOT null, that is, their expanses are populated.  The jbb_t also
// contains N pointers to "mini" Judy branches ("subexpanses") of up to M JPs
// each (see BITMAP_BRANCHMxN, for example, BITMAP_BRANCH32x8), where M x N =
// cJU_BRANCHUNUMJPS.  These are dynamically allocated and never contain
// cJ*_JPNULL* jp_Types.  An empty subexpanse is represented by no bit sets in
// the corresponding subexpanse bitmap, in which case the corresponding
// jbbs_Pjp pointers value is unused.
//
// Note that the number of valid JPs in each 1-of-N subexpanses is determined
// by POPULATION rather than by EXPANSE -- the desired outcome to save memory
// when near the leaves.  Note that the memory required for 185 JPs is about as
// much as an uncompressed 256-way branch, therefore 184 is set as the maximum.
// However, it is expected that a conversion to an uncompressed 256-way branch
// will normally take place before this limit is reached for other reasons,
// such as improving performance when the "wasted" memory is well amortized by
// the population under the branch, preserving an acceptable overall
// bytes/Index in the Judy array.
//
// The number of pointers to arrays of JPs in the Judy bitmap branch:
//
// Note:  The numbers below are the same in both 32 and 64 bit systems.

#define cJU_BRANCHBMAXJPS  184          // maximum JPs for bitmap branches.

// Convenience wrappers for referencing BranchB bitmaps or JP subarray
// pointers:
//
// Note:  JU_JBB_PJP produces a "raw" memory address that must pass through
// P_JP before use, except when freeing memory:

#define JU_JBB_BITMAP(Pjbb, SubExp)  ((Pjbb)->jbb_jbbs[SubExp].jbbs_Bitmap)
#define JU_JBB_PJP(   Pjbb, SubExp)  ((Pjbb)->jbb_jbbs[SubExp].jbbs_Pjp)

#define JU_SUBEXPB(Digit) (((Digit) / cJU_BITSPERSUBEXPB) & (cJU_NUMSUBEXPB-1))

#define JU_BITMAPTESTB(Pjbb, Index) \
        (JU_JBB_BITMAP(Pjbb, JU_SUBEXPB(Index)) &  JU_BITPOSMASKB(Index))

#define JU_BITMAPSETB(Pjbb, Index)  \
        (JU_JBB_BITMAP(Pjbb, JU_SUBEXPB(Index)) |= JU_BITPOSMASKB(Index))

// Note:  JU_BITMAPCLEARB is not defined because the code does it a faster way.

typedef struct J__UDY_BRANCH_BITMAP_SUBEXPANSE
        {
            BITMAPB_t jbbs_Bitmap;
            Pjp_t     jbbs_Pjp;

        } jbbs_t;

typedef struct J__UDY_BRANCH_BITMAP
        {
            jbbs_t jbb_jbbs   [cJU_NUMSUBEXPB];
#ifdef SUBEXPCOUNTS
            Word_t jbb_subPop1[cJU_NUMSUBEXPB];
#endif
        } jbb_t, * Pjbb_t;

#define JU_BRANCHJP_NUMJPSTOWORDS(NumJPs) (j__U_BranchBJPPopToWords[NumJPs])

#ifdef SUBEXPCOUNTS
#define cJU_NUMSUBEXPU  16      // number of subexpanse counts.
#endif


// ****************************************************************************
// JUDY BRANCH UNCOMPRESSED (JBU) SUPPORT
// ****************************************************************************

// Convenience wrapper for referencing BranchU JPs:
//
// Note:  This produces a non-"raw" address already passed through P_JBU().

#define JU_JBU_PJP(Pjp,Index,Level) \
        (&((P_JBU((Pjp)->jp_Addr))->jbu_jp[JU_DIGITATSTATE(Index, Level)]))
#define JU_JBU_PJP0(Pjp) \
        (&((P_JBU((Pjp)->jp_Addr))->jbu_jp[0]))

typedef struct J__UDY_BRANCH_UNCOMPRESSED
        {
            jp_t   jbu_jp     [cJU_BRANCHUNUMJPS];  // JPs for populated exp.
#ifdef SUBEXPCOUNTS
            Word_t jbu_subPop1[cJU_NUMSUBEXPU];
#endif
        } jbu_t, * Pjbu_t;


// ****************************************************************************
// OTHER SUPPORT FOR JUDY STATE MACHINES (SMs)
// ****************************************************************************

// OBJECT SIZES IN WORDS:
//
// Word_ts per various JudyL structures that have constant sizes.
// cJU_WORDSPERJP should always be 2; this is fundamental to the Judy
// structures.

#define cJU_WORDSPERJP (sizeof(jp_t)   / cJU_BYTESPERWORD)
#define cJU_WORDSPERCL (cJU_BYTESPERCL / cJU_BYTESPERWORD)


// OPPORTUNISTIC UNCOMPRESSION:
//
// Define populations at which a BranchL or BranchB must convert to BranchU.
// Earlier conversion is possible with good memory efficiency -- see below.

#ifndef NO_BRANCHU

// Max population below BranchL, then convert to BranchU:

#define JU_BRANCHL_MAX_POP      1000

// Minimum global population increment before next conversion of a BranchB to a
// BranchU:
//
// This is was done to allow malloc() to coalesce memory before the next big
// (~512 words) allocation.

#define JU_BTOU_POP_INCREMENT    300

// Min/max population below BranchB, then convert to BranchU:

#define JU_BRANCHB_MIN_POP       135
#define JU_BRANCHB_MAX_POP       750

#else // NO_BRANCHU

// These are set up to have conservative conversion schedules to BranchU:

#define JU_BRANCHL_MAX_POP      (-1UL)
#define JU_BTOU_POP_INCREMENT      300
#define JU_BRANCHB_MIN_POP        1000
#define JU_BRANCHB_MAX_POP      (-1UL)

#endif // NO_BRANCHU


// MISCELLANEOUS MACROS:

// Get N most significant bits from the shifted Index word:
//
// As Index words are decoded, they are shifted left so only relevant,
// undecoded Index bits remain.

#define JU_BITSFROMSFTIDX(SFTIDX, N)  ((SFTIDX) >> (cJU_BITSPERWORD - (N)))

// TBD:  I have my doubts about the necessity of these macros (dlb):

// Produce 1-digit mask at specified state:

#define cJU_MASKATSTATE(State)  (0xffL << (((State) - 1) * cJU_BITSPERBYTE))

// Get byte (digit) from Index at the specified state, right justified:
//
// Note:  State must be 1..cJU_ROOTSTATE, and Digits must be 1..(cJU_ROOTSTATE
// - 1), but theres no way to assert these within an expression.

#define JU_DIGITATSTATE(Index,cState) \
         ((uint8_t)((Index) >> (((cState) - 1) * cJU_BITSPERBYTE)))

// Similarly, place byte (digit) at correct position for the specified state:
//
// Note:  Cast digit to a Word_t first so there are no complaints or problems
// about shifting it more than 32 bits on a 64-bit system, say, when it is a
// uint8_t from jbl_Expanse[].  (Believe it or not, the C standard says to
// promote an unsigned char to a signed int; -Ac does not do this, but -Ae
// does.)
//
// Also, to make lint happy, cast the whole result again because apparently
// shifting a Word_t does not result in a Word_t!

#define JU_DIGITTOSTATE(Digit,cState) \
        ((Word_t) (((Word_t) (Digit)) << (((cState) - 1) * cJU_BITSPERBYTE)))

#endif // ! _JUDY_PRIVATE_BRANCH_INCLUDED


#ifdef TEST_INSDEL

// ****************************************************************************
// TEST CODE FOR INSERT/DELETE MACROS
// ****************************************************************************
//
// To use this, compile a temporary *.c file containing:
//
//      #define DEBUG
//      #define JUDY_ASSERT
//      #define TEST_INSDEL
//      #include "JudyPrivate.h"
//      #include "JudyPrivateBranch.h"
//
// Use a command like this:  cc -Ae +DD64 -I. -I JudyCommon -o t t.c
// For best results, include +DD64 on a 64-bit system.
//
// This test code exercises some tricky macros, but the output must be studied
// manually to verify it.  Assume that for even-index testing, whole words
// (Word_t) suffices.

#include <stdio.h>

#define INDEXES 3               // in each array.


// ****************************************************************************
// I N I T
//
// Set up variables for next test.  See usage.

FUNCTION void Init (
        int       base,
        PWord_t   PeIndex,
        PWord_t   PoIndex,
        PWord_t   Peleaf,       // always whole words.
#ifndef JU_64BIT
        uint8_t * Poleaf3)
#else
        uint8_t * Poleaf3,
        uint8_t * Poleaf5,
        uint8_t * Poleaf6,
        uint8_t * Poleaf7)
#endif
{
        int offset;

        *PeIndex = 99;

        for (offset = 0; offset <= INDEXES; ++offset)
            Peleaf[offset] = base + offset;

        for (offset = 0; offset < (INDEXES + 1) * 3; ++offset)
            Poleaf3[offset] = base + offset;

#ifndef JU_64BIT
        *PoIndex = (91 << 24) | (92 << 16) | (93 << 8) | 94;
#else

        *PoIndex = (91L << 56) | (92L << 48) | (93L << 40) | (94L << 32)
                 | (95L << 24) | (96L << 16) | (97L <<  8) |  98L;

        for (offset = 0; offset < (INDEXES + 1) * 5; ++offset)
            Poleaf5[offset] = base + offset;

        for (offset = 0; offset < (INDEXES + 1) * 6; ++offset)
            Poleaf6[offset] = base + offset;

        for (offset = 0; offset < (INDEXES + 1) * 7; ++offset)
            Poleaf7[offset] = base + offset;
#endif

} // Init()


// ****************************************************************************
// P R I N T   L E A F
//
// Print the byte values in a leaf.

FUNCTION void PrintLeaf (
        char *    Label,        // for output.
        int       IOffset,      // insertion offset in array.
        int       Indsize,      // index size in bytes.
        uint8_t * PLeaf)        // array of Index bytes.
{
        int       offset;       // in PLeaf.
        int       byte;         // in one word.

        (void) printf("%s %u: ", Label, IOffset);

        for (offset = 0; offset <= INDEXES; ++offset)
        {
            for (byte = 0; byte < Indsize; ++byte)
                (void) printf("%2d", PLeaf[(offset * Indsize) + byte]);

            (void) printf(" ");
        }

        (void) printf("\n");

} // PrintLeaf()


// ****************************************************************************
// M A I N
//
// Test program.

FUNCTION main()
{
        Word_t  eIndex;                         // even, to insert.
        Word_t  oIndex;                         // odd,  to insert.
        Word_t  eleaf [ INDEXES + 1];           // even leaf, index size 4.
        uint8_t oleaf3[(INDEXES + 1) * 3];      // odd leaf,  index size 3.
#ifdef JU_64BIT
        uint8_t oleaf5[(INDEXES + 1) * 5];      // odd leaf,  index size 5.
        uint8_t oleaf6[(INDEXES + 1) * 6];      // odd leaf,  index size 6.
        uint8_t oleaf7[(INDEXES + 1) * 7];      // odd leaf,  index size 7.
#endif
        Word_t  eleaf_2 [ INDEXES + 1];         // same, but second arrays:
        uint8_t oleaf3_2[(INDEXES + 1) * 3];
#ifdef JU_64BIT
        uint8_t oleaf5_2[(INDEXES + 1) * 5];
        uint8_t oleaf6_2[(INDEXES + 1) * 6];
        uint8_t oleaf7_2[(INDEXES + 1) * 7];
#endif
        int     ioffset;                // index insertion offset.

#ifndef JU_64BIT
#define INIT        Init( 0, & eIndex, & oIndex, eleaf,   oleaf3)
#define INIT2 INIT; Init(50, & eIndex, & oIndex, eleaf_2, oleaf3_2)
#else
#define INIT        Init( 0, & eIndex, & oIndex, eleaf,   oleaf3, \
                         oleaf5,   oleaf6,   oleaf7)
#define INIT2 INIT; Init(50, & eIndex, & oIndex, eleaf_2, oleaf3_2, \
                         oleaf5_2, oleaf6_2, oleaf7_2)
#endif

#define WSIZE sizeof (Word_t)           // shorthand.

#ifdef PRINTALL                 // to turn on "noisy" printouts.
#define PRINTLEAF(Label,IOffset,Indsize,PLeaf) \
        PrintLeaf(Label,IOffset,Indsize,PLeaf)
#else
#define PRINTLEAF(Label,IOffset,Indsize,PLeaf)  \
        if (ioffset == 0)                       \
        PrintLeaf(Label,IOffset,Indsize,PLeaf)
#endif

        (void) printf(
"In each case, tests operate on an initial array of %d indexes.  Even-index\n"
"tests set index values to 0,1,2...; odd-index tests set byte values to\n"
"0,1,2...  Inserted indexes have a value of 99 or else byte values 91,92,...\n",
                        INDEXES);

        (void) puts("\nJU_INSERTINPLACE():");

        for (ioffset = 0; ioffset <= INDEXES; ++ioffset)
        {
            INIT;
            PRINTLEAF("Before", ioffset, WSIZE, (uint8_t *) eleaf);
            JU_INSERTINPLACE(eleaf, INDEXES, ioffset, eIndex);
            PrintLeaf("After ", ioffset, WSIZE, (uint8_t *) eleaf);
        }

        (void) puts("\nJU_INSERTINPLACE3():");

        for (ioffset = 0; ioffset <= INDEXES; ++ioffset)
        {
            INIT;
            PRINTLEAF("Before", ioffset, 3, oleaf3);
            JU_INSERTINPLACE3(oleaf3, INDEXES, ioffset, oIndex);
            PrintLeaf("After ", ioffset, 3, oleaf3);
        }

#ifdef JU_64BIT
        (void) puts("\nJU_INSERTINPLACE5():");

        for (ioffset = 0; ioffset <= INDEXES; ++ioffset)
        {
            INIT;
            PRINTLEAF("Before", ioffset, 5, oleaf5);
            JU_INSERTINPLACE5(oleaf5, INDEXES, ioffset, oIndex);
            PrintLeaf("After ", ioffset, 5, oleaf5);
        }

        (void) puts("\nJU_INSERTINPLACE6():");

        for (ioffset = 0; ioffset <= INDEXES; ++ioffset)
        {
            INIT;
            PRINTLEAF("Before", ioffset, 6, oleaf6);
            JU_INSERTINPLACE6(oleaf6, INDEXES, ioffset, oIndex);
            PrintLeaf("After ", ioffset, 6, oleaf6);
        }

        (void) puts("\nJU_INSERTINPLACE7():");

        for (ioffset = 0; ioffset <= INDEXES; ++ioffset)
        {
            INIT;
            PRINTLEAF("Before", ioffset, 7, oleaf7);
            JU_INSERTINPLACE7(oleaf7, INDEXES, ioffset, oIndex);
            PrintLeaf("After ", ioffset, 7, oleaf7);
        }
#endif // JU_64BIT

        (void) puts("\nJU_DELETEINPLACE():");

        for (ioffset = 0; ioffset < INDEXES; ++ioffset)
        {
            INIT;
            PRINTLEAF("Before", ioffset, WSIZE, (uint8_t *) eleaf);
            JU_DELETEINPLACE(eleaf, INDEXES, ioffset);
            PrintLeaf("After ", ioffset, WSIZE, (uint8_t *) eleaf);
        }

        (void) puts("\nJU_DELETEINPLACE_ODD(3):");

        for (ioffset = 0; ioffset < INDEXES; ++ioffset)
        {
            INIT;
            PRINTLEAF("Before", ioffset, 3, oleaf3);
            JU_DELETEINPLACE_ODD(oleaf3, INDEXES, ioffset, 3);
            PrintLeaf("After ", ioffset, 3, oleaf3);
        }

#ifdef JU_64BIT
        (void) puts("\nJU_DELETEINPLACE_ODD(5):");

        for (ioffset = 0; ioffset < INDEXES; ++ioffset)
        {
            INIT;
            PRINTLEAF("Before", ioffset, 5, oleaf5);
            JU_DELETEINPLACE_ODD(oleaf5, INDEXES, ioffset, 5);
            PrintLeaf("After ", ioffset, 5, oleaf5);
        }

        (void) puts("\nJU_DELETEINPLACE_ODD(6):");

        for (ioffset = 0; ioffset < INDEXES; ++ioffset)
        {
            INIT;
            PRINTLEAF("Before", ioffset, 6, oleaf6);
            JU_DELETEINPLACE_ODD(oleaf6, INDEXES, ioffset, 6);
            PrintLeaf("After ", ioffset, 6, oleaf6);
        }

        (void) puts("\nJU_DELETEINPLACE_ODD(7):");

        for (ioffset = 0; ioffset < INDEXES; ++ioffset)
        {
            INIT;
            PRINTLEAF("Before", ioffset, 7, oleaf7);
            JU_DELETEINPLACE_ODD(oleaf7, INDEXES, ioffset, 7);
            PrintLeaf("After ", ioffset, 7, oleaf7);
        }
#endif // JU_64BIT

        (void) puts("\nJU_INSERTCOPY():");

        for (ioffset = 0; ioffset <= INDEXES; ++ioffset)
        {
            INIT2;
            PRINTLEAF("Before, src ", ioffset, WSIZE, (uint8_t *) eleaf);
            PRINTLEAF("Before, dest", ioffset, WSIZE, (uint8_t *) eleaf_2);
            JU_INSERTCOPY(eleaf_2, eleaf, INDEXES, ioffset, eIndex);
            PRINTLEAF("After,  src ", ioffset, WSIZE, (uint8_t *) eleaf);
            PrintLeaf("After,  dest", ioffset, WSIZE, (uint8_t *) eleaf_2);
        }

        (void) puts("\nJU_INSERTCOPY3():");

        for (ioffset = 0; ioffset <= INDEXES; ++ioffset)
        {
            INIT2;
            PRINTLEAF("Before, src ", ioffset, 3, oleaf3);
            PRINTLEAF("Before, dest", ioffset, 3, oleaf3_2);
            JU_INSERTCOPY3(oleaf3_2, oleaf3, INDEXES, ioffset, oIndex);
            PRINTLEAF("After,  src ", ioffset, 3, oleaf3);
            PrintLeaf("After,  dest", ioffset, 3, oleaf3_2);
        }

#ifdef JU_64BIT
        (void) puts("\nJU_INSERTCOPY5():");

        for (ioffset = 0; ioffset <= INDEXES; ++ioffset)
        {
            INIT2;
            PRINTLEAF("Before, src ", ioffset, 5, oleaf5);
            PRINTLEAF("Before, dest", ioffset, 5, oleaf5_2);
            JU_INSERTCOPY5(oleaf5_2, oleaf5, INDEXES, ioffset, oIndex);
            PRINTLEAF("After,  src ", ioffset, 5, oleaf5);
            PrintLeaf("After,  dest", ioffset, 5, oleaf5_2);
        }

        (void) puts("\nJU_INSERTCOPY6():");

        for (ioffset = 0; ioffset <= INDEXES; ++ioffset)
        {
            INIT2;
            PRINTLEAF("Before, src ", ioffset, 6, oleaf6);
            PRINTLEAF("Before, dest", ioffset, 6, oleaf6_2);
            JU_INSERTCOPY6(oleaf6_2, oleaf6, INDEXES, ioffset, oIndex);
            PRINTLEAF("After,  src ", ioffset, 6, oleaf6);
            PrintLeaf("After,  dest", ioffset, 6, oleaf6_2);
        }

        (void) puts("\nJU_INSERTCOPY7():");

        for (ioffset = 0; ioffset <= INDEXES; ++ioffset)
        {
            INIT2;
            PRINTLEAF("Before, src ", ioffset, 7, oleaf7);
            PRINTLEAF("Before, dest", ioffset, 7, oleaf7_2);
            JU_INSERTCOPY7(oleaf7_2, oleaf7, INDEXES, ioffset, oIndex);
            PRINTLEAF("After,  src ", ioffset, 7, oleaf7);
            PrintLeaf("After,  dest", ioffset, 7, oleaf7_2);
        }
#endif // JU_64BIT

        (void) puts("\nJU_DELETECOPY():");

        for (ioffset = 0; ioffset < INDEXES; ++ioffset)
        {
            INIT2;
            PRINTLEAF("Before, src ", ioffset, WSIZE, (uint8_t *) eleaf);
            PRINTLEAF("Before, dest", ioffset, WSIZE, (uint8_t *) eleaf_2);
            JU_DELETECOPY(eleaf_2, eleaf, INDEXES, ioffset, ignore);
            PRINTLEAF("After,  src ", ioffset, WSIZE, (uint8_t *) eleaf);
            PrintLeaf("After,  dest", ioffset, WSIZE, (uint8_t *) eleaf_2);
        }

        (void) puts("\nJU_DELETECOPY_ODD(3):");

        for (ioffset = 0; ioffset < INDEXES; ++ioffset)
        {
            INIT2;
            PRINTLEAF("Before, src ", ioffset, 3, oleaf3);
            PRINTLEAF("Before, dest", ioffset, 3, oleaf3_2);
            JU_DELETECOPY_ODD(oleaf3_2, oleaf3, INDEXES, ioffset, 3);
            PRINTLEAF("After,  src ", ioffset, 3, oleaf3);
            PrintLeaf("After,  dest", ioffset, 3, oleaf3_2);
        }

#ifdef JU_64BIT
        (void) puts("\nJU_DELETECOPY_ODD(5):");

        for (ioffset = 0; ioffset < INDEXES; ++ioffset)
        {
            INIT2;
            PRINTLEAF("Before, src ", ioffset, 5, oleaf5);
            PRINTLEAF("Before, dest", ioffset, 5, oleaf5_2);
            JU_DELETECOPY_ODD(oleaf5_2, oleaf5, INDEXES, ioffset, 5);
            PRINTLEAF("After,  src ", ioffset, 5, oleaf5);
            PrintLeaf("After,  dest", ioffset, 5, oleaf5_2);
        }

        (void) puts("\nJU_DELETECOPY_ODD(6):");

        for (ioffset = 0; ioffset < INDEXES; ++ioffset)
        {
            INIT2;
            PRINTLEAF("Before, src ", ioffset, 6, oleaf6);
            PRINTLEAF("Before, dest", ioffset, 6, oleaf6_2);
            JU_DELETECOPY_ODD(oleaf6_2, oleaf6, INDEXES, ioffset, 6);
            PRINTLEAF("After,  src ", ioffset, 6, oleaf6);
            PrintLeaf("After,  dest", ioffset, 6, oleaf6_2);
        }

        (void) puts("\nJU_DELETECOPY_ODD(7):");

        for (ioffset = 0; ioffset < INDEXES; ++ioffset)
        {
            INIT2;
            PRINTLEAF("Before, src ", ioffset, 7, oleaf7);
            PRINTLEAF("Before, dest", ioffset, 7, oleaf7_2);
            JU_DELETECOPY_ODD(oleaf7_2, oleaf7, INDEXES, ioffset, 7);
            PRINTLEAF("After,  src ", ioffset, 7, oleaf7);
            PrintLeaf("After,  dest", ioffset, 7, oleaf7_2);
        }
#endif // JU_64BIT

        return(0);

} // main()

#endif // TEST_INSDEL