The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
/***-*-C-*-******************** PRIVATE! */
/******************************* YOU SHOULD NOT EVEN INCLUDE THIS FILE! */

#ifndef _TV_SNEAKY_ON_
#error PLEASE DO NOT INCLUDE THIS FILE!
#endif

#include "tvcommon.h"

#ifndef TV_PLANT_KEY
#define TV_PLANT_KEY(k)
#endif
#ifndef TV_UPROOT_KEY
#define TV_UPROOT_KEY(k)
#endif
#ifndef TV_UNSET_DAT
#define TV_UNSET_DAT TV_UPROOT_DAT
#endif
#ifndef TV_DAT_2STRING
#define TV_DAT_2STRING(x) "?"
#endif
#ifndef TnDAT_ASSIGN
#define TnDAT_ASSIGN(lvalue,rvalue) lvalue = *rvalue
#endif
#ifndef TnDAT_FETCH
#define TnDAT_FETCH(lvalue,rvalue) *lvalue = &rvalue
#endif
#ifndef TnCLEARSLOT
#define TnCLEARSLOT(k,d)
#endif

/* CLEARSLOT2 is used to cleanup after a memcpy or memmove.  However,
   it is not used within tv_clear. */
#define TnCLEARSLOT2(tn,xx)	TnCLEARSLOT(TnKEY(tn,xx), TnDAT(tn,xx))

#define TnMIDDLE	(TnWIDTH/2)

#define TnSLOT(tn,xx)	(tn)->tn_slots[xx]
#define TnDAT(tn,xx)	(tn)->tn_slots[xx].slot_dat
#define TnDATx(tn,xx)	(tn)->tn_slots[TnSTART(tn) + xx].slot_dat

#undef TvROOT
#define TvROOT(tv)	((TN*)(tv)->xtv_root)
#undef TnKID
#define TnKID(tn,xx)	((TN*)((TN0*)tn)->tn_kids[xx])
#undef CeTN
#define CeTN(ce)	((TN*)(ce)->tce_tn)
#undef TcTN
#define TcTN(tc,xx)	((TN*)(tc)->xtc_path[xx].tce_tn)

#define TnGUARD(tn,xx)	((TN*)tn)->guard##xx

#if defined(TV_TEST) && defined(TV_XTEST)
# define TnSCANID(tn)	((TN*)tn)->tn_scanid
# define TnINITGUARD(tn)	\
	TnGUARD(tn,1)=0xbadc0de;\
	TnGUARD(tn,2)=0xbadc0de;\
	TnSCANID(tn)=0;
# define TnGUARDOK(tn) \
	(TnGUARD(tn,1)==0xbadc0de && \
	 TnGUARD(tn,2)==0xbadc0de)

#else
# define TnSCANID(tn)
# define TnINITGUARD(tn)
# define TnGUARDOK(tn)
#endif

#ifdef TV_KEYCACHE
# define TnKCACHE(tn,last)	(tn)->tn_kcache[last]
#else
# define TnKCACHE(tn,last)
#endif

#ifndef TV_KCACHE_INIT
# define TV_KCACHE_INIT(kc) STMT_START {} STMT_END
#endif
#ifndef TV_KCACHE_CLEAR
# define TV_KCACHE_CLEAR(kc) STMT_START {} STMT_END
#endif
#ifndef TV_KCACHE_LOAD
# define TV_KCACHE_LOAD(key,dat,kc) STMT_START {} STMT_END
#endif

#define TV_KCACHE_LOADl(tn) \
  TV_KCACHE_LOAD(TnKEY(tn,TnSTART(tn)), TnDAT(tn,TnSTART(tn)), TnKCACHE(tn,0))
#define TV_KCACHE_LOADr(tn) \
  TV_KCACHE_LOAD(TnKEY(tn,TnLAST(tn)), TnDAT(tn,TnLAST(tn)), TnKCACHE(tn,1))

#define TnINIT(tn,fill,left,right)		\
STMT_START {					\
  TnSTART(tn)=(TnWIDTH - (fill))/2;		\
  TnEND(tn)=TnSTART(tn) + (fill);		\
  TnLEFT_set(tn,left); TnRIGHT_set(tn,right);	\
  TnINITGUARD(tn);				\
  TV_KCACHE_INIT(TnKCACHE(tn,0));		\
  TV_KCACHE_INIT(TnKCACHE(tn,1));		\
} STMT_END

#define TcFREETN(tc,tv,tn,dtor,stepnext)		\
STMT_START {						\
    assert(tn_emptied(tn));				\
    stepnext = tc_freetn(tc, tv, (TN0*)tn, dtor);	\
} STMT_END

#ifdef TV_TEST
#  ifdef TV_KEYD
#    define TnSNIF1SLOT(tn,sx) \
(TnDAT(tn,_x) == (void*)0xbadc0de || TnKEY(tn,_x) == (char*)0xbadc0de)
#  else
     /* assumes that sizeof(TnDAT) >= sizeof(void*) */
#    define TnSNIF1SLOT(tn,sx) \
(*(void**)&TnDAT(tn,_x) == (void*)0xbadc0de)
#  endif

#define TnSNIFGUARD(tn)				\
STMT_START {					\
  register int _x;				\
  for (_x=0; _x < TnWIDTH; _x++) {		\
    if (TnSNIF1SLOT(tn,_x)) {			\
      warn("snifguard failed at %d", _x);	\
      assert(0);				\
    }						\
  }						\
} STMT_END

#else
#define TnSNIFGUARD(tn) STMT_START {} STMT_END
#endif

/* backward compatibility */
#define TnSUBl(tn,xx)	(xx==0? TnLEFT(tn) : (xx==TnFILL(tn)? TnRIGHT(tn) : 0))
#define TnSUBr(tn,xx)	(xx==TnFILL(tn)-1 ? TnRIGHT(tn) : 0)

#if defined(TV_TEST) && defined(TV_KEYD)
#define TnCLEARSLOT1(tn,xx)	TnKEY(tn,xx)=(void*)0x69696969
#define TnSLOTCLEAR(tn,xx)	(TnKEY(tn,xx)==(void*)0x69696969)
#else
#define TnCLEARSLOT1(tn,xx)
#define TnSLOTCLEAR(tn,xx)	1
#endif

#if defined(TV_KEYD)
#define TnKEY(tn,xx)		(tn)->tn_slots[xx].slot_key
#define TnKEYx(tn,xx)		(tn)->tn_slots[TnSTART(tn) + xx].slot_key
#define TnSETSLOT(tn,xx,k,d) \
	STMT_START { TnKEY(tn,xx)=k; TnDAT_ASSIGN(TnDAT(tn,xx),d); } STMT_END
#define TV_SETREMOTE(tc,key)	tc_seek(tc,key)
#else
#define TV_KEYCMP(cmp,a,b)
#define TnKEY(tn,xx)		xx
#define TnKEYx(tn,xx)		xx
#define TnSETSLOT(tn,xx,k,d) \
	STMT_START { TnDAT_ASSIGN(TnDAT(tn,xx),d); } STMT_END
#define TV_SETREMOTE(tc,key)	tc_moveto(tc,key)
#endif

#define TnSHIFT(tn,xx)						\
STMT_START {							\
  register int _sx;						\
  for (_sx=TnSTART(tn); _sx < TnSTART(tn)+(xx); _sx++) {	\
    TnCLEARSLOT1(tn,_sx);					\
    TnCLEARSLOT2(tn,_sx);					\
  }								\
  TnSTART(tn) += xx;						\
} STMT_END

#define TnPOP(tn,xx)					\
STMT_START {						\
  register int _sx;					\
  for (_sx=TnLAST(tn); _sx > TnLAST(tn)-(xx); _sx--) {	\
    TnCLEARSLOT1(tn,_sx);				\
    TnCLEARSLOT2(tn,_sx);				\
  }							\
  TnEND(tn) -= xx;					\
} STMT_END

/* must do memmove & memcpy to evade evil C++ operator overloading */
#define TnSHIFTl(tn,start,end,delta,yes)				\
STMT_START {								\
 register int _st = (start);						\
 register int _end = (end);						\
 yes = _st <= _end;							\
 if (yes) {								\
  int _z;								\
  assert(delta);							\
  memmove(&TnSLOT(tn,_st-(delta)), &TnSLOT(tn,_st),			\
          TV_SLOTSIZE*(_end-_st+1));					\
  TnSNIFGUARD(tn);							\
  for (_z=_end-(delta)+1; _z <= _end; _z++) { TnCLEARSLOT1(tn,_z); }	\
  TcRSTAT(tc,TCS_COPYSLOT,_end-_st+1);					\
 }									\
} STMT_END

#define TnSHIFTr(tn,start,end,delta,yes)			\
STMT_START {							\
 register int _st = (start);					\
 register int _end = (end);					\
 yes = _st <= _end;						\
 if (yes) {							\
  int _z;							\
  assert(delta);						\
  memmove(&TnSLOT(tn,_st+(delta)), &TnSLOT(tn,_st),		\
          TV_SLOTSIZE*(_end-_st+1));				\
  TnSNIFGUARD(tn);						\
  for (_z=_st; _z < _st+(delta); _z++) { TnCLEARSLOT1(tn,_z); }	\
  TcRSTAT(tc,TCS_COPYSLOT,_end-_st+1);				\
 }								\
} STMT_END

#define TnCOPYRANGE(sn,s1,dn,d1,len)				\
STMT_START {							\
  if (len) {							\
    assert(len > 0);						\
    memcpy(&TnSLOT(dn,d1), &TnSLOT(sn,s1), TV_SLOTSIZE * len);	\
    TnSNIFGUARD(dn);						\
    TcRSTAT(tc,TCS_COPYSLOT,(len));				\
  }								\
} STMT_END