Remove default mem buffer api
This commit is contained in:
parent
00cae20654
commit
c47748c168
280
dqn.h
280
dqn.h
@ -104,7 +104,7 @@ typedef struct DqnMemBufferBlock
|
||||
|
||||
enum DqnMemBufferFlag
|
||||
{
|
||||
DqnMemBufferFlag_IsExpandable = (1 << 0),
|
||||
DqnMemBufferFlag_IsNotExpandable = (1 << 0),
|
||||
DqnMemBufferFlag_IsFixedMemoryFromUser = (1 << 1), // NOTE(doyle): Required to indicate we CAN'T free this memory when free is called.
|
||||
};
|
||||
|
||||
@ -181,13 +181,21 @@ typedef struct DqnMemAPICallbackInfo
|
||||
void *userContext;
|
||||
union {
|
||||
struct { size_t requestSize; }; // DqnMemAPICallbackType_Alloc
|
||||
struct { void *ptrToFree; }; // DqnMemAPICallbackType_Free
|
||||
|
||||
// DqnMemAPICallbackType_Free
|
||||
struct
|
||||
{
|
||||
void *ptrToFree;
|
||||
size_t sizeToFree;
|
||||
};
|
||||
|
||||
// DqnMemAPICallbackType_Realloc
|
||||
struct
|
||||
{
|
||||
size_t newRequestSize;
|
||||
void *oldMemPtr;
|
||||
size_t oldSize;
|
||||
}; // DqnMemAPICallbackType_Realloc
|
||||
};
|
||||
};
|
||||
} DqnMemAPICallbackInfo;
|
||||
|
||||
@ -205,15 +213,11 @@ typedef struct DqnMemAPI
|
||||
void *userContext;
|
||||
} DqnMemAPI;
|
||||
|
||||
// TODO(doyle): DefaultUseMemBuffer is experimental!!!!
|
||||
DQN_FILE_SCOPE DqnMemAPI DqnMemAPI_DefaultUseMemBuffer(DqnMemBuffer *const buffer);
|
||||
DQN_FILE_SCOPE DqnMemAPI DqnMemAPI_DefaultUseCalloc();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// DArray - Dynamic Array
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// REMINDER: Dynamic Array can be used as a stack. Don't need to create one.
|
||||
// TODO(doyle): Custom allocator
|
||||
#if 1
|
||||
template <typename T>
|
||||
struct DqnArray
|
||||
@ -227,33 +231,46 @@ struct DqnArray
|
||||
|
||||
#if 0
|
||||
template <typename T>
|
||||
bool DqnArray_init (DqnArray<T> *array, size_t capacity);
|
||||
bool DqnArray_grow (DqnArray<T> *array);
|
||||
T *DqnArray_push (DqnArray<T> *array, T item);
|
||||
T *DqnArray_pop (DqnArray<T> *array)
|
||||
T *DqnArray_get (DqnArray<T> *array, u64 index);
|
||||
bool DqnArray_clear (DqnArray<T> *array);
|
||||
bool DqnArray_free (DqnArray<T> *array);
|
||||
bool DqnArray_remove (DqnArray<T> *array, u64 index);
|
||||
bool DqnArray_remove_stable(DqnArray<T> *array, u64 index);
|
||||
bool DqnArray_Init (DqnArray<T> *array, size_t capacity);
|
||||
bool DqnArray_Grow (DqnArray<T> *array);
|
||||
T *DqnArray_Push (DqnArray<T> *array, T item);
|
||||
T *DqnArray_Pop (DqnArray<T> *array)
|
||||
T *DqnArray_Get (DqnArray<T> *array, u64 index);
|
||||
bool DqnArray_Clear (DqnArray<T> *array);
|
||||
bool DqnArray_Free (DqnArray<T> *array);
|
||||
bool DqnArray_Remove (DqnArray<T> *array, u64 index);
|
||||
bool DqnArray_RemoveStable(DqnArray<T> *array, u64 index);
|
||||
#endif
|
||||
|
||||
// Implementation taken from Milton, developed by Serge at
|
||||
// https://github.com/serge-rgb/milton#license
|
||||
template <typename T>
|
||||
bool DqnArray_Free(DqnArray<T> *array)
|
||||
{
|
||||
if (array && array->data)
|
||||
{
|
||||
// TODO(doyle): Right now we assume free always works, and it probably should?
|
||||
size_t sizeToFree = (size_t)array->capacity * sizeof(T);
|
||||
DqnMemAPICallbackInfo info = DqnMemAPICallback_InfoAskFreeInternal(
|
||||
array->memAPI, array->data, sizeToFree);
|
||||
array->memAPI.callback(info, NULL);
|
||||
array->data = NULL;
|
||||
|
||||
array->count = 0;
|
||||
array->capacity = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool DqnArray_Init(DqnArray<T> *array, size_t capacity,
|
||||
DqnMemAPI memAPI = DqnMemAPI_DefaultUseCalloc())
|
||||
{
|
||||
if (!array) return false;
|
||||
if (array->data) DqnArray_Free(array);
|
||||
|
||||
if (array->data)
|
||||
{
|
||||
// TODO(doyle): Logging? The array already exists
|
||||
DqnMemAPICallbackInfo info =
|
||||
DqnMemAPICallback_InfoAskFreeInternal(array->memAPI, array->data);
|
||||
array->memAPI.callback(info, NULL);
|
||||
array->data = NULL;
|
||||
}
|
||||
array->memAPI = memAPI;
|
||||
size_t allocateSize = (size_t)capacity * sizeof(T);
|
||||
|
||||
@ -347,25 +364,6 @@ bool DqnArray_Clear(DqnArray<T> *array)
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool DqnArray_Free(DqnArray<T> *array)
|
||||
{
|
||||
if (array && array->data)
|
||||
{
|
||||
// TODO(doyle): Right now we assume free always works, and it probably should?
|
||||
DqnMemAPICallbackInfo info =
|
||||
DqnMemAPICallback_InfoAskFreeInternal(array->memAPI, array->data);
|
||||
array->memAPI.callback(info, NULL);
|
||||
array->data = NULL;
|
||||
|
||||
array->count = 0;
|
||||
array->capacity = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool DqnArray_Remove(DqnArray<T> *array, u64 index)
|
||||
{
|
||||
@ -1331,7 +1329,7 @@ DqnMemBuffer_AllocateCompatibleBlock(const DqnMemBuffer *const buffer, size_t si
|
||||
{
|
||||
if (!buffer) return NULL;
|
||||
if (buffer->flags & DqnMemBufferFlag_IsFixedMemoryFromUser) return NULL;
|
||||
if (!(buffer->flags & DqnMemBufferFlag_IsExpandable)) return NULL;
|
||||
if (buffer->flags & DqnMemBufferFlag_IsNotExpandable) return NULL;
|
||||
|
||||
DqnMemBufferBlock *block =
|
||||
DqnMemBuffer_AllocateBlockInternal(buffer->byteAlign, size);
|
||||
@ -1343,21 +1341,13 @@ DQN_FILE_SCOPE bool DqnMemBuffer_AttachBlock(DqnMemBuffer *const buffer,
|
||||
{
|
||||
if (!buffer || !newBlock) return false;
|
||||
if (buffer->flags & DqnMemBufferFlag_IsFixedMemoryFromUser) return false;
|
||||
if (buffer->flags & DqnMemBufferFlag_IsNotExpandable) return false;
|
||||
|
||||
// TODO(doyle): If we make InitWithFixedSize buffer the Is_Expandable
|
||||
// flag is not set. But if you free the buffery and try to allocate to
|
||||
// it again since the flag is not set, the buffer becomes useless as we
|
||||
// can't allocate to it anymore. How should we solve this?
|
||||
if (buffer->flags & DqnMemBufferFlag_IsExpandable)
|
||||
{
|
||||
newBlock->prevBlock = buffer->block;
|
||||
buffer->block = newBlock;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
DQN_FILE_SCOPE bool DqnMemBuffer_InitWithFixedMem(DqnMemBuffer *const buffer,
|
||||
u8 *const mem,
|
||||
const size_t memSize,
|
||||
@ -1374,7 +1364,7 @@ DQN_FILE_SCOPE bool DqnMemBuffer_InitWithFixedMem(DqnMemBuffer *const buffer,
|
||||
buffer->block->memory = mem + sizeof(DqnMemBufferBlock);
|
||||
buffer->block->used = 0;
|
||||
buffer->block->size = memSize - sizeof(DqnMemBufferBlock);
|
||||
buffer->flags = DqnMemBufferFlag_IsFixedMemoryFromUser;
|
||||
buffer->flags = (DqnMemBufferFlag_IsFixedMemoryFromUser | DqnMemBufferFlag_IsNotExpandable);
|
||||
|
||||
const u32 DEFAULT_ALIGNMENT = 4;
|
||||
buffer->tempBufferCount = 0;
|
||||
@ -1394,7 +1384,7 @@ DQN_FILE_SCOPE bool DqnMemBuffer_Init(DqnMemBuffer *const buffer, size_t size,
|
||||
|
||||
buffer->tempBufferCount = 0;
|
||||
buffer->byteAlign = byteAlign;
|
||||
buffer->flags = DqnMemBufferFlag_IsExpandable;
|
||||
buffer->flags = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1406,7 +1396,7 @@ DQN_FILE_SCOPE bool DqnMemBuffer_InitWithFixedSize(DqnMemBuffer *const buffer,
|
||||
bool result = DqnMemBuffer_Init(buffer, size, byteAlign);
|
||||
if (result)
|
||||
{
|
||||
buffer->flags = 0;
|
||||
buffer->flags |= DqnMemBufferFlag_IsNotExpandable;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1503,10 +1493,22 @@ DqnMemBuffer_FreeLastBlock(DqnMemBuffer *const buffer)
|
||||
DQN_FILE_SCOPE void DqnMemBuffer_Free(DqnMemBuffer *buffer)
|
||||
{
|
||||
if (!buffer) return;
|
||||
if (buffer->flags & DqnMemBufferFlag_IsFixedMemoryFromUser) return;
|
||||
|
||||
// NOTE(doyle): User is in charge of freeing this memory, so all we need to
|
||||
// do is clear the block.
|
||||
if (buffer->flags & DqnMemBufferFlag_IsFixedMemoryFromUser)
|
||||
{
|
||||
DQN_ASSERT(!buffer->block->prevBlock);
|
||||
DqnMemBuffer_ClearCurrBlock(buffer, false);
|
||||
return;
|
||||
}
|
||||
|
||||
while (buffer->block)
|
||||
DqnMemBuffer_FreeLastBlock(buffer);
|
||||
|
||||
// After a buffer is free, we reset the not expandable flag so that if we
|
||||
// allocate on an empty buffer it still works.
|
||||
buffer->flags &= ~DqnMemBufferFlag_IsNotExpandable;
|
||||
}
|
||||
|
||||
DQN_FILE_SCOPE void DqnMemBuffer_ClearCurrBlock(DqnMemBuffer *const buffer,
|
||||
@ -1581,12 +1583,13 @@ DqnMemAPICallback_InfoAskAllocInternal(const DqnMemAPI memAPI,
|
||||
}
|
||||
|
||||
FILE_SCOPE DqnMemAPICallbackInfo DqnMemAPICallback_InfoAskFreeInternal(
|
||||
const DqnMemAPI memAPI, void *const ptrToFree)
|
||||
const DqnMemAPI memAPI, void *const ptrToFree, const size_t sizeToFree)
|
||||
{
|
||||
DqnMemAPICallbackInfo info = {};
|
||||
info.type = DqnMemAPICallbackType_Free;
|
||||
info.userContext = memAPI.userContext;
|
||||
info.ptrToFree = ptrToFree;
|
||||
info.sizeToFree = sizeToFree;
|
||||
return info;
|
||||
}
|
||||
|
||||
@ -1653,155 +1656,6 @@ DqnMemAPI_DefaultUseCallocCallbackInternal(DqnMemAPICallbackInfo info,
|
||||
}
|
||||
}
|
||||
|
||||
FILE_SCOPE void
|
||||
DqnMemAPI_DefaultUseMemBufferCallbackInternal(DqnMemAPICallbackInfo info,
|
||||
DqnMemAPICallbackResult *result)
|
||||
{
|
||||
DQN_ASSERT(info.userContext);
|
||||
DqnMemAPI_ValidateCallbackInfo(info);
|
||||
DqnMemBuffer *const buffer = static_cast<DqnMemBuffer *>(info.userContext);
|
||||
|
||||
switch(info.type)
|
||||
{
|
||||
case DqnMemAPICallbackType_Alloc:
|
||||
{
|
||||
DQN_ASSERT(result);
|
||||
result->type = info.type;
|
||||
result->newMemPtr = DqnMemBuffer_Allocate(buffer, info.requestSize);
|
||||
}
|
||||
break;
|
||||
|
||||
// TODO(doyle): This is so badly handled. Currently MemBuffers are not
|
||||
// designed to handle realloc in anyway elegantly due to it's memory
|
||||
// block nature.
|
||||
case DqnMemAPICallbackType_Realloc:
|
||||
{
|
||||
// NOTE(doyle): Realloc implies that we want our data to be
|
||||
// contiguous. We also enforce (assert) in init that the supplied
|
||||
// memory buffer is brand new, i.e. the memory buffer is used
|
||||
// exclusively for the MemAPI operations. So if we don't have enough
|
||||
// space, we can free the entire memory buffer and reallocate
|
||||
// without having to worry about part of blocks holding data
|
||||
// belonging to other objects.
|
||||
DQN_ASSERT(result);
|
||||
result->type = info.type;
|
||||
|
||||
u8 *oldPtr = (u8 *)info.oldMemPtr;
|
||||
DqnMemBufferBlock *currBlock = buffer->block;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
// NOTE(doyle): Block containing our data must exist otherwise
|
||||
// it has been invalidly deleted without us knowing, or it
|
||||
// doesn't belong to the buffer the memAPI is using
|
||||
if (!currBlock) DQN_ASSERT(DQN_INVALID_CODE_PATH);
|
||||
|
||||
if (oldPtr >= currBlock->memory &&
|
||||
oldPtr < (currBlock->memory + currBlock->size))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
currBlock = currBlock->prevBlock;
|
||||
}
|
||||
|
||||
size_t alignedSize =
|
||||
DQN_ALIGN_POW_N(info.newRequestSize, buffer->byteAlign);
|
||||
// If true, then this block ONLY has data that this MemAPI has
|
||||
// allocated which means it's valid for us to completely free it
|
||||
// or allocate further within it.
|
||||
DqnMemBufferBlock *const oldBlock = currBlock;
|
||||
if (info.oldSize == oldBlock->used)
|
||||
{
|
||||
// NOTE(doyle): If size is the same as used, then I'm pretty
|
||||
// sure this guarantees that the old memory is a ptr to the
|
||||
// base of the memory block.
|
||||
DQN_ASSERT(oldPtr == oldBlock->memory);
|
||||
|
||||
if (alignedSize > oldBlock->size)
|
||||
{
|
||||
result->newMemPtr =
|
||||
DqnMemBuffer_Allocate(buffer, alignedSize);
|
||||
if (result->newMemPtr)
|
||||
{
|
||||
DqnMemBufferBlock *newBlock = buffer->block;
|
||||
DQN_ASSERT(oldBlock != newBlock);
|
||||
|
||||
for (u32 i = 0; i < oldBlock->used; i++)
|
||||
newBlock->memory[i] = oldBlock->memory[i];
|
||||
|
||||
newBlock->used = alignedSize;
|
||||
DqnMemBuffer_FreeBlock(buffer, oldBlock);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise, the current block still has enough space
|
||||
// so we can realloc in place.
|
||||
|
||||
// TODO(doyle): Somewhat hacky, we clear the curr block
|
||||
// pointer, and don't zero it out, and just reallocate
|
||||
// the aligned size.
|
||||
DqnMemBuffer_ClearCurrBlock(buffer, false);
|
||||
result->newMemPtr =
|
||||
DqnMemBuffer_Allocate(buffer, alignedSize);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(doyle): How to free the left over data from the old block?
|
||||
// TODO(doyle): Think about putting the old realloc block, not at
|
||||
// the front of the list, since when we realloc, we search our block
|
||||
// list for the mem block that contains our data anyway so the
|
||||
// realloc block does NOT have to be at the front of the list to use
|
||||
// it.
|
||||
// If we place the block behind the front of the list, then we also
|
||||
// need to fix the logic above using Allocate() which will
|
||||
// automatically place the block in front of the list. This way we
|
||||
// can take advantage of whatever free space is left in the block we
|
||||
// just left, instead of leaving it dead.
|
||||
|
||||
// TODO(doyle): If this code branch occurs, then when we get around
|
||||
// to implementing memory profiling, we're going to want to mark
|
||||
// this as dead memory.
|
||||
|
||||
// Otherwise, the more difficult case. This block contains other
|
||||
// data that has been allocated to it. The easy option is to
|
||||
// just allocate a new block and leave the old data lying around.
|
||||
// We force a new block to be attached which will hold our realloced
|
||||
// data.
|
||||
DqnMemBufferBlock *newBlock =
|
||||
DqnMemBuffer_AllocateCompatibleBlock(buffer, alignedSize);
|
||||
if (newBlock)
|
||||
{
|
||||
if (DqnMemBuffer_AttachBlock(buffer, newBlock))
|
||||
{
|
||||
DQN_ASSERT(buffer->block != oldBlock &&
|
||||
buffer->block == newBlock);
|
||||
|
||||
result->newMemPtr = buffer->block->memory;
|
||||
for (u32 i = 0; i < info.oldSize; i++)
|
||||
newBlock->memory[i] = oldPtr[i];
|
||||
|
||||
newBlock->used = alignedSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DqnMemAPICallbackType_Free:
|
||||
{
|
||||
// TODO(doyle): Freeing technically works, if we enforce that the
|
||||
// MemBuffer exclusively belongs to the MemAPI it's linked to.
|
||||
if (result) result->type = info.type;
|
||||
DQN_ASSERT(info.ptrToFree == buffer->block->memory);
|
||||
DqnMemBuffer_Free(buffer);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DQN_FILE_SCOPE DqnMemAPI DqnMemAPI_DefaultUseCalloc()
|
||||
{
|
||||
DqnMemAPI result = {};
|
||||
@ -1810,18 +1664,6 @@ DQN_FILE_SCOPE DqnMemAPI DqnMemAPI_DefaultUseCalloc()
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_FILE_SCOPE DqnMemAPI DqnMemAPI_DefaultUseMemBuffer(DqnMemBuffer *const buffer)
|
||||
{
|
||||
// TODO(doyle): We assert that the buffer has to be a brand new mem buffer.
|
||||
// Is this the correct design choice?
|
||||
DQN_ASSERT(buffer && buffer->block);
|
||||
|
||||
DqnMemAPI result = {};
|
||||
result.callback = DqnMemAPI_DefaultUseMemBufferCallbackInternal;
|
||||
result.userContext = buffer;
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Math
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -843,132 +843,6 @@ void ArrayTest()
|
||||
{
|
||||
DqnArray<DqnV2> array = {};
|
||||
ArrayTestMemAPIInternal(&array, DqnMemAPI_DefaultUseCalloc());
|
||||
|
||||
DqnMemBuffer largeEnoughBuffer = {};
|
||||
{
|
||||
size_t size = DQN_MEGABYTE(1);
|
||||
// Empty buffer
|
||||
{
|
||||
DqnMemBuffer_Init(&largeEnoughBuffer, size, false);
|
||||
ArrayTestMemAPIInternal(
|
||||
&array, DqnMemAPI_DefaultUseMemBuffer(&largeEnoughBuffer));
|
||||
DqnMemBuffer_Free(&largeEnoughBuffer);
|
||||
}
|
||||
|
||||
// Allocate data to buffer, and cause realloc to have to create a new
|
||||
// block
|
||||
{
|
||||
DqnMemBuffer_Init(&largeEnoughBuffer, size, false);
|
||||
|
||||
size_t usedSize = (size_t)(size * 0.5f);
|
||||
u8 *usedData =
|
||||
(u8 *)DqnMemBuffer_Allocate(&largeEnoughBuffer, usedSize);
|
||||
for (u32 i = 0; i < usedSize; i++)
|
||||
usedData[i] = 'a';
|
||||
|
||||
ArrayTestMemAPIInternal(
|
||||
&array, DqnMemAPI_DefaultUseMemBuffer(&largeEnoughBuffer));
|
||||
DqnMemBuffer_Free(&largeEnoughBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
DqnMemBuffer smallBuffer = {};
|
||||
{
|
||||
size_t size = 8;
|
||||
// Empty small buffer
|
||||
{
|
||||
DqnMemBuffer_Init(&smallBuffer, size, false);
|
||||
ArrayTestMemAPIInternal(
|
||||
&array, DqnMemAPI_DefaultUseMemBuffer(&smallBuffer));
|
||||
DqnMemBuffer_Free(&smallBuffer);
|
||||
}
|
||||
|
||||
// Allocate data to buffer, force realloc to have to create a new block
|
||||
{
|
||||
DqnMemBuffer_Init(&smallBuffer, size, false);
|
||||
|
||||
size_t usedSize = (size_t)(size * 0.5f);
|
||||
u8 *usedData = (u8 *)DqnMemBuffer_Allocate(&smallBuffer, usedSize);
|
||||
for (u32 i = 0; i < usedSize; i++)
|
||||
usedData[i] = 'a';
|
||||
ArrayTestMemAPIInternal(
|
||||
&array, DqnMemAPI_DefaultUseMemBuffer(&smallBuffer));
|
||||
DqnMemBuffer_Free(&smallBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(doyle): Doesn't work for now since after freeing a fixed size
|
||||
// buffer, it becomes useless as the not set Is_Expandable flag blocks any
|
||||
// further allocations.
|
||||
#if 0
|
||||
DqnMemBuffer largeFixedSizeBuffer = {};
|
||||
DqnMemBuffer_InitWithFixedSize(&largeFixedSizeBuffer, DQN_MEGABYTE(1), false);
|
||||
ArrayTestMemAPIInternal(&array, DqnMemAPI_DefaultUseMemBuffer(&largeFixedSizeBuffer));
|
||||
DqnMemBuffer_Free(&largeFixedSizeBuffer);
|
||||
#endif
|
||||
|
||||
{
|
||||
DqnMemBuffer smallFixedSizeBuffer = {};
|
||||
DqnMemBuffer_InitWithFixedSize(&smallFixedSizeBuffer, 8, false);
|
||||
|
||||
DQN_ASSERT(DqnArray_Init(&array, 1, DqnMemAPI_DefaultUseMemBuffer(&smallFixedSizeBuffer)));
|
||||
DQN_ASSERT(array.capacity == 1);
|
||||
DQN_ASSERT(array.count == 0);
|
||||
|
||||
// Fill the only slot in the array
|
||||
DqnV2 a = DqnV2_2f(1, 2);
|
||||
DQN_ASSERT(DqnArray_Push(&array, a));
|
||||
DQN_ASSERT(array.count == 1);
|
||||
|
||||
// Try push another, but it should fail since it's a fixed size buffer.
|
||||
// The realloc that occurs in push should also fail.
|
||||
DQN_ASSERT(!DqnArray_Push(&array, a));
|
||||
DQN_ASSERT(array.count == 1);
|
||||
DQN_ASSERT(smallFixedSizeBuffer.block->prevBlock == NULL);
|
||||
DQN_ASSERT(smallFixedSizeBuffer.block->used == 8);
|
||||
DQN_ASSERT(smallFixedSizeBuffer.block->size == 8);
|
||||
|
||||
DQN_ASSERT(DqnArray_Free(&array));
|
||||
DqnMemBuffer_Free(&smallFixedSizeBuffer);
|
||||
}
|
||||
|
||||
#if 0
|
||||
{
|
||||
u8 largeFixedMem[DQN_KILOBYTE(1)] = {};
|
||||
DqnMemBuffer largeFixedMemBuffer = {};
|
||||
DqnMemBuffer_InitWithFixedMem(&largeFixedMemBuffer, largeFixedMem,
|
||||
DQN_ARRAY_COUNT(largeFixedMem));
|
||||
ArrayTestMemAPIInternal(
|
||||
&array, DqnMemAPI_DefaultUseMemBuffer(&largeFixedMemBuffer));
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
u8 smallFixedMem[sizeof(DqnMemBufferBlock) + 8] = {};
|
||||
DqnMemBuffer smallFixedMemBuffer = {};
|
||||
DqnMemBuffer_InitWithFixedMem(&smallFixedMemBuffer, smallFixedMem,
|
||||
DQN_ARRAY_COUNT(smallFixedMem));
|
||||
|
||||
DQN_ASSERT(DqnArray_Init(&array, 1, DqnMemAPI_DefaultUseMemBuffer(&smallFixedMemBuffer)));
|
||||
DQN_ASSERT(array.capacity == 1);
|
||||
DQN_ASSERT(array.count == 0);
|
||||
|
||||
// Fill the only slot in the array
|
||||
DqnV2 a = DqnV2_2f(1, 2);
|
||||
DQN_ASSERT(DqnArray_Push(&array, a));
|
||||
DQN_ASSERT(array.count == 1);
|
||||
|
||||
// Try push another, but it should fail since it's a fixed mem buffer.
|
||||
// The realloc that occurs in push should also fail.
|
||||
DQN_ASSERT(!DqnArray_Push(&array, a));
|
||||
DQN_ASSERT(array.count == 1);
|
||||
DQN_ASSERT(smallFixedMemBuffer.block->prevBlock == NULL);
|
||||
DQN_ASSERT(smallFixedMemBuffer.block->used == 8);
|
||||
DQN_ASSERT(smallFixedMemBuffer.block->size == 8);
|
||||
|
||||
DQN_ASSERT(DqnArray_Free(&array));
|
||||
}
|
||||
|
||||
printf("ArrayTest(): Completed successfully\n");
|
||||
}
|
||||
|
||||
@ -1231,7 +1105,7 @@ void MemBufferTest()
|
||||
|
||||
// General Check buffer struct contains the values we expect from
|
||||
// initialisation
|
||||
DQN_ASSERT(buffer.flags & DqnMemBufferFlag_IsExpandable);
|
||||
DQN_ASSERT(buffer.flags == 0);
|
||||
DQN_ASSERT(buffer.tempBufferCount == 0);
|
||||
DQN_ASSERT(buffer.byteAlign == ALIGNMENT);
|
||||
DQN_ASSERT(buffer.block->size == firstBlockSize);
|
||||
|
Loading…
Reference in New Issue
Block a user