void
JMMArrayTable::_AddNewRecord
	(
	const JMMRecord& record,
	const JBoolean   checkDoubleAllocation
	)
{
	JSize index = 0;

	if (checkDoubleAllocation)
		{
		index = FindAllocatedBlock( record.GetAddress() );
		}

	if (index == 0)
		{
		// Append because new allocations tend to be free'd the fastest
		itsAllocatedTable->AppendElement(record);
		}
	else
		{
		JMMRecord thisRecord = itsAllocatedTable->GetElement(index);
		itsAllocatedBytes   -= thisRecord.GetSize();

		NotifyMultipleAllocation(record, thisRecord);

		// Might as well trust malloc--the table should never have duplicate
		// entries!
		itsAllocatedTable->SetElement(index, record);
		}

	itsAllocatedBytes += record.GetSize();
}
void
JMMHashTable::_AddNewRecord
(
    const JMMRecord& record,
    const JBoolean   checkDoubleAllocation
)
{
    JHashCursor<JMMRecord> cursor(itsAllocatedTable, reinterpret_cast<JHashValue>( record.GetAddress() ) );
    if (checkDoubleAllocation)
    {
        cursor.ForceNextMapInsertHash();
        if ( cursor.IsFull() )
        {
            JMMRecord thisRecord = cursor.GetValue();
            itsAllocatedBytes   -= thisRecord.GetSize();
            NotifyMultipleAllocation(record, thisRecord);
        }
        // Might as well trust malloc--the table should never have duplicate
        // entries!
    }
    else
    {
        cursor.ForceNextOpen();
    }
    cursor.Set(reinterpret_cast<JHashValue>( record.GetAddress() ), record);
    itsAllocatedBytes += record.GetSize();
}
JBoolean
JMMArrayTable::_SetRecordDeleted
	(
	JMMRecord*        record,
	const void*       block,
	const JCharacter* file,
	const JUInt32     line,
	const JBoolean    isArray
	)
{
	JSize index = FindAllocatedBlock(block);

	if (index != 0)
		{
		JMMRecord thisRecord = itsAllocatedTable->GetElement(index);
		thisRecord.SetDeleteLocation(file, line, isArray);
		itsAllocatedBytes -= thisRecord.GetSize();

		if (!thisRecord.ArrayNew() && isArray)
			{
			NotifyObjectDeletedAsArray(thisRecord);
			}
		else if (thisRecord.ArrayNew() && !isArray)
			{
			NotifyArrayDeletedAsObject(thisRecord);
			}

		itsAllocatedTable->RemoveElement(index);
		if (itsDeletedTable != NULL)
			{
			itsDeletedTable->AppendElement(thisRecord);
			}
		else
			{
			itsDeletedCount++;
			}

		*record = thisRecord;
		return kJTrue;
		}
	else
		{
		// Because the array is searched backwards, if it finds a block it
		// will be the most recent deallocation at that address
		index = FindDeletedBlock(block);
		if (index == 0)
			{
			NotifyUnallocatedDeletion(file, line, isArray);
			}
		else
			{
			JMMRecord thisRecord = itsDeletedTable->GetElement(index);

			NotifyMultipleDeletion(thisRecord, file, line, isArray);
			}

		return kJFalse;
		}
}
JBoolean
JMemoryManager::RecordFilter::Match
	(
	const JMMRecord& record
	)
	const
{
	JBoolean match = kJTrue;

	if (!includeInternal && record.IsManagerMemory())
		{
		match = kJFalse;
		}

	if (record.GetSize() < minSize)
		{
		match = kJFalse;
		}

	const JSize newFileLength = strlen(record.GetNewFile());
	if (match && fileName != NULL && newFileLength == fileName->GetLength())
		{
		if (record.GetNewFile() != *fileName)
			{
			match = kJFalse;
			}
		}
	else if (match && fileName != NULL)
		{
		const JCharacter *s1, *s2;
		JSize l1, l2;
		if (newFileLength > fileName->GetLength())
			{
			s1 = record.GetNewFile();
			l1 = newFileLength;
			s2 = *fileName;
			l2 = fileName->GetLength();
			}
		else
			{
			s1 = *fileName;
			l1 = fileName->GetLength();
			s2 = record.GetNewFile();
			l2 = newFileLength;
			}

		if (*(s1 + l1 - l2 - 1) != ACE_DIRECTORY_SEPARATOR_CHAR ||
			strcmp(s1 + l1 - l2, s2) != 0)
			{
			match = kJFalse;
			}
		}

	return match;
}
void
JMMHashTable::PrintAllocated
(
    const JBoolean printInternal // = kJFalse
)
const
{
    cout << "\nAllocated block statistics:" << endl;

    cout << "\nAllocated user memory:" << endl;

    JConstHashCursor<JMMRecord> cursor(itsAllocatedTable);
    JSize totalSize = 0;
    while ( cursor.NextFull() )
    {
        const JMMRecord thisRecord = cursor.GetValue();
        if ( !thisRecord.IsManagerMemory() )
        {
            PrintAllocatedRecord(thisRecord);
            totalSize += thisRecord.GetSize();
        }
    }

    cout << "\nTotal allocated memory:  " << totalSize << " bytes" << endl;

    if (printInternal)
    {
        cout << "\nThe following blocks are probably owned by the memory manager"
             << "\nand *should* still be allocated--please report all cases of user"
             << "\nallocated memory showing up on this list!" << endl;

        cursor.Reset();
        while ( cursor.NextFull() )
        {
            const JMMRecord thisRecord = cursor.GetValue();
            if ( thisRecord.IsManagerMemory() )
            {
                PrintAllocatedRecord(thisRecord);
            }
        }
    }
}
void
JMemoryManager::DeleteRecord
	(
	void*             block,
	const JCharacter* file,
	const JUInt32     line,
	const JBoolean    isArray
	)
{
	if (block == NULL)
		{
		HandleNULLDeleted(file, line, isArray);
		}
	else
		{
		JBoolean wasAllocated;
		if (itsMemoryTable != NULL)
			{
			JMMRecord record;
			wasAllocated = itsMemoryTable->SetRecordDeleted(&record, block,
															file, line, isArray);
			// Can't do this unless we're keeping records
			if (itsShredFlag && wasAllocated)
				{
				assert(record.GetAddress() == block);
				memset(block, itsDeallocateGarbage, record.GetSize() );
				}
			}
		else
			{
			wasAllocated = kJTrue; // Have to trust the client
			}

		// Try to avoid a seg fault so the program can continue
		if (wasAllocated)
			{
			free(block);
			}
		}
}
JBoolean
JMMHashTable::_SetRecordDeleted
(
    JMMRecord*        record,
    const void*       block,
    const JCharacter* file,
    const JUInt32     line,
    const JBoolean    isArray
)
{
    JHashCursor<JMMRecord> allocCursor(itsAllocatedTable, reinterpret_cast<JHashValue>(block) );
    if ( allocCursor.NextHash() )
    {
        JMMRecord thisRecord = allocCursor.GetValue();
        thisRecord.SetDeleteLocation(file, line, isArray);
        itsAllocatedBytes -= thisRecord.GetSize();

        if (!thisRecord.ArrayNew() && isArray)
        {
            NotifyObjectDeletedAsArray(thisRecord);
        }
        else if (thisRecord.ArrayNew() && !isArray)
        {
            NotifyArrayDeletedAsObject(thisRecord);
        }

        allocCursor.Remove();
        if (itsDeletedTable != NULL)
        {
            JHashCursor<JMMRecord> deallocCursor(itsDeletedTable, reinterpret_cast<JHashValue>(block) );
            deallocCursor.ForceNextOpen();
            deallocCursor.Set(reinterpret_cast<JHashValue>(block), thisRecord);
        }
        else
        {
            itsDeletedCount++;
        }

        *record = thisRecord;
        return kJTrue;
    }
    else
    {
        if (itsDeletedTable == NULL)
        {
            NotifyUnallocatedDeletion(file, line, isArray);
        }
        else
        {
            JHashCursor<JMMRecord> deallocCursor(itsDeletedTable, reinterpret_cast<JHashValue>(block) );
            if ( deallocCursor.NextHash() )
            {
                // Seek most recent deallocation at that address
                JMMRecord previousRecord = deallocCursor.GetValue();
                while ( deallocCursor.NextHash() )
                {
                    JMMRecord thisRecord = deallocCursor.GetValue();
                    if ( thisRecord.GetID() > previousRecord.GetID() )
                    {
                        previousRecord = thisRecord;
                    }
                }

                NotifyMultipleDeletion(previousRecord, file, line, isArray);
            }
            else
            {
                NotifyUnallocatedDeletion(file, line, isArray);
            }
        }
        return kJFalse;
    }
}