Lumenarium/src/gs_array.h

226 lines
6.3 KiB
C

struct free_list
{
free_list* Next;
s32 Index;
};
struct bucket_index
{
s32 Bucket;
s32 IndexInBucket;
};
inline bucket_index
GetBucketIndexForIndex (s32 Index, s32 BucketSize)
{
bucket_index Result = {};
Result.Bucket = Index / BucketSize;
Result.IndexInBucket = Index % BucketSize;
return Result;
};
struct array_entry_handle
{
s32 Generation;
s32 Index;
};
// NOTE(Peter): This is a total bastardization of the preprocessor but it works and is
// easier than writing a metaprogramming system at the moment.
// TODO(Peter): Write a metaprogramming version of this that is actually easy to debug
#define TYPEDEF_ARRAY(element_type) \
struct element_type##_array_entry { \
s32 Generation; \
union \
{ \
element_type Entry; \
free_list Free; \
}; \
}; \
\
struct element_type##_array \
{ \
element_type##_array_entry** Buckets; \
s32 BucketSize; \
s32 BucketCount; \
s32 Used; \
free_list FreeList; \
}; \
\
internal void \
GrowBuffer(element_type##_array* Buffer) \
{ \
s32 NewBucketSize = sizeof(element_type##_array_entry) * Buffer->BucketSize; \
element_type##_array_entry* NewBucket = (element_type##_array_entry*)malloc(NewBucketSize); \
GSZeroMemory((u8*)NewBucket, NewBucketSize); \
\
s32 NewBucketIndex = Buffer->BucketCount++; \
if (!Buffer->Buckets) \
{ \
Buffer->Buckets = (element_type##_array_entry**)malloc(sizeof(element_type##_array_entry*)); \
} \
else \
{ \
Buffer->Buckets = (element_type##_array_entry**)realloc(Buffer->Buckets, sizeof(element_type##_array_entry*) * Buffer->BucketCount); \
} \
Buffer->Buckets[NewBucketIndex] = NewBucket; \
} \
\
internal element_type##_array_entry* \
GetEntryAtIndex (s32 Index, element_type##_array Buffer) \
{ \
bucket_index BucketIndex = GetBucketIndexForIndex(Index, Buffer.BucketSize); \
element_type##_array_entry* Entry = Buffer.Buckets[BucketIndex.Bucket] + BucketIndex.IndexInBucket; \
return Entry; \
} \
\
internal array_entry_handle \
PushElement (element_type Data, element_type##_array* Buffer) \
{ \
array_entry_handle Result = {}; \
\
if (Buffer->FreeList.Next != &Buffer->FreeList) \
{ \
free_list* FreeList = Buffer->FreeList.Next; \
element_type##_array_entry* Entry = GetEntryAtIndex(FreeList->Index, *Buffer); \
Buffer->FreeList.Next = Entry->Free.Next; \
\
Result.Index = Entry->Free.Index; \
Result.Generation = Entry->Generation; \
Entry->Entry = Data; \
\
++Buffer->Used; \
} \
else \
{ \
if (Buffer->Used >= Buffer->BucketSize * Buffer->BucketCount) \
{ \
GrowBuffer(Buffer); \
} \
\
s32 Index = Buffer->Used++; \
s32 BucketIndex = Index / Buffer->BucketSize; \
s32 IndexInBucket = Index % Buffer->BucketSize; \
\
Buffer->Buckets[BucketIndex][IndexInBucket].Entry = Data; \
Result.Index = Index; \
Result.Generation = Buffer->Buckets[BucketIndex][IndexInBucket].Generation; \
} \
\
return Result; \
} \
\
internal element_type* \
GetElementAtIndex (s32 Index, element_type##_array Buffer) \
{ \
Assert(Index < Buffer.Used); \
element_type##_array_entry* Entry = GetEntryAtIndex(Index, Buffer); \
element_type* Result = &Entry->Entry; \
return Result; \
} \
\
internal element_type* \
GetElementWithHandle (array_entry_handle Handle, element_type##_array Buffer) \
{ \
element_type* Result = 0; \
\
element_type##_array_entry* Entry = GetEntryAtIndex(Handle.Index, Buffer); \
\
if (Entry->Generation == Handle.Generation) \
{ \
Result = &Entry->Entry; \
} \
\
return Result; \
} \
\
internal void \
RemoveElementAtIndex (s32 Index, element_type##_array* Buffer) \
{ \
Assert(Index < Buffer->Used); \
\
element_type##_array_entry* Entry = GetEntryAtIndex(Index, *Buffer); \
++Entry->Generation; \
Entry->Free.Index = Index; \
\
Entry->Free.Next = Buffer->FreeList.Next; \
Buffer->FreeList.Next = &Entry->Free; \
\
--Buffer->Used; \
} \
// END OF CRAZY MACRO
#define TYPEDEF_CONTIGUOUS_ARRAY(element_type) \
struct element_type##_contiguous_array \
{ \
element_type** Buckets; \
s32 BucketSize; \
s32 BucketCount; \
s32 Used; \
}; \
\
internal void \
GrowBuffer(element_type##_contiguous_array* Buffer) \
{ \
s32 NewBucketSize = sizeof(element_type) * Buffer->BucketSize; \
element_type* NewBucket = (element_type*)malloc(NewBucketSize); \
GSZeroMemory((u8*)NewBucket, NewBucketSize); \
\
s32 NewBucketIndex = Buffer->BucketCount++; \
if (!Buffer->Buckets) \
{ \
Buffer->Buckets = (element_type**)malloc(sizeof(element_type*)); \
} \
else \
{ \
Buffer->Buckets = (element_type**)realloc(Buffer->Buckets, sizeof(element_type*) * Buffer->BucketCount); \
} \
Buffer->Buckets[NewBucketIndex] = NewBucket; \
} \
\
internal element_type* \
GetElementAtIndex (s32 Index, element_type##_contiguous_array Buffer) \
{ \
bucket_index BucketIndex = GetBucketIndexForIndex(Index, Buffer.BucketSize); \
element_type* Entry = Buffer.Buckets[BucketIndex.Bucket] + BucketIndex.IndexInBucket; \
return Entry; \
} \
\
internal s32 \
PushElement (element_type Data, element_type##_contiguous_array* Buffer) \
{ \
s32 Result = -1; \
\
if (Buffer->Used >= Buffer->BucketSize * Buffer->BucketCount) \
{ \
GrowBuffer(Buffer); \
} \
\
s32 Index = Buffer->Used++; \
s32 BucketIndex = Index / Buffer->BucketSize; \
s32 IndexInBucket = Index % Buffer->BucketSize; \
\
Buffer->Buckets[BucketIndex][IndexInBucket] = Data; \
Result = Index; \
return Result; \
} \
\
internal void \
RemoveElementAtIndex (s32 Index, element_type##_contiguous_array* Buffer) \
{ \
Assert(Index < Buffer->Used); \
\
bucket_index IndexToRemove = GetBucketIndexForIndex(Index, Buffer->BucketSize); \
bucket_index LastIndex = GetBucketIndexForIndex(Buffer->Used - 1, Buffer->BucketSize); \
element_type ValueAtLastIndex = Buffer->Buckets[LastIndex.Bucket][LastIndex.IndexInBucket]; \
Buffer->Buckets[IndexToRemove.Bucket][IndexToRemove.IndexInBucket] = ValueAtLastIndex; \
--Buffer->Used; \
} \
// END OF CRAZY MACRO
TYPEDEF_ARRAY(array_entry_handle);
TYPEDEF_CONTIGUOUS_ARRAY(array_entry_handle);