diff options
Diffstat (limited to 'comm/mailnews/db/mork/morkArray.cpp')
-rw-r--r-- | comm/mailnews/db/mork/morkArray.cpp | 250 |
1 files changed, 250 insertions, 0 deletions
diff --git a/comm/mailnews/db/mork/morkArray.cpp b/comm/mailnews/db/mork/morkArray.cpp new file mode 100644 index 0000000000..fff5f8a626 --- /dev/null +++ b/comm/mailnews/db/mork/morkArray.cpp @@ -0,0 +1,250 @@ +/* -*- 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 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; +} + +// 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 |