/* -*- 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 // 456789_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 inPos0, 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; } // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789