summaryrefslogtreecommitdiffstats
path: root/comm/mailnews/db/mork/morkRow.h
blob: e8a8c728acaa8ae0df592c51e67260b63c5d49a8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
/* -*- 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 _MORKROW_
#define _MORKROW_ 1

#ifndef _MORK_
#  include "mork.h"
#endif

#ifndef _MORKCELL_
#  include "morkCell.h"
#endif

// 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789

class nsIMdbRow;
class nsIMdbCell;
#define morkDerived_kRow /*i*/ 0x5277 /* ascii 'Rw' */

#define morkRow_kMaxGcUses 0x0FF   /* max for 8-bit unsigned int */
#define morkRow_kMaxLength 0x0FFFF /* max for 16-bit unsigned int */
#define morkRow_kMinusOneRid ((mork_rid)-1)

#define morkRow_kTag 'r' /* magic signature for mRow_Tag */

#define morkRow_kNotedBit ((mork_u1)(1 << 0))   /* space has change notes */
#define morkRow_kRewriteBit ((mork_u1)(1 << 1)) /* must rewrite all cells */
#define morkRow_kDirtyBit ((mork_u1)(1 << 2))   /* row has been changed */

class morkRow {  // row of cells

 public:  // state is public because the entire Mork system is private
  morkRowSpace* mRow_Space;    // mRow_Space->SpaceScope() is the row scope
  morkRowObject* mRow_Object;  // refcount & other state for object sharing
  morkCell* mRow_Cells;
  mdbOid mRow_Oid;

  mork_delta mRow_Delta;  // space to note a single column change

  mork_u2 mRow_Length;  // physical count of cells in mRow_Cells
  mork_u2 mRow_Seed;    // count changes in mRow_Cells structure

  mork_u1 mRow_GcUses;  // persistent references from tables
  mork_u1 mRow_Pad;     // for u1 alignment
  mork_u1 mRow_Flags;   // one-byte flags slot
  mork_u1 mRow_Tag;     // one-byte tag (need u4 alignment pad)

 public:  // interpreting mRow_Delta
  mork_bool HasRowDelta() const { return (mRow_Delta != 0); }

  void ClearRowDelta() { mRow_Delta = 0; }

  void SetRowDelta(mork_column inCol, mork_change inChange) {
    morkDelta_Init(mRow_Delta, inCol, inChange);
  }

  mork_column GetDeltaColumn() const { return morkDelta_Column(mRow_Delta); }
  mork_change GetDeltaChange() const { return morkDelta_Change(mRow_Delta); }

 public:  // noting row changes
  void NoteRowSetAll(morkEnv* ev);
  void NoteRowSetCol(morkEnv* ev, mork_column inCol);
  void NoteRowAddCol(morkEnv* ev, mork_column inCol);
  void NoteRowCutCol(morkEnv* ev, mork_column inCol);

 public:  // flags bit twiddling
  void SetRowNoted() { mRow_Flags |= morkRow_kNotedBit; }
  void SetRowRewrite() { mRow_Flags |= morkRow_kRewriteBit; }
  void SetRowDirty() { mRow_Flags |= morkRow_kDirtyBit; }

  void ClearRowNoted() { mRow_Flags &= (mork_u1)~morkRow_kNotedBit; }
  void ClearRowRewrite() { mRow_Flags &= (mork_u1)~morkRow_kRewriteBit; }
  void SetRowClean() {
    mRow_Flags = 0;
    mRow_Delta = 0;
  }

  mork_bool IsRowNoted() const { return (mRow_Flags & morkRow_kNotedBit) != 0; }

  mork_bool IsRowRewrite() const {
    return (mRow_Flags & morkRow_kRewriteBit) != 0;
  }

  mork_bool IsRowClean() const { return (mRow_Flags & morkRow_kDirtyBit) == 0; }

  mork_bool IsRowDirty() const { return (mRow_Flags & morkRow_kDirtyBit) != 0; }

  mork_bool IsRowUsed() const { return mRow_GcUses != 0; }

 public:  // other row methods
  morkRow() {}
  explicit morkRow(const mdbOid* inOid) : mRow_Oid(*inOid) {}
  void InitRow(morkEnv* ev, const mdbOid* inOid, morkRowSpace* ioSpace,
               mork_size inLength, morkPool* ioPool);
  // if inLength is nonzero, cells will be allocated from ioPool

  morkRowObject* AcquireRowObject(morkEnv* ev, morkStore* ioStore);
  nsIMdbRow* AcquireRowHandle(morkEnv* ev, morkStore* ioStore);
  nsIMdbCell* AcquireCellHandle(morkEnv* ev, morkCell* ioCell,
                                mdb_column inColumn, mork_pos inPos);

  mork_u2 AddRowGcUse(morkEnv* ev);
  mork_u2 CutRowGcUse(morkEnv* ev);

  mork_bool MaybeDirtySpaceStoreAndRow();

 public:  // internal row methods
  void cut_all_index_entries(morkEnv* ev);

  // void cut_cell_from_space_index(morkEnv* ev, morkCell* ioCell);

  mork_count CountOverlap(morkEnv* ev, morkCell* ioVector, mork_fill inFill);
  // Count cells in ioVector that change existing cells in this row when
  // ioVector is added to the row (as in TakeCells()).   This is the set
  // of cells with the same columns in ioVector and mRow_Cells, which do
  // not have exactly the same value in mCell_Atom, and which do not both
  // have change status equal to morkChange_kCut (because cutting a cut
  // cell still yields a cell that has been cut).  CountOverlap() also
  // modifies the change attribute of any cell in ioVector to kDup when
  // the change was previously kCut and the same column cell was found
  // in this row with change also equal to kCut; this tells callers later
  // they need not look for that cell in the row again on a second pass.

  void MergeCells(morkEnv* ev, morkCell* ioVector, mork_fill inVecLength,
                  mork_fill inOldRowFill, mork_fill inOverlap);
  // MergeCells() is the part of TakeCells() that does the insertion.
  // inOldRowFill is the old value of mRow_Length, and inOverlap is the
  // number of cells in the intersection that must be updated.

  void TakeCells(morkEnv* ev, morkCell* ioVector, mork_fill inVecLength,
                 morkStore* ioStore);

  morkCell* NewCell(morkEnv* ev, mdb_column inColumn, mork_pos* outPos,
                    morkStore* ioStore);
  morkCell* GetCell(morkEnv* ev, mdb_column inColumn, mork_pos* outPos) const;
  morkCell* CellAt(morkEnv* ev, mork_pos inPos) const;

  mork_aid GetCellAtomAid(morkEnv* ev, mdb_column inColumn) const;
  // GetCellAtomAid() finds the cell with column inColumn, and sees if the
  // atom has a token ID, and returns the atom's ID if there is one.  Or
  // else zero is returned if there is no such column, or no atom, or if
  // the atom has no ID to return.  This method is intended to support
  // efficient updating of column indexes for rows in a row space.

 public:  // external row methods
  void DirtyAllRowContent(morkEnv* ev);

  morkStore* GetRowSpaceStore(morkEnv* ev) const;

  void AddColumn(morkEnv* ev, mdb_column inColumn, const mdbYarn* inYarn,
                 morkStore* ioStore);

  morkAtom* GetColumnAtom(morkEnv* ev, mdb_column inColumn);

  void NextColumn(morkEnv* ev, mdb_column* ioColumn, mdbYarn* outYarn);

  void SeekColumn(morkEnv* ev, mdb_pos inPos, mdb_column* outColumn,
                  mdbYarn* outYarn);

  void CutColumn(morkEnv* ev, mdb_column inColumn);

  morkRowCellCursor* NewRowCellCursor(morkEnv* ev, mdb_pos inPos);

  void EmptyAllCells(morkEnv* ev);
  void AddRow(morkEnv* ev, const morkRow* inSourceRow);
  void SetRow(morkEnv* ev, const morkRow* inSourceRow);
  void CutAllColumns(morkEnv* ev);

  void OnZeroRowGcUse(morkEnv* ev);
  // OnZeroRowGcUse() is called when CutRowGcUse() returns zero.

 public:  // dynamic typing
  mork_bool IsRow() const { return mRow_Tag == morkRow_kTag; }

 public:  // hash and equal
  mork_u4 HashRow() const {
    return (mRow_Oid.mOid_Scope << 16) ^ mRow_Oid.mOid_Id;
  }

  mork_bool EqualRow(const morkRow* ioRow) const {
    return ((mRow_Oid.mOid_Scope == ioRow->mRow_Oid.mOid_Scope) &&
            (mRow_Oid.mOid_Id == ioRow->mRow_Oid.mOid_Id));
  }

  mork_bool EqualOid(const mdbOid* ioOid) const {
    return ((mRow_Oid.mOid_Scope == ioOid->mOid_Scope) &&
            (mRow_Oid.mOid_Id == ioOid->mOid_Id));
  }

 public:  // errors
  static void ZeroColumnError(morkEnv* ev);
  static void LengthBeyondMaxError(morkEnv* ev);
  static void NilCellsError(morkEnv* ev);
  static void NonRowTypeError(morkEnv* ev);
  static void NonRowTypeWarning(morkEnv* ev);
  static void GcUsesUnderflowWarning(morkEnv* ev);

 private:  // copying is not allowed
  morkRow(const morkRow& other);
  morkRow& operator=(const morkRow& other);
};

// 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789

#endif /* _MORKROW_ */