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