summaryrefslogtreecommitdiffstats
path: root/db/mork/src/morkArray.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'db/mork/src/morkArray.cpp')
-rw-r--r--db/mork/src/morkArray.cpp297
1 files changed, 297 insertions, 0 deletions
diff --git a/db/mork/src/morkArray.cpp b/db/mork/src/morkArray.cpp
new file mode 100644
index 000000000..5b83b85e7
--- /dev/null
+++ b/db/mork/src/morkArray.cpp
@@ -0,0 +1,297 @@
+/* -*- 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/. */
+
+#include "nscore.h"
+
+#ifndef _MDB_
+#include "mdb.h"
+#endif
+
+#ifndef _MORK_
+#include "mork.h"
+#endif
+
+#ifndef _MORKNODE_
+#include "morkNode.h"
+#endif
+
+#ifndef _MORKENV_
+#include "morkEnv.h"
+#endif
+
+#ifndef _MORKARRAY_
+#include "morkArray.h"
+#endif
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+// ````` ````` ````` ````` `````
+// { ===== begin morkNode interface =====
+
+/*public virtual*/ void
+morkArray::CloseMorkNode(morkEnv* ev) // CloseTable() only if open
+{
+ if ( this->IsOpenNode() )
+ {
+ this->MarkClosing();
+ this->CloseArray(ev);
+ this->MarkShut();
+ }
+}
+
+/*public virtual*/
+morkArray::~morkArray() // assert CloseTable() executed earlier
+{
+ MORK_ASSERT(this->IsShutNode());
+ MORK_ASSERT(mArray_Slots==0);
+}
+
+/*public non-poly*/
+morkArray::morkArray(morkEnv* ev, const morkUsage& inUsage,
+ nsIMdbHeap* ioHeap, mork_size inSize, nsIMdbHeap* ioSlotHeap)
+: morkNode(ev, inUsage, ioHeap)
+, mArray_Slots( 0 )
+, mArray_Heap( 0 )
+, mArray_Fill( 0 )
+, mArray_Size( 0 )
+, mArray_Seed( (mork_u4)NS_PTR_TO_INT32(this) ) // "random" integer assignment
+{
+ if ( ev->Good() )
+ {
+ if ( ioSlotHeap )
+ {
+ nsIMdbHeap_SlotStrongHeap(ioSlotHeap, ev, &mArray_Heap);
+ if ( ev->Good() )
+ {
+ if ( inSize < 3 )
+ inSize = 3;
+ mdb_size byteSize = inSize * sizeof(void*);
+ void** block = 0;
+ ioSlotHeap->Alloc(ev->AsMdbEnv(), byteSize, (void**) &block);
+ if ( block && ev->Good() )
+ {
+ mArray_Slots = block;
+ mArray_Size = inSize;
+ MORK_MEMSET(mArray_Slots, 0, byteSize);
+ if ( ev->Good() )
+ mNode_Derived = morkDerived_kArray;
+ }
+ }
+ }
+ else
+ ev->NilPointerError();
+ }
+}
+
+/*public non-poly*/ void
+morkArray::CloseArray(morkEnv* ev) // called by CloseMorkNode();
+{
+ if ( this->IsNode() )
+ {
+ if ( mArray_Heap && mArray_Slots )
+ mArray_Heap->Free(ev->AsMdbEnv(), mArray_Slots);
+
+ mArray_Slots = 0;
+ mArray_Size = 0;
+ mArray_Fill = 0;
+ ++mArray_Seed;
+ nsIMdbHeap_SlotStrongHeap((nsIMdbHeap*) 0, ev, &mArray_Heap);
+ this->MarkShut();
+ }
+ else
+ this->NonNodeError(ev);
+}
+
+// } ===== end morkNode methods =====
+// ````` ````` ````` ````` `````
+
+/*static*/ void
+morkArray::NonArrayTypeError(morkEnv* ev)
+{
+ ev->NewError("non morkArray");
+}
+
+/*static*/ void
+morkArray::IndexBeyondEndError(morkEnv* ev)
+{
+ ev->NewError("array index beyond end");
+}
+
+/*static*/ void
+morkArray::NilSlotsAddressError(morkEnv* ev)
+{
+ ev->NewError("nil mArray_Slots");
+}
+
+/*static*/ void
+morkArray::FillBeyondSizeError(morkEnv* ev)
+{
+ ev->NewError("mArray_Fill > mArray_Size");
+}
+
+mork_bool
+morkArray::Grow(morkEnv* ev, mork_size inNewSize)
+// Grow() returns true if capacity becomes >= inNewSize and ev->Good()
+{
+ if ( ev->Good() && inNewSize > mArray_Size ) // make array larger?
+ {
+ if ( mArray_Fill <= mArray_Size ) // fill and size fit the invariant?
+ {
+ if (mArray_Size <= 3)
+ inNewSize = mArray_Size + 3;
+ else
+ inNewSize = mArray_Size * 2;// + 3; // try doubling size here - used to grow by 3
+
+ mdb_size newByteSize = inNewSize * sizeof(void*);
+ void** newBlock = 0;
+ mArray_Heap->Alloc(ev->AsMdbEnv(), newByteSize, (void**) &newBlock);
+ if ( newBlock && ev->Good() ) // okay new block?
+ {
+ void** oldSlots = mArray_Slots;
+ void** oldEnd = oldSlots + mArray_Fill;
+
+ void** newSlots = newBlock;
+ void** newEnd = newBlock + inNewSize;
+
+ while ( oldSlots < oldEnd )
+ *newSlots++ = *oldSlots++;
+
+ while ( newSlots < newEnd )
+ *newSlots++ = (void*) 0;
+
+ oldSlots = mArray_Slots;
+ mArray_Size = inNewSize;
+ mArray_Slots = newBlock;
+ mArray_Heap->Free(ev->AsMdbEnv(), oldSlots);
+ }
+ }
+ else
+ this->FillBeyondSizeError(ev);
+ }
+ ++mArray_Seed; // always modify seed, since caller intends to add slots
+ return ( ev->Good() && mArray_Size >= inNewSize );
+}
+
+void*
+morkArray::SafeAt(morkEnv* ev, mork_pos inPos)
+{
+ if ( mArray_Slots )
+ {
+ if ( inPos >= 0 && inPos < (mork_pos) mArray_Fill )
+ return mArray_Slots[ inPos ];
+ else
+ this->IndexBeyondEndError(ev);
+ }
+ else
+ this->NilSlotsAddressError(ev);
+
+ return (void*) 0;
+}
+
+void
+morkArray::SafeAtPut(morkEnv* ev, mork_pos inPos, void* ioSlot)
+{
+ if ( mArray_Slots )
+ {
+ if ( inPos >= 0 && inPos < (mork_pos) mArray_Fill )
+ {
+ mArray_Slots[ inPos ] = ioSlot;
+ ++mArray_Seed;
+ }
+ else
+ this->IndexBeyondEndError(ev);
+ }
+ else
+ this->NilSlotsAddressError(ev);
+}
+
+mork_pos
+morkArray::AppendSlot(morkEnv* ev, void* ioSlot)
+{
+ mork_pos outPos = -1;
+ if ( mArray_Slots )
+ {
+ mork_fill fill = mArray_Fill;
+ if ( this->Grow(ev, fill+1) )
+ {
+ outPos = (mork_pos) fill;
+ mArray_Slots[ fill ] = ioSlot;
+ mArray_Fill = fill + 1;
+ // note Grow() increments mArray_Seed
+ }
+ }
+ else
+ this->NilSlotsAddressError(ev);
+
+ return outPos;
+}
+
+void
+morkArray::AddSlot(morkEnv* ev, mork_pos inPos, void* ioSlot)
+{
+ if ( mArray_Slots )
+ {
+ mork_fill fill = mArray_Fill;
+ if ( this->Grow(ev, fill+1) )
+ {
+ void** slot = mArray_Slots; // the slot vector
+ void** end = slot + fill; // one past the last used array slot
+ slot += inPos; // the slot to be added
+
+ while ( --end >= slot ) // another slot to move upward?
+ end[ 1 ] = *end;
+
+ *slot = ioSlot;
+ mArray_Fill = fill + 1;
+ // note Grow() increments mArray_Seed
+ }
+ }
+ else
+ this->NilSlotsAddressError(ev);
+}
+
+void
+morkArray::CutSlot(morkEnv* ev, mork_pos inPos)
+{
+ MORK_USED_1(ev);
+ mork_fill fill = mArray_Fill;
+ if ( inPos >= 0 && inPos < (mork_pos) fill ) // cutting slot in used array portion?
+ {
+ void** slot = mArray_Slots; // the slot vector
+ void** end = slot + fill; // one past the last used array slot
+ slot += inPos; // the slot to be cut
+
+ while ( ++slot < end ) // another slot to move downward?
+ slot[ -1 ] = *slot;
+
+ slot[ -1 ] = 0; // clear the last used slot which is now unused
+
+ // note inPos<fill implies fill>0, so fill-1 must be nonnegative:
+ mArray_Fill = fill - 1;
+ ++mArray_Seed;
+ }
+}
+
+void
+morkArray::CutAllSlots(morkEnv* ev)
+{
+ if ( mArray_Slots )
+ {
+ if ( mArray_Fill <= mArray_Size )
+ {
+ mdb_size oldByteSize = mArray_Fill * sizeof(void*);
+ MORK_MEMSET(mArray_Slots, 0, oldByteSize);
+ }
+ else
+ this->FillBeyondSizeError(ev);
+ }
+ else
+ this->NilSlotsAddressError(ev);
+
+ ++mArray_Seed;
+ mArray_Fill = 0;
+}
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789