/***********************************************************************
*                                                                      *
*               This software is part of the ast package               *
*           Copyright (c) 1996-2006 AT&T Knowledge Ventures            *
*                      and is licensed under the                       *
*                  Common Public License, Version 1.0                  *
*                      by AT&T Knowledge Ventures                      *
*                                                                      *
*                A copy of the License is available at                 *
*            http://www.opensource.org/licenses/cpl1.0.txt             *
*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
*                                                                      *
*              Information and Software Systems Research               *
*                            AT&T Research                             *
*                           Florham Park NJ                            *
*                                                                      *
*                   Phong Vo <kpv@research.att.com>                    *
*                 Glenn Fowler <gsf@research.att.com>                  *
*                                                                      *
***********************************************************************/
#ifndef _RSHDR_H
#define _RSHDR_H	1

#if _PACKAGE_ast
#include	<ast.h>
#include	<recfmt.h>
#endif

#include	<vmalloc.h>

#include	"FEATURE/recsort"

/* because of sfio's sfreserve() semantics,
** the below parameter also limits the max size of a record that can be
** processed in rsmerge().
*/
#define RS_RESERVE	(128*1024)	/* for I/O reservation		*/

#define _RS_PRIVATE_ \
	Vmdisc_t	vmdisc;		/* vmalloc discipline		*/ \
	unsigned long	events;		/* active events		*/ \
	Void_t*		methdata;	/* private method data		*/ \
	Vmalloc_t*	vm;		/* region to allocate temp data	*/ \
	ssize_t		c_max;		/* max datasize per chain	*/ \
	ssize_t		c_size;		/* current size			*/ \
	Rsobj_t*	sorted;		/* defined after a reclist call	*/ \
	Rsobj_t**	list;		/* list of processed contexts	*/ \
	int		n_list;		/* number of such contexts	*/ \
	Rsobj_t*	free;		/* free list of objects		*/ \
	Sfio_t*		f;		/* current output stream	*/ \
	unsigned char	*rsrv, *endrsrv, *cur;	/* for fast writes	*/

#include		"recsort.h"

/* internal control bits */
#define RS_SORTED	010000		/* context has been sorted	*/
#define RS_LOCAL	020000		/* local call			*/

#if !_PACKAGE_ast
#if __STD_C
#include	<string.h>
#endif
#endif

#ifndef uchar
#define uchar		unsigned char
#endif
#ifndef ushort
#define ushort		unsigned short
#endif
#ifndef uint
#define uint		unsigned int
#endif
#ifndef ulong
#define ulong		unsigned long
#endif
#ifndef reg
#define reg		register
#endif
#ifndef NIL
#define NIL(type)	((type)0)
#endif

#ifndef UCHAR_MAX
#define UCHAR_MAX	((uchar)(~0) )
#endif
#ifndef UINT_MAX
#define UINT_MAX	((uint)(~0) )
#endif
#ifndef INT_MAX
#define INT_MAX		((int)(UINT_MAX >> 1) )
#endif

/* splay tree operations */
#define RLINK(r,x)	(r = r->left  = x)
#define LLINK(l,x)	(l = l->right = x)
#define RROTATE(r,t) 	(r->left = t->right, t->right = r, r = t)
#define LROTATE(r,t)	(r->right = t->left, t->left = r, r = t)

#define SETLOCAL(rs)	(rs->type |= RS_LOCAL)
#define GETLOCAL(rs,l)	((l = (rs->type&RS_LOCAL)), (rs->type &= ~RS_LOCAL), l)
#define RSWRITE(rs,f,t)	(SETLOCAL(rs), rswrite(rs,f,t))

/* do quick key comparisons using first 4 bytes */
#if SIZEOF_LONG == 8
#define OBJHEAD(obj)	\
	{ reg uchar*	k = obj->key; reg ulong	h = 0; \
	  switch(obj->keylen) \
	  { default :	h  = ((ulong)k[7]); \
	    case 7 :	h |= ((ulong)k[6]) << (1*CHAR_BIT); \
	    case 6 :	h |= ((ulong)k[5]) << (2*CHAR_BIT); \
	    case 5 :	h |= ((ulong)k[4]) << (3*CHAR_BIT); \
	    case 4 :	h |= ((ulong)k[3]) << (4*CHAR_BIT); \
	    case 3 :	h |= ((ulong)k[2]) << (5*CHAR_BIT); \
	    case 2 :	h |= ((ulong)k[1]) << (6*CHAR_BIT); \
	    case 1 :	h |= ((ulong)k[0]) << (7*CHAR_BIT); \
	    case 0 :	obj->order = h; \
	  } \
	}
#else /* SIZEOF_LONG == 4*/
#define OBJHEAD(obj)	\
	{ reg uchar*	k = obj->key; reg ulong	h = 0; \
	  switch(obj->keylen) \
	  { default :	h  = k[3]; \
	    case 3 :	h |= k[2] << (1*CHAR_BIT); \
	    case 2 :	h |= k[1] << (2*CHAR_BIT); \
	    case 1 :	h |= k[0] << (3*CHAR_BIT); \
	    case 0 :	obj->order = h; \
	  } \
	}
#endif

#define OBJCMP(one,two,cmp) \
	{ if((one)->order != (two)->order ) \
	    cmp = (one)->order < (two)->order ? -1 : 1; \
	  else \
	  { reg uchar *ok, *tk; reg ssize_t l, d; \
	    ok = (one)->key+SIZEOF_LONG; tk = (two)->key+SIZEOF_LONG; \
	    if((d = (l = (one)->keylen) - (two)->keylen) > 0) l -= d; \
	    for(l -= SIZEOF_LONG;;) \
	    { if(l-- <= 0)			{ cmp = d; break; } \
	      else if((cmp = *ok++ - *tk++) )	break; \
	    } \
	  } \
	}

#define MEMCPY(to,fr,n) \
	switch(n) \
	{ default:	memcpy(to,fr,n); to += n; fr += n; break; \
	  case 8 :	*to++ = *fr++; \
	  case 7 :	*to++ = *fr++; \
	  case 6 :	*to++ = *fr++; \
	  case 5 :	*to++ = *fr++; \
	  case 4 :	*to++ = *fr++; \
	  case 3 :	*to++ = *fr++; \
	  case 2 :	*to++ = *fr++; \
	  case 1 :	*to++ = *fr++; \
	}

/* merging equivalent records */
#define EQUAL(r,o,t) \
	{	if((t = r->equal) ) \
		     { t->left = (t->left->right = o); } \
		else { r->equal = (o->left = o); } \
	}

#if !_PACKAGE_ast && !__STD_C
_BEGIN_EXTERNS_
Kpvimport Void_t*	memchr _ARG_((const Void_t*, int, size_t));
Kpvimport Void_t*	memcpy _ARG_((Void_t*, const Void_t*, size_t));
_END_EXTERNS_
#endif

#define RSNOTIFY(r,o,v,x,d)	((r->events&o)?rsnotify(r,o,(Void_t*)v,(Void_t*)x,d):(0))

#define rsnotify	_rs_notify

extern int		rsnotify _ARG_((Rs_t*, int, Void_t*, Void_t*, Rsdisc_t*));

#endif /*_RSHDR_H*/
