/* -*- 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 searches. 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_ */