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 #include "nscore.h"
7
8 #ifndef _MDB_
9 # include "mdb.h"
10 #endif
11
12 #ifndef _MORK_
13 # include "mork.h"
14 #endif
15
16 #ifndef _MORKNODE_
17 # include "morkNode.h"
18 #endif
19
20 #ifndef _MORKENV_
21 # include "morkEnv.h"
22 #endif
23
24 #ifndef _MORKARRAY_
25 # include "morkArray.h"
26 #endif
27
28 // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
29
30 // ````` ````` ````` ````` `````
31 // { ===== begin morkNode interface =====
32
CloseMorkNode(morkEnv * ev)33 /*public virtual*/ void morkArray::CloseMorkNode(
34 morkEnv* ev) // CloseTable() only if open
35 {
36 if (this->IsOpenNode()) {
37 this->MarkClosing();
38 this->CloseArray(ev);
39 this->MarkShut();
40 }
41 }
42
43 /*public virtual*/
~morkArray()44 morkArray::~morkArray() // assert CloseTable() executed earlier
45 {
46 MORK_ASSERT(this->IsShutNode());
47 MORK_ASSERT(mArray_Slots == 0);
48 }
49
50 /*public non-poly*/
morkArray(morkEnv * ev,const morkUsage & inUsage,nsIMdbHeap * ioHeap,mork_size inSize,nsIMdbHeap * ioSlotHeap)51 morkArray::morkArray(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioHeap,
52 mork_size inSize, nsIMdbHeap* ioSlotHeap)
53 : morkNode(ev, inUsage, ioHeap),
54 mArray_Slots(0),
55 mArray_Heap(0),
56 mArray_Fill(0),
57 mArray_Size(0),
58 mArray_Seed(
59 (mork_u4)NS_PTR_TO_INT32(this)) // "random" integer assignment
60 {
61 if (ev->Good()) {
62 if (ioSlotHeap) {
63 nsIMdbHeap_SlotStrongHeap(ioSlotHeap, ev, &mArray_Heap);
64 if (ev->Good()) {
65 if (inSize < 3) inSize = 3;
66 mdb_size byteSize = inSize * sizeof(void*);
67 void** block = 0;
68 ioSlotHeap->Alloc(ev->AsMdbEnv(), byteSize, (void**)&block);
69 if (block && ev->Good()) {
70 mArray_Slots = block;
71 mArray_Size = inSize;
72 MORK_MEMSET(mArray_Slots, 0, byteSize);
73 if (ev->Good()) mNode_Derived = morkDerived_kArray;
74 }
75 }
76 } else
77 ev->NilPointerError();
78 }
79 }
80
CloseArray(morkEnv * ev)81 /*public non-poly*/ void morkArray::CloseArray(
82 morkEnv* ev) // called by CloseMorkNode();
83 {
84 if (this->IsNode()) {
85 if (mArray_Heap && mArray_Slots)
86 mArray_Heap->Free(ev->AsMdbEnv(), mArray_Slots);
87
88 mArray_Slots = 0;
89 mArray_Size = 0;
90 mArray_Fill = 0;
91 ++mArray_Seed;
92 nsIMdbHeap_SlotStrongHeap((nsIMdbHeap*)0, ev, &mArray_Heap);
93 this->MarkShut();
94 } else
95 this->NonNodeError(ev);
96 }
97
98 // } ===== end morkNode methods =====
99 // ````` ````` ````` ````` `````
100
NonArrayTypeError(morkEnv * ev)101 /*static*/ void morkArray::NonArrayTypeError(morkEnv* ev) {
102 ev->NewError("non morkArray");
103 }
104
IndexBeyondEndError(morkEnv * ev)105 /*static*/ void morkArray::IndexBeyondEndError(morkEnv* ev) {
106 ev->NewError("array index beyond end");
107 }
108
NilSlotsAddressError(morkEnv * ev)109 /*static*/ void morkArray::NilSlotsAddressError(morkEnv* ev) {
110 ev->NewError("nil mArray_Slots");
111 }
112
FillBeyondSizeError(morkEnv * ev)113 /*static*/ void morkArray::FillBeyondSizeError(morkEnv* ev) {
114 ev->NewError("mArray_Fill > mArray_Size");
115 }
116
Grow(morkEnv * ev,mork_size inNewSize)117 mork_bool morkArray::Grow(morkEnv* ev, mork_size inNewSize)
118 // Grow() returns true if capacity becomes >= inNewSize and ev->Good()
119 {
120 if (ev->Good() && inNewSize > mArray_Size) // make array larger?
121 {
122 if (mArray_Fill <= mArray_Size) // fill and size fit the invariant?
123 {
124 if (mArray_Size <= 3)
125 inNewSize = mArray_Size + 3;
126 else
127 inNewSize = mArray_Size *
128 2; // + 3; // try doubling size here - used to grow by 3
129
130 mdb_size newByteSize = inNewSize * sizeof(void*);
131 void** newBlock = 0;
132 mArray_Heap->Alloc(ev->AsMdbEnv(), newByteSize, (void**)&newBlock);
133 if (newBlock && ev->Good()) // okay new block?
134 {
135 void** oldSlots = mArray_Slots;
136 void** oldEnd = oldSlots + mArray_Fill;
137
138 void** newSlots = newBlock;
139 void** newEnd = newBlock + inNewSize;
140
141 while (oldSlots < oldEnd) *newSlots++ = *oldSlots++;
142
143 while (newSlots < newEnd) *newSlots++ = (void*)0;
144
145 oldSlots = mArray_Slots;
146 mArray_Size = inNewSize;
147 mArray_Slots = newBlock;
148 mArray_Heap->Free(ev->AsMdbEnv(), oldSlots);
149 }
150 } else
151 this->FillBeyondSizeError(ev);
152 }
153 ++mArray_Seed; // always modify seed, since caller intends to add slots
154 return (ev->Good() && mArray_Size >= inNewSize);
155 }
156
SafeAt(morkEnv * ev,mork_pos inPos)157 void* morkArray::SafeAt(morkEnv* ev, mork_pos inPos) {
158 if (mArray_Slots) {
159 if (inPos >= 0 && inPos < (mork_pos)mArray_Fill)
160 return mArray_Slots[inPos];
161 else
162 this->IndexBeyondEndError(ev);
163 } else
164 this->NilSlotsAddressError(ev);
165
166 return (void*)0;
167 }
168
SafeAtPut(morkEnv * ev,mork_pos inPos,void * ioSlot)169 void morkArray::SafeAtPut(morkEnv* ev, mork_pos inPos, void* ioSlot) {
170 if (mArray_Slots) {
171 if (inPos >= 0 && inPos < (mork_pos)mArray_Fill) {
172 mArray_Slots[inPos] = ioSlot;
173 ++mArray_Seed;
174 } else
175 this->IndexBeyondEndError(ev);
176 } else
177 this->NilSlotsAddressError(ev);
178 }
179
AppendSlot(morkEnv * ev,void * ioSlot)180 mork_pos morkArray::AppendSlot(morkEnv* ev, void* ioSlot) {
181 mork_pos outPos = -1;
182 if (mArray_Slots) {
183 mork_fill fill = mArray_Fill;
184 if (this->Grow(ev, fill + 1)) {
185 outPos = (mork_pos)fill;
186 mArray_Slots[fill] = ioSlot;
187 mArray_Fill = fill + 1;
188 // note Grow() increments mArray_Seed
189 }
190 } else
191 this->NilSlotsAddressError(ev);
192
193 return outPos;
194 }
195
AddSlot(morkEnv * ev,mork_pos inPos,void * ioSlot)196 void morkArray::AddSlot(morkEnv* ev, mork_pos inPos, void* ioSlot) {
197 if (mArray_Slots) {
198 mork_fill fill = mArray_Fill;
199 if (this->Grow(ev, fill + 1)) {
200 void** slot = mArray_Slots; // the slot vector
201 void** end = slot + fill; // one past the last used array slot
202 slot += inPos; // the slot to be added
203
204 while (--end >= slot) // another slot to move upward?
205 end[1] = *end;
206
207 *slot = ioSlot;
208 mArray_Fill = fill + 1;
209 // note Grow() increments mArray_Seed
210 }
211 } else
212 this->NilSlotsAddressError(ev);
213 }
214
CutSlot(morkEnv * ev,mork_pos inPos)215 void morkArray::CutSlot(morkEnv* ev, mork_pos inPos) {
216 MORK_USED_1(ev);
217 mork_fill fill = mArray_Fill;
218 if (inPos >= 0 &&
219 inPos < (mork_pos)fill) // cutting slot in used array portion?
220 {
221 void** slot = mArray_Slots; // the slot vector
222 void** end = slot + fill; // one past the last used array slot
223 slot += inPos; // the slot to be cut
224
225 while (++slot < end) // another slot to move downward?
226 slot[-1] = *slot;
227
228 slot[-1] = 0; // clear the last used slot which is now unused
229
230 // note inPos<fill implies fill>0, so fill-1 must be nonnegative:
231 mArray_Fill = fill - 1;
232 ++mArray_Seed;
233 }
234 }
235
CutAllSlots(morkEnv * ev)236 void morkArray::CutAllSlots(morkEnv* ev) {
237 if (mArray_Slots) {
238 if (mArray_Fill <= mArray_Size) {
239 mdb_size oldByteSize = mArray_Fill * sizeof(void*);
240 MORK_MEMSET(mArray_Slots, 0, oldByteSize);
241 } else
242 this->FillBeyondSizeError(ev);
243 } else
244 this->NilSlotsAddressError(ev);
245
246 ++mArray_Seed;
247 mArray_Fill = 0;
248 }
249
250 // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
251