#ifndef __CASC_SPARSE_ARRAY_H__
#define __CASC_SPARSE_ARRAY_H__
struct CASC_ARRAY_256
{
CASC_ARRAY_256()
{
memset(Pointers, 0, sizeof(Pointers));
}
CASC_ARRAY_256 * GetLowerLevel(size_t nIndex)
{
return (CASC_ARRAY_256 *)(Pointers[nIndex & 0xFF]);
}
CASC_ARRAY_256 ** SubTable(size_t ItemIndex, size_t nLevel)
{
size_t nShift = 0x20 - (nLevel * 8);
size_t nIndex = (ItemIndex >> nShift) & 0xFF;
return (CASC_ARRAY_256 **)(&Pointers[nIndex]);
}
void Reset(size_t nLevel)
{
CASC_ARRAY_256 * pLower;
if(nLevel < 3)
{
for(size_t i = 0; i < _countof(Pointers); i++)
{
if((pLower = GetLowerLevel(i)) != NULL)
{
pLower->Reset(nLevel + 1);
}
}
}
else
{
memset(Pointers, 0, sizeof(CASC_ARRAY_256));
}
}
void Free(size_t nLevel)
{
CASC_ARRAY_256 * pLower;
if(nLevel < 3)
{
for(size_t i = 0; i < _countof(Pointers); i++)
{
if((pLower = GetLowerLevel(i)) != NULL)
{
pLower->Free(nLevel + 1);
delete pLower;
}
}
}
memset(Pointers, 0, sizeof(CASC_ARRAY_256));
}
void * Pointers[0x100];
};
class CASC_SPARSE_ARRAY
{
public:
CASC_SPARSE_ARRAY()
{
m_LevelsAllocated = 0;
m_ItemCount = 0;
m_pLevel0 = NULL;
}
~CASC_SPARSE_ARRAY()
{
Free();
}
template<typename TYPE>
DWORD Create(size_t )
{
if((m_pLevel0 = new CASC_ARRAY_256()) != NULL)
{
m_LevelsAllocated++;
return ERROR_SUCCESS;
}
return ERROR_NOT_ENOUGH_MEMORY;
}
void ** ItemAt(size_t ItemIndex)
{
CASC_ARRAY_256 * pLevelN;
assert((DWORD)(ItemIndex) == ItemIndex);
if((pLevelN = m_pLevel0) != NULL)
{
if((pLevelN = GetLowerLevelTable(pLevelN, ItemIndex, 1)) != NULL)
{
if((pLevelN = GetLowerLevelTable(pLevelN, ItemIndex, 2)) != NULL)
{
if((pLevelN = GetLowerLevelTable(pLevelN, ItemIndex, 3)) != NULL)
{
return &pLevelN->Pointers[ItemIndex & 0xFF];
}
}
}
}
return NULL;
}
void ** InsertAt(size_t ItemIndex)
{
CASC_ARRAY_256 * pLevelN;
assert((DWORD)(ItemIndex) == ItemIndex);
if((pLevelN = m_pLevel0) != NULL)
{
if((pLevelN = EnsureLowerLevelTable(pLevelN, ItemIndex, 1)) != NULL)
{
if((pLevelN = EnsureLowerLevelTable(pLevelN, ItemIndex, 2)) != NULL)
{
if((pLevelN = EnsureLowerLevelTable(pLevelN, ItemIndex, 3)) != NULL)
{
if(ItemIndex >= m_ItemCount)
m_ItemCount = ItemIndex + 1;
return &pLevelN->Pointers[ItemIndex & 0xFF];
}
}
}
}
return NULL;
}
void Reset()
{
if(m_pLevel0 != NULL)
{
m_pLevel0->Reset(0);
}
}
void Free()
{
if(m_pLevel0 != NULL)
{
m_pLevel0->Free(0);
delete m_pLevel0;
}
}
size_t ItemCount()
{
return m_ItemCount;
}
size_t ItemCountMax()
{
return 0xFFFFFFFF;
}
size_t ItemSize()
{
return sizeof(void *);
}
bool IsInitialized()
{
return (m_pLevel0 != NULL);
}
#ifdef CASCLIB_DEBUG
size_t BytesAllocated()
{
return m_LevelsAllocated * sizeof(CASC_ARRAY_256);
}
void Dump(const char * szFileName)
{
FILE * fp;
size_t * RefItem;
size_t Item;
if((fp = fopen(szFileName, "wb")) != NULL)
{
for(size_t i = 0; i < m_ItemCount; i++)
{
RefItem = (size_t *)ItemAt(i);
Item = (RefItem != NULL) ? RefItem[0] : 0;
fwrite(&Item, ItemSize(), 1, fp);
}
fclose(fp);
}
}
#endif
protected:
CASC_ARRAY_256 * GetLowerLevelTable(CASC_ARRAY_256 * pTable, size_t ItemIndex, size_t nLevel)
{
CASC_ARRAY_256 ** SubTable = pTable->SubTable(ItemIndex, nLevel);
return SubTable[0];
}
CASC_ARRAY_256 * EnsureLowerLevelTable(CASC_ARRAY_256 * pTable, size_t ItemIndex, size_t nLevel)
{
CASC_ARRAY_256 ** SubTable = pTable->SubTable(ItemIndex, nLevel);
if(SubTable[0] == NULL)
{
SubTable[0] = new CASC_ARRAY_256();
m_LevelsAllocated++;
}
return SubTable[0];
}
CASC_ARRAY_256 * m_pLevel0; size_t m_LevelsAllocated; size_t m_ItemCount; };
#endif