// mk4.h --
// $Id: mk4.h,v 1.39 2004/01/26 09:54:45 jcw Exp $
// This is part of Metakit, see http://www.equi4.com/metakit/

/** @file
* Main Metakit library include file
*/

#ifndef __MK4_H__
#define __MK4_H__

//---------------------------------------------------------------------------
//
//  TITLE
//
//      The Metakit Library, by Jean-Claude Wippler, Equi4 Software, NL.
//
//  DESCRIPTION
//
//      Structured data storage with commit / rollback and on-demand loading.
//
//  ACKNOWLEDGEMENTS
//
//      To Liesbeth and Myra, for making this possible.
//
//---------------------------------------------------------------------------
//
//  NAMING CONVENTIONS        PREFIX    REMARKS
//
//      Compile time options    q4_     Always defined as 1 or 0, capitalized
//      Preprocessor defines    d4_     Use with "#ifdef" or "#if defined()"
//      Classes                 c4_     Classes, listed at start of headers
//      Typedefs                t4_     Type definitions, if outside classes
//      Global functions        f4_     Internal, these are rarely defined
//
//      Member functions                Start in uppercase
//      Instance variables      _       And start in lowercase
//      Static members          _       And start in uppercase
//
//      Local variable names            Start in lowercase
//      Formal parameter names          Start lowercase, end with underscore
//
//---------------------------------------------------------------------------

   /// Current release = 100 * major + 10 * minor + maintenance
#define d4_MetakitLibraryVersion 249    // 2.4.9.3 release, Jan 26, 2004
#define d4_MetaKitLibraryVersion d4_MetakitLibraryVersion // compat, yuck

//---------------------------------------------------------------------------
// Declarations in this file

   class c4_View;                      // a view on underlying data
   class c4_Cursor;                    // an index into a view
   class c4_RowRef;                    // a reference to a row
       class c4_Row;                   // one row in a view
   class c4_Bytes;                     // used to pass around generic data
   class c4_Storage;                   // manages view persistence
   class c4_CustomViewer;              // used for customizable views
   class c4_Stream;                    // abstract stream class
   class c4_Strategy;                  // system and file interface

   class c4_Property;                  // for access inside rows
       class c4_IntProp;
       class c4_LongProp;
       class c4_FloatProp;
       class c4_DoubleProp;
       class c4_StringProp;
       class c4_BytesProp;
       class c4_ViewProp;

   // Everything below is part of the implementation, not for public use

   class c4_Sequence;                  // a collection of rows

   class c4_Reference;                 // refers to the actual data values
       class c4_IntRef;
       class c4_LongRef;
       class c4_FloatRef;
       class c4_DoubleRef;
       class c4_BytesRef;
       class c4_StringRef;
       class c4_ViewRef;

   class c4_Dependencies;              // not defined here
   class c4_Handler;                   // not defined here
   class c4_Notifier;                  // not defined here
   class c4_Persist;                   // not defined here

//---------------------------------------------------------------------------

   // determine whether we need to include "mk4dll.h" to link as DLL
#if defined (MKDLL_EXPORTS) && !defined (q4_KITDLL)
#define q4_KITDLL 1
#endif

   // omit floats and doubles in small model 16-bit Intel builds
#if defined (_DOS) && defined (_M_I86SM) && !defined (q4_TINY)
#define q4_TINY 1
#endif

   // and here's the other end of the scale...
#if !defined (_WIN32) && !defined (q4_LONG64)
#if defined (_PA_RISC2_0) || defined (__powerpc64__) || defined(__sparcv9) || \
   defined (__x86_64__) || defined (__s390x__) || defined (__alpha) || \
   (defined (__ia64) && (!defined (__HP_aCC) || defined(__LP64__)))
#define q4_LONG64 1
#endif
#endif

   // default to inlining for maximum performance
#if !defined (q4_INLINE)
#define q4_INLINE 1
#endif

//---------------------------------------------------------------------------

   // Borland C++ and C++ Builder
#if defined (__BORLANDC__)
   // by default, if runtime is linked as a DLL, then so is Metakit
#if defined (_RTLDLL) && !defined (q4_KITDLL)
#define q4_KITDLL 1
#endif

   // Borland 5.0 supports the bool datatype
#if __BORLANDC__ >= 0x500
#define q4_BOOL 1
#endif
#endif // __BORLANDC__

   // IRIX supports the bool datatype
   // define before gcc to cover both the gcc and MipsPRO compiler
#if defined (sgi)
#define q4_BOOL 1
#undef bool
#undef true
#undef false
#endif

   // GNU gcc/egcs
#if defined (__GNUC__)
#ifndef q4_BOOL
#define q4_BOOL 1
#endif
#ifndef HAVE_LONG_LONG
#define HAVE_LONG_LONG 1
#endif
#endif

   // HP aCC
#if defined (__HP_aCC)
#ifndef HAVE_LONG_LONG
#define HAVE_LONG_LONG 1
#endif
#endif

   // Metrowerks CodeWarrior
#if defined (__MWERKS__)
#if __option(bool)
#define q4_BOOL 1       // bool datatype is optionally supported
   // undef, these conflict with c4_Storage::c4_Storage overloading
#undef bool
#undef true
#undef false
#endif
#endif

   // Microsoft Visual C++
#if defined (_MSC_VER)
   // MSVC 5.0 supports the bool datatype, MSVC 4.x has no namespaces
#if _MSC_VER >= 1100
#define q4_BOOL 1
#define LONG_LONG __int64
#else
#define q4_NO_NS 1
#endif

   // a kludge to avoid having to use ugly DLL exprt defs in this header
#pragma warning(disable: 4273) // inconsistent dll linkage
#endif // _MSC_VER

//---------------------------------------------------------------------------
// Other definitions needed by the public Metakit library header files

#if !q4_BOOL && !q4_STD         // define a bool datatype
#define false 0
#define true 1
#define bool int
#endif

#if q4_KITDLL                   // add declaration specifiers
#include "mk4dll.h"
#endif

#if q4_INLINE                   // enable inline expansion
#define d4_inline inline
#else
#define d4_inline
#endif

typedef unsigned char t4_byte;  // create typedefs for t4_byte, etc.

#if q4_LONG64
typedef int t4_i32;             // if longs are 64b, then int must be 32b
#else
typedef long t4_i32;            // if longs aren't 64b, then they are 32b
#endif

#if q4_LONG64           // choose a way to represent 64b integers
typedef long t4_i64;
#elif defined (LONG_LONG)
typedef LONG_LONG t4_i64;
#elif HAVE_LONG_LONG
typedef long long t4_i64;
#else
struct t4_i64 { long l1; long l2; };
bool operator== (const t4_i64 a_, const t4_i64 b_);
bool operator< (const t4_i64 a_, const t4_i64 b_);
#endif

//---------------------------------------------------------------------------

class c4_View
{
protected:
 c4_Sequence* _seq;

public:
/* Construction / destruction / assignment */
 c4_View (c4_Sequence* =0);
 c4_View (c4_CustomViewer*);
 c4_View (c4_Stream*);
 c4_View (const c4_Property& property_);
 c4_View (const c4_View&);
 ~c4_View ();

 c4_View& operator= (const c4_View&);
 c4_Persist* Persist() const; // added 16-11-2000 to simplify c4_Storage

/* Getting / setting the number of rows */
 int GetSize() const;
 void SetSize(int, int =-1);

 void RemoveAll();

/*: Getting / setting individual elements */
 c4_RowRef GetAt(int) const;
 c4_RowRef operator[] (int) const;

 void SetAt(int, const c4_RowRef&);
 c4_RowRef ElementAt(int);

 bool GetItem(int, int, c4_Bytes&) const;
 void SetItem(int, int, const c4_Bytes&) const;

/* These can increase the number of rows */
 void SetAtGrow(int, const c4_RowRef&);
 int Add(const c4_RowRef&);

/* Insertion / deletion of rows */
 void InsertAt(int, const c4_RowRef&, int =1);
 void RemoveAt(int, int =1);
 void InsertAt(int, const c4_View&);

 bool IsCompatibleWith(const c4_View&) const;
 void RelocateRows(int, int, c4_View&, int);

/* Dealing with the properties of this view */
 int NumProperties() const;
 const c4_Property& NthProperty(int) const;
 int FindProperty(int);
 int FindPropIndexByName(const char*) const;
 c4_View Duplicate() const;
 c4_View Clone() const;
 int AddProperty(const c4_Property&);
 c4_View operator, (const c4_Property&) const;

 const char* Description() const;

/* Derived views */
 c4_View Sort() const;
 c4_View SortOn(const c4_View&) const;
 c4_View SortOnReverse(const c4_View&, const c4_View&) const;

 c4_View Select(const c4_RowRef&) const;
 c4_View SelectRange(const c4_RowRef&, const c4_RowRef&) const;

 c4_View Project(const c4_View&) const;
 c4_View ProjectWithout(const c4_View&) const;

 int GetIndexOf(const c4_RowRef&) const;
 int RestrictSearch(const c4_RowRef&, int&, int&);

/* Custom views */
 c4_View Slice(int, int =-1, int =1) const;
 c4_View Product(const c4_View&) const;
 c4_View RemapWith(const c4_View&) const;
 c4_View Pair(const c4_View&) const;
 c4_View Concat(const c4_View&) const;
 c4_View Rename(const c4_Property&, const c4_Property&) const;

 c4_View GroupBy(const c4_View&, const c4_ViewProp&) const;
 c4_View Counts(const c4_View&, const c4_IntProp&) const;
 c4_View Unique() const;

 c4_View Union(const c4_View&) const;
 c4_View Intersect(const c4_View&) const;
 c4_View Different(const c4_View&) const;
 c4_View Minus(const c4_View&) const;

 c4_View JoinProp(const c4_ViewProp&, bool =false) const;
 c4_View Join(const c4_View&, const c4_View&, bool =false) const;

 c4_View ReadOnly() const;
 c4_View Hash(const c4_View&, int =1) const;
 c4_View Blocked() const;
 c4_View Ordered(int =1) const;
 c4_View Indexed(const c4_View&, const c4_View&, bool =false) const;

/* Searching */
 int Find(const c4_RowRef&, int =0) const;
 int Search(const c4_RowRef&) const;
 int Locate(const c4_RowRef&, int* =0) const;

/* Comparing view contents */
 int Compare(const c4_View&) const;

 friend bool operator== (const c4_View&, const c4_View&);
 friend bool operator!= (const c4_View&, const c4_View&);
 friend bool operator< (const c4_View&, const c4_View&);
 friend bool operator> (const c4_View&, const c4_View&);
 friend bool operator<= (const c4_View&, const c4_View&);
 friend bool operator>= (const c4_View&, const c4_View&);

protected:
 void _IncSeqRef();
 void _DecSeqRef();

     /// View references are allowed to peek inside view objects
 friend class c4_ViewRef;

 // DROPPED: Structure() const;
 // DROPPED: Description(const c4_View& view_);
};

//---------------------------------------------------------------------------

#if defined(os_aix) && defined(compiler_ibmcxx) && (compiler_ibmcxx > 500)
 bool operator== (const c4_RowRef& a_, const c4_RowRef& b_);
 bool operator!= (const c4_RowRef& a_, const c4_RowRef& b_);
 bool operator<= (const c4_RowRef& a_, const c4_RowRef& b_);
 bool operator>= (const c4_RowRef& a_, const c4_RowRef& b_);
 bool operator> (const c4_RowRef& a_, const c4_RowRef& b_);
 bool operator< (const c4_RowRef& a_, const c4_RowRef& b_);
#endif

class c4_Cursor
{
public:
     /// Pointer to the sequence
 c4_Sequence* _seq;
     /// Current index into the sequence
 int _index;

/* Construction / destruction / dereferencing */
     /// Construct a new cursor
 c4_Cursor (c4_Sequence&, int);

     /// Dereference this cursor to "almost" a row
 c4_RowRef operator* () const;

     /// This is the same as *(cursor + offset)
 c4_RowRef operator[] (int) const;

/* Stepping the iterator forwards / backwards */
     /// Pre-increment the cursor
 c4_Cursor& operator++ ();
     /// Post-increment the cursor
 c4_Cursor operator++ (int);
     /// Pre-decrement the cursor
 c4_Cursor& operator-- ();
     /// Post-decrement the cursor
 c4_Cursor operator-- (int);

     /// Advance by a given offset
 c4_Cursor& operator+= (int);
     /// Back up by a given offset
 c4_Cursor& operator-= (int);

     /// Subtract a specified offset
 c4_Cursor operator- (int) const;
     /// Return the distance between two cursors
 int operator- (c4_Cursor) const;

     /// Add specified offset
 friend c4_Cursor operator+ (c4_Cursor, int);
     /// Add specified offset to cursor
 friend c4_Cursor operator+ (int, c4_Cursor);

/* Comparing row positions */
     /// Return true if both cursors are equal
 friend bool operator== (c4_Cursor, c4_Cursor);
     /// Return true if both cursors are not equal
 friend bool operator!= (c4_Cursor, c4_Cursor);
     /// True if first cursor is less than second cursor
 friend bool operator< (c4_Cursor, c4_Cursor);
     /// True if first cursor is greater than second cursor
 friend bool operator> (c4_Cursor, c4_Cursor);
     /// True if first cursor is less or equal to second cursor
 friend bool operator<= (c4_Cursor, c4_Cursor);
     /// True if first cursor is greater or equal to second cursor
 friend bool operator>= (c4_Cursor, c4_Cursor);

/* Comparing row contents */
     /// Return true if the contents of both rows are equal
 friend bool operator== (const c4_RowRef&, const c4_RowRef&);
     /// Return true if the contents of both rows are not equal
 friend bool operator!= (const c4_RowRef&, const c4_RowRef&);
     /// True if first row is less than second row
 friend bool operator< (const c4_RowRef&, const c4_RowRef&);
     /// True if first row is greater than second row
 friend bool operator> (const c4_RowRef&, const c4_RowRef&);
     /// True if first row is less or equal to second row
 friend bool operator<= (const c4_RowRef&, const c4_RowRef&);
     /// True if first row is greater or equal to second row
 friend bool operator>= (const c4_RowRef&, const c4_RowRef&);
};

//---------------------------------------------------------------------------

class c4_RowRef
{
     /// A row reference is a cursor in disguise
 c4_Cursor _cursor;

public:
/* General operations */
     /// Assign the value of another row to this one
 c4_RowRef operator= (const c4_RowRef&);
     /// Return the cursor associated to this row
 c4_Cursor operator& () const;
     /// Return the underlying container view
 c4_View Container() const;

protected:
     /// Constructor, not for general use
 c4_RowRef (c4_Cursor);

 friend class c4_Cursor;
 friend class c4_Row;
};

//---------------------------------------------------------------------------
/// An entry in a collection with copy semantics.
//
//  Rows can exist by themselves and as contents of views.  Row assignment
//  implies that a copy of the contents of the originating row is made.
//
//  A row is implemented as an unattached view with exactly one element.

class c4_Row : public c4_RowRef
{
public:
     /// Construct a row with no properties
 c4_Row ();
     /// Construct a row from another one
 c4_Row (const c4_Row&);
     /// Construct a row copy from a row reference
 c4_Row (const c4_RowRef&);
     /// Destructor
 ~c4_Row ();

     /// Assign a copy of another row to this one
 c4_Row& operator= (const c4_Row&);
     /// Copy another row to this one
 c4_Row& operator= (const c4_RowRef&);

     /// Add all properties and values into this row
 void ConcatRow(const c4_RowRef&);
     /// Return a new row which is the concatenation of two others
 friend c4_Row operator+ (const c4_RowRef&, const c4_RowRef&);

private:
 static c4_Cursor Allocate();
 static void Release(c4_Cursor);
};

//---------------------------------------------------------------------------

class c4_Bytes
{
 union {
   t4_byte _buffer [16];
   double _aligner; // on a Sparc, the int below wasn't enough...
 };

 t4_byte* _contents;
 int _size;
 bool _copy;

public:
 c4_Bytes ();
 c4_Bytes (const void*, int);
 c4_Bytes (const void*, int, bool);
 c4_Bytes (const c4_Bytes&);
 ~c4_Bytes ();

 c4_Bytes& operator= (const c4_Bytes&);
 void Swap(c4_Bytes&);

 int Size() const;
 const t4_byte* Contents() const;

 t4_byte* SetBuffer(int);
 t4_byte* SetBufferClear(int);

 friend bool operator== (const c4_Bytes&, const c4_Bytes&);
 friend bool operator!= (const c4_Bytes&, const c4_Bytes&);

private:
 void _MakeCopy();
 void _LoseCopy();
};

//---------------------------------------------------------------------------

class c4_Storage : public c4_View
{
public:
     /// Construct streaming-only storage object
 c4_Storage ();
     /// Construct a storage using the specified strategy handler
 c4_Storage (c4_Strategy&, bool =false, int =1);
     /// Construct a storage object, keeping the current structure
 c4_Storage (const char*, int);
     /// Reconstruct a storage object from a suitable view
 c4_Storage (const c4_View&);
     /// Destructor, usually closes file, but does not commit by default
 ~c4_Storage ();

 void SetStructure(const char*);
 bool AutoCommit(bool =true);
 c4_Strategy& Strategy() const;
 const char* Description(const char* =0);

 bool SetAside(c4_Storage&);
 c4_Storage* GetAside() const;

 bool Commit(bool =false);
 bool Rollback(bool =false);

 c4_ViewRef View(const char*);
 c4_View GetAs(const char*);

 bool LoadFrom(c4_Stream&);
 void SaveTo(c4_Stream&);

 //DROPPED: c4_Storage (const char* filename_, const char* description_);
 //DROPPED: c4_View Store(const char* name_, const c4_View& view_);
 //DROPPED: c4_HandlerSeq& RootTable() const;
 //DROPPED: c4_RowRef xContents() const;

private:
 void Initialize(c4_Strategy&, bool, int);
};

//---------------------------------------------------------------------------

class c4_Property
{
 short _id;
 char _type;

public:
     /// Construct a new property with the give type and id
 c4_Property (char, int);
     /// Construct a new property with the give type and name
 c4_Property (char, const char*);
 ~c4_Property ();

 c4_Property (const c4_Property&);
 void operator= (const c4_Property&);

 const char* Name() const;
 char Type() const;

 int GetId() const;

 c4_Reference operator() (const c4_RowRef&) const;

 void Refs(int) const;

 c4_View operator, (const c4_Property&) const;

 static void CleanupInternalData();
};

   /// Integer properties.
class c4_IntProp : public c4_Property
{
public:
     /// Construct a new property
 c4_IntProp (const char*);
     /// Destructor
 ~c4_IntProp ();

     /// Get or set an integer property in a row
 c4_IntRef operator() (const c4_RowRef&) const;
     /// Get an integer property in a row
 t4_i32 Get(const c4_RowRef&) const;
     /// Set an integer property in a row
 void Set(const c4_RowRef&, t4_i32) const;

     /// Creates a row with one integer, shorthand for AsRow.
 c4_Row operator[] (t4_i32) const;
     /// Creates a row with one integer.
 c4_Row AsRow(t4_i32) const;
};

#if !q4_TINY

   /// Long int properties.
class c4_LongProp : public c4_Property
{
public:
     /// Construct a new property
 c4_LongProp (const char*);
     /// Destructor
 ~c4_LongProp ();

     /// Get or set a long int property in a row
 c4_LongRef operator() (const c4_RowRef&) const;
     /// Get a long int property in a row
 t4_i64 Get(const c4_RowRef&) const;
     /// Set a long int property in a row
 void Set(const c4_RowRef&, t4_i64) const;

     /// Creates a row with one long int, shorthand for AsRow.
 c4_Row operator[] (t4_i64) const;
     /// Creates a row with one long int.
 c4_Row AsRow(t4_i64) const;
};

   /// Floating point properties.
class c4_FloatProp : public c4_Property
{
public:
     /// Construct a new property
 c4_FloatProp (const char*);
     /// Destructor
 ~c4_FloatProp ();

     /// Get or set a floating point property in a row
 c4_FloatRef operator() (const c4_RowRef&) const;
     /// Get a floating point property in a row
 double Get(const c4_RowRef&) const;
     /// Set a floating point property in a row
 void Set(const c4_RowRef&, double) const;

     /// Create a row with one floating point value, shorthand for AsRow
 c4_Row operator[] (double) const;
     /// Create a row with one floating point value
 c4_Row AsRow(double) const;
};

   /// Double precision properties.
class c4_DoubleProp : public c4_Property
{
public:
     /// Construct a new property.
 c4_DoubleProp (const char*);
     /// Destructor
 ~c4_DoubleProp ();

     /// Get or set a double precision property in a row
 c4_DoubleRef operator() (const c4_RowRef&) const;
     /// Get a double precision property in a row
 double Get(const c4_RowRef&) const;
     /// Set a double precision property in a row
 void Set(const c4_RowRef&, double) const;

     /// Create a row with one double precision value, shorthand for AsRow
 c4_Row operator[] (double) const;
     /// Create a row with one double precision value
 c4_Row AsRow(double) const;
};
#endif // !q4_TINY

   /// String properties.
class c4_StringProp : public c4_Property
{
public:
     /// Construct a new property
 c4_StringProp (const char*);
     /// Destructor
 ~c4_StringProp ();

     /// Get or set a string property in a row
 c4_StringRef operator() (const c4_RowRef&) const;
     /// Get a string property in a row
 const char* Get(const c4_RowRef&) const;
     /// Set a string property in a row
 void Set(const c4_RowRef&, const char*) const;

     /// Create a row with one string, shorthand for AsRow
 c4_Row operator[] (const char*) const;
     /// Create a row with one string
 c4_Row AsRow(const char*) const;
};

   /// Binary properties.
class c4_BytesProp : public c4_Property
{
public:
     /// Construct a new property
 c4_BytesProp (const char*);
     /// Destructor
 ~c4_BytesProp ();

     /// Get or set a bytes property in a row
 c4_BytesRef operator() (const c4_RowRef&) const;
     /// Get a bytes property in a row
 c4_Bytes Get(const c4_RowRef&) const;
     /// Set a bytes property in a row
 void Set(const c4_RowRef&, const c4_Bytes&) const;

     /// Create a row with one bytes object, shorthand for AsRow
 c4_Row operator[] (const c4_Bytes&) const;
     /// Create a row with one bytes object
 c4_Row AsRow(const c4_Bytes&) const;
};

   /// View properties.
class c4_ViewProp : public c4_Property
{
public:
     /// Construct a new property
 c4_ViewProp (const char*);
     /// Destructor
 ~c4_ViewProp ();

     /// Get or set a view property in a row
 c4_ViewRef operator() (const c4_RowRef&) const;
     /// Get a view property in a row
 c4_View Get(const c4_RowRef&) const;
     /// Set a view property in a row
 void Set(const c4_RowRef&, const c4_View&) const;

     /// Create a row with one view, shorthand for AsRow
 c4_Row operator[] (const c4_View&) const;
     /// Create a row with one view
 c4_Row AsRow(const c4_View&) const;
};

//---------------------------------------------------------------------------

class c4_CustomViewer
{
protected:
     /// Constructor, must be overriden in derived class
 c4_CustomViewer ();
public:
     /// Destructor
 virtual ~c4_CustomViewer ();

     /// Return the structure of this view (initialization, called once)
 virtual c4_View GetTemplate() = 0;
     /// Return the number of rows in this view
 virtual int GetSize() = 0;
 int Lookup(const c4_RowRef&, int&);
 virtual int Lookup(c4_Cursor, int&);
     /// Fetch one data item, return it as a generic data value
 virtual bool GetItem(int, int, c4_Bytes&) = 0;
 virtual bool SetItem(int, int, const c4_Bytes&);
 bool InsertRows(int, const c4_RowRef&, int =1);
 virtual bool InsertRows(int, c4_Cursor, int =1);
 virtual bool RemoveRows(int, int =1);
};

//---------------------------------------------------------------------------
/// A stream is a virtual helper class to serialize in binary form.

class c4_Stream
{
public:
 virtual ~c4_Stream ();

     /// Fetch some bytes sequentially
 virtual int Read(void*, int) = 0;
     /// Store some bytes sequentially
 virtual bool Write(const void*, int) = 0;
};

//---------------------------------------------------------------------------
/// A strategy encapsulates code dealing with the I/O system interface.

class c4_Strategy
{
public:
 c4_Strategy ();
 virtual ~c4_Strategy ();

 virtual bool IsValid() const;
 virtual int  DataRead(t4_i32, void*, int);
 virtual void DataWrite(t4_i32, const void*, int);
 virtual void DataCommit(t4_i32);
 virtual void ResetFileMapping();
 virtual t4_i32 FileSize();
 virtual t4_i32 FreshGeneration();

 void SetBase(t4_i32);
 t4_i32 EndOfData(t4_i32 =-1);

     /// True if the storage format is not native (default is false)
 bool _bytesFlipped;
     /// Error code of last failed I/O operation, zero if I/O was ok
 int _failure;
     /// First byte in file mapping, zero if not active
 const t4_byte* _mapStart;
     /// Number of bytes filled with active data
 t4_i32 _dataSize;
 /// All file positions are relative to this offset
 t4_i32 _baseOffset;
 /// The root position of the shallow tree walks
 t4_i32 _rootPos;
 /// The size of the root column
 t4_i32 _rootLen;
};

//---------------------------------------------------------------------------
/// A sequence is an abstract base class for views on ranges of records.
//
//  Sequences represent arrays of rows (or indexed collections / tables).
//  Insertion and removal of entries is allowed, but could take linear time.
//  A reference count is maintained to decide when the object should go away.

class c4_Sequence
{
     /// Reference count
 int _refCount;
     /// Pointer to dependency list, or null if nothing depends on this
 c4_Dependencies* _dependencies;

protected:
     /// Optimization: cached property index
 int _propertyLimit;
     /// Optimization: property map for faster access
 short* _propertyMap; // see c4_HandlerSeq::Reset()
     /// allocated on first use by c4_Sequence::Buffer()
 c4_Bytes* _tempBuf;

public:
/* General */
     /// Abstract constructor
 c4_Sequence ();

 virtual int Compare(int, c4_Cursor) const;
 virtual bool RestrictSearch(c4_Cursor, int&, int&);
 void SetAt(int, c4_Cursor);
 virtual int RemapIndex(int, const c4_Sequence*) const;

/* Reference counting */
 void IncRef();
 void DecRef();
 int NumRefs() const;

/* Adding / removing rows */
     /// Return the current number of rows
 virtual int NumRows() const = 0;
 void Resize(int, int =-1);

 virtual void InsertAt(int, c4_Cursor, int =1);
 virtual void RemoveAt(int, int =1);
 virtual void Move(int, int);

/* Properties */
 int NthPropId(int) const;
 int PropIndex(int);
 int PropIndex(const c4_Property&);

     /// Return the number of data handlers in this sequence
 virtual int NumHandlers() const = 0;
     /// Return a reference to the N-th handler in this sequence
 virtual c4_Handler& NthHandler(int) const = 0;
     /// Return the context of the N-th handler in this sequence
 virtual const c4_Sequence* HandlerContext(int) const = 0;
     /// Add the specified data handler to this sequence
 virtual int AddHandler(c4_Handler*) = 0;
     /// Create a handler of the appropriate type
 virtual c4_Handler* CreateHandler(const c4_Property&) = 0;

 virtual const char* Description();

/* Element access */
     /// Return width of specified data item
 virtual int ItemSize(int, int);
     /// Retrieve one data item from this sequence
 virtual bool Get(int, int, c4_Bytes&);
     /// Store a data item into this sequence
 virtual void Set(int, const c4_Property&, const c4_Bytes&);

/* Dependency notification */
 void Attach(c4_Sequence*);
 void Detach(c4_Sequence*);
     /// Return a pointer to the dependencies, or null
 c4_Dependencies* GetDependencies() const;

 virtual c4_Notifier* PreChange(c4_Notifier&);
 virtual void PostChange(c4_Notifier&);

 const char* UseTempBuffer(const char*);

protected:
 virtual ~c4_Sequence ();

 void ClearCache();

public: //! for c4_Table::Sequence setup
 virtual void SetNumRows(int) = 0;
 virtual c4_Persist* Persist() const;

 c4_Bytes& Buffer();

private:
 c4_Sequence (const c4_Sequence&);   // not implemented
 void operator= (const c4_Sequence&); // not implemented
};

//---------------------------------------------------------------------------
/// A reference is used to get or set typed data, using derived classes.
//
//  Objects of this class are only intended to be used as a temporary handle
//  while getting and setting properties in a row.  They are normally only
//  constructed as result of function overload operators: "property (row)".

class c4_Reference
{
protected:
     /// The cursor which points to the data
 c4_Cursor _cursor;
     /// The property associated to this reference
 const c4_Property& _property;

public:
     /// Constructor
 c4_Reference (const c4_RowRef&, const c4_Property&);

     /// Assignment of one data item
 c4_Reference& operator= (const c4_Reference&);

     /// Return width of the referenced data item
 int GetSize() const;
     /// Retrieve the value of the referenced data item
 bool GetData(c4_Bytes&) const;
     /// Store a value into the referenced data item
 void SetData(const c4_Bytes&) const;

     /// Return true if the contents of both references is equal
 friend bool operator== (const c4_Reference&, const c4_Reference&);
     /// Return true if the contents of both references is not equal
 friend bool operator!= (const c4_Reference&, const c4_Reference&);

private:
 void operator& () const;            // not implemented
};

//---------------------------------------------------------------------------

   /// Used to get or set integer values.
class c4_IntRef : public c4_Reference
{
public:
     /// Constructor
 c4_IntRef (const c4_Reference&);
     /// Get the value as integer
 operator t4_i32 () const;
     /// Set the value to the specified integer
 c4_IntRef& operator= (t4_i32);
};

#if !q4_TINY

   /// Used to get or set long int values.
class c4_LongRef : public c4_Reference
{
public:
     /// Constructor
 c4_LongRef (const c4_Reference&);
     /// Get the value as long int
 operator t4_i64 () const;
     /// Set the value to the specified long int
 c4_LongRef& operator= (t4_i64);
};

   /// Used to get or set floating point values.
class c4_FloatRef : public c4_Reference
{
public:
     /// Constructor
 c4_FloatRef (const c4_Reference&);
     /// Get the value as floating point
 operator double () const;
     /// Set the value to the specified floating point
 c4_FloatRef& operator= (double);
};

   /// Used to get or set double precision values.
class c4_DoubleRef : public c4_Reference
{
public:
     /// Constructor
 c4_DoubleRef (const c4_Reference&);
     /// Get the value as floating point
 operator double () const;
     /// Set the value to the specified floating point
 c4_DoubleRef& operator= (double);
};

#endif // !q4_TINY

   /// Used to get or set binary object values.
class c4_BytesRef : public c4_Reference
{
public:
     /// Constructor
 c4_BytesRef (const c4_Reference&);
     /// Get the value as binary object
 operator c4_Bytes () const;
     /// Set the value to the specified binary object
 c4_BytesRef& operator= (const c4_Bytes&);

     /// Fetch data from the memo field, up to end if length is zero
 c4_Bytes Access(t4_i32, int =0) const;
     /// Store data, resize by diff_ bytes, return true if successful
 bool Modify(const c4_Bytes&, t4_i32, int =0) const;
};

   /// Used to get or set string values.
class c4_StringRef : public c4_Reference
{
public:
     /// Constructor
 c4_StringRef (const c4_Reference&);
     /// Get the value as string
 operator const char* () const;
     /// Set the value to the specified string
 c4_StringRef& operator= (const char*);
};

   /// Used to get or set view values.
class c4_ViewRef : public c4_Reference
{
public:
     /// Constructor
 c4_ViewRef (const c4_Reference&);
     /// Get the value as view
 operator c4_View () const;
     /// Set the value to the specified view
 c4_ViewRef& operator= (const c4_View&);
};

//---------------------------------------------------------------------------
// Debug logging option, can generate log of changes for one/all properties

#if q4_LOGPROPMODS
FILE* f4_LogPropMods(FILE* fp_, int propId_);
#else
#define f4_LogPropMods(a,b) 0
#endif

//---------------------------------------------------------------------------

#if q4_INLINE
#include "mk4.inl"
#endif

//---------------------------------------------------------------------------

#endif // __MK4_H__