Back to index

lightning-sunbird  0.9+nobinonly
morkTable.h
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-  */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #ifndef _MORKTABLE_
00039 #define _MORKTABLE_ 1
00040 
00041 #ifndef _MORK_
00042 #include "mork.h"
00043 #endif
00044 
00045 #ifndef _MORKNODE_
00046 #include "morkNode.h"
00047 #endif
00048 
00049 #ifndef _MORKDEQUE_
00050 #include "morkDeque.h"
00051 #endif
00052 
00053 #ifndef _MORKOBJECT_
00054 #include "morkObject.h"
00055 #endif
00056 
00057 #ifndef _MORKARRAY_
00058 #include "morkArray.h"
00059 #endif
00060 
00061 #ifndef _MORKROWMAP_
00062 #include "morkRowMap.h"
00063 #endif
00064 
00065 #ifndef _MORKNODEMAP_
00066 #include "morkNodeMap.h"
00067 #endif
00068 
00069 #ifndef _MORKPROBEMAP_
00070 #include "morkProbeMap.h"
00071 #endif
00072 
00073 #ifndef _MORKBEAD_
00074 #include "morkBead.h"
00075 #endif
00076 
00077 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
00078 
00079 class nsIMdbTable;
00080 #define morkDerived_kTable  /*i*/ 0x5462 /* ascii 'Tb' */
00081 
00082 /*| kStartRowArraySize: starting physical size of array for mTable_RowArray.
00083 **| We want this number very small, so that a table containing exactly one
00084 **| row member will not pay too significantly in space overhead.  But we want
00085 **| a number bigger than one, so there is some space for growth.
00086 |*/
00087 #define morkTable_kStartRowArraySize 3 /* modest starting size for array */
00088 
00089 /*| kMakeRowMapThreshold: this is the number of rows in a table which causes
00090 **| a hash table (mTable_RowMap) to be lazily created for faster member row
00091 **| identification, during such operations as cuts and adds.  This number must
00092 **| be small enough that linear searches are not bad for member counts less
00093 **| than this; but this number must also be large enough that creating a hash
00094 **| table does not increase the per-row space overhead by a big percentage.
00095 **| For speed, numbers on the order of ten to twenty are all fine; for space,
00096 **| I believe a number as small as ten will have too much space overhead.
00097 |*/
00098 #define morkTable_kMakeRowMapThreshold 17 /* when to build mTable_RowMap */
00099 
00100 #define morkTable_kStartRowMapSlotCount 13
00101 #define morkTable_kMaxTableGcUses 0x0FF /* max for 8-bit unsigned int */
00102 
00103 #define morkTable_kUniqueBit   ((mork_u1) (1 << 0))
00104 #define morkTable_kVerboseBit  ((mork_u1) (1 << 1))
00105 #define morkTable_kNotedBit    ((mork_u1) (1 << 2)) /* space has change notes */
00106 #define morkTable_kRewriteBit  ((mork_u1) (1 << 3)) /* must rewrite all rows */
00107 #define morkTable_kNewMetaBit  ((mork_u1) (1 << 4)) /* new table meta row */
00108 
00109 class morkTable : public morkObject, public morkLink, public nsIMdbTable { 
00110 
00111   // NOTE the morkLink base is for morkRowSpace::mRowSpace_TablesByPriority
00112 
00113 // public: // slots inherited from morkObject (meant to inform only)
00114   // nsIMdbHeap*    mNode_Heap;
00115 
00116   // mork_base      mNode_Base;     // must equal morkBase_kNode
00117   // mork_derived   mNode_Derived;  // depends on specific node subclass
00118   
00119   // mork_access    mNode_Access;   // kOpen, kClosing, kShut, or kDead
00120   // mork_usage     mNode_Usage;    // kHeap, kStack, kMember, kGlobal, kNone
00121   // mork_able      mNode_Mutable;  // can this node be modified?
00122   // mork_load      mNode_Load;     // is this node clean or dirty?
00123   
00124   // mork_uses      mNode_Uses;     // refcount for strong refs
00125   // mork_refs      mNode_Refs;     // refcount for strong refs + weak refs
00126 
00127   // mork_color   mBead_Color;   // ID for this bead
00128   // morkHandle*  mObject_Handle;  // weak ref to handle for this object
00129 
00130 public: // bead color setter & getter replace obsolete member mTable_Id:
00131 
00132   NS_DECL_ISUPPORTS_INHERITED
00133   mork_tid     TableId() const { return mBead_Color; }
00134   void         SetTableId(mork_tid inTid) { mBead_Color = inTid; }
00135 
00136   // we override these so we use xpcom ref-counting semantics.
00137   virtual mork_refs    AddStrongRef(morkEnv* ev);
00138   virtual mork_refs    CutStrongRef(morkEnv* ev);
00139 public: // state is public because the entire Mork system is private
00140 
00141 // { ===== begin nsIMdbCollection methods =====
00142 
00143   // { ----- begin attribute methods -----
00144   NS_IMETHOD GetSeed(nsIMdbEnv* ev,
00145     mdb_seed* outSeed);    // member change count
00146   NS_IMETHOD GetCount(nsIMdbEnv* ev,
00147     mdb_count* outCount); // member count
00148 
00149   NS_IMETHOD GetPort(nsIMdbEnv* ev,
00150     nsIMdbPort** acqPort); // collection container
00151   // } ----- end attribute methods -----
00152 
00153   // { ----- begin cursor methods -----
00154   NS_IMETHOD GetCursor( // make a cursor starting iter at inMemberPos
00155     nsIMdbEnv* ev, // context
00156     mdb_pos inMemberPos, // zero-based ordinal pos of member in collection
00157     nsIMdbCursor** acqCursor); // acquire new cursor instance
00158   // } ----- end cursor methods -----
00159 
00160   // { ----- begin ID methods -----
00161   NS_IMETHOD GetOid(nsIMdbEnv* ev,
00162     mdbOid* outOid); // read object identity
00163   NS_IMETHOD BecomeContent(nsIMdbEnv* ev,
00164     const mdbOid* inOid); // exchange content
00165   // } ----- end ID methods -----
00166 
00167   // { ----- begin activity dropping methods -----
00168   NS_IMETHOD DropActivity( // tell collection usage no longer expected
00169     nsIMdbEnv* ev);
00170   // } ----- end activity dropping methods -----
00171 
00172 // } ===== end nsIMdbCollection methods =====
00173   NS_IMETHOD SetTablePriority(nsIMdbEnv* ev, mdb_priority inPrio);
00174   NS_IMETHOD GetTablePriority(nsIMdbEnv* ev, mdb_priority* outPrio);
00175   
00176   NS_IMETHOD GetTableBeVerbose(nsIMdbEnv* ev, mdb_bool* outBeVerbose);
00177   NS_IMETHOD SetTableBeVerbose(nsIMdbEnv* ev, mdb_bool inBeVerbose);
00178   
00179   NS_IMETHOD GetTableIsUnique(nsIMdbEnv* ev, mdb_bool* outIsUnique);
00180   
00181   NS_IMETHOD GetTableKind(nsIMdbEnv* ev, mdb_kind* outTableKind);
00182   NS_IMETHOD GetRowScope(nsIMdbEnv* ev, mdb_scope* outRowScope);
00183   
00184   NS_IMETHOD GetMetaRow(
00185     nsIMdbEnv* ev, // context
00186     const mdbOid* inOptionalMetaRowOid, // can be nil to avoid specifying 
00187     mdbOid* outOid, // output meta row oid, can be nil to suppress output
00188     nsIMdbRow** acqRow); // acquire table's unique singleton meta row
00189     // The purpose of a meta row is to support the persistent recording of
00190     // meta info about a table as cells put into the distinguished meta row.
00191     // Each table has exactly one meta row, which is not considered a member
00192     // of the collection of rows inside the table.  The only way to tell
00193     // whether a row is a meta row is by the fact that it is returned by this
00194     // GetMetaRow() method from some table. Otherwise nothing distinguishes
00195     // a meta row from any other row.  A meta row can be used anyplace that
00196     // any other row can be used, and can even be put into other tables (or
00197     // the same table) as a table member, if this is useful for some reason.
00198     // The first attempt to access a table's meta row using GetMetaRow() will
00199     // cause the meta row to be created if it did not already exist.  When the
00200     // meta row is created, it will have the row oid that was previously
00201     // requested for this table's meta row; or if no oid was ever explicitly
00202     // specified for this meta row, then a unique oid will be generated in
00203     // the row scope named "m" (so obviously MDB clients should not
00204     // manually allocate any row IDs from that special meta scope namespace).
00205     // The meta row oid can be specified either when the table is created, or
00206     // else the first time that GetMetaRow() is called, by passing a non-nil
00207     // pointer to an oid for parameter inOptionalMetaRowOid.  The meta row's
00208     // actual oid is returned in outOid (if this is a non-nil pointer), and
00209     // it will be different from inOptionalMetaRowOid when the meta row was
00210     // already given a different oid earlier.
00211   // } ----- end meta attribute methods -----
00212 
00213 
00214   // { ----- begin cursor methods -----
00215   NS_IMETHOD GetTableRowCursor( // make a cursor, starting iteration at inRowPos
00216     nsIMdbEnv* ev, // context
00217     mdb_pos inRowPos, // zero-based ordinal position of row in table
00218     nsIMdbTableRowCursor** acqCursor); // acquire new cursor instance
00219   // } ----- end row position methods -----
00220 
00221   // { ----- begin row position methods -----
00222   NS_IMETHOD PosToOid( // get row member for a table position
00223     nsIMdbEnv* ev, // context
00224     mdb_pos inRowPos, // zero-based ordinal position of row in table
00225     mdbOid* outOid); // row oid at the specified position
00226 
00227   NS_IMETHOD OidToPos( // test for the table position of a row member
00228     nsIMdbEnv* ev, // context
00229     const mdbOid* inOid, // row to find in table
00230     mdb_pos* outPos); // zero-based ordinal position of row in table
00231     
00232   NS_IMETHOD PosToRow( // test for the table position of a row member
00233     nsIMdbEnv* ev, // context
00234     mdb_pos inRowPos, // zero-based ordinal position of row in table
00235     nsIMdbRow** acqRow); // acquire row at table position inRowPos
00236     
00237   NS_IMETHOD RowToPos( // test for the table position of a row member
00238     nsIMdbEnv* ev, // context
00239     nsIMdbRow* ioRow, // row to find in table
00240     mdb_pos* outPos); // zero-based ordinal position of row in table
00241   // } ----- end row position methods -----
00242 
00243   // { ----- begin oid set methods -----
00244   NS_IMETHOD AddOid( // make sure the row with inOid is a table member 
00245     nsIMdbEnv* ev, // context
00246     const mdbOid* inOid); // row to ensure membership in table
00247 
00248   NS_IMETHOD HasOid( // test for the table position of a row member
00249     nsIMdbEnv* ev, // context
00250     const mdbOid* inOid, // row to find in table
00251     mdb_bool* outHasOid); // whether inOid is a member row
00252 
00253   NS_IMETHOD CutOid( // make sure the row with inOid is not a member 
00254     nsIMdbEnv* ev, // context
00255     const mdbOid* inOid); // row to remove from table
00256   // } ----- end oid set methods -----
00257 
00258   // { ----- begin row set methods -----
00259   NS_IMETHOD NewRow( // create a new row instance in table
00260     nsIMdbEnv* ev, // context
00261     mdbOid* ioOid, // please use minus one (unbound) rowId for db-assigned IDs
00262     nsIMdbRow** acqRow); // create new row
00263 
00264   NS_IMETHOD AddRow( // make sure the row with inOid is a table member 
00265     nsIMdbEnv* ev, // context
00266     nsIMdbRow* ioRow); // row to ensure membership in table
00267 
00268   NS_IMETHOD HasRow( // test for the table position of a row member
00269     nsIMdbEnv* ev, // context
00270     nsIMdbRow* ioRow, // row to find in table
00271     mdb_bool* outHasRow); // whether row is a table member
00272 
00273   NS_IMETHOD CutRow( // make sure the row with inOid is not a member 
00274     nsIMdbEnv* ev, // context
00275     nsIMdbRow* ioRow); // row to remove from table
00276 
00277   NS_IMETHOD CutAllRows( // remove all rows from the table
00278     nsIMdbEnv* ev); // context
00279   // } ----- end row set methods -----
00280 
00281   // { ----- begin hinting methods -----
00282   NS_IMETHOD SearchColumnsHint( // advise re future expected search cols  
00283     nsIMdbEnv* ev, // context
00284     const mdbColumnSet* inColumnSet); // columns likely to be searched
00285     
00286   NS_IMETHOD SortColumnsHint( // advise re future expected sort columns  
00287     nsIMdbEnv* ev, // context
00288     const mdbColumnSet* inColumnSet); // columns for likely sort requests
00289     
00290   NS_IMETHOD StartBatchChangeHint( // advise before many adds and cuts  
00291     nsIMdbEnv* ev, // context
00292     const void* inLabel); // intend unique address to match end call
00293     // If batch starts nest by virtue of nesting calls in the stack, then
00294     // the address of a local variable makes a good batch start label that
00295     // can be used at batch end time, and such addresses remain unique.
00296     
00297   NS_IMETHOD EndBatchChangeHint( // advise before many adds and cuts  
00298     nsIMdbEnv* ev, // context
00299     const void* inLabel); // label matching start label
00300     // Suppose a table is maintaining one or many sort orders for a table,
00301     // so that every row added to the table must be inserted in each sort,
00302     // and every row cut must be removed from each sort.  If a db client
00303     // intends to make many such changes before needing any information
00304     // about the order or positions of rows inside a table, then a client
00305     // might tell the table to start batch changes in order to disable
00306     // sorting of rows for the interim.  Presumably a table will then do
00307     // a full sort of all rows at need when the batch changes end, or when
00308     // a surprise request occurs for row position during batch changes.
00309   // } ----- end hinting methods -----
00310 
00311   // { ----- begin searching methods -----
00312   NS_IMETHOD FindRowMatches( // search variable number of sorted cols
00313     nsIMdbEnv* ev, // context
00314     const mdbYarn* inPrefix, // content to find as prefix in row's column cell
00315     nsIMdbTableRowCursor** acqCursor); // set of matching rows
00316     
00317   NS_IMETHOD GetSearchColumns( // query columns used by FindRowMatches()
00318     nsIMdbEnv* ev, // context
00319     mdb_count* outCount, // context
00320     mdbColumnSet* outColSet); // caller supplied space to put columns
00321     // GetSearchColumns() returns the columns actually searched when the
00322     // FindRowMatches() method is called.  No more than mColumnSet_Count
00323     // slots of mColumnSet_Columns will be written, since mColumnSet_Count
00324     // indicates how many slots are present in the column array.  The
00325     // actual number of search column used by the table is returned in
00326     // the outCount parameter; if this number exceeds mColumnSet_Count,
00327     // then a caller needs a bigger array to read the entire column set.
00328     // The minimum of mColumnSet_Count and outCount is the number slots
00329     // in mColumnSet_Columns that were actually written by this method.
00330     //
00331     // Callers are expected to change this set of columns by calls to
00332     // nsIMdbTable::SearchColumnsHint() or SetSearchSorting(), or both.
00333   // } ----- end searching methods -----
00334 
00335   // { ----- begin sorting methods -----
00336   // sorting: note all rows are assumed sorted by row ID as a secondary
00337   // sort following the primary column sort, when table rows are sorted.
00338 
00339   NS_IMETHOD
00340   CanSortColumn( // query which column is currently used for sorting
00341     nsIMdbEnv* ev, // context
00342     mdb_column inColumn, // column to query sorting potential
00343     mdb_bool* outCanSort); // whether the column can be sorted
00344     
00345   NS_IMETHOD GetSorting( // view same table in particular sorting
00346     nsIMdbEnv* ev, // context
00347     mdb_column inColumn, // requested new column for sorting table
00348     nsIMdbSorting** acqSorting); // acquire sorting for column
00349     
00350   NS_IMETHOD SetSearchSorting( // use this sorting in FindRowMatches()
00351     nsIMdbEnv* ev, // context
00352     mdb_column inColumn, // often same as nsIMdbSorting::GetSortColumn()
00353     nsIMdbSorting* ioSorting); // requested sorting for some column
00354     // SetSearchSorting() attempts to inform the table that ioSorting
00355     // should be used during calls to FindRowMatches() for searching
00356     // the column which is actually sorted by ioSorting.  This method
00357     // is most useful in conjunction with nsIMdbSorting::SetCompare(),
00358     // because otherwise a caller would not be able to override the
00359     // comparison ordering method used during searchs.  Note that some
00360     // database implementations might be unable to use an arbitrarily
00361     // specified sort order, either due to schema or runtime interface
00362     // constraints, in which case ioSorting might not actually be used.
00363     // Presumably ioSorting is an instance that was returned from some
00364     // earlier call to nsIMdbTable::GetSorting().  A caller can also
00365     // use nsIMdbTable::SearchColumnsHint() to specify desired change
00366     // in which columns are sorted and searched by FindRowMatches().
00367     //
00368     // A caller can pass a nil pointer for ioSorting to request that
00369     // column inColumn no longer be used at all by FindRowMatches().
00370     // But when ioSorting is non-nil, then inColumn should match the
00371     // column actually sorted by ioSorting; when these do not agree,
00372     // implementations are instructed to give precedence to the column
00373     // specified by ioSorting (so this means callers might just pass
00374     // zero for inColumn when ioSorting is also provided, since then
00375     // inColumn is both redundant and ignored).
00376   // } ----- end sorting methods -----
00377 
00378   // { ----- begin moving methods -----
00379   // moving a row does nothing unless a table is currently unsorted
00380   
00381   NS_IMETHOD MoveOid( // change position of row in unsorted table
00382     nsIMdbEnv* ev, // context
00383     const mdbOid* inOid,  // row oid to find in table
00384     mdb_pos inHintFromPos, // suggested hint regarding start position
00385     mdb_pos inToPos,       // desired new position for row inRowId
00386     mdb_pos* outActualPos); // actual new position of row in table
00387 
00388   NS_IMETHOD MoveRow( // change position of row in unsorted table
00389     nsIMdbEnv* ev, // context
00390     nsIMdbRow* ioRow,  // row oid to find in table
00391     mdb_pos inHintFromPos, // suggested hint regarding start position
00392     mdb_pos inToPos,       // desired new position for row inRowId
00393     mdb_pos* outActualPos); // actual new position of row in table
00394   // } ----- end moving methods -----
00395   
00396   // { ----- begin index methods -----
00397   NS_IMETHOD AddIndex( // create a sorting index for column if possible
00398     nsIMdbEnv* ev, // context
00399     mdb_column inColumn, // the column to sort by index
00400     nsIMdbThumb** acqThumb); // acquire thumb for incremental index building
00401   // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
00402   // then the index addition will be finished.
00403   
00404   NS_IMETHOD CutIndex( // stop supporting a specific column index
00405     nsIMdbEnv* ev, // context
00406     mdb_column inColumn, // the column with index to be removed
00407     nsIMdbThumb** acqThumb); // acquire thumb for incremental index destroy
00408   // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
00409   // then the index removal will be finished.
00410   
00411   NS_IMETHOD HasIndex( // query for current presence of a column index
00412     nsIMdbEnv* ev, // context
00413     mdb_column inColumn, // the column to investigate
00414     mdb_bool* outHasIndex); // whether column has index for this column
00415 
00416   
00417   NS_IMETHOD EnableIndexOnSort( // create an index for col on first sort
00418     nsIMdbEnv* ev, // context
00419     mdb_column inColumn); // the column to index if ever sorted
00420   
00421   NS_IMETHOD QueryIndexOnSort( // check whether index on sort is enabled
00422     nsIMdbEnv* ev, // context
00423     mdb_column inColumn, // the column to investigate
00424     mdb_bool* outIndexOnSort); // whether column has index-on-sort enabled
00425   
00426   NS_IMETHOD DisableIndexOnSort( // prevent future index creation on sort
00427     nsIMdbEnv* ev, // context
00428     mdb_column inColumn); // the column to index if ever sorted
00429   // } ----- end index methods -----
00430 
00431   morkStore*      mTable_Store;   // non-refcnted ptr to port
00432 
00433   // mTable_RowSpace->SpaceScope() is row scope 
00434   morkRowSpace*   mTable_RowSpace; // non-refcnted ptr to containing space
00435 
00436   morkRow*        mTable_MetaRow; // table's actual meta row
00437   mdbOid          mTable_MetaRowOid; // oid for meta row
00438   
00439   morkRowMap*     mTable_RowMap;     // (strong ref) hash table of all members
00440   morkArray       mTable_RowArray;   // array of morkRow pointers
00441   
00442   morkList        mTable_ChangeList;      // list of table changes
00443   mork_u2         mTable_ChangesCount; // length of changes list 
00444   mork_u2         mTable_ChangesMax;   // max list length before rewrite 
00445   
00446   // mork_tid        mTable_Id;
00447   mork_kind       mTable_Kind;
00448   
00449   mork_u1         mTable_Flags;         // bit flags
00450   mork_priority   mTable_Priority;      // 0..9, any other value equals 9
00451   mork_u1         mTable_GcUses;        // persistent references from cells
00452   mork_u1         mTable_Pad;      // for u4 alignment
00453 
00454 public: // flags bit twiddling
00455   
00456   void SetTableUnique() { mTable_Flags |= morkTable_kUniqueBit; }
00457   void SetTableVerbose() { mTable_Flags |= morkTable_kVerboseBit; }
00458   void SetTableNoted() { mTable_Flags |= morkTable_kNotedBit; }
00459   void SetTableRewrite() { mTable_Flags |= morkTable_kRewriteBit; }
00460   void SetTableNewMeta() { mTable_Flags |= morkTable_kNewMetaBit; }
00461 
00462   void ClearTableUnique() { mTable_Flags &= (mork_u1) ~morkTable_kUniqueBit; }
00463   void ClearTableVerbose() { mTable_Flags &= (mork_u1) ~morkTable_kVerboseBit; }
00464   void ClearTableNoted() { mTable_Flags &= (mork_u1) ~morkTable_kNotedBit; }
00465   void ClearTableRewrite() { mTable_Flags &= (mork_u1) ~morkTable_kRewriteBit; }
00466   void ClearTableNewMeta() { mTable_Flags &= (mork_u1) ~morkTable_kNewMetaBit; }
00467 
00468   mork_bool IsTableUnique() const
00469   { return ( mTable_Flags & morkTable_kUniqueBit ) != 0; }
00470   
00471   mork_bool IsTableVerbose() const
00472   { return ( mTable_Flags & morkTable_kVerboseBit ) != 0; }
00473   
00474   mork_bool IsTableNoted() const
00475   { return ( mTable_Flags & morkTable_kNotedBit ) != 0; }
00476   
00477   mork_bool IsTableRewrite() const
00478   { return ( mTable_Flags & morkTable_kRewriteBit ) != 0; }
00479   
00480   mork_bool IsTableNewMeta() const
00481   { return ( mTable_Flags & morkTable_kNewMetaBit ) != 0; }
00482 
00483 public: // table dirty handling more complex than morkNode::SetNodeDirty() etc.
00484 
00485   void SetTableDirty() { this->SetNodeDirty(); }
00486   void SetTableClean(morkEnv* ev);
00487    
00488   mork_bool IsTableClean() const { return this->IsNodeClean(); }
00489   mork_bool IsTableDirty() const { return this->IsNodeDirty(); }
00490 
00491 public: // morkNode memory management operators
00492   void* operator new(size_t inSize, nsIMdbHeap& ioHeap, morkEnv* ev) CPP_THROW_NEW
00493   { return morkNode::MakeNew(inSize, ioHeap, ev); }
00494   
00495  
00496 // { ===== begin morkNode interface =====
00497 public: // morkNode virtual methods
00498   virtual void CloseMorkNode(morkEnv* ev); // CloseTable() if open
00499   virtual ~morkTable(); // assert that close executed earlier
00500   
00501 public: // morkTable construction & destruction
00502   morkTable(morkEnv* ev, const morkUsage& inUsage,
00503     nsIMdbHeap* ioNodeHeap, morkStore* ioStore,
00504     nsIMdbHeap* ioSlotHeap, morkRowSpace* ioRowSpace,
00505     const mdbOid* inOptionalMetaRowOid, // can be nil to avoid specifying 
00506     mork_tid inTableId,
00507     mork_kind inKind, mork_bool inMustBeUnique);
00508   void CloseTable(morkEnv* ev); // called by CloseMorkNode();
00509 
00510 private: // copying is not allowed
00511   morkTable(const morkTable& other);
00512   morkTable& operator=(const morkTable& other);
00513 
00514 public: // dynamic type identification
00515   mork_bool IsTable() const
00516   { return IsNode() && mNode_Derived == morkDerived_kTable; }
00517 // } ===== end morkNode methods =====
00518 
00519 public: // errors
00520   static void NonTableTypeError(morkEnv* ev);
00521   static void NonTableTypeWarning(morkEnv* ev);
00522   static void NilRowSpaceError(morkEnv* ev);
00523 
00524 public: // warnings
00525   static void TableGcUsesUnderflowWarning(morkEnv* ev);
00526 
00527 public: // noting table changes
00528 
00529   mork_bool HasChangeOverflow() const
00530   { return mTable_ChangesCount >= mTable_ChangesMax; }
00531 
00532   void NoteTableSetAll(morkEnv* ev);
00533   void NoteTableMoveRow(morkEnv* ev, morkRow* ioRow, mork_pos inPos);
00534 
00535   void note_row_change(morkEnv* ev, mork_change inChange, morkRow* ioRow);
00536   void note_row_move(morkEnv* ev, morkRow* ioRow, mork_pos inNewPos);
00537   
00538   void NoteTableAddRow(morkEnv* ev, morkRow* ioRow)
00539   { this->note_row_change(ev, morkChange_kAdd, ioRow); }
00540   
00541   void NoteTableCutRow(morkEnv* ev, morkRow* ioRow)
00542   { this->note_row_change(ev, morkChange_kCut, ioRow); }
00543   
00544 protected: // internal row map methods
00545 
00546   morkRow* find_member_row(morkEnv* ev, morkRow* ioRow);
00547   void build_row_map(morkEnv* ev);
00548 
00549 public: // other table methods
00550   
00551   mork_bool MaybeDirtySpaceStoreAndTable();
00552 
00553   morkRow* GetMetaRow(morkEnv* ev, const mdbOid* inOptionalMetaRowOid);
00554   
00555   mork_u2 AddTableGcUse(morkEnv* ev);
00556   mork_u2 CutTableGcUse(morkEnv* ev);
00557 
00558   // void DirtyAllTableContent(morkEnv* ev);
00559 
00560   mork_seed TableSeed() const { return mTable_RowArray.mArray_Seed; }
00561   
00562   morkRow* SafeRowAt(morkEnv* ev, mork_pos inPos)
00563   { return (morkRow*) mTable_RowArray.SafeAt(ev, inPos); }
00564 
00565   nsIMdbTable* AcquireTableHandle(morkEnv* ev); // mObject_Handle
00566   
00567   mork_count GetRowCount() const { return mTable_RowArray.mArray_Fill; }
00568 
00569   mork_bool IsTableUsed() const
00570   { return (mTable_GcUses != 0 || this->GetRowCount() != 0); }
00571 
00572   void GetTableOid(morkEnv* ev, mdbOid* outOid);
00573   mork_pos  ArrayHasOid(morkEnv* ev, const mdbOid* inOid);
00574   mork_bool MapHasOid(morkEnv* ev, const mdbOid* inOid);
00575   mork_bool AddRow(morkEnv* ev, morkRow* ioRow); // returns ev->Good()
00576   mork_bool CutRow(morkEnv* ev, morkRow* ioRow); // returns ev->Good()
00577   mork_bool CutAllRows(morkEnv* ev); // returns ev->Good()
00578   
00579   mork_pos MoveRow(morkEnv* ev, morkRow* ioRow, // change row position
00580     mork_pos inHintFromPos, // suggested hint regarding start position
00581     mork_pos inToPos); // desired new position for row ioRow
00582     // MoveRow() returns the actual position of ioRow afterwards; this
00583     // position is -1 if and only if ioRow was not found as a member.     
00584 
00585 
00586   morkTableRowCursor* NewTableRowCursor(morkEnv* ev, mork_pos inRowPos);
00587 
00588 public: // typesafe refcounting inlines calling inherited morkNode methods
00589   static void SlotWeakTable(morkTable* me,
00590     morkEnv* ev, morkTable** ioSlot)
00591   { morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
00592   
00593   static void SlotStrongTable(morkTable* me,
00594     morkEnv* ev, morkTable** ioSlot)
00595   { morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
00596 };
00597 
00598 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
00599 
00600 // use negative values for kCut and kAdd, to keep non-neg move pos distinct:
00601 #define morkTableChange_kCut ((mork_pos) -1) /* shows row was cut */
00602 #define morkTableChange_kAdd ((mork_pos) -2) /* shows row was added */
00603 #define morkTableChange_kNone ((mork_pos) -3) /* unknown change */
00604 
00605 class morkTableChange : public morkNext { 
00606 public: // state is public because the entire Mork system is private
00607 
00608   morkRow*  mTableChange_Row; // the row in the change
00609   
00610   mork_pos  mTableChange_Pos; // kAdd, kCut, or non-neg for row move
00611 
00612 public:
00613   morkTableChange(morkEnv* ev, mork_change inChange, morkRow* ioRow);
00614   // use this constructor for inChange == morkChange_kAdd or morkChange_kCut
00615   
00616   morkTableChange(morkEnv* ev, morkRow* ioRow, mork_pos inPos);
00617   // use this constructor when the row is moved
00618 
00619 public:
00620   void UnknownChangeError(morkEnv* ev) const; // morkChange_kAdd or morkChange_kCut
00621   void NegativeMovePosError(morkEnv* ev) const; // move must be non-neg position
00622   
00623 public:
00624   
00625   mork_bool IsAddRowTableChange() const
00626   { return ( mTableChange_Pos == morkTableChange_kAdd ); }
00627   
00628   mork_bool IsCutRowTableChange() const
00629   { return ( mTableChange_Pos == morkTableChange_kCut ); }
00630   
00631   mork_bool IsMoveRowTableChange() const
00632   { return ( mTableChange_Pos >= 0 ); }
00633 
00634 public:
00635   
00636   mork_pos GetMovePos() const { return mTableChange_Pos; }
00637   // GetMovePos() assumes that IsMoveRowTableChange() is true.
00638 };
00639 
00640 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
00641 
00642 #define morkDerived_kTableMap  /*i*/ 0x744D /* ascii 'tM' */
00643 
00644 /*| morkTableMap: maps mork_token -> morkTable
00645 |*/
00646 #ifdef MORK_BEAD_OVER_NODE_MAPS
00647 class morkTableMap : public morkBeadMap { 
00648 #else /*MORK_BEAD_OVER_NODE_MAPS*/
00649 class morkTableMap : public morkNodeMap { // for mapping tokens to tables
00650 #endif /*MORK_BEAD_OVER_NODE_MAPS*/
00651 
00652 public:
00653 
00654   virtual ~morkTableMap();
00655   morkTableMap(morkEnv* ev, const morkUsage& inUsage,
00656     nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap);
00657 
00658 public: // other map methods
00659 
00660 #ifdef MORK_BEAD_OVER_NODE_MAPS
00661   mork_bool  AddTable(morkEnv* ev, morkTable* ioTable)
00662   { return this->AddBead(ev, ioTable); }
00663   // the AddTable() boolean return equals ev->Good().
00664 
00665   mork_bool  CutTable(morkEnv* ev, mork_tid inTid)
00666   { return this->CutBead(ev, inTid); }
00667   // The CutTable() boolean return indicates whether removal happened. 
00668   
00669   morkTable*  GetTable(morkEnv* ev, mork_tid inTid)
00670   { return (morkTable*) this->GetBead(ev, inTid); }
00671   // Note the returned table does NOT have an increase in refcount for this.
00672 
00673   mork_num CutAllTables(morkEnv* ev)
00674   { return this->CutAllBeads(ev); }
00675   // CutAllTables() releases all the referenced table values.
00676   
00677 #else /*MORK_BEAD_OVER_NODE_MAPS*/
00678   mork_bool  AddTable(morkEnv* ev, morkTable* ioTable)
00679   { return this->AddNode(ev, ioTable->TableId(), ioTable); }
00680   // the AddTable() boolean return equals ev->Good().
00681 
00682   mork_bool  CutTable(morkEnv* ev, mork_tid inTid)
00683   { return this->CutNode(ev, inTid); }
00684   // The CutTable() boolean return indicates whether removal happened. 
00685   
00686   morkTable*  GetTable(morkEnv* ev, mork_tid inTid)
00687   { return (morkTable*) this->GetNode(ev, inTid); }
00688   // Note the returned table does NOT have an increase in refcount for this.
00689 
00690   mork_num CutAllTables(morkEnv* ev)
00691   { return this->CutAllNodes(ev); }
00692   // CutAllTables() releases all the referenced table values.
00693 #endif /*MORK_BEAD_OVER_NODE_MAPS*/
00694 
00695 };
00696 
00697 #ifdef MORK_BEAD_OVER_NODE_MAPS
00698 class morkTableMapIter: public morkBeadMapIter {
00699 #else /*MORK_BEAD_OVER_NODE_MAPS*/
00700 class morkTableMapIter: public morkMapIter{ // typesafe wrapper class
00701 #endif /*MORK_BEAD_OVER_NODE_MAPS*/
00702 
00703 public:
00704 
00705 #ifdef MORK_BEAD_OVER_NODE_MAPS
00706   morkTableMapIter(morkEnv* ev, morkTableMap* ioMap)
00707   : morkBeadMapIter(ev, ioMap) { }
00708  
00709   morkTableMapIter( ) : morkBeadMapIter()  { }
00710   void InitTableMapIter(morkEnv* ev, morkTableMap* ioMap)
00711   { this->InitBeadMapIter(ev, ioMap); }
00712    
00713   morkTable* FirstTable(morkEnv* ev)
00714   { return (morkTable*) this->FirstBead(ev); }
00715   
00716   morkTable* NextTable(morkEnv* ev)
00717   { return (morkTable*) this->NextBead(ev); }
00718   
00719   morkTable* HereTable(morkEnv* ev)
00720   { return (morkTable*) this->HereBead(ev); }
00721   
00722 
00723 #else /*MORK_BEAD_OVER_NODE_MAPS*/
00724   morkTableMapIter(morkEnv* ev, morkTableMap* ioMap)
00725   : morkMapIter(ev, ioMap) { }
00726  
00727   morkTableMapIter( ) : morkMapIter()  { }
00728   void InitTableMapIter(morkEnv* ev, morkTableMap* ioMap)
00729   { this->InitMapIter(ev, ioMap); }
00730    
00731   mork_change*
00732   FirstTable(morkEnv* ev, mork_tid* outTid, morkTable** outTable)
00733   { return this->First(ev, outTid, outTable); }
00734   
00735   mork_change*
00736   NextTable(morkEnv* ev, mork_tid* outTid, morkTable** outTable)
00737   { return this->Next(ev, outTid, outTable); }
00738   
00739   mork_change*
00740   HereTable(morkEnv* ev, mork_tid* outTid, morkTable** outTable)
00741   { return this->Here(ev, outTid, outTable); }
00742   
00743   // cutting while iterating hash map might dirty the parent table:
00744   mork_change*
00745   CutHereTable(morkEnv* ev, mork_tid* outTid, morkTable** outTable)
00746   { return this->CutHere(ev, outTid, outTable); }
00747 #endif /*MORK_BEAD_OVER_NODE_MAPS*/
00748 };
00749 
00750 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
00751 
00752 #endif /* _MORKTABLE_ */
00753