/*
This product contains certain software code or other information
("AT&T Software") proprietary to AT&T Corp. ("AT&T").  The AT&T
Software is provided to you "AS IS".  YOU ASSUME TOTAL RESPONSIBILITY
AND RISK FOR USE OF THE AT&T SOFTWARE.  AT&T DOES NOT MAKE, AND
EXPRESSLY DISCLAIMS, ANY EXPRESS OR IMPLIED WARRANTIES OF ANY KIND
WHATSOEVER, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, WARRANTIES OF
TITLE OR NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS, ANY
WARRANTIES ARISING BY USAGE OF TRADE, COURSE OF DEALING OR COURSE OF
PERFORMANCE, OR ANY WARRANTY THAT THE AT&T SOFTWARE IS "ERROR FREE" OR
WILL MEET YOUR REQUIREMENTS.

Unless you accept a license to use the AT&T Software, you shall not
reverse compile, disassemble or otherwise reverse engineer this
product to ascertain the source code for any AT&T Software.

(c) AT&T Corp. All rights reserved.  AT&T is a registered trademark of AT&T Corp.

***********************************************************************

History:

      24/11/99  - initial release by Hartmut Liefke, liefke@seas.upenn.edu
                                     Dan Suciu,      suciu@research.att.com
*/
// This module contains the memory streamer class
// The memory streamer represents a sequence of memory blocks
// that grows over time. The blocks at the beginning are small, while
// later, larger blocks are allocated.
// The memory streamer is the core of the container implementation

#pragma once

#include "XMillData.h"

#define BLOCKSIZE_IDXNUM 16

class Session;

struct MemStreamBlock
   // Defines one single data block
{
   MemStreamBlock *next;            // The next data block of the same streamer
   unsigned long  blocksize:28;     // The size of this block
   unsigned long  blocksizeidxidx:4;// The block size index (i.e. the index within blocksizeidxs)
   unsigned long  cursize;          // The current number of bytes in this block

//   MemStreamBlock *myprev,*mynext;   // Previous and next block
//   unsigned long  idx;

   char           data[1];       // The first byte of the data
                                 // (The other data comes DIRECTLY afterwards)
};

struct MemStreamMarker
   // Represents a marker in the memory stream
   // Markers are used so that everything appended to the Streamer
   // after the marker can be deleted
   // Several markers can exist in the Streamer and they are
   // in backwards references in a single-chained list.
{
   MemStreamBlock    *block;  // The block of the previous marker,
   MemStreamMarker   *pos;    // The pointer to the previous marker
                              // The pointers are NULL, if there is no previous marker
};

class MemStreamer
{
	Session *session;
   MemStreamBlock    *firstblock;         // The first block of the streamer
   MemStreamBlock    *curblock;           // The current block, which is also the last block
   unsigned long     overallsize:28;      // The overall size of the memory streamer
   unsigned long     curblocksizeidxidx:4;
   MemStreamMarker   curmarker;           // The position of the current marker is stored here
                                          // If there is no marker, then both pointers are NULL

   void ReleaseBlock(MemStreamBlock *block);
      // Releases the block from the mem streamer
      // Typically, this is the last block in the chain - but it could
      // also be in the middle

   MemStreamBlock *AllocateNewBlock();
      // Allocates a new block
      // The size is determined by the next index in blocksizeidxs

public:
   MemStreamer(Session *s=NULL,unsigned long firstblocksizeidx=0);
   ~MemStreamer();

   void Initialize(Session *s,unsigned long firstblocksizeidx=0);
      // Initializes the memstreamer and sets the first block index step

   void *operator new(size_t size, MemStreamer *mem);
   void operator delete(void *ptr);

	int GetSize();
   MemStreamBlock *GetFirstBlock();

   void WordAlign();
      // Allocated 1 to 3 bytes to align the current memory pointer
      // to an address divisible by 4.

   char *GetByteBlock(unsigned len);
      // The main function for allocated more memory of size 'len'.
      // The function checks the current block and if there is not enough space,
      // the function 'AllocateNewBlock' is called.

	char *ClearBlock(char *data, unsigned len);

	void ReleaseByteBlock(unsigned len);
      // Removes 'len' bytes from the current block

//******************************************************************************

   void StoreData(char *data,unsigned len);
      // Stores the a sequence of bytes in the memory streamer
      // The bytes can be distributed over many blocks

	// The following auxiliary methods allow the easy storage of simple data values
   void StoreChar(unsigned char c);
      // Stores one single character

   void StoreCompressedUInt(unsigned long val,unsigned char offs=0);
      // Stores a compressed unsigned integer
      // The values below the offset threshold are reserved for other use.
      // Hence, the offset is basically added to 'val'.
      // The offset *must* be smaller than 128

	void StoreCompressedSInt(char isneg,unsigned long val);
      // Stores a signed integer in compressed format
      // The sign is in 'isneg' and 'val' is the basis

   void StoreCompressedSInt(long val);
      // Stores a signed integer in compressed format

   void StoreUInt32(unsigned long val);
      // Stores a unsigned integer in compressed format

   void StoreSInt32(char isneg,unsigned long val);
      // Stores a signed integer in compressed format

//**********************************************************************************

   void StartNewMemBlock();
      // Creates a new marker on the memory streamer

   void RemoveLastMemBlock();
      // Removes a the data up to the last memory marker

   void ReleaseMemory(unsigned long firstblocksizeidx);
      // Releases the entire memory of the memstreamer
};
