netscape-revival
lib/mac/TX/Array.cp
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
#include "Array.h"
//***************************************************************************************************
#ifdef txtnDebug
short gCountArrays = 0;
#endif
//***************************************************************************************************
CArray::CArray()
{
}
//***************************************************************************************************
void CArray::IArray(short arrayElementSize, short moreElementsCount /*= 0*/)
{
#ifdef txtnDebug
++gCountArrays;
#endif
fElementSize = arrayElementSize;
fHandle = NewHandle(0);
fLogicalCount = 0;
fPhysicalCount = 0;
fLockLevel = 0;
if ((fMoreElementsCount = moreElementsCount) <= 0)
fMoreElementsCount = 1;
}
//***************************************************************************************************
void CArray::Free()
{
#ifdef txtnDebug
--gCountArrays;
#endif
if (fHandle)
::DisposeHandle(fHandle);
}
//***************************************************************************************************
// //////////
// jah 950130...
Handle CArray::GetDataHandle(void)
{
return fHandle;
}
void CArray::SetDataHandle(Handle inHandle, short inElementSize)
{
if (fHandle)
DisposeHandle(fHandle);
fHandle = inHandle;
fElementSize = inElementSize;
if (inHandle) {
fLogicalCount = GetHandleSize(inHandle) / fElementSize; // necessary?
fLockLevel = !((HGetState(inHandle) & 0x80) == 0);
} else {
fLogicalCount = 0;
fLockLevel = 0;
}
fPhysicalCount = fLogicalCount; // ???
}
// \\\\\\\\\\
//***************************************************************************************************
void* CArray::LockArray(Boolean moveHi /*= false*/)
{
if (fLockLevel++ == 0) {
if (moveHi)
MoveHHi(fHandle);
HLock(fHandle);
}
return GetElementPtr(0);
}
//***************************************************************************************************
void CArray::UnlockArray()
{
#ifdef txtnDebug
if (fLockLevel < 0)
SignalPStr_("\p UnlockArray!!");
#endif
if (fLockLevel && (--fLockLevel == 0))
HUnlock(fHandle);
}
//***************************************************************************************************
void* CArray::GetElementPtr(long elementIndex) const
{
#ifdef txtnDebug
if ((elementIndex < -1) || (elementIndex > fLogicalCount))
/*should be elementIndex >= fLogicalCount, but sometimes callers will not use the ptr
, its only within a loop which not be entered */
{SignalPStr_("\pBad element index");}
#endif
register long val = long(*fHandle) + elementIndex*fElementSize;
return (fLockLevel > 0) ? StripAddress(Ptr(val)) : (void*)val;
}
//***************************************************************************************************
void* CArray::GetLastElementPtr() const
{
return GetElementPtr(fLogicalCount-1);
}
//***************************************************************************************************
void CArray::SetElementsVal(long elementIndex, const void* newElementsPtr, long countElements /*= 1*/)
//Assumed to not disturb memory (see InsertElements for ex)
{
#ifdef txtnDebug
if ((elementIndex < 0) || (elementIndex+countElements > fLogicalCount))
SignalPStr_("\pBad element index");
#endif
BlockMoveData(newElementsPtr, GetElementPtr(elementIndex), countElements*fElementSize);
}
//***************************************************************************************************
void CArray::GetElementsVal(long elementIndex, void* elementsPtr, long countElements /*= 1*/)
//Assumed to not disturb memory (see InsertElements for ex)
{
#ifdef txtnDebug
if ((elementIndex < 0) || (elementIndex+countElements > fLogicalCount))
SignalPStr_("\pBad element index");
#endif
BlockMoveData(GetElementPtr(elementIndex), elementsPtr, countElements*fElementSize);
}
//***************************************************************************************************
void* CArray::InsertElements(long countToInsert, const void* newElementsVal, long insertIndex /* = -1*/)
{
Assert_(fLockLevel == 0);
Assert_(countToInsert >= 0);
long oldElementsCount = fLogicalCount;
long newElementsCount = oldElementsCount + countToInsert;
if (newElementsCount > fPhysicalCount) {
long newActElementsCount;
if (fMoreElementsCount > countToInsert)
newActElementsCount = oldElementsCount + fMoreElementsCount;
else
newActElementsCount = newElementsCount;
OSErr err = SetArraySize(newActElementsCount);
if (err) {
//try to not use fMoreElementsCount
if (newActElementsCount != newElementsCount) { //==> newActElementsCount > newElementsCount
err = SetArraySize(newElementsCount);
}
if (err) {return nil;}
}
}
fLogicalCount = newElementsCount;
if (insertIndex < 0)
insertIndex = oldElementsCount;
void* insertPtr = GetElementPtr(insertIndex);
if (insertIndex != oldElementsCount)
SetElementsVal(insertIndex+countToInsert, insertPtr, oldElementsCount-insertIndex);
if (newElementsVal)
SetElementsVal(insertIndex, newElementsVal, countToInsert);
return insertPtr;
}
//***************************************************************************************************
void CArray::CheckUnusedCount()
{
long register requiredPhysicalCount = fLogicalCount + fMoreElementsCount;
if (fPhysicalCount > requiredPhysicalCount)
SetArraySize(requiredPhysicalCount);
}
//***************************************************************************************************
long CArray::RemoveElements(long removeIndex, long countToRemove)
{
Assert_(fLogicalCount - countToRemove >= 0);
long srcMoveIndex = removeIndex + countToRemove;
long countToMove = fLogicalCount - srcMoveIndex;
if (countToMove > 0)
SetElementsVal(removeIndex, GetElementPtr(srcMoveIndex), countToMove);
fLogicalCount -= countToRemove;
CheckUnusedCount();
return fLogicalCount;
}
//***************************************************************************************************
OSErr CArray::ReplaceElements(long oldCount, long newCount, long replaceIndex, const void* newElements)
{
Assert_(replaceIndex >= 0);
Assert_(oldCount >= 0);
Assert_(newCount >= 0);
long countToAdd = newCount - oldCount;
if (countToAdd > 0) {
if (InsertElements(countToAdd, nil, replaceIndex) == nil)
return memFullErr;
}
else {
if (countToAdd < 0) {
/*we don't use "this" since someone may override RemoveElements. our call here is actually
an implementation detail and not required
*/
CArray::RemoveElements(replaceIndex, -countToAdd);
}
}
if (newElements)
SetElementsVal(replaceIndex, newElements, newCount);
return noErr;
}
//***************************************************************************************************
OSErr CArray::SetArraySize(long newElementsCount)
{
if (newElementsCount != fPhysicalCount) {
#ifdef txtnDebug
if (newElementsCount > fPhysicalCount)
Assert_(fLockLevel == 0);
#endif
SetHandleSize(fHandle, newElementsCount*fElementSize);
OSErr theMemErr = MemError();
if (!theMemErr)
fPhysicalCount = newElementsCount;
return theMemErr;
}
else
return noErr;
}
//***************************************************************************************************
OSErr CArray::Reserve(long extraCount)
{
OSErr err;
if (extraCount > 0) {
long currCount = fLogicalCount;
err = SetElementsCount(currCount + extraCount);
fLogicalCount = currCount;
}
else
{err = noErr;}
return err;
}
//***************************************************************************************************
OSErr CArray::SetElementsCount(long newCount)
{
Assert_(newCount >= 0);
OSErr err = noErr;
if (newCount > fPhysicalCount) {
if (!InsertElements(newCount-fLogicalCount, nil))
err = memFullErr;
}
else {
fLogicalCount = newCount;
CheckUnusedCount();
}
return err;
}
//***************************************************************************************************
void CArray::Compact()
{
SetArraySize(fLogicalCount);
}
//***************************************************************************************************
CLongTagArray::CLongTagArray()
{
}
//***************************************************************************************************
long CLongTagArray::Search(long val, long* foundVal) const
/*
¥returns the index of the element whose entry starts with a long value == "val"
, the insert index if not found
¥ foundVal is set to the value at the found index
¥ no special handling if the searched value is duplicated
*/
{
register long left = 0;
register long right = fLogicalCount-1;
if (right < left) {//fLogicalCount == 0
*foundVal = -1;
return 0;
}
*foundVal = *(long*) GetElementPtr(0);
if (val <= *foundVal) {return 0;}
*foundVal = *(long*)GetLastElementPtr();
if (val > *foundVal) {return fLogicalCount;}
long insertIndex;
do {
long testIndex = (left+right) >> 1; // /2
long testedVal = *(long*)GetElementPtr(testIndex);
long delta = testedVal-val;
if (!delta) {
*foundVal = val;
return testIndex;
}
if (delta > 0) {
right = testIndex-1;
insertIndex = testIndex;
*foundVal = testedVal;
}
else
left = testIndex+1;
}
while (right >= left);
return insertIndex;
}
//***************************************************************************************************
long CLongTagArray::SearchBigger(long val) const
/* ¥returns the index of the first element whose entry starts with a long > val
¥ no special handling if the searched value is duplicated
*/
{
long foundVal;
long theIndex = Search(val, &foundVal);
long lastElemIndex = fLogicalCount-1;
if (theIndex > lastElemIndex)
theIndex = lastElemIndex;
else {
if ((foundVal <= val) && (theIndex < lastElemIndex))
++theIndex;
}
return theIndex;
}
//***************************************************************************************************