Alien-Judy

 view release on metacpan or  search on metacpan

src/judy-1.0.5/src/JudyCommon/JudyPrevNextEmpty.c  view on Meta::CPAN


#ifdef TRACEJPSE
#include "JudyPrintJP.c"
#endif


// ****************************************************************************
// J U D Y   1   P R E V   E M P T Y
// J U D Y   1   N E X T   E M P T Y
// J U D Y   L   P R E V   E M P T Y
// J U D Y   L   N E X T   E M P T Y
//
// See the manual entry for the API.
//
// OVERVIEW OF Judy*PrevEmpty() / Judy*NextEmpty():
//
// See also for comparison the equivalent comments in JudyPrevNext.c.
//
// Take the callers *PIndex and subtract/add 1, but watch out for
// underflow/overflow, which means "no previous/next empty index found."  Use a
// reentrant switch statement (state machine, see SMGetRestart and
// SMGetContinue) to decode Index, starting with the JRP (PArray), through a
// JPM and branches, if any, down to an immediate or a leaf.  Look for Index in
// that immediate or leaf, and if not found (invalid index), return success
// (Index is empty).
//
// This search can result in a dead end where taking a different path is
// required.  There are four kinds of dead ends:
//
// BRANCH PRIMARY dead end:  Encountering a fully-populated JP for the
// appropriate digit in Index.  Search sideways in the branch for the
// previous/next absent/null/non-full JP, and if one is found, set Index to the
// highest/lowest index possible in that JPs expanse.  Then if the JP is an
// absent or null JP, return success; otherwise for a non-full JP, traverse
// through the partially populated JP.
//
// BRANCH SECONDARY dead end:  Reaching the end of a branch during a sideways
// search after a branch primary dead end.  Set Index to the lowest/highest
// index possible in the whole branchs expanse (one higher/lower than the
// previous/next branchs expanse), then restart at the top of the tree, which
// includes pre-decrementing/incrementing Index (again) and watching for
// underflow/overflow (again).
//
// LEAF PRIMARY dead end:  Finding a valid (non-empty) index in an immediate or
// leaf matching Index.  Search sideways in the immediate/leaf for the
// previous/next empty index; if found, set *PIndex to match and return success.
//
// LEAF SECONDARY dead end:  Reaching the end of an immediate or leaf during a
// sideways search after a leaf primary dead end.  Just as for a branch
// secondary dead end, restart at the top of the tree with Index set to the
// lowest/highest index possible in the whole immediate/leafs expanse.
// TBD:  If leaf secondary dead end occurs, could shortcut and treat it as a
// branch primary dead end; but this would require remembering the parent
// branchs type and offset (a "one-deep stack"), and also wrestling with
// narrow pointers, at least for leaves (but not for immediates).
//
// Note some ASYMMETRIES between SearchValid and SearchEmpty:
//
// - The SearchValid code, upon descending through a narrow pointer, if Index
//   is outside the expanse of the subsidiary node (effectively a secondary
//   dead end), must decide whether to backtrack or findlimit.  But the
//   SearchEmpty code simply returns success (Index is empty).
//
// - Similarly, the SearchValid code, upon finding no previous/next index in
//   the expanse of a narrow pointer (again, a secondary dead end), can simply
//   start to backtrack at the parent JP.  But the SearchEmpty code would have
//   to first determine whether or not the parent JPs narrow expanse contains
//   a previous/next empty index outside the subexpanse.  Rather than keeping a
//   parent state stack and backtracking this way, upon a secondary dead end,
//   the SearchEmpty code simply restarts at the top of the tree, whether or
//   not a narrow pointer is involved.  Again, see the equivalent comments in
//   JudyPrevNext.c for comparison.
//
// This function is written iteratively for speed, rather than recursively.
//
// TBD:  Wed like to enhance this function to make successive searches faster.
// This would require saving some previous state, including the previous Index
// returned, and in which leaf it was found.  If the next call is for the same
// Index and the array has not been modified, start at the same leaf.  This
// should be much easier to implement since this is iterative rather than
// recursive code.

#ifdef JUDY1
#ifdef JUDYPREV
FUNCTION int Judy1PrevEmpty
#else
FUNCTION int Judy1NextEmpty
#endif
#else
#ifdef JUDYPREV
FUNCTION int JudyLPrevEmpty
#else
FUNCTION int JudyLNextEmpty
#endif
#endif
        (
	Pcvoid_t  PArray,	// Judy array to search.
	Word_t *  PIndex,	// starting point and result.
	PJError_t PJError	// optional, for returning error info.
        )
{
	Word_t	  Index;	// fast copy, in a register.
	Pjp_t	  Pjp;		// current JP.
	Pjbl_t	  Pjbl;		// Pjp->jp_Addr masked and cast to types:
	Pjbb_t	  Pjbb;
	Pjbu_t	  Pjbu;
	Pjlb_t	  Pjlb;
	PWord_t	  Pword;	// alternate name for use by GET* macros.

	Word_t	  digit;	// next digit to decode from Index.
	Word_t	  digits;	// current state in SM = digits left to decode.
	Word_t	  pop0;		// in a leaf.
	Word_t	  pop0mask;	// precalculated to avoid variable shifts.
	long	  offset;	// within a branch or leaf (can be large).
	int	  subexp;	// subexpanse in a bitmap branch.
	BITMAPB_t bitposmaskB;	// bit in bitmap for bitmap branch.
	BITMAPL_t bitposmaskL;	// bit in bitmap for bitmap leaf.
	Word_t	  possfullJP1;	// JP types for possibly full subexpanses:
	Word_t	  possfullJP2;
	Word_t	  possfullJP3;



( run in 1.144 second using v1.01-cache-2.11-cpan-c966e8aa7e8 )