// mk4.h --
// $Id: mk4.h,v 1.22 2002/04/29 12:54:54 wcvs 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 245    // 2.4.5 release, April 29, 2002

//---------------------------------------------------------------------------
// 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... Alpha has 64-bit longs
#if (defined (__alpha) || defined (__ia64)) && \
			!defined (_WIN32) && !defined (q4_LONG64)
#define q4_LONG64 1
#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__) && !defined (q4_BOOL)
#define q4_BOOL 1
#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&);
};

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

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

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

#endif // __MK4_H__
