summaryrefslogtreecommitdiff
path: root/db/mork/src/morkTable.h
diff options
context:
space:
mode:
Diffstat (limited to 'db/mork/src/morkTable.h')
-rw-r--r--db/mork/src/morkTable.h729
1 files changed, 729 insertions, 0 deletions
diff --git a/db/mork/src/morkTable.h b/db/mork/src/morkTable.h
new file mode 100644
index 0000000000..c9428fd964
--- /dev/null
+++ b/db/mork/src/morkTable.h
@@ -0,0 +1,729 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _MORKTABLE_
+#define _MORKTABLE_ 1
+
+#ifndef _MORK_
+#include "mork.h"
+#endif
+
+#ifndef _MORKNODE_
+#include "morkNode.h"
+#endif
+
+#ifndef _MORKDEQUE_
+#include "morkDeque.h"
+#endif
+
+#ifndef _MORKOBJECT_
+#include "morkObject.h"
+#endif
+
+#ifndef _MORKARRAY_
+#include "morkArray.h"
+#endif
+
+#ifndef _MORKROWMAP_
+#include "morkRowMap.h"
+#endif
+
+#ifndef _MORKNODEMAP_
+#include "morkNodeMap.h"
+#endif
+
+#ifndef _MORKPROBEMAP_
+#include "morkProbeMap.h"
+#endif
+
+#ifndef _MORKBEAD_
+#include "morkBead.h"
+#endif
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+class nsIMdbTable;
+#define morkDerived_kTable /*i*/ 0x5462 /* ascii 'Tb' */
+
+/*| kStartRowArraySize: starting physical size of array for mTable_RowArray.
+**| We want this number very small, so that a table containing exactly one
+**| row member will not pay too significantly in space overhead. But we want
+**| a number bigger than one, so there is some space for growth.
+|*/
+#define morkTable_kStartRowArraySize 3 /* modest starting size for array */
+
+/*| kMakeRowMapThreshold: this is the number of rows in a table which causes
+**| a hash table (mTable_RowMap) to be lazily created for faster member row
+**| identification, during such operations as cuts and adds. This number must
+**| be small enough that linear searches are not bad for member counts less
+**| than this; but this number must also be large enough that creating a hash
+**| table does not increase the per-row space overhead by a big percentage.
+**| For speed, numbers on the order of ten to twenty are all fine; for space,
+**| I believe a number as small as ten will have too much space overhead.
+|*/
+#define morkTable_kMakeRowMapThreshold 17 /* when to build mTable_RowMap */
+
+#define morkTable_kStartRowMapSlotCount 13
+#define morkTable_kMaxTableGcUses 0x0FF /* max for 8-bit unsigned int */
+
+#define morkTable_kUniqueBit ((mork_u1) (1 << 0))
+#define morkTable_kVerboseBit ((mork_u1) (1 << 1))
+#define morkTable_kNotedBit ((mork_u1) (1 << 2)) /* space has change notes */
+#define morkTable_kRewriteBit ((mork_u1) (1 << 3)) /* must rewrite all rows */
+#define morkTable_kNewMetaBit ((mork_u1) (1 << 4)) /* new table meta row */
+
+class morkTable : public morkObject, public morkLink, public nsIMdbTable {
+
+ // NOTE the morkLink base is for morkRowSpace::mRowSpace_TablesByPriority
+
+// public: // slots inherited from morkObject (meant to inform only)
+ // nsIMdbHeap* mNode_Heap;
+
+ // mork_base mNode_Base; // must equal morkBase_kNode
+ // mork_derived mNode_Derived; // depends on specific node subclass
+
+ // mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead
+ // mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone
+ // mork_able mNode_Mutable; // can this node be modified?
+ // mork_load mNode_Load; // is this node clean or dirty?
+
+ // mork_uses mNode_Uses; // refcount for strong refs
+ // mork_refs mNode_Refs; // refcount for strong refs + weak refs
+
+ // mork_color mBead_Color; // ID for this bead
+ // morkHandle* mObject_Handle; // weak ref to handle for this object
+
+public: // bead color setter & getter replace obsolete member mTable_Id:
+
+ NS_DECL_ISUPPORTS_INHERITED
+ mork_tid TableId() const { return mBead_Color; }
+ void SetTableId(mork_tid inTid) { mBead_Color = inTid; }
+
+ // we override these so we use xpcom ref-counting semantics.
+#ifndef _MSC_VER
+ // The first declaration of AddStrongRef is to suppress -Werror,-Woverloaded-virtual.
+ virtual mork_refs AddStrongRef(nsIMdbEnv* ev) override;
+#endif
+ virtual mork_refs AddStrongRef(morkEnv* ev) override;
+#ifndef _MSC_VER
+ // The first declaration of CutStrongRef is to suppress -Werror,-Woverloaded-virtual.
+ virtual nsresult CutStrongRef(nsIMdbEnv* ev) override;
+#endif
+ virtual mork_refs CutStrongRef(morkEnv* ev) override;
+public: // state is public because the entire Mork system is private
+
+// { ===== begin nsIMdbCollection methods =====
+
+ // { ----- begin attribute methods -----
+ NS_IMETHOD GetSeed(nsIMdbEnv* ev,
+ mdb_seed* outSeed) override; // member change count
+ NS_IMETHOD GetCount(nsIMdbEnv* ev,
+ mdb_count* outCount) override; // member count
+
+ NS_IMETHOD GetPort(nsIMdbEnv* ev,
+ nsIMdbPort** acqPort) override; // collection container
+ // } ----- end attribute methods -----
+
+ // { ----- begin cursor methods -----
+ NS_IMETHOD GetCursor( // make a cursor starting iter at inMemberPos
+ nsIMdbEnv* ev, // context
+ mdb_pos inMemberPos, // zero-based ordinal pos of member in collection
+ nsIMdbCursor** acqCursor) override; // acquire new cursor instance
+ // } ----- end cursor methods -----
+
+ // { ----- begin ID methods -----
+ NS_IMETHOD GetOid(nsIMdbEnv* ev,
+ mdbOid* outOid) override; // read object identity
+ NS_IMETHOD BecomeContent(nsIMdbEnv* ev,
+ const mdbOid* inOid) override; // exchange content
+ // } ----- end ID methods -----
+
+ // { ----- begin activity dropping methods -----
+ NS_IMETHOD DropActivity( // tell collection usage no longer expected
+ nsIMdbEnv* ev) override;
+ // } ----- end activity dropping methods -----
+
+// } ===== end nsIMdbCollection methods =====
+ NS_IMETHOD SetTablePriority(nsIMdbEnv* ev, mdb_priority inPrio) override;
+ NS_IMETHOD GetTablePriority(nsIMdbEnv* ev, mdb_priority* outPrio) override;
+
+ NS_IMETHOD GetTableBeVerbose(nsIMdbEnv* ev, mdb_bool* outBeVerbose) override;
+ NS_IMETHOD SetTableBeVerbose(nsIMdbEnv* ev, mdb_bool inBeVerbose) override;
+
+ NS_IMETHOD GetTableIsUnique(nsIMdbEnv* ev, mdb_bool* outIsUnique) override;
+
+ NS_IMETHOD GetTableKind(nsIMdbEnv* ev, mdb_kind* outTableKind) override;
+ NS_IMETHOD GetRowScope(nsIMdbEnv* ev, mdb_scope* outRowScope) override;
+
+ NS_IMETHOD GetMetaRow(
+ nsIMdbEnv* ev, // context
+ const mdbOid* inOptionalMetaRowOid, // can be nil to avoid specifying
+ mdbOid* outOid, // output meta row oid, can be nil to suppress output
+ nsIMdbRow** acqRow) override; // acquire table's unique singleton meta row
+ // The purpose of a meta row is to support the persistent recording of
+ // meta info about a table as cells put into the distinguished meta row.
+ // Each table has exactly one meta row, which is not considered a member
+ // of the collection of rows inside the table. The only way to tell
+ // whether a row is a meta row is by the fact that it is returned by this
+ // GetMetaRow() method from some table. Otherwise nothing distinguishes
+ // a meta row from any other row. A meta row can be used anyplace that
+ // any other row can be used, and can even be put into other tables (or
+ // the same table) as a table member, if this is useful for some reason.
+ // The first attempt to access a table's meta row using GetMetaRow() will
+ // cause the meta row to be created if it did not already exist. When the
+ // meta row is created, it will have the row oid that was previously
+ // requested for this table's meta row; or if no oid was ever explicitly
+ // specified for this meta row, then a unique oid will be generated in
+ // the row scope named "m" (so obviously MDB clients should not
+ // manually allocate any row IDs from that special meta scope namespace).
+ // The meta row oid can be specified either when the table is created, or
+ // else the first time that GetMetaRow() is called, by passing a non-nil
+ // pointer to an oid for parameter inOptionalMetaRowOid. The meta row's
+ // actual oid is returned in outOid (if this is a non-nil pointer), and
+ // it will be different from inOptionalMetaRowOid when the meta row was
+ // already given a different oid earlier.
+ // } ----- end meta attribute methods -----
+
+
+ // { ----- begin cursor methods -----
+ NS_IMETHOD GetTableRowCursor( // make a cursor, starting iteration at inRowPos
+ nsIMdbEnv* ev, // context
+ mdb_pos inRowPos, // zero-based ordinal position of row in table
+ nsIMdbTableRowCursor** acqCursor) override; // acquire new cursor instance
+ // } ----- end row position methods -----
+
+ // { ----- begin row position methods -----
+ NS_IMETHOD PosToOid( // get row member for a table position
+ nsIMdbEnv* ev, // context
+ mdb_pos inRowPos, // zero-based ordinal position of row in table
+ mdbOid* outOid) override; // row oid at the specified position
+
+ NS_IMETHOD OidToPos( // test for the table position of a row member
+ nsIMdbEnv* ev, // context
+ const mdbOid* inOid, // row to find in table
+ mdb_pos* outPos) override; // zero-based ordinal position of row in table
+
+ NS_IMETHOD PosToRow( // test for the table position of a row member
+ nsIMdbEnv* ev, // context
+ mdb_pos inRowPos, // zero-based ordinal position of row in table
+ nsIMdbRow** acqRow) override; // acquire row at table position inRowPos
+
+ NS_IMETHOD RowToPos( // test for the table position of a row member
+ nsIMdbEnv* ev, // context
+ nsIMdbRow* ioRow, // row to find in table
+ mdb_pos* outPos) override; // zero-based ordinal position of row in table
+ // } ----- end row position methods -----
+
+ // { ----- begin oid set methods -----
+ NS_IMETHOD AddOid( // make sure the row with inOid is a table member
+ nsIMdbEnv* ev, // context
+ const mdbOid* inOid) override; // row to ensure membership in table
+
+ NS_IMETHOD HasOid( // test for the table position of a row member
+ nsIMdbEnv* ev, // context
+ const mdbOid* inOid, // row to find in table
+ mdb_bool* outHasOid) override; // whether inOid is a member row
+
+ NS_IMETHOD CutOid( // make sure the row with inOid is not a member
+ nsIMdbEnv* ev, // context
+ const mdbOid* inOid) override; // row to remove from table
+ // } ----- end oid set methods -----
+
+ // { ----- begin row set methods -----
+ NS_IMETHOD NewRow( // create a new row instance in table
+ nsIMdbEnv* ev, // context
+ mdbOid* ioOid, // please use minus one (unbound) rowId for db-assigned IDs
+ nsIMdbRow** acqRow) override; // create new row
+
+ NS_IMETHOD AddRow( // make sure the row with inOid is a table member
+ nsIMdbEnv* ev, // context
+ nsIMdbRow* ioRow) override; // row to ensure membership in table
+
+ NS_IMETHOD HasRow( // test for the table position of a row member
+ nsIMdbEnv* ev, // context
+ nsIMdbRow* ioRow, // row to find in table
+ mdb_bool* outHasRow) override; // whether row is a table member
+
+ NS_IMETHOD CutRow( // make sure the row with inOid is not a member
+ nsIMdbEnv* ev, // context
+ nsIMdbRow* ioRow) override; // row to remove from table
+
+ NS_IMETHOD CutAllRows( // remove all rows from the table
+ nsIMdbEnv* ev) override; // context
+ // } ----- end row set methods -----
+
+ // { ----- begin hinting methods -----
+ NS_IMETHOD SearchColumnsHint( // advise re future expected search cols
+ nsIMdbEnv* ev, // context
+ const mdbColumnSet* inColumnSet) override; // columns likely to be searched
+
+ NS_IMETHOD SortColumnsHint( // advise re future expected sort columns
+ nsIMdbEnv* ev, // context
+ const mdbColumnSet* inColumnSet) override; // columns for likely sort requests
+
+ NS_IMETHOD StartBatchChangeHint( // advise before many adds and cuts
+ nsIMdbEnv* ev, // context
+ const void* inLabel) override; // intend unique address to match end call
+ // If batch starts nest by virtue of nesting calls in the stack, then
+ // the address of a local variable makes a good batch start label that
+ // can be used at batch end time, and such addresses remain unique.
+
+ NS_IMETHOD EndBatchChangeHint( // advise before many adds and cuts
+ nsIMdbEnv* ev, // context
+ const void* inLabel) override; // label matching start label
+ // Suppose a table is maintaining one or many sort orders for a table,
+ // so that every row added to the table must be inserted in each sort,
+ // and every row cut must be removed from each sort. If a db client
+ // intends to make many such changes before needing any information
+ // about the order or positions of rows inside a table, then a client
+ // might tell the table to start batch changes in order to disable
+ // sorting of rows for the interim. Presumably a table will then do
+ // a full sort of all rows at need when the batch changes end, or when
+ // a surprise request occurs for row position during batch changes.
+ // } ----- end hinting methods -----
+
+ // { ----- begin searching methods -----
+ NS_IMETHOD FindRowMatches( // search variable number of sorted cols
+ nsIMdbEnv* ev, // context
+ const mdbYarn* inPrefix, // content to find as prefix in row's column cell
+ nsIMdbTableRowCursor** acqCursor) override; // set of matching rows
+
+ NS_IMETHOD GetSearchColumns( // query columns used by FindRowMatches()
+ nsIMdbEnv* ev, // context
+ mdb_count* outCount, // context
+ mdbColumnSet* outColSet) override; // caller supplied space to put columns
+ // GetSearchColumns() returns the columns actually searched when the
+ // FindRowMatches() method is called. No more than mColumnSet_Count
+ // slots of mColumnSet_Columns will be written, since mColumnSet_Count
+ // indicates how many slots are present in the column array. The
+ // actual number of search column used by the table is returned in
+ // the outCount parameter; if this number exceeds mColumnSet_Count,
+ // then a caller needs a bigger array to read the entire column set.
+ // The minimum of mColumnSet_Count and outCount is the number slots
+ // in mColumnSet_Columns that were actually written by this method.
+ //
+ // Callers are expected to change this set of columns by calls to
+ // nsIMdbTable::SearchColumnsHint() or SetSearchSorting(), or both.
+ // } ----- end searching methods -----
+
+ // { ----- begin sorting methods -----
+ // sorting: note all rows are assumed sorted by row ID as a secondary
+ // sort following the primary column sort, when table rows are sorted.
+
+ NS_IMETHOD
+ CanSortColumn( // query which column is currently used for sorting
+ nsIMdbEnv* ev, // context
+ mdb_column inColumn, // column to query sorting potential
+ mdb_bool* outCanSort) override; // whether the column can be sorted
+
+ NS_IMETHOD GetSorting( // view same table in particular sorting
+ nsIMdbEnv* ev, // context
+ mdb_column inColumn, // requested new column for sorting table
+ nsIMdbSorting** acqSorting) override; // acquire sorting for column
+
+ NS_IMETHOD SetSearchSorting( // use this sorting in FindRowMatches()
+ nsIMdbEnv* ev, // context
+ mdb_column inColumn, // often same as nsIMdbSorting::GetSortColumn()
+ nsIMdbSorting* ioSorting) override; // requested sorting for some column
+ // SetSearchSorting() attempts to inform the table that ioSorting
+ // should be used during calls to FindRowMatches() for searching
+ // the column which is actually sorted by ioSorting. This method
+ // is most useful in conjunction with nsIMdbSorting::SetCompare(),
+ // because otherwise a caller would not be able to override the
+ // comparison ordering method used during searchs. Note that some
+ // database implementations might be unable to use an arbitrarily
+ // specified sort order, either due to schema or runtime interface
+ // constraints, in which case ioSorting might not actually be used.
+ // Presumably ioSorting is an instance that was returned from some
+ // earlier call to nsIMdbTable::GetSorting(). A caller can also
+ // use nsIMdbTable::SearchColumnsHint() to specify desired change
+ // in which columns are sorted and searched by FindRowMatches().
+ //
+ // A caller can pass a nil pointer for ioSorting to request that
+ // column inColumn no longer be used at all by FindRowMatches().
+ // But when ioSorting is non-nil, then inColumn should match the
+ // column actually sorted by ioSorting; when these do not agree,
+ // implementations are instructed to give precedence to the column
+ // specified by ioSorting (so this means callers might just pass
+ // zero for inColumn when ioSorting is also provided, since then
+ // inColumn is both redundant and ignored).
+ // } ----- end sorting methods -----
+
+ // { ----- begin moving methods -----
+ // moving a row does nothing unless a table is currently unsorted
+
+ NS_IMETHOD MoveOid( // change position of row in unsorted table
+ nsIMdbEnv* ev, // context
+ const mdbOid* inOid, // row oid to find in table
+ mdb_pos inHintFromPos, // suggested hint regarding start position
+ mdb_pos inToPos, // desired new position for row inRowId
+ mdb_pos* outActualPos) override; // actual new position of row in table
+
+ NS_IMETHOD MoveRow( // change position of row in unsorted table
+ nsIMdbEnv* ev, // context
+ nsIMdbRow* ioRow, // row oid to find in table
+ mdb_pos inHintFromPos, // suggested hint regarding start position
+ mdb_pos inToPos, // desired new position for row inRowId
+ mdb_pos* outActualPos) override; // actual new position of row in table
+ // } ----- end moving methods -----
+
+ // { ----- begin index methods -----
+ NS_IMETHOD AddIndex( // create a sorting index for column if possible
+ nsIMdbEnv* ev, // context
+ mdb_column inColumn, // the column to sort by index
+ nsIMdbThumb** acqThumb) override; // acquire thumb for incremental index building
+ // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
+ // then the index addition will be finished.
+
+ NS_IMETHOD CutIndex( // stop supporting a specific column index
+ nsIMdbEnv* ev, // context
+ mdb_column inColumn, // the column with index to be removed
+ nsIMdbThumb** acqThumb) override; // acquire thumb for incremental index destroy
+ // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
+ // then the index removal will be finished.
+
+ NS_IMETHOD HasIndex( // query for current presence of a column index
+ nsIMdbEnv* ev, // context
+ mdb_column inColumn, // the column to investigate
+ mdb_bool* outHasIndex) override; // whether column has index for this column
+
+
+ NS_IMETHOD EnableIndexOnSort( // create an index for col on first sort
+ nsIMdbEnv* ev, // context
+ mdb_column inColumn) override; // the column to index if ever sorted
+
+ NS_IMETHOD QueryIndexOnSort( // check whether index on sort is enabled
+ nsIMdbEnv* ev, // context
+ mdb_column inColumn, // the column to investigate
+ mdb_bool* outIndexOnSort) override; // whether column has index-on-sort enabled
+
+ NS_IMETHOD DisableIndexOnSort( // prevent future index creation on sort
+ nsIMdbEnv* ev, // context
+ mdb_column inColumn) override; // the column to index if ever sorted
+ // } ----- end index methods -----
+
+ morkStore* mTable_Store; // non-refcnted ptr to port
+
+ // mTable_RowSpace->SpaceScope() is row scope
+ morkRowSpace* mTable_RowSpace; // non-refcnted ptr to containing space
+
+ morkRow* mTable_MetaRow; // table's actual meta row
+ mdbOid mTable_MetaRowOid; // oid for meta row
+
+ morkRowMap* mTable_RowMap; // (strong ref) hash table of all members
+ morkArray mTable_RowArray; // array of morkRow pointers
+
+ morkList mTable_ChangeList; // list of table changes
+ mork_u2 mTable_ChangesCount; // length of changes list
+ mork_u2 mTable_ChangesMax; // max list length before rewrite
+
+ // mork_tid mTable_Id;
+ mork_kind mTable_Kind;
+
+ mork_u1 mTable_Flags; // bit flags
+ mork_priority mTable_Priority; // 0..9, any other value equals 9
+ mork_u1 mTable_GcUses; // persistent references from cells
+ mork_u1 mTable_Pad; // for u4 alignment
+
+public: // flags bit twiddling
+
+ void SetTableUnique() { mTable_Flags |= morkTable_kUniqueBit; }
+ void SetTableVerbose() { mTable_Flags |= morkTable_kVerboseBit; }
+ void SetTableNoted() { mTable_Flags |= morkTable_kNotedBit; }
+ void SetTableRewrite() { mTable_Flags |= morkTable_kRewriteBit; }
+ void SetTableNewMeta() { mTable_Flags |= morkTable_kNewMetaBit; }
+
+ void ClearTableUnique() { mTable_Flags &= (mork_u1) ~morkTable_kUniqueBit; }
+ void ClearTableVerbose() { mTable_Flags &= (mork_u1) ~morkTable_kVerboseBit; }
+ void ClearTableNoted() { mTable_Flags &= (mork_u1) ~morkTable_kNotedBit; }
+ void ClearTableRewrite() { mTable_Flags &= (mork_u1) ~morkTable_kRewriteBit; }
+ void ClearTableNewMeta() { mTable_Flags &= (mork_u1) ~morkTable_kNewMetaBit; }
+
+ mork_bool IsTableUnique() const
+ { return ( mTable_Flags & morkTable_kUniqueBit ) != 0; }
+
+ mork_bool IsTableVerbose() const
+ { return ( mTable_Flags & morkTable_kVerboseBit ) != 0; }
+
+ mork_bool IsTableNoted() const
+ { return ( mTable_Flags & morkTable_kNotedBit ) != 0; }
+
+ mork_bool IsTableRewrite() const
+ { return ( mTable_Flags & morkTable_kRewriteBit ) != 0; }
+
+ mork_bool IsTableNewMeta() const
+ { return ( mTable_Flags & morkTable_kNewMetaBit ) != 0; }
+
+public: // table dirty handling more complex than morkNode::SetNodeDirty() etc.
+
+ void SetTableDirty() { this->SetNodeDirty(); }
+ void SetTableClean(morkEnv* ev);
+
+ mork_bool IsTableClean() const { return this->IsNodeClean(); }
+ mork_bool IsTableDirty() const { return this->IsNodeDirty(); }
+
+public: // morkNode memory management operators
+ void* operator new(size_t inSize, nsIMdbHeap& ioHeap, morkEnv* ev) CPP_THROW_NEW
+ { return morkNode::MakeNew(inSize, ioHeap, ev); }
+
+
+// { ===== begin morkNode interface =====
+public: // morkNode virtual methods
+ virtual void CloseMorkNode(morkEnv* ev) override; // CloseTable() if open
+
+public: // morkTable construction & destruction
+ morkTable(morkEnv* ev, const morkUsage& inUsage,
+ nsIMdbHeap* ioNodeHeap, morkStore* ioStore,
+ nsIMdbHeap* ioSlotHeap, morkRowSpace* ioRowSpace,
+ const mdbOid* inOptionalMetaRowOid, // can be nil to avoid specifying
+ mork_tid inTableId,
+ mork_kind inKind, mork_bool inMustBeUnique);
+ void CloseTable(morkEnv* ev); // called by CloseMorkNode();
+
+private: // copying is not allowed
+ morkTable(const morkTable& other);
+ morkTable& operator=(const morkTable& other);
+ virtual ~morkTable(); // assert that close executed earlier
+
+public: // dynamic type identification
+ mork_bool IsTable() const
+ { return IsNode() && mNode_Derived == morkDerived_kTable; }
+// } ===== end morkNode methods =====
+
+public: // errors
+ static void NonTableTypeError(morkEnv* ev);
+ static void NonTableTypeWarning(morkEnv* ev);
+ static void NilRowSpaceError(morkEnv* ev);
+
+public: // warnings
+ static void TableGcUsesUnderflowWarning(morkEnv* ev);
+
+public: // noting table changes
+
+ mork_bool HasChangeOverflow() const
+ { return mTable_ChangesCount >= mTable_ChangesMax; }
+
+ void NoteTableSetAll(morkEnv* ev);
+ void NoteTableMoveRow(morkEnv* ev, morkRow* ioRow, mork_pos inPos);
+
+ void note_row_change(morkEnv* ev, mork_change inChange, morkRow* ioRow);
+ void note_row_move(morkEnv* ev, morkRow* ioRow, mork_pos inNewPos);
+
+ void NoteTableAddRow(morkEnv* ev, morkRow* ioRow)
+ { this->note_row_change(ev, morkChange_kAdd, ioRow); }
+
+ void NoteTableCutRow(morkEnv* ev, morkRow* ioRow)
+ { this->note_row_change(ev, morkChange_kCut, ioRow); }
+
+protected: // internal row map methods
+
+ morkRow* find_member_row(morkEnv* ev, morkRow* ioRow);
+ void build_row_map(morkEnv* ev);
+
+public: // other table methods
+
+ mork_bool MaybeDirtySpaceStoreAndTable();
+
+ morkRow* GetMetaRow(morkEnv* ev, const mdbOid* inOptionalMetaRowOid);
+
+ mork_u2 AddTableGcUse(morkEnv* ev);
+ mork_u2 CutTableGcUse(morkEnv* ev);
+
+ // void DirtyAllTableContent(morkEnv* ev);
+
+ mork_seed TableSeed() const { return mTable_RowArray.mArray_Seed; }
+
+ morkRow* SafeRowAt(morkEnv* ev, mork_pos inPos)
+ { return (morkRow*) mTable_RowArray.SafeAt(ev, inPos); }
+
+ nsIMdbTable* AcquireTableHandle(morkEnv* ev); // mObject_Handle
+
+ mork_count GetRowCount() const { return mTable_RowArray.mArray_Fill; }
+
+ mork_bool IsTableUsed() const
+ { return (mTable_GcUses != 0 || this->GetRowCount() != 0); }
+
+ void GetTableOid(morkEnv* ev, mdbOid* outOid);
+ mork_pos ArrayHasOid(morkEnv* ev, const mdbOid* inOid);
+ mork_bool MapHasOid(morkEnv* ev, const mdbOid* inOid);
+ mork_bool AddRow(morkEnv* ev, morkRow* ioRow); // returns ev->Good()
+ mork_bool CutRow(morkEnv* ev, morkRow* ioRow); // returns ev->Good()
+ mork_bool CutAllRows(morkEnv* ev); // returns ev->Good()
+
+ mork_pos MoveRow(morkEnv* ev, morkRow* ioRow, // change row position
+ mork_pos inHintFromPos, // suggested hint regarding start position
+ mork_pos inToPos); // desired new position for row ioRow
+ // MoveRow() returns the actual position of ioRow afterwards; this
+ // position is -1 if and only if ioRow was not found as a member.
+
+
+ morkTableRowCursor* NewTableRowCursor(morkEnv* ev, mork_pos inRowPos);
+
+public: // typesafe refcounting inlines calling inherited morkNode methods
+ static void SlotWeakTable(morkTable* me,
+ morkEnv* ev, morkTable** ioSlot)
+ { morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
+
+ static void SlotStrongTable(morkTable* me,
+ morkEnv* ev, morkTable** ioSlot)
+ { morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
+};
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+// use negative values for kCut and kAdd, to keep non-neg move pos distinct:
+#define morkTableChange_kCut ((mork_pos) -1) /* shows row was cut */
+#define morkTableChange_kAdd ((mork_pos) -2) /* shows row was added */
+#define morkTableChange_kNone ((mork_pos) -3) /* unknown change */
+
+class morkTableChange : public morkNext {
+public: // state is public because the entire Mork system is private
+
+ morkRow* mTableChange_Row; // the row in the change
+
+ mork_pos mTableChange_Pos; // kAdd, kCut, or non-neg for row move
+
+public:
+ morkTableChange(morkEnv* ev, mork_change inChange, morkRow* ioRow);
+ // use this constructor for inChange == morkChange_kAdd or morkChange_kCut
+
+ morkTableChange(morkEnv* ev, morkRow* ioRow, mork_pos inPos);
+ // use this constructor when the row is moved
+
+public:
+ void UnknownChangeError(morkEnv* ev) const; // morkChange_kAdd or morkChange_kCut
+ void NegativeMovePosError(morkEnv* ev) const; // move must be non-neg position
+
+public:
+
+ mork_bool IsAddRowTableChange() const
+ { return ( mTableChange_Pos == morkTableChange_kAdd ); }
+
+ mork_bool IsCutRowTableChange() const
+ { return ( mTableChange_Pos == morkTableChange_kCut ); }
+
+ mork_bool IsMoveRowTableChange() const
+ { return ( mTableChange_Pos >= 0 ); }
+
+public:
+
+ mork_pos GetMovePos() const { return mTableChange_Pos; }
+ // GetMovePos() assumes that IsMoveRowTableChange() is true.
+};
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+#define morkDerived_kTableMap /*i*/ 0x744D /* ascii 'tM' */
+
+/*| morkTableMap: maps mork_token -> morkTable
+|*/
+#ifdef MORK_BEAD_OVER_NODE_MAPS
+class morkTableMap : public morkBeadMap {
+#else /*MORK_BEAD_OVER_NODE_MAPS*/
+class morkTableMap : public morkNodeMap { // for mapping tokens to tables
+#endif /*MORK_BEAD_OVER_NODE_MAPS*/
+
+public:
+
+ virtual ~morkTableMap();
+ morkTableMap(morkEnv* ev, const morkUsage& inUsage,
+ nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap);
+
+public: // other map methods
+
+#ifdef MORK_BEAD_OVER_NODE_MAPS
+ mork_bool AddTable(morkEnv* ev, morkTable* ioTable)
+ { return this->AddBead(ev, ioTable); }
+ // the AddTable() boolean return equals ev->Good().
+
+ mork_bool CutTable(morkEnv* ev, mork_tid inTid)
+ { return this->CutBead(ev, inTid); }
+ // The CutTable() boolean return indicates whether removal happened.
+
+ morkTable* GetTable(morkEnv* ev, mork_tid inTid)
+ { return (morkTable*) this->GetBead(ev, inTid); }
+ // Note the returned table does NOT have an increase in refcount for this.
+
+ mork_num CutAllTables(morkEnv* ev)
+ { return this->CutAllBeads(ev); }
+ // CutAllTables() releases all the referenced table values.
+
+#else /*MORK_BEAD_OVER_NODE_MAPS*/
+ mork_bool AddTable(morkEnv* ev, morkTable* ioTable)
+ { return this->AddNode(ev, ioTable->TableId(), ioTable); }
+ // the AddTable() boolean return equals ev->Good().
+
+ mork_bool CutTable(morkEnv* ev, mork_tid inTid)
+ { return this->CutNode(ev, inTid); }
+ // The CutTable() boolean return indicates whether removal happened.
+
+ morkTable* GetTable(morkEnv* ev, mork_tid inTid)
+ { return (morkTable*) this->GetNode(ev, inTid); }
+ // Note the returned table does NOT have an increase in refcount for this.
+
+ mork_num CutAllTables(morkEnv* ev)
+ { return this->CutAllNodes(ev); }
+ // CutAllTables() releases all the referenced table values.
+#endif /*MORK_BEAD_OVER_NODE_MAPS*/
+
+};
+
+#ifdef MORK_BEAD_OVER_NODE_MAPS
+class morkTableMapIter: public morkBeadMapIter {
+#else /*MORK_BEAD_OVER_NODE_MAPS*/
+class morkTableMapIter: public morkMapIter{ // typesafe wrapper class
+#endif /*MORK_BEAD_OVER_NODE_MAPS*/
+
+public:
+
+#ifdef MORK_BEAD_OVER_NODE_MAPS
+ morkTableMapIter(morkEnv* ev, morkTableMap* ioMap)
+ : morkBeadMapIter(ev, ioMap) { }
+
+ morkTableMapIter( ) : morkBeadMapIter() { }
+ void InitTableMapIter(morkEnv* ev, morkTableMap* ioMap)
+ { this->InitBeadMapIter(ev, ioMap); }
+
+ morkTable* FirstTable(morkEnv* ev)
+ { return (morkTable*) this->FirstBead(ev); }
+
+ morkTable* NextTable(morkEnv* ev)
+ { return (morkTable*) this->NextBead(ev); }
+
+ morkTable* HereTable(morkEnv* ev)
+ { return (morkTable*) this->HereBead(ev); }
+
+
+#else /*MORK_BEAD_OVER_NODE_MAPS*/
+ morkTableMapIter(morkEnv* ev, morkTableMap* ioMap)
+ : morkMapIter(ev, ioMap) { }
+
+ morkTableMapIter( ) : morkMapIter() { }
+ void InitTableMapIter(morkEnv* ev, morkTableMap* ioMap)
+ { this->InitMapIter(ev, ioMap); }
+
+ mork_change*
+ FirstTable(morkEnv* ev, mork_tid* outTid, morkTable** outTable)
+ { return this->First(ev, outTid, outTable); }
+
+ mork_change*
+ NextTable(morkEnv* ev, mork_tid* outTid, morkTable** outTable)
+ { return this->Next(ev, outTid, outTable); }
+
+ mork_change*
+ HereTable(morkEnv* ev, mork_tid* outTid, morkTable** outTable)
+ { return this->Here(ev, outTid, outTable); }
+
+ // cutting while iterating hash map might dirty the parent table:
+ mork_change*
+ CutHereTable(morkEnv* ev, mork_tid* outTid, morkTable** outTable)
+ { return this->CutHere(ev, outTid, outTable); }
+#endif /*MORK_BEAD_OVER_NODE_MAPS*/
+};
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+#endif /* _MORKTABLE_ */
+