1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #ifndef _MORKTABLE_ 7 #define _MORKTABLE_ 1 8 9 #ifndef _MORK_ 10 # include "mork.h" 11 #endif 12 13 #ifndef _MORKNODE_ 14 # include "morkNode.h" 15 #endif 16 17 #ifndef _MORKDEQUE_ 18 # include "morkDeque.h" 19 #endif 20 21 #ifndef _MORKOBJECT_ 22 # include "morkObject.h" 23 #endif 24 25 #ifndef _MORKARRAY_ 26 # include "morkArray.h" 27 #endif 28 29 #ifndef _MORKROWMAP_ 30 # include "morkRowMap.h" 31 #endif 32 33 #ifndef _MORKNODEMAP_ 34 # include "morkNodeMap.h" 35 #endif 36 37 #ifndef _MORKPROBEMAP_ 38 # include "morkProbeMap.h" 39 #endif 40 41 #ifndef _MORKBEAD_ 42 # include "morkBead.h" 43 #endif 44 45 // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 46 47 class nsIMdbTable; 48 #define morkDerived_kTable /*i*/ 0x5462 /* ascii 'Tb' */ 49 50 /*| kStartRowArraySize: starting physical size of array for mTable_RowArray. 51 **| We want this number very small, so that a table containing exactly one 52 **| row member will not pay too significantly in space overhead. But we want 53 **| a number bigger than one, so there is some space for growth. 54 |*/ 55 #define morkTable_kStartRowArraySize 3 /* modest starting size for array */ 56 57 /*| kMakeRowMapThreshold: this is the number of rows in a table which causes 58 **| a hash table (mTable_RowMap) to be lazily created for faster member row 59 **| identification, during such operations as cuts and adds. This number must 60 **| be small enough that linear searches are not bad for member counts less 61 **| than this; but this number must also be large enough that creating a hash 62 **| table does not increase the per-row space overhead by a big percentage. 63 **| For speed, numbers on the order of ten to twenty are all fine; for space, 64 **| I believe a number as small as ten will have too much space overhead. 65 |*/ 66 #define morkTable_kMakeRowMapThreshold 17 /* when to build mTable_RowMap */ 67 68 #define morkTable_kStartRowMapSlotCount 13 69 #define morkTable_kMaxTableGcUses 0x0FF /* max for 8-bit unsigned int */ 70 71 #define morkTable_kUniqueBit ((mork_u1)(1 << 0)) 72 #define morkTable_kVerboseBit ((mork_u1)(1 << 1)) 73 #define morkTable_kNotedBit ((mork_u1)(1 << 2)) /* space has change notes */ 74 #define morkTable_kRewriteBit ((mork_u1)(1 << 3)) /* must rewrite all rows */ 75 #define morkTable_kNewMetaBit ((mork_u1)(1 << 4)) /* new table meta row */ 76 77 class morkTable : public morkObject, public morkLink, public nsIMdbTable { 78 // NOTE the morkLink base is for morkRowSpace::mRowSpace_TablesByPriority 79 80 // public: // slots inherited from morkObject (meant to inform only) 81 // nsIMdbHeap* mNode_Heap; 82 83 // mork_base mNode_Base; // must equal morkBase_kNode 84 // mork_derived mNode_Derived; // depends on specific node subclass 85 86 // mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead 87 // mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone 88 // mork_able mNode_Mutable; // can this node be modified? 89 // mork_load mNode_Load; // is this node clean or dirty? 90 91 // mork_uses mNode_Uses; // refcount for strong refs 92 // mork_refs mNode_Refs; // refcount for strong refs + weak refs 93 94 // mork_color mBead_Color; // ID for this bead 95 // morkHandle* mObject_Handle; // weak ref to handle for this object 96 97 public: // bead color setter & getter replace obsolete member mTable_Id: 98 NS_DECL_ISUPPORTS_INHERITED TableId()99 mork_tid TableId() const { return mBead_Color; } SetTableId(mork_tid inTid)100 void SetTableId(mork_tid inTid) { mBead_Color = inTid; } 101 102 // we override these so we use xpcom ref-counting semantics. 103 #ifndef _MSC_VER 104 // The first declaration of AddStrongRef is to suppress 105 // -Werror,-Woverloaded-virtual. 106 virtual mork_refs AddStrongRef(nsIMdbEnv* ev) override; 107 #endif 108 virtual mork_refs AddStrongRef(morkEnv* ev) override; 109 #ifndef _MSC_VER 110 // The first declaration of CutStrongRef is to suppress 111 // -Werror,-Woverloaded-virtual. 112 virtual nsresult CutStrongRef(nsIMdbEnv* ev) override; 113 #endif 114 virtual mork_refs CutStrongRef(morkEnv* ev) override; 115 116 public: 117 // { ===== begin nsIMdbCollection methods ===== 118 // { ----- begin attribute methods ----- 119 NS_IMETHOD GetSeed(nsIMdbEnv* ev, 120 mdb_seed* outSeed) override; // member change count 121 NS_IMETHOD GetCount(nsIMdbEnv* ev, 122 mdb_count* outCount) override; // member count 123 124 NS_IMETHOD GetPort(nsIMdbEnv* ev, 125 nsIMdbPort** acqPort) override; // collection container 126 // } ----- end attribute methods ----- 127 128 // { ----- begin cursor methods ----- 129 NS_IMETHOD GetCursor( // make a cursor starting iter at inMemberPos 130 nsIMdbEnv* ev, // context 131 mdb_pos inMemberPos, // zero-based ordinal pos of member in collection 132 nsIMdbCursor** acqCursor) override; // acquire new cursor instance 133 // } ----- end cursor methods ----- 134 135 // { ----- begin ID methods ----- 136 NS_IMETHOD GetOid(nsIMdbEnv* ev, 137 mdbOid* outOid) override; // read object identity 138 NS_IMETHOD BecomeContent(nsIMdbEnv* ev, 139 const mdbOid* inOid) override; // exchange content 140 // } ----- end ID methods ----- 141 142 // { ----- begin activity dropping methods ----- 143 NS_IMETHOD DropActivity( // tell collection usage no longer expected 144 nsIMdbEnv* ev) override; 145 // } ----- end activity dropping methods ----- 146 147 // } ===== end nsIMdbCollection methods ===== 148 NS_IMETHOD SetTablePriority(nsIMdbEnv* ev, mdb_priority inPrio) override; 149 NS_IMETHOD GetTablePriority(nsIMdbEnv* ev, mdb_priority* outPrio) override; 150 151 NS_IMETHOD GetTableBeVerbose(nsIMdbEnv* ev, mdb_bool* outBeVerbose) override; 152 NS_IMETHOD SetTableBeVerbose(nsIMdbEnv* ev, mdb_bool inBeVerbose) override; 153 154 NS_IMETHOD GetTableIsUnique(nsIMdbEnv* ev, mdb_bool* outIsUnique) override; 155 156 NS_IMETHOD GetTableKind(nsIMdbEnv* ev, mdb_kind* outTableKind) override; 157 NS_IMETHOD GetRowScope(nsIMdbEnv* ev, mdb_scope* outRowScope) override; 158 159 NS_IMETHOD GetMetaRow( 160 nsIMdbEnv* ev, // context 161 const mdbOid* inOptionalMetaRowOid, // can be nil to avoid specifying 162 mdbOid* outOid, // output meta row oid, can be nil to suppress output 163 nsIMdbRow** acqRow) 164 override; // acquire table's unique singleton meta row 165 // The purpose of a meta row is to support the persistent recording of 166 // meta info about a table as cells put into the distinguished meta row. 167 // Each table has exactly one meta row, which is not considered a member 168 // of the collection of rows inside the table. The only way to tell 169 // whether a row is a meta row is by the fact that it is returned by this 170 // GetMetaRow() method from some table. Otherwise nothing distinguishes 171 // a meta row from any other row. A meta row can be used anyplace that 172 // any other row can be used, and can even be put into other tables (or 173 // the same table) as a table member, if this is useful for some reason. 174 // The first attempt to access a table's meta row using GetMetaRow() will 175 // cause the meta row to be created if it did not already exist. When the 176 // meta row is created, it will have the row oid that was previously 177 // requested for this table's meta row; or if no oid was ever explicitly 178 // specified for this meta row, then a unique oid will be generated in 179 // the row scope named "m" (so obviously MDB clients should not 180 // manually allocate any row IDs from that special meta scope namespace). 181 // The meta row oid can be specified either when the table is created, or 182 // else the first time that GetMetaRow() is called, by passing a non-nil 183 // pointer to an oid for parameter inOptionalMetaRowOid. The meta row's 184 // actual oid is returned in outOid (if this is a non-nil pointer), and 185 // it will be different from inOptionalMetaRowOid when the meta row was 186 // already given a different oid earlier. 187 // } ----- end meta attribute methods ----- 188 189 // { ----- begin cursor methods ----- 190 NS_IMETHOD 191 GetTableRowCursor( // make a cursor, starting iteration at inRowPos 192 nsIMdbEnv* ev, // context 193 mdb_pos inRowPos, // zero-based ordinal position of row in table 194 nsIMdbTableRowCursor** acqCursor) 195 override; // acquire new cursor instance 196 // } ----- end row position methods ----- 197 198 // { ----- begin row position methods ----- 199 NS_IMETHOD PosToOid( // get row member for a table position 200 nsIMdbEnv* ev, // context 201 mdb_pos inRowPos, // zero-based ordinal position of row in table 202 mdbOid* outOid) override; // row oid at the specified position 203 204 NS_IMETHOD OidToPos( // test for the table position of a row member 205 nsIMdbEnv* ev, // context 206 const mdbOid* inOid, // row to find in table 207 mdb_pos* outPos) override; // zero-based ordinal position of row in table 208 209 NS_IMETHOD PosToRow( // test for the table position of a row member 210 nsIMdbEnv* ev, // context 211 mdb_pos inRowPos, // zero-based ordinal position of row in table 212 nsIMdbRow** acqRow) override; // acquire row at table position inRowPos 213 214 NS_IMETHOD RowToPos( // test for the table position of a row member 215 nsIMdbEnv* ev, // context 216 nsIMdbRow* ioRow, // row to find in table 217 mdb_pos* outPos) override; // zero-based ordinal position of row in table 218 // } ----- end row position methods ----- 219 220 // { ----- begin oid set methods ----- 221 NS_IMETHOD AddOid( // make sure the row with inOid is a table member 222 nsIMdbEnv* ev, // context 223 const mdbOid* inOid) override; // row to ensure membership in table 224 225 NS_IMETHOD HasOid( // test for the table position of a row member 226 nsIMdbEnv* ev, // context 227 const mdbOid* inOid, // row to find in table 228 mdb_bool* outHasOid) override; // whether inOid is a member row 229 230 NS_IMETHOD CutOid( // make sure the row with inOid is not a member 231 nsIMdbEnv* ev, // context 232 const mdbOid* inOid) override; // row to remove from table 233 // } ----- end oid set methods ----- 234 235 // { ----- begin row set methods ----- 236 NS_IMETHOD NewRow( // create a new row instance in table 237 nsIMdbEnv* ev, // context 238 mdbOid* 239 ioOid, // please use minus one (unbound) rowId for db-assigned IDs 240 nsIMdbRow** acqRow) override; // create new row 241 242 NS_IMETHOD AddRow( // make sure the row with inOid is a table member 243 nsIMdbEnv* ev, // context 244 nsIMdbRow* ioRow) override; // row to ensure membership in table 245 246 NS_IMETHOD HasRow( // test for the table position of a row member 247 nsIMdbEnv* ev, // context 248 nsIMdbRow* ioRow, // row to find in table 249 mdb_bool* outHasRow) override; // whether row is a table member 250 251 NS_IMETHOD CutRow( // make sure the row with inOid is not a member 252 nsIMdbEnv* ev, // context 253 nsIMdbRow* ioRow) override; // row to remove from table 254 255 NS_IMETHOD CutAllRows( // remove all rows from the table 256 nsIMdbEnv* ev) override; // context 257 // } ----- end row set methods ----- 258 259 // { ----- begin hinting methods ----- 260 NS_IMETHOD SearchColumnsHint( // advise re future expected search cols 261 nsIMdbEnv* ev, // context 262 const mdbColumnSet* inColumnSet) 263 override; // columns likely to be searched 264 265 NS_IMETHOD SortColumnsHint( // advise re future expected sort columns 266 nsIMdbEnv* ev, // context 267 const mdbColumnSet* inColumnSet) 268 override; // columns for likely sort requests 269 270 NS_IMETHOD StartBatchChangeHint( // advise before many adds and cuts 271 nsIMdbEnv* ev, // context 272 const void* inLabel) override; // intend unique address to match end call 273 // If batch starts nest by virtue of nesting calls in the stack, then 274 // the address of a local variable makes a good batch start label that 275 // can be used at batch end time, and such addresses remain unique. 276 277 NS_IMETHOD EndBatchChangeHint( // advise before many adds and cuts 278 nsIMdbEnv* ev, // context 279 const void* inLabel) override; // label matching start label 280 // Suppose a table is maintaining one or many sort orders for a table, 281 // so that every row added to the table must be inserted in each sort, 282 // and every row cut must be removed from each sort. If a db client 283 // intends to make many such changes before needing any information 284 // about the order or positions of rows inside a table, then a client 285 // might tell the table to start batch changes in order to disable 286 // sorting of rows for the interim. Presumably a table will then do 287 // a full sort of all rows at need when the batch changes end, or when 288 // a surprise request occurs for row position during batch changes. 289 // } ----- end hinting methods ----- 290 291 // { ----- begin searching methods ----- 292 NS_IMETHOD FindRowMatches( // search variable number of sorted cols 293 nsIMdbEnv* ev, // context 294 const mdbYarn* 295 inPrefix, // content to find as prefix in row's column cell 296 nsIMdbTableRowCursor** acqCursor) override; // set of matching rows 297 298 NS_IMETHOD GetSearchColumns( // query columns used by FindRowMatches() 299 nsIMdbEnv* ev, // context 300 mdb_count* outCount, // context 301 mdbColumnSet* outColSet) 302 override; // caller supplied space to put columns 303 // GetSearchColumns() returns the columns actually searched when the 304 // FindRowMatches() method is called. No more than mColumnSet_Count 305 // slots of mColumnSet_Columns will be written, since mColumnSet_Count 306 // indicates how many slots are present in the column array. The 307 // actual number of search column used by the table is returned in 308 // the outCount parameter; if this number exceeds mColumnSet_Count, 309 // then a caller needs a bigger array to read the entire column set. 310 // The minimum of mColumnSet_Count and outCount is the number slots 311 // in mColumnSet_Columns that were actually written by this method. 312 // 313 // Callers are expected to change this set of columns by calls to 314 // nsIMdbTable::SearchColumnsHint() or SetSearchSorting(), or both. 315 // } ----- end searching methods ----- 316 317 // { ----- begin sorting methods ----- 318 // sorting: note all rows are assumed sorted by row ID as a secondary 319 // sort following the primary column sort, when table rows are sorted. 320 321 NS_IMETHOD 322 CanSortColumn( // query which column is currently used for sorting 323 nsIMdbEnv* ev, // context 324 mdb_column inColumn, // column to query sorting potential 325 mdb_bool* outCanSort) override; // whether the column can be sorted 326 327 NS_IMETHOD GetSorting( // view same table in particular sorting 328 nsIMdbEnv* ev, // context 329 mdb_column inColumn, // requested new column for sorting table 330 nsIMdbSorting** acqSorting) override; // acquire sorting for column 331 332 NS_IMETHOD SetSearchSorting( // use this sorting in FindRowMatches() 333 nsIMdbEnv* ev, // context 334 mdb_column inColumn, // often same as nsIMdbSorting::GetSortColumn() 335 nsIMdbSorting* ioSorting) override; // requested sorting for some column 336 // SetSearchSorting() attempts to inform the table that ioSorting 337 // should be used during calls to FindRowMatches() for searching 338 // the column which is actually sorted by ioSorting. This method 339 // is most useful in conjunction with nsIMdbSorting::SetCompare(), 340 // because otherwise a caller would not be able to override the 341 // comparison ordering method used during searches. Note that some 342 // database implementations might be unable to use an arbitrarily 343 // specified sort order, either due to schema or runtime interface 344 // constraints, in which case ioSorting might not actually be used. 345 // Presumably ioSorting is an instance that was returned from some 346 // earlier call to nsIMdbTable::GetSorting(). A caller can also 347 // use nsIMdbTable::SearchColumnsHint() to specify desired change 348 // in which columns are sorted and searched by FindRowMatches(). 349 // 350 // A caller can pass a nil pointer for ioSorting to request that 351 // column inColumn no longer be used at all by FindRowMatches(). 352 // But when ioSorting is non-nil, then inColumn should match the 353 // column actually sorted by ioSorting; when these do not agree, 354 // implementations are instructed to give precedence to the column 355 // specified by ioSorting (so this means callers might just pass 356 // zero for inColumn when ioSorting is also provided, since then 357 // inColumn is both redundant and ignored). 358 // } ----- end sorting methods ----- 359 360 // { ----- begin moving methods ----- 361 // moving a row does nothing unless a table is currently unsorted 362 363 NS_IMETHOD MoveOid( // change position of row in unsorted table 364 nsIMdbEnv* ev, // context 365 const mdbOid* inOid, // row oid to find in table 366 mdb_pos inHintFromPos, // suggested hint regarding start position 367 mdb_pos inToPos, // desired new position for row inRowId 368 mdb_pos* outActualPos) override; // actual new position of row in table 369 370 NS_IMETHOD MoveRow( // change position of row in unsorted table 371 nsIMdbEnv* ev, // context 372 nsIMdbRow* ioRow, // row oid to find in table 373 mdb_pos inHintFromPos, // suggested hint regarding start position 374 mdb_pos inToPos, // desired new position for row inRowId 375 mdb_pos* outActualPos) override; // actual new position of row in table 376 // } ----- end moving methods ----- 377 378 // { ----- begin index methods ----- 379 NS_IMETHOD AddIndex( // create a sorting index for column if possible 380 nsIMdbEnv* ev, // context 381 mdb_column inColumn, // the column to sort by index 382 nsIMdbThumb** acqThumb) 383 override; // acquire thumb for incremental index building 384 // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and 385 // then the index addition will be finished. 386 387 NS_IMETHOD CutIndex( // stop supporting a specific column index 388 nsIMdbEnv* ev, // context 389 mdb_column inColumn, // the column with index to be removed 390 nsIMdbThumb** acqThumb) 391 override; // acquire thumb for incremental index destroy 392 // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and 393 // then the index removal will be finished. 394 395 NS_IMETHOD HasIndex( // query for current presence of a column index 396 nsIMdbEnv* ev, // context 397 mdb_column inColumn, // the column to investigate 398 mdb_bool* outHasIndex) 399 override; // whether column has index for this column 400 401 NS_IMETHOD EnableIndexOnSort( // create an index for col on first sort 402 nsIMdbEnv* ev, // context 403 mdb_column inColumn) override; // the column to index if ever sorted 404 405 NS_IMETHOD QueryIndexOnSort( // check whether index on sort is enabled 406 nsIMdbEnv* ev, // context 407 mdb_column inColumn, // the column to investigate 408 mdb_bool* outIndexOnSort) 409 override; // whether column has index-on-sort enabled 410 411 NS_IMETHOD DisableIndexOnSort( // prevent future index creation on sort 412 nsIMdbEnv* ev, // context 413 mdb_column inColumn) override; // the column to index if ever sorted 414 // } ----- end index methods ----- 415 416 morkStore* mTable_Store; // non-refcnted ptr to port 417 418 // mTable_RowSpace->SpaceScope() is row scope 419 morkRowSpace* mTable_RowSpace; // non-refcnted ptr to containing space 420 421 morkRow* mTable_MetaRow; // table's actual meta row 422 mdbOid mTable_MetaRowOid; // oid for meta row 423 424 morkRowMap* mTable_RowMap; // (strong ref) hash table of all members 425 morkArray mTable_RowArray; // array of morkRow pointers 426 427 morkList mTable_ChangeList; // list of table changes 428 mork_u2 mTable_ChangesCount; // length of changes list 429 mork_u2 mTable_ChangesMax; // max list length before rewrite 430 431 // mork_tid mTable_Id; 432 mork_kind mTable_Kind; 433 434 mork_u1 mTable_Flags; // bit flags 435 mork_priority mTable_Priority; // 0..9, any other value equals 9 436 mork_u1 mTable_GcUses; // persistent references from cells 437 mork_u1 mTable_Pad; // for u4 alignment 438 439 public: // flags bit twiddling SetTableUnique()440 void SetTableUnique() { mTable_Flags |= morkTable_kUniqueBit; } SetTableVerbose()441 void SetTableVerbose() { mTable_Flags |= morkTable_kVerboseBit; } SetTableNoted()442 void SetTableNoted() { mTable_Flags |= morkTable_kNotedBit; } SetTableRewrite()443 void SetTableRewrite() { mTable_Flags |= morkTable_kRewriteBit; } SetTableNewMeta()444 void SetTableNewMeta() { mTable_Flags |= morkTable_kNewMetaBit; } 445 ClearTableUnique()446 void ClearTableUnique() { mTable_Flags &= (mork_u1)~morkTable_kUniqueBit; } ClearTableVerbose()447 void ClearTableVerbose() { mTable_Flags &= (mork_u1)~morkTable_kVerboseBit; } ClearTableNoted()448 void ClearTableNoted() { mTable_Flags &= (mork_u1)~morkTable_kNotedBit; } ClearTableRewrite()449 void ClearTableRewrite() { mTable_Flags &= (mork_u1)~morkTable_kRewriteBit; } ClearTableNewMeta()450 void ClearTableNewMeta() { mTable_Flags &= (mork_u1)~morkTable_kNewMetaBit; } 451 IsTableUnique()452 mork_bool IsTableUnique() const { 453 return (mTable_Flags & morkTable_kUniqueBit) != 0; 454 } 455 IsTableVerbose()456 mork_bool IsTableVerbose() const { 457 return (mTable_Flags & morkTable_kVerboseBit) != 0; 458 } 459 IsTableNoted()460 mork_bool IsTableNoted() const { 461 return (mTable_Flags & morkTable_kNotedBit) != 0; 462 } 463 IsTableRewrite()464 mork_bool IsTableRewrite() const { 465 return (mTable_Flags & morkTable_kRewriteBit) != 0; 466 } 467 IsTableNewMeta()468 mork_bool IsTableNewMeta() const { 469 return (mTable_Flags & morkTable_kNewMetaBit) != 0; 470 } 471 472 public 473 : // table dirty handling more complex than morkNode::SetNodeDirty() etc. SetTableDirty()474 void SetTableDirty() { this->SetNodeDirty(); } 475 void SetTableClean(morkEnv* ev); 476 IsTableClean()477 mork_bool IsTableClean() const { return this->IsNodeClean(); } IsTableDirty()478 mork_bool IsTableDirty() const { return this->IsNodeDirty(); } 479 480 public: // morkNode memory management operators new(size_t inSize,nsIMdbHeap & ioHeap,morkEnv * ev)481 void* operator new(size_t inSize, nsIMdbHeap& ioHeap, 482 morkEnv* ev) noexcept(true) { 483 return morkNode::MakeNew(inSize, ioHeap, ev); 484 } 485 486 // { ===== begin morkNode interface ===== 487 public: // morkNode virtual methods 488 virtual void CloseMorkNode(morkEnv* ev) override; // CloseTable() if open 489 490 public: // morkTable construction & destruction 491 morkTable( 492 morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioNodeHeap, 493 morkStore* ioStore, nsIMdbHeap* ioSlotHeap, morkRowSpace* ioRowSpace, 494 const mdbOid* inOptionalMetaRowOid, // can be nil to avoid specifying 495 mork_tid inTableId, mork_kind inKind, mork_bool inMustBeUnique); 496 void CloseTable(morkEnv* ev); // called by CloseMorkNode(); 497 498 private: // copying is not allowed 499 morkTable(const morkTable& other); 500 morkTable& operator=(const morkTable& other); 501 virtual ~morkTable(); // assert that close executed earlier 502 503 public: // dynamic type identification IsTable()504 mork_bool IsTable() const { 505 return IsNode() && mNode_Derived == morkDerived_kTable; 506 } 507 // } ===== end morkNode methods ===== 508 509 public: // errors 510 static void NonTableTypeError(morkEnv* ev); 511 static void NonTableTypeWarning(morkEnv* ev); 512 static void NilRowSpaceError(morkEnv* ev); 513 514 public: // warnings 515 static void TableGcUsesUnderflowWarning(morkEnv* ev); 516 517 public: // noting table changes HasChangeOverflow()518 mork_bool HasChangeOverflow() const { 519 return mTable_ChangesCount >= mTable_ChangesMax; 520 } 521 522 void NoteTableSetAll(morkEnv* ev); 523 void NoteTableMoveRow(morkEnv* ev, morkRow* ioRow, mork_pos inPos); 524 525 void note_row_change(morkEnv* ev, mork_change inChange, morkRow* ioRow); 526 void note_row_move(morkEnv* ev, morkRow* ioRow, mork_pos inNewPos); 527 NoteTableAddRow(morkEnv * ev,morkRow * ioRow)528 void NoteTableAddRow(morkEnv* ev, morkRow* ioRow) { 529 this->note_row_change(ev, morkChange_kAdd, ioRow); 530 } 531 NoteTableCutRow(morkEnv * ev,morkRow * ioRow)532 void NoteTableCutRow(morkEnv* ev, morkRow* ioRow) { 533 this->note_row_change(ev, morkChange_kCut, ioRow); 534 } 535 536 protected: // internal row map methods 537 morkRow* find_member_row(morkEnv* ev, morkRow* ioRow); 538 void build_row_map(morkEnv* ev); 539 540 public: // other table methods 541 mork_bool MaybeDirtySpaceStoreAndTable(); 542 543 morkRow* GetMetaRow(morkEnv* ev, const mdbOid* inOptionalMetaRowOid); 544 545 mork_u2 AddTableGcUse(morkEnv* ev); 546 mork_u2 CutTableGcUse(morkEnv* ev); 547 548 // void DirtyAllTableContent(morkEnv* ev); 549 TableSeed()550 mork_seed TableSeed() const { return mTable_RowArray.mArray_Seed; } 551 SafeRowAt(morkEnv * ev,mork_pos inPos)552 morkRow* SafeRowAt(morkEnv* ev, mork_pos inPos) { 553 return (morkRow*)mTable_RowArray.SafeAt(ev, inPos); 554 } 555 556 nsIMdbTable* AcquireTableHandle(morkEnv* ev); // mObject_Handle 557 GetRowCount()558 mork_count GetRowCount() const { return mTable_RowArray.mArray_Fill; } 559 IsTableUsed()560 mork_bool IsTableUsed() const { 561 return (mTable_GcUses != 0 || this->GetRowCount() != 0); 562 } 563 564 void GetTableOid(morkEnv* ev, mdbOid* outOid); 565 mork_pos ArrayHasOid(morkEnv* ev, const mdbOid* inOid); 566 mork_bool MapHasOid(morkEnv* ev, const mdbOid* inOid); 567 mork_bool AddRow(morkEnv* ev, morkRow* ioRow); // returns ev->Good() 568 mork_bool CutRow(morkEnv* ev, morkRow* ioRow); // returns ev->Good() 569 mork_bool CutAllRows(morkEnv* ev); // returns ev->Good() 570 571 mork_pos MoveRow( 572 morkEnv* ev, morkRow* ioRow, // change row position 573 mork_pos inHintFromPos, // suggested hint regarding start position 574 mork_pos inToPos); // desired new position for row ioRow 575 // MoveRow() returns the actual position of ioRow afterwards; this 576 // position is -1 if and only if ioRow was not found as a member. 577 578 morkTableRowCursor* NewTableRowCursor(morkEnv* ev, mork_pos inRowPos); 579 580 public: // typesafe refcounting inlines calling inherited morkNode methods SlotWeakTable(morkTable * me,morkEnv * ev,morkTable ** ioSlot)581 static void SlotWeakTable(morkTable* me, morkEnv* ev, morkTable** ioSlot) { 582 morkNode::SlotWeakNode((morkNode*)me, ev, (morkNode**)ioSlot); 583 } 584 SlotStrongTable(morkTable * me,morkEnv * ev,morkTable ** ioSlot)585 static void SlotStrongTable(morkTable* me, morkEnv* ev, morkTable** ioSlot) { 586 morkNode::SlotStrongNode((morkNode*)me, ev, (morkNode**)ioSlot); 587 } 588 }; 589 590 // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 591 592 // use negative values for kCut and kAdd, to keep non-neg move pos distinct: 593 #define morkTableChange_kCut ((mork_pos)-1) /* shows row was cut */ 594 #define morkTableChange_kAdd ((mork_pos)-2) /* shows row was added */ 595 #define morkTableChange_kNone ((mork_pos)-3) /* unknown change */ 596 597 class morkTableChange : public morkNext { 598 public: // state is public because the entire Mork system is private 599 morkRow* mTableChange_Row; // the row in the change 600 601 mork_pos mTableChange_Pos; // kAdd, kCut, or non-neg for row move 602 603 public: 604 morkTableChange(morkEnv* ev, mork_change inChange, morkRow* ioRow); 605 // use this constructor for inChange == morkChange_kAdd or morkChange_kCut 606 607 morkTableChange(morkEnv* ev, morkRow* ioRow, mork_pos inPos); 608 // use this constructor when the row is moved 609 610 public: 611 void UnknownChangeError( 612 morkEnv* ev) const; // morkChange_kAdd or morkChange_kCut 613 void NegativeMovePosError( 614 morkEnv* ev) const; // move must be non-neg position 615 616 public: IsAddRowTableChange()617 mork_bool IsAddRowTableChange() const { 618 return (mTableChange_Pos == morkTableChange_kAdd); 619 } 620 IsCutRowTableChange()621 mork_bool IsCutRowTableChange() const { 622 return (mTableChange_Pos == morkTableChange_kCut); 623 } 624 IsMoveRowTableChange()625 mork_bool IsMoveRowTableChange() const { return (mTableChange_Pos >= 0); } 626 627 public: GetMovePos()628 mork_pos GetMovePos() const { return mTableChange_Pos; } 629 // GetMovePos() assumes that IsMoveRowTableChange() is true. 630 }; 631 632 // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 633 634 #define morkDerived_kTableMap /*i*/ 0x744D /* ascii 'tM' */ 635 636 /*| morkTableMap: maps mork_token -> morkTable 637 |*/ 638 #ifdef MORK_BEAD_OVER_NODE_MAPS 639 class morkTableMap : public morkBeadMap { 640 #else /*MORK_BEAD_OVER_NODE_MAPS*/ 641 class morkTableMap : public morkNodeMap { // for mapping tokens to tables 642 #endif /*MORK_BEAD_OVER_NODE_MAPS*/ 643 644 public: 645 virtual ~morkTableMap(); 646 morkTableMap(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioHeap, 647 nsIMdbHeap* ioSlotHeap); 648 649 public: // other map methods 650 #ifdef MORK_BEAD_OVER_NODE_MAPS AddTable(morkEnv * ev,morkTable * ioTable)651 mork_bool AddTable(morkEnv* ev, morkTable* ioTable) { 652 return this->AddBead(ev, ioTable); 653 } 654 // the AddTable() boolean return equals ev->Good(). 655 CutTable(morkEnv * ev,mork_tid inTid)656 mork_bool CutTable(morkEnv* ev, mork_tid inTid) { 657 return this->CutBead(ev, inTid); 658 } 659 // The CutTable() boolean return indicates whether removal happened. 660 GetTable(morkEnv * ev,mork_tid inTid)661 morkTable* GetTable(morkEnv* ev, mork_tid inTid) { 662 return (morkTable*)this->GetBead(ev, inTid); 663 } 664 // Note the returned table does NOT have an increase in refcount for this. 665 CutAllTables(morkEnv * ev)666 mork_num CutAllTables(morkEnv* ev) { return this->CutAllBeads(ev); } 667 // CutAllTables() releases all the referenced table values. 668 669 #else /*MORK_BEAD_OVER_NODE_MAPS*/ 670 mork_bool AddTable(morkEnv* ev, morkTable* ioTable) { 671 return this->AddNode(ev, ioTable->TableId(), ioTable); 672 } 673 // the AddTable() boolean return equals ev->Good(). 674 675 mork_bool CutTable(morkEnv* ev, mork_tid inTid) { 676 return this->CutNode(ev, inTid); 677 } 678 // The CutTable() boolean return indicates whether removal happened. 679 680 morkTable* GetTable(morkEnv* ev, mork_tid inTid) { 681 return (morkTable*)this->GetNode(ev, inTid); 682 } 683 // Note the returned table does NOT have an increase in refcount for this. 684 685 mork_num CutAllTables(morkEnv* ev) { return this->CutAllNodes(ev); } 686 // CutAllTables() releases all the referenced table values. 687 #endif /*MORK_BEAD_OVER_NODE_MAPS*/ 688 }; 689 690 #ifdef MORK_BEAD_OVER_NODE_MAPS 691 class morkTableMapIter : public morkBeadMapIter { 692 #else /*MORK_BEAD_OVER_NODE_MAPS*/ 693 class morkTableMapIter : public morkMapIter { // typesafe wrapper class 694 #endif /*MORK_BEAD_OVER_NODE_MAPS*/ 695 696 public: 697 #ifdef MORK_BEAD_OVER_NODE_MAPS morkTableMapIter(morkEnv * ev,morkTableMap * ioMap)698 morkTableMapIter(morkEnv* ev, morkTableMap* ioMap) 699 : morkBeadMapIter(ev, ioMap) {} 700 morkTableMapIter()701 morkTableMapIter() : morkBeadMapIter() {} InitTableMapIter(morkEnv * ev,morkTableMap * ioMap)702 void InitTableMapIter(morkEnv* ev, morkTableMap* ioMap) { 703 this->InitBeadMapIter(ev, ioMap); 704 } 705 FirstTable(morkEnv * ev)706 morkTable* FirstTable(morkEnv* ev) { return (morkTable*)this->FirstBead(ev); } 707 NextTable(morkEnv * ev)708 morkTable* NextTable(morkEnv* ev) { return (morkTable*)this->NextBead(ev); } 709 HereTable(morkEnv * ev)710 morkTable* HereTable(morkEnv* ev) { return (morkTable*)this->HereBead(ev); } 711 712 #else /*MORK_BEAD_OVER_NODE_MAPS*/ 713 morkTableMapIter(morkEnv* ev, morkTableMap* ioMap) : morkMapIter(ev, ioMap) {} 714 715 morkTableMapIter() : morkMapIter() {} 716 void InitTableMapIter(morkEnv* ev, morkTableMap* ioMap) { 717 this->InitMapIter(ev, ioMap); 718 } 719 720 mork_change* FirstTable(morkEnv* ev, mork_tid* outTid, morkTable** outTable) { 721 return this->First(ev, outTid, outTable); 722 } 723 724 mork_change* NextTable(morkEnv* ev, mork_tid* outTid, morkTable** outTable) { 725 return this->Next(ev, outTid, outTable); 726 } 727 728 mork_change* HereTable(morkEnv* ev, mork_tid* outTid, morkTable** outTable) { 729 return this->Here(ev, outTid, outTable); 730 } 731 732 // cutting while iterating hash map might dirty the parent table: 733 mork_change* CutHereTable(morkEnv* ev, mork_tid* outTid, 734 morkTable** outTable) { 735 return this->CutHere(ev, outTid, outTable); 736 } 737 #endif /*MORK_BEAD_OVER_NODE_MAPS*/ 738 }; 739 740 // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 741 742 #endif /* _MORKTABLE_ */ 743