diff options
Diffstat (limited to 'db/mork/src/morkArray.cpp')
-rw-r--r-- | db/mork/src/morkArray.cpp | 297 |
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 |