/****************************************************************************
 *   rtentry.h : 
 *   		header file for Rtree Entry class.
 *	
 *   Change Log :
 *		 09-17-1997 Initial version,  Liujian Qian
 *
 *   $Id: rtentry.h,v 1.4 1998/12/02 04:03:45 qian Exp $
 ***************************************************************************/
#ifndef _RTENTRY_H_
#define _RTENTRY_H_

#include "memory.h"
#include "gadt_rect.h"
#include "rtbasic.h"


class	RNode;		//forward declaration


/**
 * 

      the pointer part of an RTree entry.

      THe RPtr of a RTree entry can either be a child node (page          
      id) if a non-leaf node owns the entry; or it can be a tuple          
      id in the case of leaf node. A tuple id is a long integer            
      identifying a spatial tuple stored somewhere in a spatial      
      database.                                                            

      When the RTree is distributed, the ptr may also distinct between
      pointing to a local node or a remote node. 
*/
class RPtr
{
    char	is_remote;	//true if pointing to a remote node
    char	is_leaf;	//used only during search
    short	host_id;	//-1 means local
    long        the_id;		//either the page id or tuple id (in leaf node)
    
public:
    ///
    RPtr() 
	: is_remote(0), is_leaf(0), host_id(-1), the_id(0) {};
    ///
    RPtr(long _id, int hid=-1) 
	:is_leaf(0), host_id(hid), the_id(_id) { is_remote = (host_id<0)?0:1; };
    ///
    virtual ~RPtr()   {};
    ///
    virtual RPtr& 	operator= (const RPtr& a);
    ///
    virtual bool	operator==(const RPtr& a)const;
    ///
    void		init()    {is_leaf=is_remote = 0, host_id = -1, the_id = 0;}
    
    //GROUP:  handy operations
    ///
    virtual int		hostId() const	{return host_id; }
    ///
    virtual int		isRemote() const{return is_remote; }
    ///
    virtual long	id() const	{return the_id; }
    ///
    virtual void	setHostId(int hid) {host_id = hid; }
    ///
    virtual void	setId (long _id)   {the_id = _id; }
    ///
    virtual void	setRemote()	{is_remote = 1; }
    ///
    bool		isLeaf()	{return is_leaf; }
    ///
    void		setLeaf (char lf=1)      { is_leaf=lf;}
    
    //GROUP: pack/unpack stuff
    /// 
    // pack data into the pipe
    virtual Result	pack(DataPipe& p) 
    {
	p<<is_remote<<is_leaf<<host_id<<the_id; 
	return GOk;
    }
    ///
    // unpack data from the pipe
    virtual Result	unpack(DataPipe& p)
    {
	//p.seek(0);
	if(p.eop()) 
	    msgFail("already at end of pipe");
	p>>is_remote>>is_leaf>>host_id>>the_id;
	return GOk;
    }
    
    ///
    // return packed (persistent) size of a RTree pointer
    virtual int		getPSize() const
    {
	return sizeof(int)*2 + sizeof(long);
    }

    friend  ostream&	operator<<(ostream& os, const RPtr& p);
};

class REntryPool;

/**
      Class for RTree entries.


      Each RTree entry (or index record as in Guttman '84) consists of
      two parts, one is the Key, the other a pointer. The Key is a 
      rectangle (using GRect) and is of type RTKey; the pointer is 
      defined by the RPtr class, which may contain a child node (page) id 
      or a real tuple id if the entry is in a leaf node.

      The main methods for the REntry class includes those that compares
      keys and such. Most of Key related methods has already been 
      implemented in our GRect class so no reinventing the wheel here.

      Note that this class is the in-memory representation of an RTree
      entry; before the entry goes to a disk, it has to be pack()'ed.
      Similarly the unpack() function should be used when a node page
      just loaded into memory.
      
*/
class REntry 
{	
    friend	class REntryPool;
    
    //core stuff
    RKey		_key;	//the key part
    RPtr		ptr;	//the pointer part
    
    //in-memory stuff
    int			_level;	//level of the rtree where this entry resides

    REntry		*next; //for preallocated entry pool stuff 
    
public:
    ///
    NOP			REntry() : _level(-1),next(0) {};
    ///
    NOP			REntry( RKey k, RPtr p, int l) 
	                        : _key(k), ptr(p), _level(l){};
    ///
    virtual NOP		~REntry();
    ///
    virtual REntry& 	operator= (const REntry& a) ;
    ///
    virtual void	init() ;
    ///
    void * 		operator new(size_t);
    ///
    void  		operator delete(void* ep, size_t);
    ///
    friend ostream&	operator<<(ostream& os, const REntry& e);

    //====================================================
    //====
    // GROUP:  predicates relatd emethods
    //====
    //====================================================

    ///
    // general comparison method
    //
    virtual int		cmp 	   (const REntry& other) const;
    ///
    // compare two entries based on their (key's) hilbert order
    //
    virtual int		hCmp	   (const REntry& other) const;
    
    ///
    // check whether this key satisfies the predicate.
    //
    virtual bool	consistent (const RPred& pred);

    virtual int		equal 	   (const REntry& other) const;
    ///
    // check whether the two keys are the same
    //
    virtual bool 	operator== (const REntry& other);
    ///
    // check whether this key overlaps/intersects the "other" entry
    //
    virtual bool	overlaps   (const REntry& other) const ;
    ///
    // check whether this entry contains/covers the "other" entry
    //
    virtual bool	contains   (const REntry& other) const;
    ///
    // check whether this entry is inside the "other" entry
    //
    virtual bool	isInside   (const REntry& other) const;

    ///
    // calculate the penalty of inserting a new entry
    //
    virtual RPenalty	penalty	(const REntry& other) const;

    //====================================================
    //====
    // GROUP:  pack/unpack methods
    //====
    //====================================================
    
    ///
    // pack the data member into a pipe (which 
    // can be stored onto disk pages)
    //
    virtual Result	pack	(DataPipe& p);
    ///
    // unpack/restore the data member out of a pipe
    //
    virtual Result	unpack  (DataPipe& p);
    ///
    // return the persistent (packed) size of an entry
    // this should be a fixed size for current implementation
    //
    virtual int		getPSize();
    
    //====================================================
    //====
    // GROUP:  other handy methods
    //====
    //====================================================

    ///
    // return the hilbert order of the entry
    //
    long		hOrder    () const { return 0; /*bogus*/ }    
    ///
    // return the  key (the bounding box)
    //
    const RKey&		key       () const {return _key; }
    ///
    void		setKey	  (const GRect& r) {_key=r; }
    ///
    void		setKey	  (Coord xl, Coord yl, 
				   Coord xh, Coord yh) {
	                                     _key.set(xl, yl, xh, yh);}
    ///
    RPtr&		pointer	 () const { return (RPtr&) ptr; };
    ///
    void		setPointer (const RPtr& p) {ptr = p; }
    ///
    int			level      () const {return _level; }    
    ///
    void		setLevel  (int l) {_level = l; ptr.setLeaf(l==0?1:0); }
    ///
    void		setLeaf (bool t)  {ptr.setLeaf(t); };
    
    
};



// below is a dirty hack for two types of stacks; 
// they really ought to be two instances of same stack template.
// will modify to use <STL> soon... 


/**
 * @internal 
 * the stack class for RTree pointers; for keeping the path
 */
class RPtrStk
{
public:
    enum {  MAX_STK_SZ = 16 };	// 16 ought be enough

private:
    RPtr		_stk[MAX_STK_SZ];
    short		_top;
    
public:
    NOP			RPtrStk() :_top(0) {};
    NOP			~RPtrStk() {};
    inline RPtrStk&	operator=(const RPtrStk& t);

    inline void		push(const RPtr& p);    
    inline RPtr&	pop();
    inline RPtr&	top();
    inline RPtr&	second();
    inline RPtr&	bottom();

    inline void		updateTop(const RPtr& p);
    
    inline short	size()   {return _top; }
    inline bool		isFull() { return _top >= MAX_STK_SZ; }
    inline bool		isEmpty(){ return _top == 0; }

    inline void		reset()  { _top = 0; }
    
    friend ostream&	operator<<(ostream& os, const RPtrStk& t);
};

inline void 	RPtrStk::push(const RPtr& ptr)
{
    if(isFull()) {
	msgWarn("RTree Stack overflow!");
	abort();
    }

    _stk[_top++] = ptr;
}
    
inline RPtr&	RPtrStk::pop()
{
    GAssert(!isEmpty());
    return _stk[--_top];
}
    
inline RPtr&	RPtrStk::top()
{
    GAssert(!isEmpty()) ;
    return _stk[_top-1];
}

inline RPtr&	RPtrStk::second()
{
    GAssert(_top > 1);
    return _stk[_top-2];
}

inline RPtr&	RPtrStk::bottom()
{
    GAssert(! isEmpty());
    return _stk[0];
}

inline void	RPtrStk::updateTop(const RPtr& p)
{
    GAssert(! isEmpty());
    _stk[_top-1] = p;
}

inline RPtrStk&	RPtrStk::operator=(const RPtrStk& t)
{
    _top = t._top;
    memcpy((char*)_stk, (char*)&t._stk, sizeof(RPtr)*MAX_STK_SZ);

    return *this;
}


////////////////
// the stack class for RTree entries; used during search
//
/**
 * @internal
 */
class REntryStk
{
public:
    enum {  MAX_STK_SZ = 1024 };	// an arbitrary limit

private:
    REntry		_stk[MAX_STK_SZ];
    short		_top;
    
public:
    NOP			REntryStk() :_top(0) {};
    NOP			~REntryStk() {};
    inline REntryStk&	operator=(const REntryStk& t);

    inline void		push(const REntry& p);    
    inline REntry&	pop();
    inline REntry&	top();
    inline REntry&	second();
    inline REntry&	bottom();

    inline void		updateTop(const REntry& p);
    
    inline short	size()   {return _top; }
    inline bool		isFull() { return _top >= MAX_STK_SZ; }
    inline bool		isEmpty(){ return _top == 0; }

    inline void		reset()  { _top = 0; }
    
    friend ostream&	operator<<(ostream& os, const REntryStk& t);
};

inline void 	REntryStk::push(const REntry& ptr)
{
    if(isFull()) {
	msgWarn("RTree Stack overflow!");
	abort();
    }

    _stk[_top++] = ptr;
}
    
inline REntry&	REntryStk::pop()
{
    GAssert(!isEmpty());
    return _stk[--_top];
}
    
inline REntry&	REntryStk::top()
{
    GAssert(!isEmpty()) ;
    return _stk[_top-1];
}

inline REntry&	REntryStk::second()
{
    GAssert(_top > 1);
    return _stk[_top-2];
}

inline REntry&	REntryStk::bottom()
{
    GAssert(! isEmpty());
    return _stk[0];
}

inline void	REntryStk::updateTop(const REntry& p)
{
    GAssert(! isEmpty());
    _stk[_top-1] = p;
}

inline REntryStk&	REntryStk::operator=(const REntryStk& t)
{
    _top = t._top;
    memcpy((char*)_stk, (char*)&t._stk, sizeof(REntry)*MAX_STK_SZ);

    return *this;
}





/**
  @internal

  REntryPool --

DESCRIPTION

     THis class manages a pool of RTree entries. This is meant to speed up
     the allocation/freeing of individual entries. The pool is 
     extended with POOL_DELTA  of entries each time.
     It is a globaly shared pool. *No mutex has been placed to protect it.*

*/
class REntryPool
{
    enum {POOL_DELTA = 400};
    
    static int 	  	n_total;
    static int	  	n_free;
    static REntry*   	pool;
    
public:
    
    ///
    // allocate an entry record from the pool
    static REntry* 	allocEntry();
    ///
    // free an entry record and put it back to the pool
    static void		freeEntry(REntry* ep);
    ///
    // extend the capacity of the pool w/ 'incr' of new episodes
    static Result	extendPool(int incr=POOL_DELTA);
    ///
    // free all entry; vacate the pool
    static void		freeAll();
    
    static void		stats (){
	                              cout<<"total rtree entries allocated: "
					  <<n_total<<", free rtree entries: "
					  <<n_free<<endl; 
                        }
};
        

#endif





Documentation generated by lqian@lqian-sun on Wed Jul 14 09:36:10 EDT 1999