Compare commits
4 Commits
7ad10ba734
...
7568c2138b
Author | SHA1 | Date | |
---|---|---|---|
7568c2138b | |||
8995fe67f8 | |||
49e7b40b08 | |||
1721dc813a |
137
pl_memory.h
137
pl_memory.h
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
pl_memory
|
pl_memory.h
|
||||||
* no dependencies
|
* no dependencies
|
||||||
* simple
|
* simple memory allocators
|
||||||
|
|
||||||
Do this:
|
Do this:
|
||||||
#define PL_MEMORY_IMPLEMENTATION
|
#define PL_MEMORY_IMPLEMENTATION
|
||||||
@ -19,9 +19,9 @@
|
|||||||
* override assert by defining PL_ASSERT(x)
|
* override assert by defining PL_ASSERT(x)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// library version
|
// library version (format XYYZZ)
|
||||||
#define PL_MEMORY_VERSION "0.6.0"
|
#define PL_MEMORY_VERSION "1.0.0"
|
||||||
#define PL_MEMORY_VERSION_NUM 00600
|
#define PL_MEMORY_VERSION_NUM 10000
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Index of this file:
|
Index of this file:
|
||||||
@ -59,10 +59,10 @@ Index of this file:
|
|||||||
// [SECTION] forward declarations & basic types
|
// [SECTION] forward declarations & basic types
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// basic types
|
||||||
typedef struct _plTempAllocator plTempAllocator;
|
typedef struct _plTempAllocator plTempAllocator;
|
||||||
typedef struct _plStackAllocator plStackAllocator;
|
typedef struct _plStackAllocator plStackAllocator;
|
||||||
typedef struct _plPoolAllocator plPoolAllocator;
|
typedef struct _plPoolAllocator plPoolAllocator;
|
||||||
typedef struct _plPoolAllocatorNode plPoolAllocatorNode;
|
|
||||||
|
|
||||||
typedef size_t plStackAllocatorMarker;
|
typedef size_t plStackAllocatorMarker;
|
||||||
|
|
||||||
@ -105,7 +105,14 @@ void pl_stack_allocator_free_bottom_to_marker(plStackAllocator
|
|||||||
|
|
||||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~pool allocator~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~pool allocator~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
void pl_pool_allocator_init (plPoolAllocator*, size_t szItemCount, size_t szItemSize, size_t szItemAlignment, size_t* pszBufferSize, void*);
|
// Notes
|
||||||
|
// - setting pBuffer to NULL, will set pszBufferSize to required buffer size
|
||||||
|
// so you can allocate a properly sized buffer for the szItemCount (then call function again)
|
||||||
|
// - to use a stack allocated buffer, first call the function with szItemCount = 0 & pszBufferSize
|
||||||
|
// set to size of the buffer; the function will return the number of items that can be support;
|
||||||
|
// call function again with this number
|
||||||
|
|
||||||
|
size_t pl_pool_allocator_init (plPoolAllocator*, size_t szItemCount, size_t szItemSize, size_t szItemAlignment, size_t* pszBufferSize, void* pBuffer);
|
||||||
void* pl_pool_allocator_alloc(plPoolAllocator*);
|
void* pl_pool_allocator_alloc(plPoolAllocator*);
|
||||||
void pl_pool_allocator_free (plPoolAllocator*, void* pItem);
|
void pl_pool_allocator_free (plPoolAllocator*, void* pItem);
|
||||||
|
|
||||||
@ -113,6 +120,9 @@ void pl_pool_allocator_free (plPoolAllocator*, void* pItem);
|
|||||||
// [SECTION] structs
|
// [SECTION] structs
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// the details of the following structures don't matter to you, but they must
|
||||||
|
// be visible so you can handle the memory allocations for them
|
||||||
|
|
||||||
typedef struct _plTempAllocator
|
typedef struct _plTempAllocator
|
||||||
{
|
{
|
||||||
size_t szSize;
|
size_t szSize;
|
||||||
@ -122,6 +132,8 @@ typedef struct _plTempAllocator
|
|||||||
char** ppcMemoryBlocks;
|
char** ppcMemoryBlocks;
|
||||||
size_t szMemoryBlockCount;
|
size_t szMemoryBlockCount;
|
||||||
size_t szMemoryBlockCapacity;
|
size_t szMemoryBlockCapacity;
|
||||||
|
size_t szCurrentBlockSizes;
|
||||||
|
size_t szNextBlockSizes;
|
||||||
} plTempAllocator;
|
} plTempAllocator;
|
||||||
|
|
||||||
typedef struct _plStackAllocator
|
typedef struct _plStackAllocator
|
||||||
@ -132,6 +144,7 @@ typedef struct _plStackAllocator
|
|||||||
size_t szTopOffset;
|
size_t szTopOffset;
|
||||||
} plStackAllocator;
|
} plStackAllocator;
|
||||||
|
|
||||||
|
typedef struct _plPoolAllocatorNode plPoolAllocatorNode;
|
||||||
typedef struct _plPoolAllocatorNode
|
typedef struct _plPoolAllocatorNode
|
||||||
{
|
{
|
||||||
plPoolAllocatorNode* ptNextNode;
|
plPoolAllocatorNode* ptNextNode;
|
||||||
@ -159,7 +172,6 @@ Index of this file:
|
|||||||
// [SECTION] defines
|
// [SECTION] defines
|
||||||
// [SECTION] internal api
|
// [SECTION] internal api
|
||||||
// [SECTION] public api implementation
|
// [SECTION] public api implementation
|
||||||
// [SECTION] internal api implementation
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -182,24 +194,19 @@ Index of this file:
|
|||||||
#define PL_MEMORY_FREE(x) free(x)
|
#define PL_MEMORY_FREE(x) free(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifndef PL_ASSERT
|
#ifndef PL_ASSERT
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#define PL_ASSERT(x) assert((x))
|
#define PL_ASSERT(x) assert((x))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef PL_MEMORY_TEMP_STACK_BLOCK_SIZE
|
|
||||||
#define PL_MEMORY_TEMP_BLOCK_SIZE 4194304
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define PL__ALIGN_UP(num, align) (((num) + ((align)-1)) & ~((align)-1))
|
#define PL__ALIGN_UP(num, align) (((num) + ((align)-1)) & ~((align)-1))
|
||||||
|
|
||||||
#ifndef pl_vnsprintf
|
#ifndef pl_vnsprintf
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#define pl_vnsprintf vnsprintf
|
#define pl_vnsprintf vsnprintf
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h> // varargs
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// [SECTION] internal api
|
// [SECTION] internal api
|
||||||
@ -238,7 +245,6 @@ pl__align_forward_size(size_t szPtr, size_t szAlign)
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// [SECTION] public api implementation
|
// [SECTION] public api implementation
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -248,6 +254,9 @@ pl_aligned_alloc(size_t szAlignment, size_t szSize)
|
|||||||
{
|
{
|
||||||
void* pBuffer = NULL;
|
void* pBuffer = NULL;
|
||||||
|
|
||||||
|
if(szAlignment == 0)
|
||||||
|
szAlignment = pl__get_next_power_of_2(szSize);
|
||||||
|
|
||||||
// ensure power of 2
|
// ensure power of 2
|
||||||
PL_ASSERT((szAlignment & (szAlignment -1)) == 0 && "alignment must be a power of 2");
|
PL_ASSERT((szAlignment & (szAlignment -1)) == 0 && "alignment must be a power of 2");
|
||||||
|
|
||||||
@ -294,6 +303,8 @@ pl_temp_allocator_alloc(plTempAllocator* ptAllocator, size_t szSize)
|
|||||||
ptAllocator->szSize = PL_MEMORY_TEMP_STACK_SIZE;
|
ptAllocator->szSize = PL_MEMORY_TEMP_STACK_SIZE;
|
||||||
ptAllocator->pcBuffer = ptAllocator->acStackBuffer;
|
ptAllocator->pcBuffer = ptAllocator->acStackBuffer;
|
||||||
ptAllocator->szOffset = 0;
|
ptAllocator->szOffset = 0;
|
||||||
|
ptAllocator->szCurrentBlockSizes = PL_MEMORY_TEMP_STACK_SIZE * 2;
|
||||||
|
ptAllocator->szNextBlockSizes = PL_MEMORY_TEMP_STACK_SIZE * 2;
|
||||||
memset(ptAllocator->acStackBuffer, 0, PL_MEMORY_TEMP_STACK_SIZE);
|
memset(ptAllocator->acStackBuffer, 0, PL_MEMORY_TEMP_STACK_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -302,7 +313,6 @@ pl_temp_allocator_alloc(plTempAllocator* ptAllocator, size_t szSize)
|
|||||||
// not enough room is available
|
// not enough room is available
|
||||||
if(szSize > ptAllocator->szSize - ptAllocator->szOffset)
|
if(szSize > ptAllocator->szSize - ptAllocator->szOffset)
|
||||||
{
|
{
|
||||||
PL_ASSERT(szSize < PL_MEMORY_TEMP_BLOCK_SIZE);
|
|
||||||
if(ptAllocator->szMemoryBlockCapacity == 0) // first overflow
|
if(ptAllocator->szMemoryBlockCapacity == 0) // first overflow
|
||||||
{
|
{
|
||||||
// allocate block array
|
// allocate block array
|
||||||
@ -310,30 +320,64 @@ pl_temp_allocator_alloc(plTempAllocator* ptAllocator, size_t szSize)
|
|||||||
ptAllocator->ppcMemoryBlocks = (char**)PL_MEMORY_ALLOC(sizeof(char*) * ptAllocator->szMemoryBlockCapacity);
|
ptAllocator->ppcMemoryBlocks = (char**)PL_MEMORY_ALLOC(sizeof(char*) * ptAllocator->szMemoryBlockCapacity);
|
||||||
memset(ptAllocator->ppcMemoryBlocks, 0, (sizeof(char*) * ptAllocator->szMemoryBlockCapacity));
|
memset(ptAllocator->ppcMemoryBlocks, 0, (sizeof(char*) * ptAllocator->szMemoryBlockCapacity));
|
||||||
|
|
||||||
|
size_t szNewBlockSize = ptAllocator->szCurrentBlockSizes;
|
||||||
|
if(szSize > szNewBlockSize)
|
||||||
|
{
|
||||||
|
ptAllocator->szNextBlockSizes = szSize;
|
||||||
|
szNewBlockSize = szSize;
|
||||||
|
}
|
||||||
|
|
||||||
// allocate first block
|
// allocate first block
|
||||||
ptAllocator->ppcMemoryBlocks[0] = (char*)PL_MEMORY_ALLOC(PL_MEMORY_TEMP_BLOCK_SIZE);
|
ptAllocator->ppcMemoryBlocks[0] = (char*)PL_MEMORY_ALLOC(szNewBlockSize);
|
||||||
ptAllocator->szSize = PL_MEMORY_TEMP_BLOCK_SIZE;
|
ptAllocator->szSize = szNewBlockSize;
|
||||||
ptAllocator->szOffset = 0;
|
ptAllocator->szOffset = 0;
|
||||||
ptAllocator->pcBuffer = ptAllocator->ppcMemoryBlocks[0];
|
ptAllocator->pcBuffer = ptAllocator->ppcMemoryBlocks[0];
|
||||||
}
|
}
|
||||||
else if(ptAllocator->szMemoryBlockCount == ptAllocator->szMemoryBlockCapacity) // grow memory block storage
|
else if(ptAllocator->szMemoryBlockCount == ptAllocator->szMemoryBlockCapacity) // grow memory block storage
|
||||||
{
|
{
|
||||||
|
|
||||||
|
size_t szNewBlockSize = ptAllocator->szCurrentBlockSizes;
|
||||||
|
if(szSize > szNewBlockSize)
|
||||||
|
{
|
||||||
|
ptAllocator->szNextBlockSizes = szSize;
|
||||||
|
szNewBlockSize = szSize;
|
||||||
|
}
|
||||||
|
|
||||||
char** ppcOldBlocks = ptAllocator->ppcMemoryBlocks;
|
char** ppcOldBlocks = ptAllocator->ppcMemoryBlocks;
|
||||||
ptAllocator->ppcMemoryBlocks = (char**)PL_MEMORY_ALLOC(sizeof(char*) * (ptAllocator->szMemoryBlockCapacity + 1));
|
ptAllocator->ppcMemoryBlocks = (char**)PL_MEMORY_ALLOC(sizeof(char*) * (ptAllocator->szMemoryBlockCapacity + 1));
|
||||||
memset(ptAllocator->ppcMemoryBlocks, 0, (sizeof(char*) * (ptAllocator->szMemoryBlockCapacity + 1)));
|
memset(ptAllocator->ppcMemoryBlocks, 0, (sizeof(char*) * (ptAllocator->szMemoryBlockCapacity + 1)));
|
||||||
memcpy(ptAllocator->ppcMemoryBlocks, ppcOldBlocks, sizeof(char*) * ptAllocator->szMemoryBlockCapacity);
|
memcpy(ptAllocator->ppcMemoryBlocks, ppcOldBlocks, sizeof(char*) * ptAllocator->szMemoryBlockCapacity);
|
||||||
ptAllocator->szMemoryBlockCapacity++;
|
ptAllocator->szMemoryBlockCapacity++;
|
||||||
ptAllocator->ppcMemoryBlocks[ptAllocator->szMemoryBlockCount] = (char*)PL_MEMORY_ALLOC(PL_MEMORY_TEMP_BLOCK_SIZE);
|
ptAllocator->ppcMemoryBlocks[ptAllocator->szMemoryBlockCount] = (char*)PL_MEMORY_ALLOC(szNewBlockSize);
|
||||||
ptAllocator->szSize = PL_MEMORY_TEMP_BLOCK_SIZE;
|
ptAllocator->szSize = szNewBlockSize;
|
||||||
ptAllocator->pcBuffer = ptAllocator->ppcMemoryBlocks[ptAllocator->szMemoryBlockCount];
|
ptAllocator->pcBuffer = ptAllocator->ppcMemoryBlocks[ptAllocator->szMemoryBlockCount];
|
||||||
ptAllocator->szOffset = 0;
|
ptAllocator->szOffset = 0;
|
||||||
}
|
}
|
||||||
else // block is available
|
else if(szSize <= ptAllocator->szCurrentBlockSizes) // block available & small enough
|
||||||
{
|
{
|
||||||
ptAllocator->szSize = PL_MEMORY_TEMP_BLOCK_SIZE;
|
ptAllocator->szSize = ptAllocator->szCurrentBlockSizes;
|
||||||
ptAllocator->szOffset = 0;
|
ptAllocator->szOffset = 0;
|
||||||
ptAllocator->pcBuffer = ptAllocator->ppcMemoryBlocks[ptAllocator->szMemoryBlockCount];
|
ptAllocator->pcBuffer = ptAllocator->ppcMemoryBlocks[ptAllocator->szMemoryBlockCount];
|
||||||
}
|
}
|
||||||
|
else // block available but too small
|
||||||
|
{
|
||||||
|
size_t szNewBlockSize = ptAllocator->szCurrentBlockSizes;
|
||||||
|
if(szSize > szNewBlockSize)
|
||||||
|
{
|
||||||
|
ptAllocator->szNextBlockSizes = szSize;
|
||||||
|
szNewBlockSize = szSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
char** ppcOldBlocks = ptAllocator->ppcMemoryBlocks;
|
||||||
|
ptAllocator->ppcMemoryBlocks = (char**)PL_MEMORY_ALLOC(sizeof(char*) * (ptAllocator->szMemoryBlockCapacity + 1));
|
||||||
|
memset(ptAllocator->ppcMemoryBlocks, 0, (sizeof(char*) * (ptAllocator->szMemoryBlockCapacity + 1)));
|
||||||
|
memcpy(ptAllocator->ppcMemoryBlocks, ppcOldBlocks, sizeof(char*) * ptAllocator->szMemoryBlockCapacity);
|
||||||
|
ptAllocator->szMemoryBlockCapacity++;
|
||||||
|
ptAllocator->ppcMemoryBlocks[ptAllocator->szMemoryBlockCount] = (char*)PL_MEMORY_ALLOC(szNewBlockSize);
|
||||||
|
ptAllocator->szSize = szNewBlockSize;
|
||||||
|
ptAllocator->pcBuffer = ptAllocator->ppcMemoryBlocks[ptAllocator->szMemoryBlockCount];
|
||||||
|
ptAllocator->szOffset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
ptAllocator->szMemoryBlockCount++;
|
ptAllocator->szMemoryBlockCount++;
|
||||||
}
|
}
|
||||||
@ -350,6 +394,17 @@ pl_temp_allocator_reset(plTempAllocator* ptAllocator)
|
|||||||
ptAllocator->szOffset = 0;
|
ptAllocator->szOffset = 0;
|
||||||
ptAllocator->szMemoryBlockCount = 0;
|
ptAllocator->szMemoryBlockCount = 0;
|
||||||
ptAllocator->pcBuffer = ptAllocator->acStackBuffer;
|
ptAllocator->pcBuffer = ptAllocator->acStackBuffer;
|
||||||
|
|
||||||
|
if(ptAllocator->szCurrentBlockSizes != ptAllocator->szNextBlockSizes)
|
||||||
|
{
|
||||||
|
for(size_t i = 0; i < ptAllocator->szMemoryBlockCapacity; i++)
|
||||||
|
{
|
||||||
|
PL_MEMORY_FREE(ptAllocator->ppcMemoryBlocks[i]);
|
||||||
|
ptAllocator->ppcMemoryBlocks[i] = (char*)PL_MEMORY_ALLOC(ptAllocator->szNextBlockSizes);
|
||||||
|
memset(ptAllocator->ppcMemoryBlocks[i], 0, ptAllocator->szNextBlockSizes);
|
||||||
|
}
|
||||||
|
ptAllocator->szCurrentBlockSizes = ptAllocator->szNextBlockSizes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -418,7 +473,8 @@ pl_stack_allocator_alloc(plStackAllocator* ptAllocator, size_t szSize)
|
|||||||
{
|
{
|
||||||
size_t szOffset = ptAllocator->szBottomOffset + szSize;
|
size_t szOffset = ptAllocator->szBottomOffset + szSize;
|
||||||
|
|
||||||
PL_ASSERT(szOffset < ptAllocator->szTopOffset && "stack allocator full");
|
if(szOffset >= ptAllocator->szTopOffset)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
// update offset
|
// update offset
|
||||||
void* pBuffer = ptAllocator->pucBuffer + ptAllocator->szBottomOffset;
|
void* pBuffer = ptAllocator->pucBuffer + ptAllocator->szBottomOffset;
|
||||||
@ -437,7 +493,8 @@ pl_stack_allocator_aligned_alloc(plStackAllocator* ptAllocator, size_t szSize, s
|
|||||||
uintptr_t pOffset = pl__align_forward_uintptr(pCurrentPointer, szAlignment);
|
uintptr_t pOffset = pl__align_forward_uintptr(pCurrentPointer, szAlignment);
|
||||||
pOffset -= (uintptr_t)ptAllocator->pucBuffer;
|
pOffset -= (uintptr_t)ptAllocator->pucBuffer;
|
||||||
|
|
||||||
PL_ASSERT(pOffset + szSize <= ptAllocator->szTopOffset && "linear allocator full");
|
if(pOffset + szSize > ptAllocator->szTopOffset)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
// check if allocator has enough space left
|
// check if allocator has enough space left
|
||||||
if(pOffset + szSize <= ptAllocator->szSize)
|
if(pOffset + szSize <= ptAllocator->szSize)
|
||||||
@ -467,7 +524,8 @@ pl_stack_allocator_aligned_alloc_top(plStackAllocator* ptAllocator, size_t szSiz
|
|||||||
uintptr_t pOffset = pl__align_forward_uintptr(pCurrentPointer, szAlignment);
|
uintptr_t pOffset = pl__align_forward_uintptr(pCurrentPointer, szAlignment);
|
||||||
pOffset -= (uintptr_t)ptAllocator->pucBuffer;
|
pOffset -= (uintptr_t)ptAllocator->pucBuffer;
|
||||||
|
|
||||||
PL_ASSERT(pOffset + szSize <= ptAllocator->szTopOffset && "linear allocator full");
|
if(pOffset + szSize > ptAllocator->szTopOffset)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
// check if allocator has enough space left
|
// check if allocator has enough space left
|
||||||
if(pOffset + szSize <= ptAllocator->szSize)
|
if(pOffset + szSize <= ptAllocator->szSize)
|
||||||
@ -492,7 +550,8 @@ pl_stack_allocator_alloc_top(plStackAllocator* ptAllocator, size_t szSize)
|
|||||||
{
|
{
|
||||||
size_t szOffset = ptAllocator->szTopOffset - szSize;
|
size_t szOffset = ptAllocator->szTopOffset - szSize;
|
||||||
|
|
||||||
PL_ASSERT(szOffset > ptAllocator->szBottomOffset && szOffset < ptAllocator->szTopOffset && "stack allocator full");
|
if(szOffset < ptAllocator->szBottomOffset || szOffset > ptAllocator->szTopOffset)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
// update offset
|
// update offset
|
||||||
void* pBuffer = ptAllocator->pucBuffer + szOffset;
|
void* pBuffer = ptAllocator->pucBuffer + szOffset;
|
||||||
@ -562,24 +621,36 @@ pl_stack_allocator_reset(plStackAllocator* ptAllocator)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
size_t
|
||||||
pl_pool_allocator_init(plPoolAllocator* ptAllocator, size_t szItemCount, size_t szItemSize, size_t szItemAlignment, size_t* pszBufferSize, void* pBuffer)
|
pl_pool_allocator_init(plPoolAllocator* ptAllocator, size_t szItemCount, size_t szItemSize, size_t szItemAlignment, size_t* pszBufferSize, void* pBuffer)
|
||||||
{
|
{
|
||||||
PL_ASSERT(ptAllocator);
|
PL_ASSERT(ptAllocator);
|
||||||
PL_ASSERT(szItemCount > 0);
|
|
||||||
PL_ASSERT(szItemSize > 0);
|
PL_ASSERT(szItemSize > 0);
|
||||||
PL_ASSERT(pszBufferSize);
|
PL_ASSERT(pszBufferSize);
|
||||||
|
|
||||||
if(szItemAlignment == 0)
|
// gotta have room for node in unused blocks
|
||||||
|
if(szItemSize < sizeof(plPoolAllocatorNode))
|
||||||
{
|
{
|
||||||
|
szItemSize = sizeof(plPoolAllocatorNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// let us calculate alignment
|
||||||
|
if(szItemAlignment == 0)
|
||||||
szItemAlignment = pl__get_next_power_of_2(szItemSize);
|
szItemAlignment = pl__get_next_power_of_2(szItemSize);
|
||||||
|
|
||||||
|
// let us calculate number of items
|
||||||
|
if(szItemCount == 0 && *pszBufferSize > 0)
|
||||||
|
{
|
||||||
|
size_t szAlignedItemSize = pl__align_forward_size(szItemSize, szItemAlignment);
|
||||||
|
szItemCount = (*pszBufferSize - szItemAlignment) / (szAlignedItemSize);
|
||||||
|
return szItemCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(pBuffer == NULL)
|
if(pBuffer == NULL)
|
||||||
{
|
{
|
||||||
size_t szAlignedItemSize = pl__align_forward_size(szItemSize, szItemAlignment);
|
size_t szAlignedItemSize = pl__align_forward_size(szItemSize, szItemAlignment);
|
||||||
*pszBufferSize = szAlignedItemSize * szItemCount + szItemAlignment;
|
*pszBufferSize = szAlignedItemSize * szItemCount + szItemAlignment;
|
||||||
return;
|
return szItemCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
ptAllocator->szFreeItems = szItemCount;
|
ptAllocator->szFreeItems = szItemCount;
|
||||||
@ -593,7 +664,6 @@ pl_pool_allocator_init(plPoolAllocator* ptAllocator, size_t szItemCount, size_t
|
|||||||
uintptr_t pStart = pl__align_forward_uintptr(pInitialStart, (uintptr_t)szItemAlignment);
|
uintptr_t pStart = pl__align_forward_uintptr(pInitialStart, (uintptr_t)szItemAlignment);
|
||||||
ptAllocator->szUsableSize -= (size_t)(pStart - pInitialStart);
|
ptAllocator->szUsableSize -= (size_t)(pStart - pInitialStart);
|
||||||
|
|
||||||
PL_ASSERT(ptAllocator->szItemSize >= sizeof(plPoolAllocatorNode) && "pool allocator item size too small");
|
|
||||||
PL_ASSERT(ptAllocator->szUsableSize >= ptAllocator->szItemSize * szItemCount && "pool allocator buffer size too small");
|
PL_ASSERT(ptAllocator->szUsableSize >= ptAllocator->szItemSize * szItemCount && "pool allocator buffer size too small");
|
||||||
|
|
||||||
unsigned char* pUsableBuffer = (unsigned char*)pStart;
|
unsigned char* pUsableBuffer = (unsigned char*)pStart;
|
||||||
@ -604,6 +674,7 @@ pl_pool_allocator_init(plPoolAllocator* ptAllocator, size_t szItemCount, size_t
|
|||||||
pNode0->ptNextNode = pNode1;
|
pNode0->ptNextNode = pNode1;
|
||||||
}
|
}
|
||||||
ptAllocator->pFreeList = (plPoolAllocatorNode*)pUsableBuffer;
|
ptAllocator->pFreeList = (plPoolAllocatorNode*)pUsableBuffer;
|
||||||
|
return szItemCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
void*
|
void*
|
||||||
@ -628,4 +699,4 @@ pl_pool_allocator_free(plPoolAllocator* ptAllocator, void* pItem)
|
|||||||
ptAllocator->pFreeList->ptNextNode = pOldFreeNode;
|
ptAllocator->pFreeList->ptNextNode = pOldFreeNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif // PL_MEMORY_IMPLEMENTATION
|
25
pl_stl.h
25
pl_stl.h
@ -1,15 +1,16 @@
|
|||||||
/*
|
/*
|
||||||
pl_stl.h
|
pl_stl.h
|
||||||
|
* no dependencies
|
||||||
|
* simple asci & binary stl parser
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// library version
|
// library version (format XYYZZ)
|
||||||
#define PL_STL_VERSION "0.2.0"
|
#define PL_STL_VERSION "1.0.0"
|
||||||
#define PL_STL_VERSION_NUM 00200
|
#define PL_STL_VERSION_NUM 10000
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Index of this file:
|
Index of this file:
|
||||||
// [SECTION] header mess
|
// [SECTION] header mess
|
||||||
// [SECTION] includes
|
|
||||||
// [SECTION] forward declarations & basic types
|
// [SECTION] forward declarations & basic types
|
||||||
// [SECTION] public api
|
// [SECTION] public api
|
||||||
// [SECTION] structs
|
// [SECTION] structs
|
||||||
@ -23,12 +24,6 @@ Index of this file:
|
|||||||
#ifndef PL_STL_H
|
#ifndef PL_STL_H
|
||||||
#define PL_STL_H
|
#define PL_STL_H
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// [SECTION] includes
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// [SECTION] forward declarations & basic types
|
// [SECTION] forward declarations & basic types
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -50,7 +45,7 @@ typedef struct _plStlInfo
|
|||||||
size_t szPositionStreamSize;
|
size_t szPositionStreamSize;
|
||||||
size_t szNormalStreamSize;
|
size_t szNormalStreamSize;
|
||||||
size_t szIndexBufferSize;
|
size_t szIndexBufferSize;
|
||||||
bool bPreloaded;
|
int iPreloaded;
|
||||||
} plStlInfo;
|
} plStlInfo;
|
||||||
|
|
||||||
#endif // PL_STL_H
|
#endif // PL_STL_H
|
||||||
@ -104,11 +99,11 @@ pl_load_stl(const char* pcData, size_t szDataSize, float* afPositionStream, floa
|
|||||||
ptInfoOut = &_tInternalInfo;
|
ptInfoOut = &_tInternalInfo;
|
||||||
|
|
||||||
bool bAsci = strncmp(pcData, "solid", 5) == 0;
|
bool bAsci = strncmp(pcData, "solid", 5) == 0;
|
||||||
size_t szFacetCount = ptInfoOut->bPreloaded ? ptInfoOut->szIndexBufferSize / 3 : 0;
|
size_t szFacetCount = ptInfoOut->iPreloaded ? ptInfoOut->szIndexBufferSize / 3 : 0;
|
||||||
size_t szCurrentCursor = 0;
|
size_t szCurrentCursor = 0;
|
||||||
size_t szVertexCount = ptInfoOut->bPreloaded ? ptInfoOut->szIndexBufferSize : 0;
|
size_t szVertexCount = ptInfoOut->iPreloaded ? ptInfoOut->szIndexBufferSize : 0;
|
||||||
|
|
||||||
if(!ptInfoOut->bPreloaded)
|
if(!ptInfoOut->iPreloaded)
|
||||||
{
|
{
|
||||||
|
|
||||||
// find number of vertices & facets
|
// find number of vertices & facets
|
||||||
@ -131,7 +126,7 @@ pl_load_stl(const char* pcData, size_t szDataSize, float* afPositionStream, floa
|
|||||||
szVertexCount = szFacetCount * 3;
|
szVertexCount = szFacetCount * 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
ptInfoOut->bPreloaded = true;
|
ptInfoOut->iPreloaded = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ptInfoOut->szIndexBufferSize = szFacetCount * 3;
|
ptInfoOut->szIndexBufferSize = szFacetCount * 3;
|
||||||
|
79
pl_string.h
79
pl_string.h
@ -1,5 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
pl_string
|
pl_string.h
|
||||||
|
* no dependencies
|
||||||
|
* simple string ops
|
||||||
|
|
||||||
Do this:
|
Do this:
|
||||||
#define PL_STRING_IMPLEMENTATION
|
#define PL_STRING_IMPLEMENTATION
|
||||||
before you include this file in *one* C or C++ file to create the implementation.
|
before you include this file in *one* C or C++ file to create the implementation.
|
||||||
@ -11,9 +14,9 @@
|
|||||||
#include "pl_string.h"
|
#include "pl_string.h"
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// library version
|
// library version (format XYYZZ)
|
||||||
#define PL_STRING_VERSION "0.2.0"
|
#define PL_STRING_VERSION "1.0.0"
|
||||||
#define PL_STRING_VERSION_NUM 00200
|
#define PL_STRING_VERSION_NUM 10000
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Index of this file:
|
Index of this file:
|
||||||
@ -47,10 +50,10 @@ uint32_t pl_str_hash_data(const void* pData, size_t szDataSize, uint32_t uSee
|
|||||||
uint32_t pl_str_hash (const char* pcData, size_t szDataSize, uint32_t uSeed);
|
uint32_t pl_str_hash (const char* pcData, size_t szDataSize, uint32_t uSeed);
|
||||||
|
|
||||||
// file/path string ops
|
// file/path string ops
|
||||||
const char* pl_str_get_file_extension(const char* pcFilePath, char* pcExtensionOut);
|
const char* pl_str_get_file_extension(const char* pcFilePath, char* pcExtensionOut, size_t szOutSize);
|
||||||
const char* pl_str_get_file_name (const char* pcFilePath, char* pcFileOut);
|
const char* pl_str_get_file_name (const char* pcFilePath, char* pcFileOut, size_t szOutSize);
|
||||||
const char* pl_str_get_file_name_only(const char* pcFilePath, char* pcFileOut);
|
bool pl_str_get_file_name_only(const char* pcFilePath, char* pcFileOut, size_t szOutSize);
|
||||||
void pl_str_get_directory (const char* pcFilePath, char* pcDirectoryOut);
|
bool pl_str_get_directory (const char* pcFilePath, char* pcDirectoryOut, size_t szOutSize);
|
||||||
|
|
||||||
// misc. opts
|
// misc. opts
|
||||||
bool pl_str_concatenate (const char* pcStr0, const char* pcStr1, char* pcStringOut, size_t szDataSize);
|
bool pl_str_concatenate (const char* pcStr0, const char* pcStr1, char* pcStringOut, size_t szDataSize);
|
||||||
@ -165,7 +168,7 @@ pl_str_hash(const char* pcData, size_t szDataSize, uint32_t uSeed)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const char*
|
const char*
|
||||||
pl_str_get_file_extension(const char* pcFilePath, char* pcExtensionOut)
|
pl_str_get_file_extension(const char* pcFilePath, char* pcExtensionOut, size_t szOutSize)
|
||||||
{
|
{
|
||||||
const char* pcResult = NULL;
|
const char* pcResult = NULL;
|
||||||
const size_t szLen = strlen(pcFilePath);
|
const size_t szLen = strlen(pcFilePath);
|
||||||
@ -194,7 +197,8 @@ pl_str_get_file_extension(const char* pcFilePath, char* pcExtensionOut)
|
|||||||
char c = pcFilePath[szLen - i - 1];
|
char c = pcFilePath[szLen - i - 1];
|
||||||
if(c == '.')
|
if(c == '.')
|
||||||
{
|
{
|
||||||
if(pcExtensionOut) strcpy(pcExtensionOut, &pcFilePath[szLen - i]);
|
if(pcExtensionOut)
|
||||||
|
strncpy(pcExtensionOut, &pcFilePath[szLen - i], szOutSize);
|
||||||
pcResult = &pcFilePath[szLen - i];
|
pcResult = &pcFilePath[szLen - i];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -202,14 +206,15 @@ pl_str_get_file_extension(const char* pcFilePath, char* pcExtensionOut)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(pcExtensionOut) memset(pcExtensionOut, 0, 1);
|
if(pcExtensionOut)
|
||||||
|
memset(pcExtensionOut, 0, szOutSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
return pcResult;
|
return pcResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char*
|
const char*
|
||||||
pl_str_get_file_name(const char* pcFilePath, char* pcFileOut)
|
pl_str_get_file_name(const char* pcFilePath, char* pcFileOut, size_t szOutSize)
|
||||||
{
|
{
|
||||||
const char* pcResult = pcFilePath;
|
const char* pcResult = pcFilePath;
|
||||||
const size_t szLen = strlen(pcFilePath);
|
const size_t szLen = strlen(pcFilePath);
|
||||||
@ -233,7 +238,8 @@ pl_str_get_file_name(const char* pcFilePath, char* pcFileOut)
|
|||||||
|
|
||||||
if(uSlashCount == 0)
|
if(uSlashCount == 0)
|
||||||
{
|
{
|
||||||
if(pcFileOut) strcpy(pcFileOut, &pcFilePath[i + 1]);
|
if(pcFileOut)
|
||||||
|
strncpy(pcFileOut, &pcFilePath[i + 1], szOutSize);
|
||||||
pcResult = &pcFilePath[i + 1];
|
pcResult = &pcFilePath[i + 1];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -241,16 +247,26 @@ pl_str_get_file_name(const char* pcFilePath, char* pcFileOut)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(pcFileOut) memcpy(pcFileOut, pcFilePath, szLen + 1);
|
if(pcFileOut)
|
||||||
|
{
|
||||||
|
size_t szCopySize = szLen + 1;
|
||||||
|
if(szCopySize > szOutSize)
|
||||||
|
szCopySize = szOutSize;
|
||||||
|
memcpy(pcFileOut, pcFilePath, szCopySize);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return pcResult;
|
return pcResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char*
|
bool
|
||||||
pl_str_get_file_name_only(const char* pcFilePath, char* pcFileOut)
|
pl_str_get_file_name_only(const char* pcFilePath, char* pcFileOut, size_t szOutSize)
|
||||||
{
|
{
|
||||||
const char* pcResult = pcFilePath;
|
PL_ASSERT(pcFileOut && "pl_str_get_file_name_only requires pcFileOut to be valid pointer");
|
||||||
|
|
||||||
|
if(pcFileOut == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
const size_t szLen = strlen(pcFilePath);
|
const size_t szLen = strlen(pcFilePath);
|
||||||
|
|
||||||
// check if string includes directory
|
// check if string includes directory
|
||||||
@ -272,19 +288,24 @@ pl_str_get_file_name_only(const char* pcFilePath, char* pcFileOut)
|
|||||||
|
|
||||||
if(uSlashCount == 0)
|
if(uSlashCount == 0)
|
||||||
{
|
{
|
||||||
if(pcFileOut) strcpy(pcFileOut, &pcFilePath[i + 1]);
|
if(pcFileOut)
|
||||||
pcResult = &pcFilePath[i + 1];
|
strncpy(pcFileOut, &pcFilePath[i + 1], szOutSize);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(pcFileOut) memcpy(pcFileOut, pcFilePath, szLen + 1);
|
if(pcFileOut)
|
||||||
|
{
|
||||||
|
if(szLen + 1 > szOutSize)
|
||||||
|
return false;
|
||||||
|
memcpy(pcFileOut, pcFilePath, szLen + 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const size_t szOutLen = strlen(pcFileOut);
|
if(szLen > szOutSize)
|
||||||
|
return false;
|
||||||
bool bPeriodReached = false;
|
bool bPeriodReached = false;
|
||||||
for(size_t i = 0; i < szLen; i++)
|
for(size_t i = 0; i < szLen; i++)
|
||||||
{
|
{
|
||||||
@ -299,15 +320,17 @@ pl_str_get_file_name_only(const char* pcFilePath, char* pcFileOut)
|
|||||||
pcFileOut[i] = 0;
|
pcFileOut[i] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
return pcResult;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
bool
|
||||||
pl_str_get_directory(const char* pcFilePath, char* pcDirectoryOut)
|
pl_str_get_directory(const char* pcFilePath, char* pcDirectoryOut, size_t szOutSize)
|
||||||
{
|
{
|
||||||
size_t szLen = strlen(pcFilePath);
|
size_t szLen = strlen(pcFilePath);
|
||||||
strcpy(pcDirectoryOut, pcFilePath);
|
strncpy(pcDirectoryOut, pcFilePath, szOutSize);
|
||||||
|
|
||||||
|
if(szLen > szOutSize || szOutSize < 2)
|
||||||
|
return false;
|
||||||
|
|
||||||
while(szLen > 0)
|
while(szLen > 0)
|
||||||
{
|
{
|
||||||
@ -323,6 +346,7 @@ pl_str_get_directory(const char* pcFilePath, char* pcDirectoryOut)
|
|||||||
pcDirectoryOut[0] = '.';
|
pcDirectoryOut[0] = '.';
|
||||||
pcDirectoryOut[1] = '/';
|
pcDirectoryOut[1] = '/';
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -333,7 +357,6 @@ pl_str_concatenate(const char* pcStr0, const char* pcStr1, char* pcStringOut, si
|
|||||||
|
|
||||||
if(szLen0 + szLen1 > szDataSize)
|
if(szLen0 + szLen1 > szDataSize)
|
||||||
{
|
{
|
||||||
PL_ASSERT(false && "buffer provided not big enough");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
230
pl_test.h
230
pl_test.h
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
pl_test
|
pl_test.h
|
||||||
Do this:
|
Do this:
|
||||||
#define PL_TEST_IMPLEMENTATION
|
#define PL_TEST_IMPLEMENTATION
|
||||||
before you include this file in *one* C or C++ file to create the implementation.
|
before you include this file in *one* C or C++ file to create the implementation.
|
||||||
@ -9,17 +9,22 @@
|
|||||||
#include ...
|
#include ...
|
||||||
#define PL_TEST_IMPLEMENTATION
|
#define PL_TEST_IMPLEMENTATION
|
||||||
#include "pl_test.h"
|
#include "pl_test.h"
|
||||||
|
Notes:
|
||||||
|
* for console color output on windows, define "PL_TEST_WIN32_COLOR" before
|
||||||
|
including the implementation
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// library version
|
// library version (format XYYZZ)
|
||||||
#define PL_TEST_VERSION "0.1.0"
|
#define PL_TEST_VERSION "1.0.0"
|
||||||
#define PL_TEST_VERSION_NUM 00100
|
#define PL_TEST_VERSION_NUM 10000
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Index of this file:
|
Index of this file:
|
||||||
// [SECTION] header mess
|
// [SECTION] header mess
|
||||||
// [SECTION] includes
|
// [SECTION] includes
|
||||||
// [SECTION] public api
|
// [SECTION] public api
|
||||||
|
// [SECTION] structs
|
||||||
|
// [SECTION] private
|
||||||
// [SECTION] c file
|
// [SECTION] c file
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -34,8 +39,8 @@ Index of this file:
|
|||||||
// [SECTION] includes
|
// [SECTION] includes
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h> // bool
|
||||||
#include <stdint.h>
|
#include <stdint.h> // uint32_t
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// [SECTION] forward declarations & basic types
|
// [SECTION] forward declarations & basic types
|
||||||
@ -43,6 +48,7 @@ Index of this file:
|
|||||||
|
|
||||||
// forward declarations
|
// forward declarations
|
||||||
typedef struct _plTestContext plTestContext;
|
typedef struct _plTestContext plTestContext;
|
||||||
|
typedef struct _plTestOptions plTestOptions;
|
||||||
|
|
||||||
typedef void (*PL_TEST_FUNCTION)(void*);
|
typedef void (*PL_TEST_FUNCTION)(void*);
|
||||||
|
|
||||||
@ -52,26 +58,29 @@ typedef void (*PL_TEST_FUNCTION)(void*);
|
|||||||
|
|
||||||
#define pl_test_register_test(TEST, DATA) pl__test_register_test((TEST), (DATA), #TEST)
|
#define pl_test_register_test(TEST, DATA) pl__test_register_test((TEST), (DATA), #TEST)
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// [SECTION] public api
|
// [SECTION] public api
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
plTestContext* pl_create_test_context(void);
|
plTestContext* pl_create_test_context(plTestOptions);
|
||||||
|
|
||||||
// tests
|
// tests
|
||||||
void pl__test_register_test(PL_TEST_FUNCTION tTest, void* pData, const char* pcName);
|
void pl_test_run_suite(const char* pcSuiteName);
|
||||||
bool pl_test_run(void);
|
bool pl_test_finish(void);
|
||||||
|
|
||||||
// booleans
|
// booleans
|
||||||
bool pl_test_expect_true (bool bValue, const char* pcMsg);
|
bool pl_test_expect_true (bool bValue, const char* pcMsg);
|
||||||
bool pl_test_expect_false(bool bValue, const char* pcMsg);
|
bool pl_test_expect_false(bool bValue, const char* pcMsg);
|
||||||
|
|
||||||
// numbers
|
// integers
|
||||||
bool pl_test_expect_int_equal (int iValue0, int iValue1, const char* pcMsg);
|
bool pl_test_expect_int_equal (int iValue0, int iValue1, const char* pcMsg);
|
||||||
bool pl_test_expect_int_not_equal (int iValue0, int iValue1, const char* pcMsg);
|
bool pl_test_expect_int_not_equal (int iValue0, int iValue1, const char* pcMsg);
|
||||||
bool pl_test_expect_unsigned_equal (uint32_t uValue0, uint32_t uValue1, const char* pcMsg);
|
bool pl_test_expect_uint32_equal (uint32_t uValue0, uint32_t uValue1, const char* pcMsg);
|
||||||
bool pl_test_expect_unsigned_not_equal (uint32_t uValue0, uint32_t uValue1, const char* pcMsg);
|
bool pl_test_expect_uint32_not_equal(uint32_t uValue0, uint32_t uValue1, const char* pcMsg);
|
||||||
|
bool pl_test_expect_uint64_equal (uint64_t uValue0, uint64_t uValue1, const char* pcMsg);
|
||||||
|
bool pl_test_expect_uint64_not_equal(uint64_t uValue0, uint64_t uValue1, const char* pcMsg);
|
||||||
|
|
||||||
|
// floating point
|
||||||
bool pl_test_expect_float_near_equal (float fValue0, float fValue1, float fError, const char* pcMsg);
|
bool pl_test_expect_float_near_equal (float fValue0, float fValue1, float fError, const char* pcMsg);
|
||||||
bool pl_test_expect_float_near_not_equal (float fValue0, float fValue1, float fError, const char* pcMsg);
|
bool pl_test_expect_float_near_not_equal (float fValue0, float fValue1, float fError, const char* pcMsg);
|
||||||
bool pl_test_expect_double_near_equal (double dValue0, double dValue1, double dError, const char* pcMsg);
|
bool pl_test_expect_double_near_equal (double dValue0, double dValue1, double dError, const char* pcMsg);
|
||||||
@ -81,6 +90,23 @@ bool pl_test_expect_double_near_not_equal(double dValue0, double dValue1, double
|
|||||||
bool pl_test_expect_string_equal (const char* pcValue0, const char* pcValue1, const char* pcMsg);
|
bool pl_test_expect_string_equal (const char* pcValue0, const char* pcValue1, const char* pcMsg);
|
||||||
bool pl_test_expect_string_not_equal(const char* pcValue0, const char* pcValue1, const char* pcMsg);
|
bool pl_test_expect_string_not_equal(const char* pcValue0, const char* pcValue1, const char* pcMsg);
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// [SECTION] structs
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
typedef struct _plTestOptions
|
||||||
|
{
|
||||||
|
bool bPrintSuiteResults;
|
||||||
|
bool bPrintAllPassedChecks;
|
||||||
|
bool bPrintColor;
|
||||||
|
} plTestOptions;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// [SECTION] private
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void pl__test_register_test(PL_TEST_FUNCTION tTest, void* pData, const char* pcName);
|
||||||
|
|
||||||
#endif // PL_TEST_H
|
#endif // PL_TEST_H
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -100,6 +126,13 @@ Index of this file:
|
|||||||
|
|
||||||
#ifdef PL_TEST_IMPLEMENTATION
|
#ifdef PL_TEST_IMPLEMENTATION
|
||||||
|
|
||||||
|
#if defined(PL_TEST_WIN32_COLOR) || defined(_WIN32)
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <windows.h>
|
||||||
|
static DWORD gtOriginalMode = 0;
|
||||||
|
static HANDLE gtStdOutHandle = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// [SECTION] includes
|
// [SECTION] includes
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -135,7 +168,10 @@ typedef struct _plTestContext
|
|||||||
uint32_t uTestSize;
|
uint32_t uTestSize;
|
||||||
uint32_t uTestCapacity;
|
uint32_t uTestCapacity;
|
||||||
uint32_t uFailedTest;
|
uint32_t uFailedTest;
|
||||||
bool bPrintPasses;
|
plTestOptions tOptions;
|
||||||
|
|
||||||
|
uint32_t uTotalPassedTests;
|
||||||
|
uint32_t uTotalFailedTests;
|
||||||
} plTestContext;
|
} plTestContext;
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -149,12 +185,26 @@ plTestContext* gptTestContext = NULL;
|
|||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
plTestContext*
|
plTestContext*
|
||||||
pl_create_test_context(void)
|
pl_create_test_context(plTestOptions tOptions)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#if defined(PL_TEST_WIN32_COLOR) || defined(_WIN32)
|
||||||
|
DWORD tCurrentMode = 0;
|
||||||
|
gtStdOutHandle = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
if(gtStdOutHandle == INVALID_HANDLE_VALUE)
|
||||||
|
exit(GetLastError());
|
||||||
|
if(!GetConsoleMode(gtStdOutHandle, &tCurrentMode))
|
||||||
|
exit(GetLastError());
|
||||||
|
gtOriginalMode = tCurrentMode;
|
||||||
|
tCurrentMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; // enable ANSI escape codes
|
||||||
|
if(!SetConsoleMode(gtStdOutHandle, tCurrentMode))
|
||||||
|
exit(GetLastError());
|
||||||
|
#endif
|
||||||
|
|
||||||
gptTestContext = (plTestContext*)malloc(sizeof(plTestContext));
|
gptTestContext = (plTestContext*)malloc(sizeof(plTestContext));
|
||||||
memset(gptTestContext, 0, sizeof(plTestContext));
|
memset(gptTestContext, 0, sizeof(plTestContext));
|
||||||
gptTestContext->uTestCapacity = 64;
|
gptTestContext->uTestCapacity = 64;
|
||||||
gptTestContext->bPrintPasses = false;
|
gptTestContext->tOptions = tOptions;
|
||||||
gptTestContext->atTests = (plTest*)malloc(gptTestContext->uTestCapacity * sizeof(plTest));
|
gptTestContext->atTests = (plTest*)malloc(gptTestContext->uTestCapacity * sizeof(plTest));
|
||||||
memset(gptTestContext->atTests, 0, sizeof(gptTestContext->uTestCapacity * sizeof(plTest)));
|
memset(gptTestContext->atTests, 0, sizeof(gptTestContext->uTestCapacity * sizeof(plTest)));
|
||||||
return gptTestContext;
|
return gptTestContext;
|
||||||
@ -179,30 +229,67 @@ pl__test_register_test(PL_TEST_FUNCTION tTest, void* pData, const char* pcName)
|
|||||||
gptTestContext->atTests[gptTestContext->uTestSize - 1].pData = pData;
|
gptTestContext->atTests[gptTestContext->uTestSize - 1].pData = pData;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
pl_test_run(void)
|
pl_test_run_suite(const char* pcSuiteName)
|
||||||
{
|
{
|
||||||
|
printf("\n------%s suite------\n\n", pcSuiteName);
|
||||||
|
|
||||||
for(uint32_t i = 0; i < gptTestContext->uTestSize; i++)
|
for(uint32_t i = 0; i < gptTestContext->uTestSize; i++)
|
||||||
{
|
{
|
||||||
|
|
||||||
gptTestContext->ptCurrentTest = &gptTestContext->atTests[i];
|
gptTestContext->ptCurrentTest = &gptTestContext->atTests[i];
|
||||||
gptTestContext->ptCurrentTest->bFailureOccured = false;
|
gptTestContext->ptCurrentTest->bFailureOccured = false;
|
||||||
|
|
||||||
printf("-----------------------------------\n");
|
printf("running -> \"%s\"\n", gptTestContext->ptCurrentTest->pcName);
|
||||||
printf("\"%s\" running...\n\n", gptTestContext->ptCurrentTest->pcName);
|
|
||||||
gptTestContext->ptCurrentTest->tTest(gptTestContext->ptCurrentTest->pData);
|
gptTestContext->ptCurrentTest->tTest(gptTestContext->ptCurrentTest->pData);
|
||||||
|
|
||||||
if(gptTestContext->ptCurrentTest->bFailureOccured)
|
if(gptTestContext->ptCurrentTest->bFailureOccured)
|
||||||
{
|
{
|
||||||
pl__test_print_red("\n\n\"%s\" failed", NULL, gptTestContext->ptCurrentTest->pcName);
|
pl__test_print_red("%s", NULL, " -> failed");
|
||||||
gptTestContext->uFailedTest++;
|
gptTestContext->uFailedTest++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
printf("\n\n\"%s\" passed\n\n", gptTestContext->ptCurrentTest->pcName);
|
pl__test_print_green("%s", NULL, " passed");
|
||||||
printf("-----------------------------------\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return gptTestContext->uFailedTest == 0;
|
if(gptTestContext->tOptions.bPrintSuiteResults)
|
||||||
|
{
|
||||||
|
printf("\nPassed: ");
|
||||||
|
pl__test_print_green("%u", NULL, gptTestContext->uTestSize - gptTestContext->uFailedTest);
|
||||||
|
|
||||||
|
printf("Failed: ");
|
||||||
|
pl__test_print_red("%u", NULL, gptTestContext->uFailedTest);
|
||||||
|
}
|
||||||
|
|
||||||
|
// printf("\n------End tests------\n\n");
|
||||||
|
|
||||||
|
// reset context
|
||||||
|
gptTestContext->uTotalPassedTests += gptTestContext->uTestSize - gptTestContext->uFailedTest;
|
||||||
|
gptTestContext->uTotalFailedTests += gptTestContext->uFailedTest;
|
||||||
|
gptTestContext->uTestSize = 0;
|
||||||
|
gptTestContext->uFailedTest = 0;
|
||||||
|
gptTestContext->ptCurrentTest = NULL;
|
||||||
|
memset(gptTestContext->atTests, 0, sizeof(plTest) * gptTestContext->uTestCapacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
pl_test_finish(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
printf("\n------Results------\n");
|
||||||
|
|
||||||
|
printf("\nTests passed: ");
|
||||||
|
pl__test_print_green("%u", NULL, gptTestContext->uTotalPassedTests);
|
||||||
|
|
||||||
|
printf("Tests failed: ");
|
||||||
|
pl__test_print_red("%u", NULL, gptTestContext->uTotalFailedTests);
|
||||||
|
|
||||||
|
#if defined(PL_TEST_WIN32_COLOR) || defined(_WIN32)
|
||||||
|
if(!SetConsoleMode(gtStdOutHandle, gtOriginalMode))
|
||||||
|
exit(GetLastError());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return gptTestContext->uTotalFailedTests == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -210,6 +297,7 @@ pl_test_expect_true(bool bValue, const char* pcMsg)
|
|||||||
{
|
{
|
||||||
if(bValue)
|
if(bValue)
|
||||||
{
|
{
|
||||||
|
if(gptTestContext->tOptions.bPrintAllPassedChecks)
|
||||||
pl__test_print_green("Value: true | Expected Value: true", pcMsg);
|
pl__test_print_green("Value: true | Expected Value: true", pcMsg);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -229,64 +317,67 @@ pl_test_expect_false(bool bValue, const char* pcMsg)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(gptTestContext->tOptions.bPrintAllPassedChecks)
|
||||||
pl__test_print_green("Value: false | Expected Value: false", pcMsg);
|
pl__test_print_green("Value: false | Expected Value: false", pcMsg);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define pl__test_expect_equal(value0, value1, pcMsg, format) \
|
||||||
|
if((value0) == (value1)) \
|
||||||
|
{ \
|
||||||
|
if(gptTestContext->tOptions.bPrintAllPassedChecks) \
|
||||||
|
pl__test_print_green(format " equals " format " | Equality Expected", (pcMsg), (value0), (value1)); \
|
||||||
|
return true; \
|
||||||
|
} \
|
||||||
|
pl__test_print_red(format " does not equal " format " | Equality Expected", (pcMsg), (value0), (value1)); \
|
||||||
|
gptTestContext->ptCurrentTest->bFailureOccured = true; \
|
||||||
|
return false;
|
||||||
|
|
||||||
|
#define pl__test_expect_not_equal(value0, value1, pcMsg, format) \
|
||||||
|
if((value0) == (value1)) \
|
||||||
|
{ \
|
||||||
|
pl__test_print_red(format " equals " format " | Equality Not Expected", (pcMsg), (value0), (value1)); \
|
||||||
|
gptTestContext->ptCurrentTest->bFailureOccured = true; \
|
||||||
|
return false; \
|
||||||
|
} \
|
||||||
|
if(gptTestContext->tOptions.bPrintAllPassedChecks) \
|
||||||
|
pl__test_print_green(format " does not equal " format " | Equality Expected", (pcMsg), (value0), (value1)); \
|
||||||
|
return true;
|
||||||
|
|
||||||
bool
|
bool
|
||||||
pl_test_expect_int_equal(int iValue0, int iValue1, const char* pcMsg)
|
pl_test_expect_int_equal(int iValue0, int iValue1, const char* pcMsg)
|
||||||
{
|
{
|
||||||
if(iValue0 == iValue1)
|
pl__test_expect_equal(iValue0, iValue1, pcMsg, "%i");
|
||||||
{
|
|
||||||
pl__test_print_green("%i equals %i | Equality Expected", pcMsg, iValue0, iValue1);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
pl__test_print_red("%i does not equal %i | Equality Expected", pcMsg, iValue0, iValue1);
|
|
||||||
gptTestContext->ptCurrentTest->bFailureOccured = true;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
pl_test_expect_int_not_equal(int iValue0, int iValue1, const char* pcMsg)
|
pl_test_expect_int_not_equal(int iValue0, int iValue1, const char* pcMsg)
|
||||||
{
|
{
|
||||||
if(iValue0 == iValue1)
|
pl__test_expect_not_equal(iValue0, iValue1, pcMsg, "%i");
|
||||||
{
|
|
||||||
pl__test_print_red("%i equals %i | Equality Not Expected", pcMsg, iValue0, iValue1);
|
|
||||||
gptTestContext->ptCurrentTest->bFailureOccured = true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
pl__test_print_green("%i does not equal %i | Equality Not Expected", pcMsg, iValue0, iValue1);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
pl_test_expect_unsigned_equal(uint32_t uValue0, uint32_t uValue1, const char* pcMsg)
|
pl_test_expect_uint64_equal(uint64_t uValue0, uint64_t uValue1, const char* pcMsg)
|
||||||
{
|
{
|
||||||
if(uValue0 == uValue1)
|
pl__test_expect_equal(uValue0, uValue1, pcMsg, "%llu");
|
||||||
{
|
|
||||||
pl__test_print_green("%u equals %u | Equality Expected", pcMsg, uValue0, uValue1);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
pl__test_print_red("%u does not equal %u | Equality Expected", pcMsg, uValue0, uValue1);
|
|
||||||
gptTestContext->ptCurrentTest->bFailureOccured = true;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
pl_test_expect_unsigned_not_equal(uint32_t uValue0, uint32_t uValue1, const char* pcMsg)
|
pl_test_expect_uint64_not_equal(uint64_t uValue0, uint64_t uValue1, const char* pcMsg)
|
||||||
{
|
{
|
||||||
if(uValue0 == uValue1)
|
pl__test_expect_not_equal(uValue0, uValue1, pcMsg, "%llu");
|
||||||
{
|
|
||||||
pl__test_print_red("%u equals %u | Equality Not Expected", pcMsg, uValue0, uValue1);
|
|
||||||
gptTestContext->ptCurrentTest->bFailureOccured = true;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pl__test_print_green("%u does not equal %u | Equality Not Expected", pcMsg, uValue0, uValue1);
|
bool
|
||||||
return true;
|
pl_test_expect_uint32_equal(uint32_t uValue0, uint32_t uValue1, const char* pcMsg)
|
||||||
|
{
|
||||||
|
pl__test_expect_equal(uValue0, uValue1, pcMsg, "%u");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
pl_test_expect_uint32_not_equal(uint32_t uValue0, uint32_t uValue1, const char* pcMsg)
|
||||||
|
{
|
||||||
|
pl__test_expect_not_equal(uValue0, uValue1, pcMsg, "%u");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -306,6 +397,7 @@ pl_test_expect_double_near_equal(double dValue0, double dValue1, double dError,
|
|||||||
{
|
{
|
||||||
if(dValue0 >= dValue1 - dError && dValue0 <= dValue1 + dError)
|
if(dValue0 >= dValue1 - dError && dValue0 <= dValue1 + dError)
|
||||||
{
|
{
|
||||||
|
if(gptTestContext->tOptions.bPrintAllPassedChecks)
|
||||||
pl__test_print_green("%0.6f equals %0.6f | Equality Expected within %0.6f", pcMsg, dValue0, dValue1, dError);
|
pl__test_print_green("%0.6f equals %0.6f | Equality Expected within %0.6f", pcMsg, dValue0, dValue1, dError);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -325,6 +417,7 @@ pl_test_expect_double_near_not_equal(double dValue0, double dValue1, double dErr
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(gptTestContext->tOptions.bPrintAllPassedChecks)
|
||||||
pl__test_print_green("%0.6f does not equal %0.6f | Equality Not Expected within %0.6f", pcMsg, dValue0, dValue1, dError);
|
pl__test_print_green("%0.6f does not equal %0.6f | Equality Not Expected within %0.6f", pcMsg, dValue0, dValue1, dError);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -334,6 +427,7 @@ pl_test_expect_string_equal(const char* pcValue0, const char* pcValue1, const ch
|
|||||||
{
|
{
|
||||||
if(strcmp(pcValue0, pcValue1) == 0)
|
if(strcmp(pcValue0, pcValue1) == 0)
|
||||||
{
|
{
|
||||||
|
if(gptTestContext->tOptions.bPrintAllPassedChecks)
|
||||||
pl__test_print_green("\"%s\" equals \"%s\" | Equality Expected", pcMsg, pcValue0, pcValue1);
|
pl__test_print_green("\"%s\" equals \"%s\" | Equality Expected", pcMsg, pcValue0, pcValue1);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -348,6 +442,7 @@ pl_test_expect_string_not_equal(const char* pcValue0, const char* pcValue1, cons
|
|||||||
{
|
{
|
||||||
if(strcmp(pcValue0, pcValue1) == 0)
|
if(strcmp(pcValue0, pcValue1) == 0)
|
||||||
{
|
{
|
||||||
|
if(gptTestContext->tOptions.bPrintAllPassedChecks)
|
||||||
pl__test_print_green("\"%s\" equals \"%s\" | Equality Not Expected", pcMsg, pcValue0, pcValue1);
|
pl__test_print_green("\"%s\" equals \"%s\" | Equality Not Expected", pcMsg, pcValue0, pcValue1);
|
||||||
gptTestContext->ptCurrentTest->bFailureOccured = true;
|
gptTestContext->ptCurrentTest->bFailureOccured = true;
|
||||||
return false;
|
return false;
|
||||||
@ -373,12 +468,15 @@ pl__test_print_va(const char* cPFormat, va_list args)
|
|||||||
|
|
||||||
void static
|
void static
|
||||||
pl__test_print_red(const char* cPFormat, const char* pcMsg, ...)
|
pl__test_print_red(const char* cPFormat, const char* pcMsg, ...)
|
||||||
|
{
|
||||||
|
if(gptTestContext->tOptions.bPrintColor)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
printf("[91m");
|
printf("[91m");
|
||||||
#else
|
#else
|
||||||
printf("\033[91m");
|
printf("\033[91m");
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
va_list argptr;
|
va_list argptr;
|
||||||
va_start(argptr, pcMsg);
|
va_start(argptr, pcMsg);
|
||||||
@ -390,24 +488,27 @@ pl__test_print_red(const char* cPFormat, const char* pcMsg, ...)
|
|||||||
else
|
else
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
|
if(gptTestContext->tOptions.bPrintColor)
|
||||||
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
printf("[0m");
|
printf("[0m");
|
||||||
#else
|
#else
|
||||||
printf("\033[0m");
|
printf("\033[0m");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pl__test_print_green(const char* cPFormat, const char* pcMsg, ...)
|
pl__test_print_green(const char* cPFormat, const char* pcMsg, ...)
|
||||||
{
|
{
|
||||||
if(!gptTestContext->bPrintPasses)
|
if(gptTestContext->tOptions.bPrintColor)
|
||||||
return;
|
{
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
printf("[92m");
|
printf("[92m");
|
||||||
#else
|
#else
|
||||||
printf("\033[92m");
|
printf("\033[92m");
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
va_list argptr;
|
va_list argptr;
|
||||||
va_start(argptr, pcMsg);
|
va_start(argptr, pcMsg);
|
||||||
@ -419,11 +520,14 @@ pl__test_print_green(const char* cPFormat, const char* pcMsg, ...)
|
|||||||
else
|
else
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
|
if(gptTestContext->tOptions.bPrintColor)
|
||||||
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
printf("[0m");
|
printf("[0m");
|
||||||
#else
|
#else
|
||||||
printf("\033[0m");
|
printf("\033[0m");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif // PL_TEST_IMPLEMENTATION
|
#endif // PL_TEST_IMPLEMENTATION
|
Loading…
Reference in New Issue
Block a user