/****************************************************************************
 *   datapipe.h : 
 *   	
 *	HEader file for data pipe class.
 *	
 *   Change Log :
 *		  July-12 1997 Initial version,  Liujian Qian
 *
 *   $Id: gdatapipe.h,v 1.6 1999/02/03 06:45:00 qian Exp $
 ***************************************************************************/

#ifndef _DATA_PIPE_H_
#define _DATA_PIPE_H_

#include <string.h>
#include "gcxx.h"


/**
      DataPipe maintains an extensible in-memory binary data stream.

      This class can be used as a <b> dynamic array </b> or a pipeline
      stream for serializing classes' persistent data members.  

      The central information about  the pipe is the 'cursor', which
      indicates the current position where subsequent methods such as
      <b> append </b>, and <b> fetch </b> will start. Such methods
      will  reposition the cursor accordingly upon the completion of
      the operation. Other important data members of DataPipe includes
      the "size" of the data in the pipe and the "ptr" to the location
      wehre the data is stored in memory.

      Every ADT in GFC defines at least two methods to store/retrive persistent
      member data into and out of a pipe. They are the <b> store </b>
      method and the <b> load </b> method. Additionaly there are two
      global operators "DataPipe<<" and "DataPipe>>" for each ADT which  can 
      be used handy when pumping  several ADT  objects into the same pipe.  
            

      Some sample use:
      <pre>
      GPolygon poly1;
      GRect rect1;
      
      ... do some thing on poly1  and rect1 ...
      
      DataPipe p;
      p << poly1 <<rect1;

      db.create_record(p.ptr(), p.size());  //store into the database

      DataPipe also accepts standard built-in types such as int, float,
      char* etc. Here is another example:

      DataPipe p1;
      int 	x=100, y=200;
      float 	dist = 1000;
      char	*name = "Pittsburgh";
      p1 <<x << y << dist << name;

      DataPipe p2 (p);
      p2 >> x2 >> y2 >> dist2 >> name2;
      ...
      
      </pre>

TODO
      Make DataPipe be able to redirect to i/o streams.

*/
class DataPipe 
{    
    friend	class GSlab;
    friend	class GRasterIO;
    
    int 	cur;		//cursor
    int 	_capacity;       
    int 	data_len;	//actual length been used
    bool	attached;	//1 if the udp is attached to an external ptr
    char* 	udp;
    
    enum {delta=512};
    
public:
    
    /**
     * seek directions
     */
    enum seek_dir {BEGIN=0, END=1, CURRENT=2};

public:			

    /**
     */
    DataPipe() : cur(0),_capacity(0),data_len(0),attached(0),udp(0){};
    /**
     */
    DataPipe(int len);
    /**
     */
    DataPipe(const DataPipe& a);

    /**
     */
    DataPipe(const char* d, int length);

    /**
     */
    virtual ~DataPipe();

    /**
     * asignment operator
     */
    virtual DataPipe& 	operator= (const DataPipe& a); 
    
public:   

    /**
     * This method appends data to the pipe.
     * append new data to the end of the existing data buffer
     * and advance cursor. The buffer in the pipe get automatically
     * expanded if length is greater than available space in pipe.
     * @param	data	 is the data to be add to the pipe
     * 		length   the size of the new data
     */
    Result 		append(const char* data, int length);  

    /** 
     * insert a chunk of data at the beginning of the pipe.
     * New data is always put in the position 0 of the internal buffer.
     * Existing data gets shifted to the tail by "length". 
     */
    Result 		insert(const char* data, int length);  

    /**
     * copy a chunk of data starting at cursor into 'dest';
     * the cursor in the pipe is advanced accordingly 
     */
    Result 		fetch(char* dest, int length);

    /**
     * attach this pipe to a  pointer
     */
    Result 		attach(void* p, int space);
    /**
     * detach the previously attached pointer
     */
    Result 		detach(void);
    /**
     * extend the capacity for the pipe to the 'new_capacity'. Old
     * contents are preserved.
     */
    Result 		extendTo(int new_capacity);    

    /**
     * move the cursor to the specified position
     */
    Result 	        seek(int off, int dir=BEGIN);
    /**
     * return the position (beginning with 0) of the cursor 
     */
    int		        pos (void) {return cur; };
    /**
     * return the pointer at cursor
     */
    inline char*  	cursor(void) const   {
	                            return (cur>=data_len && 
					    data_len>0)?
						 (char*)0 : 
						 (char*)(udp+cur); 
                                    }
    /**
     * memset all data to zeros;  keep the capacity intact; 
     * reset cursor to 0
     */
    inline void   	recycle();


    /**
     * return the pointer to the beginning of the data
     */
    inline char*        ptr(void) const {return (char*)udp; }
    /**
     * type conversiion operator; 
     */
    operator 		char*()   { return (char*)udp;  }
    /**
     * const char* conversion 
     */
    operator 		const char*() {return (const char*)udp; }    
    /**
     * return true if reached end of pipe (eop)
     */
    inline bool   	eop(void) const {return cur>=data_len;} ;
    /**
     * return the data size 
     */
    inline int    	size(void) const  {return data_len; }
    /**
     * return the capacity
     */
    inline int    	capacity(void) {return _capacity;}
    /**
     * reutrn free space in the array
     */
    inline int    	remainder(void) const  {return _capacity-data_len;}
    /**
     * print the data pipe
     */
    friend ostream& 	operator<<(ostream& s, const DataPipe& p);
    
private:
    /** 
     * increase the capacity by incr_sz. Negative 
     * increment is ignored.
     */
    Result 		extend(int incr_sz=delta);

    void   		setDataLen (int l) {data_len = l; }
    
};

inline void
DataPipe::recycle() 
{ 
    if(udp) 
	memset(udp, 0, _capacity); 
    data_len = cur =0;
}
    

extern DataPipe& operator<< (DataPipe& s, const char& c);
extern DataPipe& operator<< (DataPipe& s, const unsigned char&  c);
extern DataPipe& operator<< (DataPipe& s, const int& i);
extern DataPipe& operator<< (DataPipe& s, const short& t);
extern DataPipe& operator<< (DataPipe& s, const long& i);
extern DataPipe& operator<< (DataPipe& s, const unsigned int& i);
extern DataPipe& operator<< (DataPipe& s, const unsigned short& t);
extern DataPipe& operator<< (DataPipe& s, const unsigned long& i);
extern DataPipe& operator<< (DataPipe& s, const float& f);
extern DataPipe& operator<< (DataPipe& s, const double& d);
extern DataPipe& operator<< (DataPipe& s, const char* string);
#ifndef _WIN32
extern DataPipe& operator<< (DataPipe& s, const int64& i);
#endif

extern DataPipe& operator>> (DataPipe& s,  char& c);
extern DataPipe& operator>> (DataPipe& s,  unsigned char&  c);
extern DataPipe& operator>> (DataPipe& s,  int& i);
extern DataPipe& operator>> (DataPipe& s,  short& t);
extern DataPipe& operator>> (DataPipe& s,  long& i);
extern DataPipe& operator>> (DataPipe& s,  unsigned int& i);
extern DataPipe& operator>> (DataPipe& s,  unsigned short& t);
extern DataPipe& operator>> (DataPipe& s,  unsigned long& i);
extern DataPipe& operator>> (DataPipe& s,  float& f);
extern DataPipe& operator>> (DataPipe& s,  double& d);
extern DataPipe& operator>> (DataPipe& s,  char* string);
#ifndef _WIN32
extern DataPipe& operator>> (DataPipe& s,  int64& i);
#endif


#endif






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