1
0

build: 1.0
All checks were successful
Tests / Ubuntu (push) Successful in 10s

This commit is contained in:
Jonathan Hoffstadt 2024-11-18 19:54:23 -06:00
parent 95454b54f7
commit aebd939d7d
15 changed files with 2466 additions and 1826 deletions

46
README.md Normal file
View File

@ -0,0 +1,46 @@
## Pilot Light Libraries
Single-file MIT licensed libraries for C/C++. These are "STB" style libraries (more info [here](https://github.com/nothings/stb)).
### Libraries
Library | Lastest Version | Category | Lines of Code | Description
--------------------- | ---- | -------- | --- | --------------------------------
**[pl_ds.h](pl_ds.h)** | 1.0 | utility | 691 | typesafe dynamic array and hash tables for C
**[pl_json.h](pl_json.h)** | 1.0 | parsing | 2067 | json reading & writing for C
**[pl_log.h](pl_log.h)** | 1.0 | utility | 1295 | small logging library for C
**[pl_math.h](pl_math.h)** | 1.0 | math | 800 | small math library for C (vectors, matrices, quaternions, etc.)
**[pl_memory.h](pl_memory.h)** | 1.0 | utility | 699 | various memory allocators for C
**[pl_profile.h](pl_profile.h)** | 1.0 | utility | 551 | small profiling library for C
**[pl_stl.h](pl_stl.h)** | 1.0 | parsing | 340 | small STL file parser
**[pl_string.h](pl_string.h)** | 1.0 | utility | 439 | string utilities for C
**[pl_test.h](pl_test.h)** | 1.0 | misc | 543 | small testing library for C
Total libraries: 9
Total lines of C code: 7425
## FAQ
### How do I use these libraries?
The idea behind single-header file libraries is that they're easy to distribute and deploy
because all the code is contained in a single file. By default, the .h files in here act as
their own header files, i.e. they declare the functions contained in the file but don't
actually result in any code getting compiled.
So in addition, you should select _exactly one_ C/C++ source file that actually instantiates
the code, preferably a file you're not editing frequently. This file should define a
specific macro (this is documented per-library) to actually enable the function definitions.
For example, to use pl_log, you should have exactly one C/C++ file that doesn't
include pl_log.h regularly, but instead does
#define PL_LOG_IMPLEMENTATION
#include "pl_log.h"
The right macro to define is pointed out right at the top of each of these libraries.
### Where is the documentation?
The documentation is included at the top of each file.

238
pl_ds.h
View File

@ -3,9 +3,9 @@
* data structures * data structures
*/ */
// library version // library version (format XYYZZ)
#define PL_DS_VERSION "0.5.2" #define PL_DS_VERSION "1.0.0"
#define PL_DS_VERSION_NUM 00502 #define PL_DS_VERSION_NUM 10000
/* /*
Index of this file: Index of this file:
@ -15,8 +15,8 @@ Index of this file:
// [SECTION] forward declarations // [SECTION] forward declarations
// [SECTION] public api (stretchy buffer) // [SECTION] public api (stretchy buffer)
// [SECTION] public api (hashmap) // [SECTION] public api (hashmap)
// [SECTION] internal // [SECTION] internal (stretchy buffer)
// [SECTION] public api implementation (hashmap) // [SECTION] internal (hashmap)
*/ */
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -125,16 +125,16 @@ HASHMAPS
uint64_t pl_hm_hash(const void* pData, size_t szDataSize, uint64_t uSeed); uint64_t pl_hm_hash(const void* pData, size_t szDataSize, uint64_t uSeed);
Returns the CRC64 hash of some arbitrary data. Returns the CRC64 hash of some arbitrary data.
pl__hm_resize: pl_hm_resize:
void pl__hm_resize(plHashMap*, uint32_t); void pl_hm_resize(plHashMap*, uint32_t);
Resizes the hashmap or frees it if zero is used. Resizes the hashmap or frees it if zero is used.
pl_hm_free: pl_hm_free:
void pl_hm_free(plHashMap*); void pl_hm_free(plHashMap*);
Frees the hashmap internal memory. Frees the hashmap internal memory.
pl__hm_insert: pl_hm_insert:
void pl__hm_insert(plHashMap*, uint64_t ulKey, uint64_t ulValue); void pl_hm_insert(plHashMap*, uint64_t ulKey, uint64_t ulValue);
Adds an entry to the hashmap where ulKey is a hashed key (usually a string) and Adds an entry to the hashmap where ulKey is a hashed key (usually a string) and
ulValue is the index into the value array. ulValue is the index into the value array.
@ -158,8 +158,8 @@ HASHMAPS
bool pl_hm_has_key(plHashMap*, const char*); bool pl_hm_has_key(plHashMap*, const char*);
Same as pl_hm_has_key but performs the hash for you. Same as pl_hm_has_key but performs the hash for you.
pl__hm_insert_str: pl_hm_insert_str:
void pl__hm_insert_str(plHashMap*, const char* pcKey, uint64_t ulValue); void pl_hm_insert_str(plHashMap*, const char* pcKey, uint64_t ulValue);
Same as pl__hm_insert but performs the hash for you. Same as pl__hm_insert but performs the hash for you.
pl_hm_lookup_str: pl_hm_lookup_str:
@ -173,10 +173,12 @@ HASHMAPS
COMPILE TIME OPTIONS COMPILE TIME OPTIONS
* Change allocators by defining both: * Change allocators by defining both:
PL_LOG_ALLOC(x) PL_DS_ALLOC(x)
PL_LOG_FREE(x) PL_DS_FREE(x)
* Change initial hashmap size: * Change initial hashmap size:
PL_DS_HASHMAP_INITIAL_SIZE (default is 256) PL_DS_HASHMAP_INITIAL_SIZE (default is 256) // should be power of 2
* Change assert by defining:
PL_DS_ASSERT(x)
*/ */
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -215,25 +217,11 @@ COMPILE TIME OPTIONS
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include <stdint.h> // uint32_t #include <stdint.h> // uint32_t
#include <stdlib.h> // malloc, free
#include <string.h> // memset, memmove #include <string.h> // memset, memmove
#include <stdbool.h> // bool #include <stdbool.h> // bool
#include <stdarg.h> // arg vars #include <stdarg.h> // arg vars
#include <stdio.h> // vsprintf #include <stdio.h> // vsprintf
//-----------------------------------------------------------------------------
// [SECTION] documentation
//-----------------------------------------------------------------------------
typedef struct _plHashMap
{
uint32_t _uItemCount;
uint32_t _uBucketCount;
uint64_t* _aulKeys; // stored keys used for rehashing during growth
uint64_t* _aulValueIndices; // indices into value array (user held)
uint64_t* _sbulFreeIndices; // free list of available indices
} plHashMap;
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// [SECTION] public api (stretchy buffer) // [SECTION] public api (stretchy buffer)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -312,30 +300,43 @@ typedef struct _plHashMap
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#define pl_hm_resize(ptHashMap, uBucketCount) \ #define pl_hm_resize(ptHashMap, uBucketCount) \
pl__hm_resize(ptHashMap, uBucketCount, __FILE__, __LINE__) pl__hm_resize(&(ptHashMap), (uBucketCount), __FILE__, __LINE__)
#define pl_hm_insert(ptHashMap, ulKey, ulValue) \ #define pl_hm_insert(ptHashMap, ulKey, ulValue) \
pl__hm_insert(ptHashMap, ulKey, ulValue, __FILE__, __LINE__) pl__hm_insert(&(ptHashMap), (ulKey), (ulValue), __FILE__, __LINE__)
#define pl_hm_free(ptHashMap) \
pl__hm_free(&(ptHashMap))
#define pl_hm_remove(ptHashMap, ulKey) \
pl__hm_remove(&(ptHashMap), (ulKey))
#define pl_hm_remove_str(ptHashMap, pcKey) \
pl_hm_remove((ptHashMap), pl_hm_hash_str((pcKey)))
#define pl_hm_lookup(ptHashMap, ulKey) \
pl__hm_lookup(&(ptHashMap), (ulKey))
#define pl_hm_get_free_index(ptHashMap) \
pl__hm_get_free_index(&(ptHashMap))
#define pl_hm_has_key(ptHashMap, ulKey) \
pl__hm_has_key(&(ptHashMap), (ulKey))
#define pl_hm_has_key_str(ptHashMap, pcKey) \
pl_hm_has_key((ptHashMap), pl_hm_hash_str((pcKey)))
#define pl_hm_lookup_str(ptHashMap, pcKey) \
pl_hm_lookup((ptHashMap), pl_hm_hash_str((pcKey)))
#define pl_hm_insert_str(ptHashMap, pcKey, ulValue) \ #define pl_hm_insert_str(ptHashMap, pcKey, ulValue) \
pl__hm_insert_str(ptHashMap, pcKey, ulValue, __FILE__, __LINE__) pl_hm_insert((ptHashMap), pl_hm_hash_str((pcKey)), (ulValue))
static inline void pl__hm_resize (plHashMap* ptHashMap, uint32_t uBucketCount, const char* pcFile, int iLine);
static inline void pl_hm_free (plHashMap* ptHashMap) { pl__hm_resize(ptHashMap, 0, "", 0);}
static inline void pl__hm_insert (plHashMap* ptHashMap, uint64_t ulKey, uint64_t ulValue, const char* pcFile, int iLine);
static inline void pl_hm_remove (plHashMap* ptHashMap, uint64_t ulKey);
static inline uint64_t pl_hm_lookup (plHashMap* ptHashMap, uint64_t ulKey);
static inline uint64_t pl_hm_get_free_index(plHashMap* ptHashMap);
static inline bool pl_hm_has_key (plHashMap* ptHashMap, uint64_t ulKey);
static inline uint64_t pl_hm_hash_str(const char* pcKey); static inline uint64_t pl_hm_hash_str(const char* pcKey);
static inline uint64_t pl_hm_hash (const void* pData, size_t szDataSize, uint64_t uSeed); static inline uint64_t pl_hm_hash (const void* pData, size_t szDataSize, uint64_t uSeed);
static inline void pl__hm_insert_str (plHashMap* ptHashMap, const char* pcKey, uint64_t ulValue, const char* pcFile, int iLine);
static inline void pl_hm_remove_str (plHashMap* ptHashMap, const char* pcKey);
static inline uint64_t pl_hm_lookup_str (plHashMap* ptHashMap, const char* pcKey);
static inline bool pl_hm_has_key_str (plHashMap* ptHashMap, const char* pcKey);
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// [SECTION] internal // [SECTION] internal (stretchy buffer)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#define pl__sb_header(buf) ((plSbHeader_*)(((char*)(buf)) - sizeof(plSbHeader_))) #define pl__sb_header(buf) ((plSbHeader_*)(((char*)(buf)) - sizeof(plSbHeader_)))
@ -413,17 +414,60 @@ pl__sb_sprintf(char** ppcBuffer, const char* pcFormat, ...)
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// [SECTION] public api implementation (hashmap) // [SECTION] internal (hashmap)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
static inline void typedef struct plHashMap
pl__hm_resize(plHashMap* ptHashMap, uint32_t uBucketCount, const char* pcFile, int iLine)
{ {
int _iMemoryOwned; // did we allocate this
uint32_t _uItemCount;
uint32_t _uBucketCount;
uint64_t* _aulKeys; // stored keys used for rehashing during growth
uint64_t* _aulValueIndices; // indices into value array (user held)
uint64_t* _sbulFreeIndices; // free list of available indices
} plHashMap;
static inline uint64_t pl__hm_lookup (plHashMap** ptHashMap, uint64_t ulKey);
static inline uint64_t pl__hm_get_free_index(plHashMap** ptHashMap);
static inline bool pl__hm_has_key (plHashMap** pptHashMap, uint64_t ulKey);
static inline void pl__hm_resize (plHashMap** pptHashMap, uint32_t uBucketCount, const char* pcFile, int iLine);
static inline void pl__hm_free (plHashMap** pptHashMap) { pl__hm_resize(pptHashMap, 0, "", 0);}
static inline void pl__hm_insert (plHashMap** pptHashMap, uint64_t ulKey, uint64_t ulValue, const char* pcFile, int iLine);
static inline void pl__hm_remove (plHashMap** pptHashMap, uint64_t ulKey);
static inline size_t
pl__ds_get_next_power_of_2(size_t n)
{
size_t ulResult = 1;
if (n && !(n & (n - 1)))
ulResult = n;
while (ulResult < n)
ulResult <<= 1;
return ulResult;
}
static inline void
pl__hm_resize(plHashMap** pptHashMap, uint32_t uBucketCount, const char* pcFile, int iLine)
{
plHashMap* ptHashMap = *pptHashMap;
if(ptHashMap == NULL && uBucketCount == 0)
return;
if(ptHashMap == NULL)
{
ptHashMap = PL_DS_ALLOC(sizeof(plHashMap));
memset(ptHashMap, 0, sizeof(plHashMap));
ptHashMap->_iMemoryOwned = 1;
*pptHashMap = ptHashMap;
}
const uint32_t uOldBucketCount = ptHashMap->_uBucketCount; const uint32_t uOldBucketCount = ptHashMap->_uBucketCount;
uint64_t* sbulOldValueIndices = ptHashMap->_aulValueIndices; uint64_t* sbulOldValueIndices = ptHashMap->_aulValueIndices;
uint64_t* aulOldKeys = ptHashMap->_aulKeys; uint64_t* aulOldKeys = ptHashMap->_aulKeys;
ptHashMap->_uBucketCount = uBucketCount < PL_DS_HASHMAP_INITIAL_SIZE ? PL_DS_HASHMAP_INITIAL_SIZE : uBucketCount;
ptHashMap->_uBucketCount = uBucketCount < PL_DS_HASHMAP_INITIAL_SIZE ? PL_DS_HASHMAP_INITIAL_SIZE : (uint32_t)pl__ds_get_next_power_of_2(uBucketCount);
if(uBucketCount > 0) if(uBucketCount > 0)
{ {
@ -432,18 +476,20 @@ pl__hm_resize(plHashMap* ptHashMap, uint32_t uBucketCount, const char* pcFile, i
memset(ptHashMap->_aulValueIndices, 0xff, sizeof(uint64_t) * ptHashMap->_uBucketCount); memset(ptHashMap->_aulValueIndices, 0xff, sizeof(uint64_t) * ptHashMap->_uBucketCount);
memset(ptHashMap->_aulKeys, 0xff, sizeof(uint64_t) * ptHashMap->_uBucketCount); memset(ptHashMap->_aulKeys, 0xff, sizeof(uint64_t) * ptHashMap->_uBucketCount);
uint64_t mask = uOldBucketCount - 1;
for(uint32_t i = 0; i < uOldBucketCount; i++) for(uint32_t i = 0; i < uOldBucketCount; i++)
{ {
const uint64_t ulKey = aulOldKeys[i]; const uint64_t ulKey = aulOldKeys[i];
uint64_t ulOldModKey = ulKey % uOldBucketCount; uint64_t ulOldModKey = ulKey & mask;
while(aulOldKeys[ulOldModKey] != ulKey && aulOldKeys[ulOldModKey] != UINT64_MAX) while(aulOldKeys[ulOldModKey] != ulKey && aulOldKeys[ulOldModKey] != UINT64_MAX)
ulOldModKey = (ulOldModKey + 1) % uOldBucketCount; ulOldModKey = (ulOldModKey + 1) & mask;
const uint64_t ulValue = sbulOldValueIndices[ulOldModKey]; const uint64_t ulValue = sbulOldValueIndices[ulOldModKey];
ptHashMap->_uItemCount--; ptHashMap->_uItemCount--;
pl__hm_insert(ptHashMap, ulKey, ulValue, pcFile, iLine); pl__hm_insert(pptHashMap, ulKey, ulValue, pcFile, iLine);
} }
} }
else else
@ -452,6 +498,11 @@ pl__hm_resize(plHashMap* ptHashMap, uint32_t uBucketCount, const char* pcFile, i
ptHashMap->_aulKeys = NULL; ptHashMap->_aulKeys = NULL;
pl_sb_free(ptHashMap->_sbulFreeIndices); pl_sb_free(ptHashMap->_sbulFreeIndices);
ptHashMap->_uItemCount = 0; ptHashMap->_uItemCount = 0;
if(ptHashMap->_iMemoryOwned)
{
PL_DS_FREE(ptHashMap);
*pptHashMap = NULL;
}
} }
if(sbulOldValueIndices) if(sbulOldValueIndices)
@ -465,18 +516,29 @@ pl__hm_resize(plHashMap* ptHashMap, uint32_t uBucketCount, const char* pcFile, i
} }
static inline void static inline void
pl__hm_insert(plHashMap* ptHashMap, uint64_t ulKey, uint64_t ulValue, const char* pcFile, int iLine) pl__hm_insert(plHashMap** pptHashMap, uint64_t ulKey, uint64_t ulValue, const char* pcFile, int iLine)
{ {
if(ptHashMap->_uBucketCount == 0) plHashMap* ptHashMap = *pptHashMap;
pl__hm_resize(ptHashMap, PL_DS_HASHMAP_INITIAL_SIZE, pcFile, iLine);
else if(((float)ptHashMap->_uItemCount / (float)ptHashMap->_uBucketCount) > 0.60f)
pl__hm_resize(ptHashMap, ptHashMap->_uBucketCount * 2, pcFile, iLine);
uint64_t ulModKey = ulKey % ptHashMap->_uBucketCount; if(ptHashMap == NULL)
{
ptHashMap = PL_DS_ALLOC_INDIRECT(sizeof(plHashMap), pcFile, iLine);
memset(ptHashMap, 0, sizeof(plHashMap));
ptHashMap->_iMemoryOwned = 1;
*pptHashMap = ptHashMap;
}
if(ptHashMap->_uBucketCount == 0)
pl__hm_resize(pptHashMap, PL_DS_HASHMAP_INITIAL_SIZE, pcFile, iLine);
else if(((float)ptHashMap->_uItemCount / (float)ptHashMap->_uBucketCount) > 0.60f)
pl__hm_resize(pptHashMap, ptHashMap->_uBucketCount * 2, pcFile, iLine);
uint64_t mask = ptHashMap->_uBucketCount - 1;
uint64_t ulModKey = ulKey & mask;
while(ptHashMap->_aulKeys[ulModKey] != ulKey && ptHashMap->_aulKeys[ulModKey] != UINT64_MAX) while(ptHashMap->_aulKeys[ulModKey] != ulKey && ptHashMap->_aulKeys[ulModKey] != UINT64_MAX)
{ {
ulModKey = (ulModKey + 1) % ptHashMap->_uBucketCount; ulModKey = (ulModKey + 1) & mask;
if(ptHashMap->_aulKeys[ulModKey] == UINT64_MAX - 1) if(ptHashMap->_aulKeys[ulModKey] == UINT64_MAX - 1)
break; break;
} }
@ -487,14 +549,16 @@ pl__hm_insert(plHashMap* ptHashMap, uint64_t ulKey, uint64_t ulValue, const char
} }
static inline void static inline void
pl_hm_remove(plHashMap* ptHashMap, uint64_t ulKey) pl__hm_remove(plHashMap** pptHashMap, uint64_t ulKey)
{ {
plHashMap* ptHashMap = *pptHashMap;
PL_DS_ASSERT(ptHashMap->_uBucketCount > 0 && "hashmap has no items"); PL_DS_ASSERT(ptHashMap->_uBucketCount > 0 && "hashmap has no items");
uint64_t ulModKey = ulKey % ptHashMap->_uBucketCount; uint64_t mask = ptHashMap->_uBucketCount - 1;
uint64_t ulModKey = ulKey & mask;
while(ptHashMap->_aulKeys[ulModKey] != ulKey && ptHashMap->_aulKeys[ulModKey] != UINT64_MAX) while(ptHashMap->_aulKeys[ulModKey] != ulKey && ptHashMap->_aulKeys[ulModKey] != UINT64_MAX)
ulModKey = (ulModKey + 1) % ptHashMap->_uBucketCount; ulModKey = (ulModKey + 1) & mask;
const uint64_t ulValue = ptHashMap->_aulValueIndices[ulModKey]; const uint64_t ulValue = ptHashMap->_aulValueIndices[ulModKey];
pl_sb_push(ptHashMap->_sbulFreeIndices, ulValue); pl_sb_push(ptHashMap->_sbulFreeIndices, ulValue);
@ -568,15 +632,20 @@ pl_hm_hash(const void* pData, size_t szDataSize, uint64_t uSeed)
} }
static inline uint64_t static inline uint64_t
pl_hm_lookup(plHashMap* ptHashMap, uint64_t ulKey) pl__hm_lookup(plHashMap** pptHashMap, uint64_t ulKey)
{ {
plHashMap* ptHashMap = *pptHashMap;
if(ptHashMap == NULL)
return UINT64_MAX;
if(ptHashMap->_uBucketCount == 0) if(ptHashMap->_uBucketCount == 0)
return UINT64_MAX; return UINT64_MAX;
uint64_t ulModKey = ulKey % ptHashMap->_uBucketCount; uint64_t mask = ptHashMap->_uBucketCount - 1;
uint64_t ulModKey = ulKey & mask;
while(ptHashMap->_aulKeys[ulModKey] != ulKey && ptHashMap->_aulKeys[ulModKey] != UINT64_MAX) while(ptHashMap->_aulKeys[ulModKey] != ulKey && ptHashMap->_aulKeys[ulModKey] != UINT64_MAX)
ulModKey = (ulModKey + 1) % ptHashMap->_uBucketCount; ulModKey = (ulModKey + 1) & mask;
if(ptHashMap->_aulKeys[ulModKey] == UINT64_MAX) if(ptHashMap->_aulKeys[ulModKey] == UINT64_MAX)
return UINT64_MAX; return UINT64_MAX;
@ -585,8 +654,12 @@ pl_hm_lookup(plHashMap* ptHashMap, uint64_t ulKey)
} }
static inline uint64_t static inline uint64_t
pl_hm_get_free_index(plHashMap* ptHashMap) pl__hm_get_free_index(plHashMap** pptHashMap)
{ {
plHashMap* ptHashMap = *pptHashMap;
if(ptHashMap == NULL)
return UINT64_MAX;
uint64_t ulResult = UINT64_MAX; uint64_t ulResult = UINT64_MAX;
if(pl_sb_size(ptHashMap->_sbulFreeIndices) > 0) if(pl_sb_size(ptHashMap->_sbulFreeIndices) > 0)
{ {
@ -595,43 +668,24 @@ pl_hm_get_free_index(plHashMap* ptHashMap)
return ulResult; return ulResult;
} }
static inline void
pl__hm_insert_str(plHashMap* ptHashMap, const char* pcKey, uint64_t ulValue, const char* pcFile, int iLine)
{
pl__hm_insert(ptHashMap, pl_hm_hash_str(pcKey), ulValue, pcFile, iLine);
}
static inline void
pl_hm_remove_str(plHashMap* ptHashMap, const char* pcKey)
{
pl_hm_remove(ptHashMap, pl_hm_hash_str(pcKey));
}
static inline uint64_t
pl_hm_lookup_str(plHashMap* ptHashMap, const char* pcKey)
{
return pl_hm_lookup(ptHashMap, pl_hm_hash_str(pcKey));
}
static inline bool static inline bool
pl_hm_has_key(plHashMap* ptHashMap, uint64_t ulKey) pl__hm_has_key(plHashMap** pptHashMap, uint64_t ulKey)
{ {
plHashMap* ptHashMap = *pptHashMap;
if(ptHashMap == NULL)
return false;
if(ptHashMap->_uItemCount == 0) if(ptHashMap->_uItemCount == 0)
return false; return false;
uint64_t ulModKey = ulKey % ptHashMap->_uBucketCount; uint64_t mask = ptHashMap->_uBucketCount - 1;
uint64_t ulModKey = ulKey & mask;
while(ptHashMap->_aulKeys[ulModKey] != ulKey && ptHashMap->_aulKeys[ulModKey] != UINT64_MAX) while(ptHashMap->_aulKeys[ulModKey] != ulKey && ptHashMap->_aulKeys[ulModKey] != UINT64_MAX)
ulModKey = (ulModKey + 1) % ptHashMap->_uBucketCount; ulModKey = (ulModKey + 1) & mask;
return ptHashMap->_aulKeys[ulModKey] != UINT64_MAX; return ptHashMap->_aulKeys[ulModKey] != UINT64_MAX;
} }
static inline bool
pl_hm_has_key_str(plHashMap* ptHashMap, const char* pcKey)
{
return pl_hm_has_key(ptHashMap, pl_hm_hash_str(pcKey));
}
#endif // PL_DS_H #endif // PL_DS_H

1159
pl_json.h

File diff suppressed because it is too large Load Diff

781
pl_log.h

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,6 @@
/* /*
pl_math.h, v0.6 (WIP) pl_math.h
* simple math library
Do this: Do this:
#define PL_MATH_INCLUDE_FUNCTIONS #define PL_MATH_INCLUDE_FUNCTIONS
@ -12,9 +13,9 @@
#include "pl_math.h" #include "pl_math.h"
*/ */
// library version // library version (format XYYZZ)
#define PL_MATH_VERSION "0.7.0" #define PL_MATH_VERSION "1.0.0"
#define PL_MATH_VERSION_NUM 00700 #define PL_MATH_VERSION_NUM 10000
/* /*
Index of this file: Index of this file:
@ -29,6 +30,7 @@ Index of this file:
// [SECTION] matrix ops // [SECTION] matrix ops
// [SECTION] quaternion ops // [SECTION] quaternion ops
// [SECTION] rect ops // [SECTION] rect ops
// [SECTION] colors
// [SECTION] implementations // [SECTION] implementations
*/ */
@ -187,7 +189,11 @@ typedef struct _plAABB
#include <math.h> #include <math.h>
#include <stdbool.h> // bool #include <stdbool.h> // bool
#include <stdint.h> // uint*_t #include <stdint.h> // uint*_t
#ifndef PL_ASSERT
#include <assert.h> #include <assert.h>
#define PL_ASSERT(x) assert((x))
#endif
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// [SECTION] helpers // [SECTION] helpers
@ -239,8 +245,6 @@ static inline float pl_clamp01f(float fValue) { re
static inline double pl_clamp01d(double dValue) { return pl_clampd(0.0, dValue, 1.0); } static inline double pl_clamp01d(double dValue) { return pl_clampd(0.0, dValue, 1.0); }
static inline size_t pl_align_up(size_t szValue, size_t szAlign) { return ((szValue + (szAlign - 1)) & ~(szAlign - 1)); } static inline size_t pl_align_up(size_t szValue, size_t szAlign) { return ((szValue + (szAlign - 1)) & ~(szAlign - 1)); }
#define PL__ALIGN_UP(num, align) (((num) + ((align)-1)) & ~((align)-1))
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// [SECTION] vector ops // [SECTION] vector ops
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -257,12 +261,10 @@ static inline plVec3 pl_floor_vec3 (plVec3 tVec)
static inline plVec4 pl_floor_vec4 (plVec4 tVec) { return pl_create_vec4(floorf(tVec.x), floorf(tVec.y), floorf(tVec.z), floorf(tVec.w));} static inline plVec4 pl_floor_vec4 (plVec4 tVec) { return pl_create_vec4(floorf(tVec.x), floorf(tVec.y), floorf(tVec.z), floorf(tVec.w));}
// binary ops // binary ops
static inline plVec2 pl_lerp_vec2(plVec2 t0, plVec2 t1, float fAmount) { return pl_create_vec2(t0.x + (t1.x - t0.x) * fAmount, t0.y + (t1.y - t0.y) * fAmount);} static inline plVec2 pl_lerp_vec2(plVec2 t0, plVec2 t1, float fAmount) { return pl_create_vec2(t0.x + (t1.x - t0.x) * fAmount, t0.y + (t1.y - t0.y) * fAmount);}
static inline plVec3 pl_lerp_vec3(plVec3 t0, plVec3 t1, float fAmount) { return pl_create_vec3(t0.x + (t1.x - t0.x) * fAmount, t0.y + (t1.y - t0.y) * fAmount, t0.z + (t1.z - t0.z) * fAmount);} static inline plVec3 pl_lerp_vec3(plVec3 t0, plVec3 t1, float fAmount) { return pl_create_vec3(t0.x + (t1.x - t0.x) * fAmount, t0.y + (t1.y - t0.y) * fAmount, t0.z + (t1.z - t0.z) * fAmount);}
static inline plVec4 pl_lerp_vec4(plVec4 t0, plVec4 t1, float fAmount) { return pl_create_vec4(t0.x + (t1.x - t0.x) * fAmount, t0.y + (t1.y - t0.y) * fAmount, t0.z + (t1.z - t0.z) * fAmount, t0.w + (t1.w - t0.w) * fAmount);} static inline plVec4 pl_lerp_vec4(plVec4 t0, plVec4 t1, float fAmount) { return pl_create_vec4(t0.x + (t1.x - t0.x) * fAmount, t0.y + (t1.y - t0.y) * fAmount, t0.z + (t1.z - t0.z) * fAmount, t0.w + (t1.w - t0.w) * fAmount);}
static inline plVec2 pl_clamp_vec2(plVec2 tMin, plVec2 tValue, plVec2 tMax) { return pl_create_vec2(pl_clampf(tMin.x, tValue.x, tMax.x), pl_clampf(tMin.y, tValue.y, tMax.y));} static inline plVec2 pl_clamp_vec2(plVec2 tMin, plVec2 tValue, plVec2 tMax) { return pl_create_vec2(pl_clampf(tMin.x, tValue.x, tMax.x), pl_clampf(tMin.y, tValue.y, tMax.y));}
static inline plVec3 pl_clamp_vec3(plVec3 tMin, plVec3 tValue, plVec3 tMax) { return pl_create_vec3(pl_clampf(tMin.x, tValue.x, tMax.x), pl_clampf(tMin.y, tValue.y, tMax.y), pl_clampf(tMax.z, tValue.z, tMax.z));} static inline plVec3 pl_clamp_vec3(plVec3 tMin, plVec3 tValue, plVec3 tMax) { return pl_create_vec3(pl_clampf(tMin.x, tValue.x, tMax.x), pl_clampf(tMin.y, tValue.y, tMax.y), pl_clampf(tMax.z, tValue.z, tMax.z));}
static inline plVec4 pl_clamp_vec4(plVec4 tMin, plVec4 tValue, plVec4 tMax) { return pl_create_vec4(pl_clampf(tMin.x, tValue.x, tMax.x), pl_clampf(tMin.y, tValue.y, tMax.y), pl_clampf(tMax.z, tValue.z, tMax.z), pl_clampf(tMax.w, tValue.w, tMax.w));} static inline plVec4 pl_clamp_vec4(plVec4 tMin, plVec4 tValue, plVec4 tMax) { return pl_create_vec4(pl_clampf(tMin.x, tValue.x, tMax.x), pl_clampf(tMin.y, tValue.y, tMax.y), pl_clampf(tMax.z, tValue.z, tMax.z), pl_clampf(tMax.w, tValue.w, tMax.w));}
@ -274,10 +276,11 @@ static inline plVec2 pl_max_vec2 (plVec2 tValue0, plVec2 tValue1)
static inline plVec3 pl_max_vec3(plVec3 tValue0, plVec3 tValue1) { return pl_create_vec3(pl_maxf(tValue0.x, tValue1.x), pl_maxf(tValue0.y, tValue1.y), pl_maxf(tValue0.z, tValue1.z));} static inline plVec3 pl_max_vec3(plVec3 tValue0, plVec3 tValue1) { return pl_create_vec3(pl_maxf(tValue0.x, tValue1.x), pl_maxf(tValue0.y, tValue1.y), pl_maxf(tValue0.z, tValue1.z));}
static inline plVec4 pl_max_vec4(plVec4 tValue0, plVec4 tValue1) { return pl_create_vec4(pl_maxf(tValue0.x, tValue1.x), pl_maxf(tValue0.y, tValue1.y), pl_maxf(tValue0.z, tValue1.z), pl_maxf(tValue0.w, tValue1.w));} static inline plVec4 pl_max_vec4(plVec4 tValue0, plVec4 tValue1) { return pl_create_vec4(pl_maxf(tValue0.x, tValue1.x), pl_maxf(tValue0.y, tValue1.y), pl_maxf(tValue0.z, tValue1.z), pl_maxf(tValue0.w, tValue1.w));}
static inline plVec3 pl_cross_vec3(plVec3 tVec1, plVec3 tVec2) { return pl_create_vec3(tVec1.y * tVec2.z - tVec2.y * tVec1.z, tVec1.z * tVec2.x - tVec2.z * tVec1.x, tVec1.x * tVec2.y - tVec2.x * tVec1.y); }
static inline float pl_dot_vec2(plVec2 tVec1, plVec2 tVec2) { return tVec1.x * tVec2.x + tVec1.y * tVec2.y; } static inline float pl_dot_vec2(plVec2 tVec1, plVec2 tVec2) { return tVec1.x * tVec2.x + tVec1.y * tVec2.y; }
static inline float pl_dot_vec3(plVec3 tVec1, plVec3 tVec2) { return tVec1.x * tVec2.x + tVec1.y * tVec2.y + tVec1.z * tVec2.z; } static inline float pl_dot_vec3(plVec3 tVec1, plVec3 tVec2) { return tVec1.x * tVec2.x + tVec1.y * tVec2.y + tVec1.z * tVec2.z; }
static inline float pl_dot_vec4(plVec4 tVec1, plVec4 tVec2) { return tVec1.x * tVec2.x + tVec1.y * tVec2.y + tVec1.z * tVec2.z + tVec1.w * tVec2.w; } static inline float pl_dot_vec4(plVec4 tVec1, plVec4 tVec2) { return tVec1.x * tVec2.x + tVec1.y * tVec2.y + tVec1.z * tVec2.z + tVec1.w * tVec2.w; }
static inline plVec3 pl_cross_vec3 (plVec3 tVec1, plVec3 tVec2) { return pl_create_vec3(tVec1.y * tVec2.z - tVec2.y * tVec1.z, tVec1.z * tVec2.x - tVec2.z * tVec1.x, tVec1.x * tVec2.y - tVec2.x * tVec1.y); }
static inline plVec2 pl_add_vec2(plVec2 tVec1, plVec2 tVec2) { return pl_create_vec2(tVec1.x + tVec2.x, tVec1.y + tVec2.y); } static inline plVec2 pl_add_vec2(plVec2 tVec1, plVec2 tVec2) { return pl_create_vec2(tVec1.x + tVec2.x, tVec1.y + tVec2.y); }
static inline plVec3 pl_add_vec3(plVec3 tVec1, plVec3 tVec2) { return pl_create_vec3(tVec1.x + tVec2.x, tVec1.y + tVec2.y, tVec1.z + tVec2.z); } static inline plVec3 pl_add_vec3(plVec3 tVec1, plVec3 tVec2) { return pl_create_vec3(tVec1.x + tVec2.x, tVec1.y + tVec2.y, tVec1.z + tVec2.z); }
@ -385,6 +388,28 @@ static inline plRect pl_rect_move_start (const plRect* ptRect, float fX, floa
static inline plRect pl_rect_move_start_x (const plRect* ptRect, float fX) { const plRect tResult = { { fX, ptRect->tMin.y}, { fX + ptRect->tMax.x - ptRect->tMin.x, ptRect->tMax.y} }; return tResult;} static inline plRect pl_rect_move_start_x (const plRect* ptRect, float fX) { const plRect tResult = { { fX, ptRect->tMin.y}, { fX + ptRect->tMax.x - ptRect->tMin.x, ptRect->tMax.y} }; return tResult;}
static inline plRect pl_rect_move_start_y (const plRect* ptRect, float fY) { const plRect tResult = {{ ptRect->tMin.x, fY}, { ptRect->tMax.x, fY + ptRect->tMax.y - ptRect->tMin.y}}; return tResult;} static inline plRect pl_rect_move_start_y (const plRect* ptRect, float fY) { const plRect tResult = {{ ptRect->tMin.x, fY}, { ptRect->tMax.x, fY + ptRect->tMax.y - ptRect->tMin.y}}; return tResult;}
//-----------------------------------------------------------------------------
// [SECTION] colors
//-----------------------------------------------------------------------------
// creates packed 32-bit encoded colors
#define PL_COLOR_32_RGBA(R, G, B, A) ((uint32_t)(255.0f * (R) + 0.5f) | (uint32_t) (255.0f * (G) + 0.5f) << 8 | (uint32_t) (255.0f * (B) + 0.5f) << 16 | (uint32_t) (255.0f * (A) + 0.5f) << 24)
#define PL_COLOR_32_VEC4(X) ((uint32_t)(255.0f * (X).r + 0.5f) | (uint32_t) (255.0f * (X).g + 0.5f) << 8 | (uint32_t) (255.0f * (X).b + 0.5f) << 16 | (uint32_t) (255.0f * (X).a + 0.5f) << 24)
#define PL_COLOR_32_RGB(R, G, B) ((uint32_t)(255.0f * (R) + 0.5f) | (uint32_t) (255.0f * (G) + 0.5f) << 8 | (uint32_t) (255.0f * (B) + 0.5f) << 16 | (uint32_t) (255.5f) << 24)
#define PL_COLOR_32_VEC3(X) ((uint32_t)(255.0f * (X).r + 0.5f) | (uint32_t) (255.0f * (X).g + 0.5f) << 8 | (uint32_t) (255.0f * (X).b + 0.5f) << 16 | (uint32_t) (255.5f) << 24)
#define PL_COLOR_32_WHITE UINT32_MAX
#define PL_COLOR_32_BLACK 0x00
#define PL_COLOR_32_RED 0xFF0000FF
#define PL_COLOR_32_BLUE 0xFFFF0000
#define PL_COLOR_32_DARK_BLUE 0xFF8B0000
#define PL_COLOR_32_GREEN 0xFF00FF00
#define PL_COLOR_32_YELLOW 0xFF00FFFF
#define PL_COLOR_32_ORANGE 0xFF00A5FF
#define PL_COLOR_32_MAGENTA 0xFFFF00FF
#define PL_COLOR_32_CYAN 0xFFFFFF00
#define PL_COLOR_32_GREY 0xFF808080
#define PL_COLOR_32_LIGHT_GREY 0xFFD3D3D3
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// [SECTION] implementations // [SECTION] implementations
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -728,7 +753,7 @@ pl_decompose_matrix(const plMat4* ptM, plVec3* ptS, plVec4* ptQ, plVec3* ptT)
} }
} }
assert(!(ptQ->d[3] < 0.0f)); PL_ASSERT(!(ptQ->d[3] < 0.0f));
} }
static inline plVec4 static inline plVec4

View File

@ -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.5.0" #define PL_MEMORY_VERSION "1.0.0"
#define PL_MEMORY_VERSION_NUM 00500 #define PL_MEMORY_VERSION_NUM 10000
/* /*
Index of this file: Index of this file:
@ -53,18 +53,16 @@ Index of this file:
// [SECTION] includes // [SECTION] includes
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include <stdint.h> // uint*_t
#include <stddef.h> // size_t #include <stddef.h> // size_t
#include <stdbool.h> // bool
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// [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;
@ -74,65 +72,57 @@ typedef size_t plStackAllocatorMarker;
//~~~~~~~~~~~~~~~~~~~~~~~~~general purpose allocation~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~~~~~~~~~~~~~~~~~~~~~~~~~general purpose allocation~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void* pl_aligned_alloc(size_t szAlignment, size_t szSize); void* pl_aligned_alloc(size_t szAlignment, size_t);
void pl_aligned_free (void* pBuffer); void pl_aligned_free (void*);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~virtual memory system~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Notes
// - API subject to change slightly
// - additional error checks needs to be added
// - committed memory does not necessarily mean the memory has been mapped to physical
// memory. This is happens when the memory is actually touched. Even so, on Windows
// you can not commit more memmory then you have in your page file.
// - uncommitted memory does not necessarily mean the memory will be immediately
// evicted. It is up to the OS.
size_t pl_get_page_size (void); // returns memory page size
void* pl_virtual_alloc (void* pAddress, size_t szSize); // reserves & commits a block of memory. pAddress is starting address or use NULL to have system choose. szSize must be a multiple of memory page size.
void* pl_virtual_reserve (void* pAddress, size_t szSize); // reserves a block of memory. pAddress is starting address or use NULL to have system choose. szSize must be a multiple of memory page size.
void* pl_virtual_commit (void* pAddress, size_t szSize); // commits a block of reserved memory. szSize must be a multiple of memory page size.
void pl_virtual_uncommit(void* pAddress, size_t szSize); // uncommits a block of committed memory.
void pl_virtual_free (void* pAddress, size_t szSize); // frees a block of previously reserved/committed memory. Must be the starting address returned from "pl_virtual_reserve()" or "pl_virtual_alloc()"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~temporary allocator~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~~~~~~~~~~~~~~~~~~~~~~~~~~~temporary allocator~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void* pl_temp_allocator_alloc (plTempAllocator* ptAllocator, size_t szSize); void* pl_temp_allocator_alloc (plTempAllocator*, size_t);
void pl_temp_allocator_reset (plTempAllocator* ptAllocator); void pl_temp_allocator_reset (plTempAllocator*);
void pl_temp_allocator_free (plTempAllocator* ptAllocator); void pl_temp_allocator_free (plTempAllocator*);
char* pl_temp_allocator_sprintf(plTempAllocator* ptAllocator, const char* cPFormat, ...); char* pl_temp_allocator_sprintf(plTempAllocator*, const char* cPFormat, ...);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~stack allocators~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~stack allocators~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// common // common
void pl_stack_allocator_init (plStackAllocator* ptAllocator, size_t szSize, void* pBuffer); void pl_stack_allocator_init(plStackAllocator*, size_t, void*);
// single stack // single stack
void* pl_stack_allocator_alloc (plStackAllocator* ptAllocator, size_t szSize); void* pl_stack_allocator_alloc (plStackAllocator*, size_t);
void* pl_stack_allocator_aligned_alloc (plStackAllocator* ptAllocator, size_t szSize, size_t szAlignment); void* pl_stack_allocator_aligned_alloc (plStackAllocator*, size_t, size_t szAlignment);
plStackAllocatorMarker pl_stack_allocator_marker (plStackAllocator* ptAllocator); plStackAllocatorMarker pl_stack_allocator_marker (plStackAllocator*);
void pl_stack_allocator_free_to_marker(plStackAllocator* ptAllocator, plStackAllocatorMarker tMarker); void pl_stack_allocator_free_to_marker(plStackAllocator*, plStackAllocatorMarker);
void pl_stack_allocator_reset (plStackAllocator* ptAllocator); void pl_stack_allocator_reset (plStackAllocator*);
// double sided stack // double sided stack
void* pl_stack_allocator_aligned_alloc_bottom (plStackAllocator* ptAllocator, size_t szSize, size_t szAlignment); void* pl_stack_allocator_aligned_alloc_bottom (plStackAllocator*, size_t, size_t szAlignment);
plStackAllocatorMarker pl_stack_allocator_top_marker (plStackAllocator* ptAllocator); plStackAllocatorMarker pl_stack_allocator_top_marker (plStackAllocator*);
plStackAllocatorMarker pl_stack_allocator_bottom_marker (plStackAllocator* ptAllocator); plStackAllocatorMarker pl_stack_allocator_bottom_marker (plStackAllocator*);
void* pl_stack_allocator_alloc_bottom (plStackAllocator* ptAllocator, size_t szSize); void* pl_stack_allocator_alloc_bottom (plStackAllocator*, size_t);
void* pl_stack_allocator_alloc_top (plStackAllocator* ptAllocator, size_t szSize); void* pl_stack_allocator_alloc_top (plStackAllocator*, size_t);
void pl_stack_allocator_free_top_to_marker (plStackAllocator* ptAllocator, plStackAllocatorMarker tMarker); void pl_stack_allocator_free_top_to_marker (plStackAllocator*, plStackAllocatorMarker);
void pl_stack_allocator_free_bottom_to_marker(plStackAllocator* ptAllocator, plStackAllocatorMarker tMarker); void pl_stack_allocator_free_bottom_to_marker(plStackAllocator*, plStackAllocatorMarker);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~pool allocator~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~pool allocator~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void pl_pool_allocator_init (plPoolAllocator* ptAllocator, size_t szItemCount, size_t szItemSize, size_t szItemAlignment, size_t* pszBufferSize, void* pBuffer); // Notes
void* pl_pool_allocator_alloc(plPoolAllocator* ptAllocator); // - setting pBuffer to NULL, will set pszBufferSize to required buffer size
void pl_pool_allocator_free (plPoolAllocator* ptAllocator, void* pItem); // so you can allocate a properly sized buffer for the requested 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 supported;
// 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_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;
@ -142,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
@ -152,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;
@ -179,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
*/ */
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -202,36 +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
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h> // VirtualAlloc, VirtualFree
#include <sysinfoapi.h> // page size
#elif defined(__APPLE__)
#include <unistd.h>
#include <sys/mman.h>
#else // linux
#include <unistd.h>
#include <sys/mman.h>
#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
@ -270,96 +245,18 @@ pl__align_forward_size(size_t szPtr, size_t szAlign)
return p; return p;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// [SECTION] public api implementation // [SECTION] public api implementation
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
size_t
pl_get_page_size(void)
{
#ifdef _WIN32
SYSTEM_INFO tInfo = {0};
GetSystemInfo(&tInfo);
return (size_t)tInfo.dwPageSize;
#elif defined(__APPLE__)
return (size_t)getpagesize();
#else // linux
return (size_t)getpagesize();
#endif
}
void*
pl_virtual_alloc(void* pAddress, size_t szSize)
{
#ifdef _WIN32
return VirtualAlloc(pAddress, szSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
#elif defined(__APPLE__)
void* pResult = mmap(pAddress, szSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
return pResult;
#else // linux
void* pResult = mmap(pAddress, szSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
return pResult;
#endif
}
void*
pl_virtual_reserve(void* pAddress, size_t szSize)
{
#ifdef _WIN32
return VirtualAlloc(pAddress, szSize, MEM_RESERVE, PAGE_READWRITE);
#elif defined(__APPLE__)
void* pResult = mmap(pAddress, szSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
return pResult;
#else // linux
void* pResult = mmap(pAddress, szSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
return pResult;
#endif
}
void*
pl_virtual_commit(void* pAddress, size_t szSize)
{
#ifdef _WIN32
return VirtualAlloc(pAddress, szSize, MEM_COMMIT, PAGE_READWRITE);
#elif defined(__APPLE__)
mprotect(pAddress, szSize, PROT_READ | PROT_WRITE);
return pAddress;
#else // linux
mprotect(pAddress, szSize, PROT_READ | PROT_WRITE);
return pAddress;
#endif
}
void
pl_virtual_free(void* pAddress, size_t szSize)
{
#ifdef _WIN32
PL_ASSERT(VirtualFree(pAddress, szSize, MEM_RELEASE));
#elif defined(__APPLE__)
PL_ASSERT(munmap(pAddress, szSize) == 0);
#else // linux
PL_ASSERT(munmap(pAddress, szSize) == 0); //-V586
#endif
}
void
pl_virtual_uncommit(void* pAddress, size_t szSize)
{
#ifdef _WIN32
PL_ASSERT(VirtualFree(pAddress, szSize, MEM_DECOMMIT));
#elif defined(__APPLE__)
mprotect(pAddress, szSize, PROT_NONE);
#else // linux
mprotect(pAddress, szSize, PROT_NONE);
#endif
}
void* void*
pl_aligned_alloc(size_t szAlignment, size_t szSize) 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");
@ -406,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);
} }
@ -414,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
@ -422,30 +320,61 @@ 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;
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++;
} }
@ -462,6 +391,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
@ -530,7 +470,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;
@ -549,7 +490,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)
@ -579,7 +521,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)
@ -604,7 +547,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;
@ -674,24 +618,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;
@ -705,7 +661,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;
@ -716,6 +671,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*
@ -740,4 +696,4 @@ pl_pool_allocator_free(plPoolAllocator* ptAllocator, void* pItem)
ptAllocator->pFreeList->ptNextNode = pOldFreeNode; ptAllocator->pFreeList->ptNextNode = pOldFreeNode;
} }
#endif #endif // PL_MEMORY_IMPLEMENTATION

View File

@ -1,5 +1,6 @@
/* /*
pl_profile pl_profile.h
* simple profiling library
Do this: Do this:
#define PL_PROFILE_IMPLEMENTATION #define PL_PROFILE_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 +12,9 @@
#include "pl_profile.h" #include "pl_profile.h"
*/ */
// library version // library version (format XYYZZ)
#define PL_PROFILE_VERSION "0.2.0" #define PL_PROFILE_VERSION "1.0.0"
#define PL_PROFILE_VERSION_NUM 00200 #define PL_PROFILE_VERSION_NUM 10000
/* /*
Index of this file: Index of this file:
@ -76,7 +77,7 @@ SAMPLING
RETRIEVING RESULTS RETRIEVING RESULTS
pl_get_last_frame_samples: pl_get_last_frame_samples:
plProfileSample* pl_get_last_frame_samples(uint32_t* puSize); plProfileSample* pl_get_last_frame_samples(uint32_t* puSizeOut);
Returns samples from last frame. Call after "pl_end_profile_frame". Returns samples from last frame. Call after "pl_end_profile_frame".
@ -105,8 +106,9 @@ COMPILE TIME OPTIONS
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// forward declarations // forward declarations
typedef struct _plProfileSample plProfileSample; typedef struct _plProfileSample plProfileSample; // single sample result
typedef struct _plProfileContext plProfileContext; typedef struct _plProfileInit plProfileInit; // profile context init info
typedef struct _plProfileContext plProfileContext; // opaque type
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// [SECTION] public api // [SECTION] public api
@ -115,7 +117,7 @@ typedef struct _plProfileContext plProfileContext;
#ifdef PL_PROFILE_ON #ifdef PL_PROFILE_ON
// setup/shutdown // setup/shutdown
#define pl_create_profile_context(ptContext) pl__create_profile_context() #define pl_create_profile_context(tInit) pl__create_profile_context((tInit))
#define pl_cleanup_profile_context() pl__cleanup_profile_context() #define pl_cleanup_profile_context() pl__cleanup_profile_context()
#define pl_set_profile_context(ptContext) pl__set_profile_context((ptContext)) #define pl_set_profile_context(ptContext) pl__set_profile_context((ptContext))
#define pl_get_profile_context() pl__get_profile_context() #define pl_get_profile_context() pl__get_profile_context()
@ -125,9 +127,9 @@ typedef struct _plProfileContext plProfileContext;
#define pl_end_profile_frame() pl__end_profile_frame() #define pl_end_profile_frame() pl__end_profile_frame()
// samples // samples
#define pl_begin_profile_sample(pcName) pl__begin_profile_sample((pcName)) #define pl_begin_profile_sample(uThreadIndex, pcName) pl__begin_profile_sample((uThreadIndex), (pcName))
#define pl_end_profile_sample() pl__end_profile_sample() #define pl_end_profile_sample(uThreadIndex) pl__end_profile_sample((uThreadIndex))
#define pl_get_last_frame_samples(puSize) pl__get_last_frame_samples((puSize)) #define pl_get_last_frame_samples(uThreadIndex, puSize) pl__get_last_frame_samples((uThreadIndex), (puSize))
#endif // PL_PROFILE_ON #endif // PL_PROFILE_ON
@ -143,14 +145,19 @@ typedef struct _plProfileSample
uint32_t uDepth; uint32_t uDepth;
} plProfileSample; } plProfileSample;
typedef struct _plProfileInit
{
uint32_t uThreadCount;
} plProfileInit;
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// [SECTION] internal api // [SECTION] internal api
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// setup/shutdown // setup/shutdown
plProfileContext* pl__create_profile_context (void); plProfileContext* pl__create_profile_context (plProfileInit);
void pl__cleanup_profile_context(void); void pl__cleanup_profile_context(void);
void pl__set_profile_context (plProfileContext* ptContext); void pl__set_profile_context (plProfileContext*);
plProfileContext* pl__get_profile_context (void); plProfileContext* pl__get_profile_context (void);
// frames // frames
@ -158,20 +165,21 @@ void pl__begin_profile_frame(void);
void pl__end_profile_frame (void); void pl__end_profile_frame (void);
// samples // samples
void pl__begin_profile_sample(const char* pcName); void pl__begin_profile_sample(uint32_t uThreadIndex, const char* pcName);
void pl__end_profile_sample (void); void pl__end_profile_sample (uint32_t uThreadIndex);
plProfileSample* pl__get_last_frame_samples(uint32_t* puSize); plProfileSample* pl__get_last_frame_samples(uint32_t uThreadIndex, uint32_t* puSizeOut);
#ifndef PL_PROFILE_ON #ifndef PL_PROFILE_ON
#define pl_create_profile_context(ptContext) NULL #define pl_create_profile_context(ptContext) NULL
#define pl_cleanup_profile_context() // #define pl_cleanup_profile_context() //
#define pl_set_profile_context(ptContext) // #define pl_set_profile_context(ptContext) //
#define pl_get_profile_context() NULL #define pl_get_profile_context() NULL
#define pl_begin_profile_frame(ulFrame) // #define pl_begin_profile_frame() //
#define pl_end_profile_frame() // #define pl_end_profile_frame() //
#define pl_begin_profile_sample(pcName) // #define pl_begin_profile_sampleuThreadIndex(uThreadIndex, pcName) //
#define pl_end_profile_sample() // #define pl_end_profile_sample(uThreadIndex) //
#define pl_get_last_frame_samples(puSize) NULL #define pl_get_last_frame_samples(uThreadIndex, puSize) NULL
#define pl_get_profile_overhead() 0.0
#endif #endif
#endif // PL_PROFILE_H #endif // PL_PROFILE_H
@ -212,6 +220,9 @@ Index of this file:
// [SECTION] includes // [SECTION] includes
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include <stdbool.h> // bool
#include <string.h> // memset
#ifdef _WIN32 #ifdef _WIN32
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>
@ -225,7 +236,7 @@ Index of this file:
// [SECTION] global context // [SECTION] global context
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
plProfileContext* gTPProfileContext = NULL; static plProfileContext* gptProfileContext = NULL;
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// [SECTION] internal structs // [SECTION] internal structs
@ -257,13 +268,19 @@ typedef struct _plProfileFrame
uint32_t uOverflowSampleCapacity; uint32_t uOverflowSampleCapacity;
} plProfileFrame; } plProfileFrame;
typedef struct _plProfileThreadData
{
plProfileFrame atFrames[2];
plProfileFrame* ptCurrentFrame;
plProfileFrame* ptLastFrame;
} plProfileThreadData;
typedef struct _plProfileContext typedef struct _plProfileContext
{ {
double dStartTime; double dStartTime;
uint64_t ulFrame; uint64_t ulFrame;
plProfileFrame atFrames[2]; plProfileThreadData* ptThreadData;
plProfileFrame* ptCurrentFrame; uint32_t uThreadCount;
plProfileFrame* ptLastFrame;
void* pInternal; void* pInternal;
} plProfileContext; } plProfileContext;
@ -286,7 +303,7 @@ pl__get_wall_clock(void)
{ {
double dResult = 0; double dResult = 0;
#ifdef _WIN32 #ifdef _WIN32
INT64 slPerfFrequency = *(INT64*)gTPProfileContext->pInternal; INT64 slPerfFrequency = *(INT64*)gptProfileContext->pInternal;
INT64 slPerfCounter; INT64 slPerfCounter;
QueryPerformanceCounter((LARGE_INTEGER*)&slPerfCounter); QueryPerformanceCounter((LARGE_INTEGER*)&slPerfCounter);
dResult = (double)slPerfCounter / (double)slPerfFrequency; dResult = (double)slPerfCounter / (double)slPerfFrequency;
@ -296,7 +313,7 @@ pl__get_wall_clock(void)
struct timespec ts; struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts); clock_gettime(CLOCK_MONOTONIC, &ts);
uint64_t nsec_count = ts.tv_nsec + ts.tv_sec * 1e9; uint64_t nsec_count = ts.tv_nsec + ts.tv_sec * 1e9;
dResult = (double)nsec_count / *(double*)gTPProfileContext->pInternal; dResult = (double)nsec_count / *(double*)gptProfileContext->pInternal;
#endif #endif
return dResult; return dResult;
} }
@ -306,17 +323,23 @@ pl__get_wall_clock(void)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
plProfileContext* plProfileContext*
pl__create_profile_context(void) pl__create_profile_context(plProfileInit tInit)
{ {
// allocate context // allocate context
plProfileContext* ptContext = (plProfileContext*)PL_PROFILE_ALLOC(sizeof(plProfileContext)); plProfileContext* ptContext = (plProfileContext*)PL_PROFILE_ALLOC(sizeof(plProfileContext));
memset(ptContext, 0, sizeof(plProfileContext)); memset(ptContext, 0, sizeof(plProfileContext));
gTPProfileContext = ptContext; gptProfileContext = ptContext;
// clock setup // clock setup
#ifdef _WIN32 #ifdef _WIN32
static INT64 slPerfFrequency = 0; static INT64 slPerfFrequency = 0;
PL_ASSERT(QueryPerformanceFrequency((LARGE_INTEGER*)&slPerfFrequency)); BOOL bResult = QueryPerformanceFrequency((LARGE_INTEGER*)&slPerfFrequency);
if(!bResult)
{
PL_PROFILE_FREE(gptProfileContext);
gptProfileContext = NULL;
return NULL;
}
ptContext->pInternal = &slPerfFrequency; ptContext->pInternal = &slPerfFrequency;
#elif defined(__APPLE__) #elif defined(__APPLE__)
// no setup required // no setup required
@ -324,7 +347,10 @@ pl__create_profile_context(void)
static struct timespec ts; static struct timespec ts;
if (clock_getres(CLOCK_MONOTONIC, &ts) != 0) if (clock_getres(CLOCK_MONOTONIC, &ts) != 0)
{ {
PL_ASSERT(false && "clock_getres() failed"); // PL_ASSERT(false && "clock_getres() failed");
PL_PROFILE_FREE(gptProfileContext);
gptProfileContext = NULL;
return NULL;
} }
static double dPerFrequency = 0.0; static double dPerFrequency = 0.0;
@ -333,73 +359,97 @@ pl__create_profile_context(void)
#endif #endif
ptContext->dStartTime = pl__get_wall_clock(); ptContext->dStartTime = pl__get_wall_clock();
ptContext->ptCurrentFrame = &ptContext->atFrames[0]; ptContext->uThreadCount = tInit.uThreadCount;
ptContext->atFrames[0].uSampleCapacity = 256; ptContext->ptThreadData = (plProfileThreadData*)PL_PROFILE_ALLOC(sizeof(plProfileThreadData) * tInit.uThreadCount);
ptContext->atFrames[0].uSampleStackCapacity = 256; memset(ptContext->ptThreadData, 0, sizeof(plProfileThreadData) * tInit.uThreadCount);
ptContext->atFrames[1].uSampleCapacity = 256; for(uint32_t i = 0; i < tInit.uThreadCount; i++)
ptContext->atFrames[1].uSampleStackCapacity = 256; {
ptContext->atFrames[0].ptSamples = ptContext->atFrames[0].atSamples; ptContext->ptThreadData[i].ptCurrentFrame = &ptContext->ptThreadData[i].atFrames[0];
ptContext->atFrames[1].ptSamples = ptContext->atFrames[1].atSamples; ptContext->ptThreadData[i].atFrames[0].uSampleCapacity = 256;
ptContext->atFrames[0].puSampleStack = ptContext->atFrames[0].auSampleStack; ptContext->ptThreadData[i].atFrames[0].uSampleStackCapacity = 256;
ptContext->atFrames[1].puSampleStack = ptContext->atFrames[1].auSampleStack; ptContext->ptThreadData[i].atFrames[1].uSampleCapacity = 256;
ptContext->ptLastFrame = &ptContext->atFrames[0]; ptContext->ptThreadData[i].atFrames[1].uSampleStackCapacity = 256;
ptContext->ptThreadData[i].atFrames[0].ptSamples = ptContext->ptThreadData[i].atFrames[0].atSamples;
ptContext->ptThreadData[i].atFrames[1].ptSamples = ptContext->ptThreadData[i].atFrames[1].atSamples;
ptContext->ptThreadData[i].atFrames[0].puSampleStack = ptContext->ptThreadData[i].atFrames[0].auSampleStack;
ptContext->ptThreadData[i].atFrames[1].puSampleStack = ptContext->ptThreadData[i].atFrames[1].auSampleStack;
ptContext->ptThreadData[i].ptLastFrame = &ptContext->ptThreadData[i].atFrames[0];
}
return ptContext; return ptContext;
} }
void void
pl__cleanup_profile_context(void) pl__cleanup_profile_context(void)
{ {
for(uint32_t i = 0; i < gptProfileContext->uThreadCount; i++)
for(uint32_t i = 0; i < 2; i++) {
for(uint32_t j = 0; j < 2; j++)
{ {
if(gTPProfileContext->atFrames[i].bOverflowInUse)
PL_PROFILE_FREE(gTPProfileContext->atFrames[i].ptSamples);
if(gTPProfileContext->atFrames[i].bSampleStackOverflowInUse) if(gptProfileContext->ptThreadData[i].atFrames[j].bOverflowInUse)
PL_PROFILE_FREE(gTPProfileContext->atFrames[i].puSampleStack); PL_PROFILE_FREE(gptProfileContext->ptThreadData[i].atFrames[j].ptSamples);
if(gptProfileContext->ptThreadData[i].atFrames[j].bSampleStackOverflowInUse)
PL_PROFILE_FREE(gptProfileContext->ptThreadData[i].atFrames[j].puSampleStack);
}
} }
PL_PROFILE_FREE(gTPProfileContext); PL_PROFILE_FREE(gptProfileContext->ptThreadData);
gTPProfileContext = NULL; PL_PROFILE_FREE(gptProfileContext);
gptProfileContext = NULL;
} }
void void
pl__set_profile_context(plProfileContext* ptContext) pl__set_profile_context(plProfileContext* ptContext)
{ {
PL_ASSERT(ptContext && "profile context is NULL"); gptProfileContext = ptContext;
gTPProfileContext = ptContext;
} }
plProfileContext* plProfileContext*
pl__get_profile_context(void) pl__get_profile_context(void)
{ {
PL_ASSERT(gTPProfileContext && "no global log context set"); return gptProfileContext;
return gTPProfileContext;
} }
void void
pl__begin_profile_frame(void) pl__begin_profile_frame(void)
{ {
gTPProfileContext->ulFrame++;
gTPProfileContext->ptCurrentFrame = &gTPProfileContext->atFrames[gTPProfileContext->ulFrame % 2]; if(gptProfileContext == NULL)
gTPProfileContext->ptCurrentFrame->dDuration = 0.0; {
gTPProfileContext->ptCurrentFrame->dInternalDuration = 0.0; plProfileInit tInit = {
gTPProfileContext->ptCurrentFrame->dStartTime = pl__get_wall_clock(); .uThreadCount = 1
gTPProfileContext->ptCurrentFrame->uTotalSampleSize = 0; };
pl__create_profile_context(tInit);
}
gptProfileContext->ulFrame++;
for(uint32_t i = 0; i < gptProfileContext->uThreadCount; i++)
{
gptProfileContext->ptThreadData[i].ptCurrentFrame = &gptProfileContext->ptThreadData[i].atFrames[gptProfileContext->ulFrame % 2];
gptProfileContext->ptThreadData[i].ptCurrentFrame->dDuration = 0.0;
gptProfileContext->ptThreadData[i].ptCurrentFrame->dInternalDuration = 0.0;
gptProfileContext->ptThreadData[i].ptCurrentFrame->dStartTime = pl__get_wall_clock();
gptProfileContext->ptThreadData[i].ptCurrentFrame->uTotalSampleSize = 0;
}
} }
void void
pl__end_profile_frame(void) pl__end_profile_frame(void)
{ {
gTPProfileContext->ptCurrentFrame->dDuration = pl__get_wall_clock() - gTPProfileContext->ptCurrentFrame->dStartTime; for(uint32_t i = 0; i < gptProfileContext->uThreadCount; i++)
gTPProfileContext->ptLastFrame = gTPProfileContext->ptCurrentFrame; {
gptProfileContext->ptThreadData[i].ptCurrentFrame->dDuration = pl__get_wall_clock() - gptProfileContext->ptThreadData[i].ptCurrentFrame->dStartTime;
gptProfileContext->ptThreadData[i].ptLastFrame = gptProfileContext->ptThreadData[i].ptCurrentFrame;
}
} }
void void
pl__begin_profile_sample(const char* pcName) pl__begin_profile_sample(uint32_t uThreadIndex, const char* pcName)
{ {
const double dCurrentInternalTime = pl__get_wall_clock(); const double dCurrentInternalTime = pl__get_wall_clock();
plProfileFrame* ptCurrentFrame = gTPProfileContext->ptCurrentFrame; plProfileFrame* ptCurrentFrame = gptProfileContext->ptThreadData[uThreadIndex].ptCurrentFrame;
uint32_t uSampleIndex = ptCurrentFrame->uTotalSampleSize; uint32_t uSampleIndex = ptCurrentFrame->uTotalSampleSize;
plProfileSample* ptSample = pl__get_sample(ptCurrentFrame); plProfileSample* ptSample = pl__get_sample(ptCurrentFrame);
@ -414,10 +464,10 @@ pl__begin_profile_sample(const char* pcName)
} }
void void
pl__end_profile_sample(void) pl__end_profile_sample(uint32_t uThreadIndex)
{ {
const double dCurrentInternalTime = pl__get_wall_clock(); const double dCurrentInternalTime = pl__get_wall_clock();
plProfileFrame* ptCurrentFrame = gTPProfileContext->ptCurrentFrame; plProfileFrame* ptCurrentFrame = gptProfileContext->ptThreadData[uThreadIndex].ptCurrentFrame;
plProfileSample* ptLastSample = &ptCurrentFrame->ptSamples[pl__pop_sample_stack(ptCurrentFrame)]; plProfileSample* ptLastSample = &ptCurrentFrame->ptSamples[pl__pop_sample_stack(ptCurrentFrame)];
PL_ASSERT(ptLastSample && "Begin/end profile sample mismatch"); PL_ASSERT(ptLastSample && "Begin/end profile sample mismatch");
ptLastSample->dDuration = pl__get_wall_clock() - ptLastSample->dStartTime; ptLastSample->dDuration = pl__get_wall_clock() - ptLastSample->dStartTime;
@ -426,9 +476,9 @@ pl__end_profile_sample(void)
} }
plProfileSample* plProfileSample*
pl__get_last_frame_samples(uint32_t* puSize) pl__get_last_frame_samples(uint32_t uThreadIndex, uint32_t* puSize)
{ {
plProfileFrame* ptFrame = gTPProfileContext->ptLastFrame; plProfileFrame* ptFrame = gptProfileContext->ptThreadData[uThreadIndex].ptLastFrame;
if(puSize) if(puSize)
*puSize = ptFrame->uTotalSampleSize; *puSize = ptFrame->uTotalSampleSize;

View File

@ -1,15 +1,26 @@
/* /*
pl_stl.h pl_stl.h
* no dependencies
* simple asci & binary stl parser
Do this:
#define PL_STL_IMPLEMENTATION
before you include this file in *one* C or C++ file to create the implementation.
// i.e. it should look like this:
#include ...
#include ...
#include ...
#define PL_STL_IMPLEMENTATION
#include "pl_stl.h"
*/ */
// 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 +34,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 +55,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 +109,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 +136,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;

View File

@ -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,20 @@ pl_str_get_file_name_only(const char* pcFilePath, char* pcFileOut)
if(uSlashCount == 0) if(uSlashCount == 0)
{ {
if(pcFileOut) strcpy(pcFileOut, &pcFilePath[i + 1]); strncpy(pcFileOut, &pcFilePath[i + 1], szOutSize);
pcResult = &pcFilePath[i + 1];
break; break;
} }
} }
} }
else else
{ {
if(pcFileOut) memcpy(pcFileOut, pcFilePath, szLen + 1); 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 +316,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 +342,7 @@ pl_str_get_directory(const char* pcFilePath, char* pcDirectoryOut)
pcDirectoryOut[0] = '.'; pcDirectoryOut[0] = '.';
pcDirectoryOut[1] = '/'; pcDirectoryOut[1] = '/';
} }
return true;
} }
bool bool
@ -333,7 +353,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;
} }

240
pl_test.h
View File

@ -1,5 +1,7 @@
/* /*
pl_test pl_test.h
* simple test librsry
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 +11,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 +41,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 +50,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 +60,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 +92,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 +128,14 @@ 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;
static bool gbActiveColor = 0;
#endif
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// [SECTION] includes // [SECTION] includes
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -135,7 +171,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 +188,30 @@ 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;
gbActiveColor = true;
gtStdOutHandle = GetStdHandle(STD_OUTPUT_HANDLE);
if(gtStdOutHandle == INVALID_HANDLE_VALUE)
gbActiveColor = false;
else if(!GetConsoleMode(gtStdOutHandle, &tCurrentMode))
gbActiveColor = false;
gtOriginalMode = tCurrentMode;
tCurrentMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; // enable ANSI escape codes
if(!SetConsoleMode(gtStdOutHandle, tCurrentMode))
gbActiveColor = false;
if(!gbActiveColor)
tOptions.bPrintColor = false;
#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 +236,70 @@ 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(gbActiveColor)
{
if(!SetConsoleMode(gtStdOutHandle, gtOriginalMode))
exit(GetLastError());
}
#endif
return gptTestContext->uTotalFailedTests == 0;
} }
bool bool
@ -210,6 +307,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 +327,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 +407,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 +427,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 +437,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 +452,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 +478,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(""); printf("");
#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 +498,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(""); printf("");
#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(""); printf("");
#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 +530,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(""); printf("");
#else #else
printf("\033[0m"); printf("\033[0m");
#endif #endif
} }
}
#endif // PL_TEST_IMPLEMENTATION #endif // PL_TEST_IMPLEMENTATION

View File

@ -1,26 +1,51 @@
#include "pl_ds_tests.h" #include "pl_ds_tests.h"
#include "pl_json_tests.h" #include "pl_json_tests.h"
#include "pl_memory_tests.h"
#include "pl_string_tests.h"
int main() int main()
{ {
plTestContext* ptTestContext = pl_create_test_context(); // create test context
plTestOptions tOptions = {
.bPrintSuiteResults = true,
.bPrintColor = true
};
plTestContext* ptTestContext = pl_create_test_context(tOptions);
// data structure tests // pl_json.h tests
pl_test_register_test(hashmap_test_0, NULL); pl_json_tests(NULL);
pl_test_run_suite("pl_json.h");
// json tests // pl_memory.h tests
pl_test_register_test(json_test_0, NULL); pl_memory_tests(NULL);
pl_test_run_suite("pl_memory.h");
if(!pl_test_run()) // pl_ds.h tests
pl_ds_tests(NULL);
pl_test_run_suite("pl_ds.h");
// pl_string.h tests
pl_string_tests(NULL);
pl_test_run_suite("pl_string.h");
bool bResult = pl_test_finish();
if(!bResult)
{ {
exit(1); exit(1);
} }
return 0; return 0;
} }
#define PL_TEST_IMPLEMENTATION
#include "pl_test.h"
#define PL_JSON_IMPLEMENTATION #define PL_JSON_IMPLEMENTATION
#include "pl_json.h" #include "pl_json.h"
#define PL_MEMORY_IMPLEMENTATION
#include "pl_memory.h"
#define PL_STRING_IMPLEMENTATION
#include "pl_string.h"
#define PL_TEST_WIN32_COLOR
#define PL_TEST_IMPLEMENTATION
#include "pl_test.h"

View File

@ -6,97 +6,104 @@
#include <stdint.h> #include <stdint.h>
#include "pl_ds.h" #include "pl_ds.h"
static void void
hashmap_test_0(void* pData) hashmap_test_0(void* pData)
{ {
// hashmap 0 plHashMap* ptHashMap = NULL;
{
plHashMap tHashMap = {0};
int* sbiValues = NULL; int* sbiValues = NULL;
pl_sb_push(sbiValues, 0); pl_sb_push(sbiValues, 0);
pl_sb_push(sbiValues, 69); pl_sb_push(sbiValues, 69);
pl_hm_insert(&tHashMap, pl_hm_hash_str("Dirty Number"), pl_sb_size(sbiValues) - 1); pl_hm_insert(ptHashMap, pl_hm_hash_str("Dirty Number"), pl_sb_size(sbiValues) - 1);
pl_sb_push(sbiValues, 117); pl_sb_push(sbiValues, 117);
pl_hm_insert(&tHashMap, pl_hm_hash_str("Spartan Number"), pl_sb_size(sbiValues) - 1); pl_hm_insert(ptHashMap, pl_hm_hash_str("Spartan Number"), pl_sb_size(sbiValues) - 1);
for(uint32_t i = 0; i < 3000; i++) for(uint32_t i = 0; i < 3000; i++)
{ {
pl_sb_push(sbiValues, i); pl_sb_push(sbiValues, i);
pl_hm_insert(&tHashMap, pl_hm_hash("Spartan Number2", strlen("Spartan Number2"), i), pl_sb_size(sbiValues) - 1); pl_hm_insert(ptHashMap, pl_hm_hash("Spartan Number2", strlen("Spartan Number2"), i), pl_sb_size(sbiValues) - 1);
} }
pl_test_expect_int_equal(sbiValues[pl_hm_lookup(&tHashMap, pl_hm_hash_str("Dirty Number"))], 69, NULL); pl_test_expect_int_equal(sbiValues[pl_hm_lookup(ptHashMap, pl_hm_hash_str("Dirty Number"))], 69, NULL);
pl_test_expect_int_equal(sbiValues[pl_hm_lookup(&tHashMap, pl_hm_hash_str("Spartan Number"))], 117, NULL); pl_test_expect_int_equal(sbiValues[pl_hm_lookup(ptHashMap, pl_hm_hash_str("Spartan Number"))], 117, NULL);
pl_hm_remove(&tHashMap, pl_hm_hash_str("Dirty Number")); pl_hm_remove(ptHashMap, pl_hm_hash_str("Dirty Number"));
uint64_t ulFreeIndex = pl_hm_get_free_index(&tHashMap); uint64_t ulFreeIndex = pl_hm_get_free_index(ptHashMap);
if(ulFreeIndex == UINT64_MAX) if(ulFreeIndex == UINT64_MAX)
{ {
pl_sb_add(sbiValues); pl_sb_add(sbiValues);
ulFreeIndex = pl_sb_size(sbiValues) - 1; ulFreeIndex = pl_sb_size(sbiValues) - 1;
} }
sbiValues[ulFreeIndex] = 666999; sbiValues[ulFreeIndex] = 666999;
pl_hm_insert(&tHashMap, pl_hm_hash_str("Extra dirty number"), ulFreeIndex); pl_hm_insert(ptHashMap, pl_hm_hash_str("Extra dirty number"), ulFreeIndex);
pl_test_expect_int_equal(sbiValues[pl_hm_lookup(&tHashMap, pl_hm_hash_str("Extra dirty number"))], 666999, NULL); pl_test_expect_int_equal(sbiValues[pl_hm_lookup(ptHashMap, pl_hm_hash_str("Extra dirty number"))], 666999, NULL);
pl_test_expect_int_equal(sbiValues[pl_hm_lookup(&tHashMap, pl_hm_hash_str("Extra dirty number"))], 666999, NULL); pl_test_expect_int_equal(sbiValues[pl_hm_lookup(ptHashMap, pl_hm_hash_str("Extra dirty number"))], 666999, NULL);
pl_test_expect_int_equal(sbiValues[pl_hm_lookup(&tHashMap, pl_hm_hash_str("Spartan Number"))], 117, NULL); pl_test_expect_int_equal(sbiValues[pl_hm_lookup(ptHashMap, pl_hm_hash_str("Spartan Number"))], 117, NULL);
pl_hm_free(&tHashMap); pl_hm_free(ptHashMap);
pl_sb_free(sbiValues); pl_sb_free(sbiValues);
} }
// hashmap 1 void
hashmap_test_1(void* pData)
{ {
plHashMap tHashMap = {0}; plHashMap* ptHashMap = NULL;
pl_hm_insert(&tHashMap, pl_hm_hash_str("Dirty Number"), 69); pl_hm_insert(ptHashMap, pl_hm_hash_str("Dirty Number"), 69);
pl_hm_insert(&tHashMap, pl_hm_hash_str("Spartan Number"), 117); pl_hm_insert(ptHashMap, pl_hm_hash_str("Spartan Number"), 117);
pl_test_expect_int_equal((int)pl_hm_lookup(&tHashMap, pl_hm_hash_str("Dirty Number")), 69, NULL); pl_test_expect_int_equal((int)pl_hm_lookup(ptHashMap, pl_hm_hash_str("Dirty Number")), 69, NULL);
pl_test_expect_int_equal((int)pl_hm_lookup(&tHashMap, pl_hm_hash_str("Spartan Number")), 117, NULL); pl_test_expect_int_equal((int)pl_hm_lookup(ptHashMap, pl_hm_hash_str("Spartan Number")), 117, NULL);
pl_hm_free(&tHashMap); pl_hm_free(ptHashMap);
} }
// hashmap 2 void
hashmap_test_2(void* pData)
{ {
plHashMap tHashMap = {0}; plHashMap* ptHashMap = NULL;
int* sbiValues = NULL; int* sbiValues = NULL;
pl_sb_push(sbiValues, 0); pl_sb_push(sbiValues, 0);
pl_sb_push(sbiValues, 69); pl_sb_push(sbiValues, 69);
pl_hm_insert_str(&tHashMap, "Dirty Number", pl_sb_size(sbiValues) - 1); pl_hm_insert_str(ptHashMap, "Dirty Number", pl_sb_size(sbiValues) - 1);
pl_sb_push(sbiValues, 117); pl_sb_push(sbiValues, 117);
pl_hm_insert_str(&tHashMap, "Spartan Number", pl_sb_size(sbiValues) - 1); pl_hm_insert_str(ptHashMap, "Spartan Number", pl_sb_size(sbiValues) - 1);
for(uint32_t i = 0; i < 79; i++) for(uint32_t i = 0; i < 79; i++)
{ {
pl_sb_push(sbiValues, 118); pl_sb_push(sbiValues, 118);
pl_hm_insert_str(&tHashMap, "Spartan Number2", pl_sb_size(sbiValues) - 1); pl_hm_insert_str(ptHashMap, "Spartan Number2", pl_sb_size(sbiValues) - 1);
} }
pl_test_expect_int_equal(sbiValues[pl_hm_lookup_str(&tHashMap, "Dirty Number")], 69, NULL); pl_test_expect_int_equal(sbiValues[pl_hm_lookup_str(ptHashMap, "Dirty Number")], 69, NULL);
pl_test_expect_int_equal(sbiValues[pl_hm_lookup_str(&tHashMap, "Spartan Number")], 117, NULL); pl_test_expect_int_equal(sbiValues[pl_hm_lookup_str(ptHashMap, "Spartan Number")], 117, NULL);
pl_hm_remove_str(&tHashMap, "Dirty Number"); pl_hm_remove_str(ptHashMap, "Dirty Number");
uint64_t ulFreeIndex = pl_hm_get_free_index(&tHashMap); uint64_t ulFreeIndex = pl_hm_get_free_index(ptHashMap);
if(ulFreeIndex == UINT64_MAX) if(ulFreeIndex == UINT64_MAX)
{ {
pl_sb_add(sbiValues); pl_sb_add(sbiValues);
ulFreeIndex = pl_sb_size(sbiValues) - 1; ulFreeIndex = pl_sb_size(sbiValues) - 1;
} }
sbiValues[ulFreeIndex] = 666999; sbiValues[ulFreeIndex] = 666999;
pl_hm_insert_str(&tHashMap, "Extra dirty number", ulFreeIndex); pl_hm_insert_str(ptHashMap, "Extra dirty number", ulFreeIndex);
pl_test_expect_int_equal(sbiValues[pl_hm_lookup_str(&tHashMap, "Extra dirty number")], 666999, NULL); pl_test_expect_int_equal(sbiValues[pl_hm_lookup_str(ptHashMap, "Extra dirty number")], 666999, NULL);
pl_test_expect_int_equal(sbiValues[pl_hm_lookup_str(&tHashMap, "Extra dirty number")], 666999, NULL); pl_test_expect_int_equal(sbiValues[pl_hm_lookup_str(ptHashMap, "Extra dirty number")], 666999, NULL);
pl_test_expect_int_equal(sbiValues[pl_hm_lookup_str(&tHashMap, "Spartan Number")], 117, NULL); pl_test_expect_int_equal(sbiValues[pl_hm_lookup_str(ptHashMap, "Spartan Number")], 117, NULL);
pl_hm_free(&tHashMap); pl_hm_free(ptHashMap);
pl_sb_free(sbiValues); pl_sb_free(sbiValues);
} }
void
pl_ds_tests(void* pData)
{
pl_test_register_test(hashmap_test_0, NULL);
pl_test_register_test(hashmap_test_1, NULL);
pl_test_register_test(hashmap_test_2, NULL);
} }

View File

@ -6,82 +6,82 @@
#include <stdint.h> #include <stdint.h>
#include "pl_json.h" #include "pl_json.h"
static void void
json_test_0(void* pData) write_json_test(void* pData)
{ {
char* pcBuffer = NULL; char** ppcBuffer = pData;
// write json
{
// root object // root object
plJsonObject tRootJsonObject = {0}; plJsonObject* ptRootJsonObject = pl_json_new_root_object("ROOT");
pl_json_add_string_member(&tRootJsonObject, "first name", "John"); pl_json_add_string_member(ptRootJsonObject, "first name", "John");
pl_json_add_string_member(&tRootJsonObject, "last name", "Doe"); pl_json_add_string_member(ptRootJsonObject, "last name", "Doe");
pl_json_add_int_member(&tRootJsonObject, "age", 40); pl_json_add_int_member(ptRootJsonObject, "age", 40);
pl_json_add_bool_member(&tRootJsonObject, "tall", false); pl_json_add_bool_member(ptRootJsonObject, "tall", false);
pl_json_add_bool_member(&tRootJsonObject, "hungry", true); pl_json_add_bool_member(ptRootJsonObject, "hungry", true);
int aScores[] = {100, 86, 46}; int aScores[] = {100, 86, 46};
pl_json_add_int_array(&tRootJsonObject, "scores", aScores, 3); pl_json_add_int_array(ptRootJsonObject, "scores", aScores, 3);
char* aPets[] = {"Riley", "Luna", "Chester"}; char* aPets[] = {"Riley", "Luna", "Chester"};
pl_json_add_string_array(&tRootJsonObject, "pets", aPets, 3); pl_json_add_string_array(ptRootJsonObject, "pets", aPets, 3);
// member object // member object
plJsonObject tBestFriend = {0};
pl_json_add_string_member(&tBestFriend, "first name", "John");
pl_json_add_string_member(&tBestFriend, "last name", "Doe");
pl_json_add_int_member(&tBestFriend, "age", 40);
pl_json_add_bool_member(&tBestFriend, "tall", false);
pl_json_add_bool_member(&tBestFriend, "hungry", true);
pl_json_add_string_array(&tBestFriend, "pets", aPets, 3);
pl_json_add_int_array(&tBestFriend, "scores", aScores, 3);
pl_json_add_member(&tRootJsonObject, "best friend", &tBestFriend); plJsonObject* ptBestFriend = pl_json_add_member(ptRootJsonObject, "best friend");
pl_json_add_string_member(ptBestFriend, "first name", "John");
pl_json_add_string_member(ptBestFriend, "last name", "Doe");
pl_json_add_int_member(ptBestFriend, "age", 40);
pl_json_add_bool_member(ptBestFriend, "tall", false);
pl_json_add_bool_member(ptBestFriend, "hungry", true);
pl_json_add_string_array(ptBestFriend, "pets", aPets, 3);
pl_json_add_int_array(ptBestFriend, "scores", aScores, 3);
// friend member object // friend member object
plJsonObject atFriends[2] = {0}; plJsonObject* ptFriends = pl_json_add_member_array(ptRootJsonObject, "friends", 2);
plJsonObject* ptFriend0 = pl_json_member_by_index(ptFriends, 0);
int aScores0[] = {88, 86, 100}; int aScores0[] = {88, 86, 100};
pl_json_add_string_member(&atFriends[0], "first name", "Jacob"); pl_json_add_string_member(ptFriend0, "first name", "Jacob");
pl_json_add_string_member(&atFriends[0], "last name", "Smith"); pl_json_add_string_member(ptFriend0, "last name", "Smith");
pl_json_add_int_member(&atFriends[0], "age", 23); pl_json_add_int_member(ptFriend0, "age", 23);
pl_json_add_bool_member(&atFriends[0], "tall", true); pl_json_add_bool_member(ptFriend0, "tall", true);
pl_json_add_bool_member(&atFriends[0], "hungry", false); pl_json_add_bool_member(ptFriend0, "hungry", false);
pl_json_add_int_array(&atFriends[0], "scores", aScores0, 3); pl_json_add_int_array(ptFriend0, "scores", aScores0, 3);
plJsonObject* ptFriend1 = pl_json_member_by_index(ptFriends, 1);
int aScores1[] = {80, 80, 100}; int aScores1[] = {80, 80, 100};
pl_json_add_string_member(&atFriends[1], "first name", "Chance"); pl_json_add_string_member(ptFriend1, "first name", "Chance");
pl_json_add_string_member(&atFriends[1], "last name", "Dale"); pl_json_add_string_member(ptFriend1, "last name", "Dale");
pl_json_add_int_member(&atFriends[1], "age", 48); pl_json_add_int_member(ptFriend1, "age", 48);
pl_json_add_bool_member(&atFriends[1], "tall", true); pl_json_add_bool_member(ptFriend1, "tall", true);
pl_json_add_bool_member(&atFriends[1], "hungry", true); pl_json_add_bool_member(ptFriend1, "hungry", true);
pl_json_add_int_array(&atFriends[1], "scores", aScores1, 3); pl_json_add_int_array(ptFriend1, "scores", aScores1, 3);
pl_json_add_member_array(&tRootJsonObject, "friends", atFriends, 2);
uint32_t uBufferSize = 0; uint32_t uBufferSize = 0;
pl_write_json(&tRootJsonObject, NULL, &uBufferSize); pl_write_json(ptRootJsonObject, NULL, &uBufferSize);
pcBuffer = malloc(uBufferSize + 1); *ppcBuffer = malloc(uBufferSize + 1);
memset(pcBuffer, 0, uBufferSize + 1); memset(*ppcBuffer, 0, uBufferSize + 1);
pl_write_json(&tRootJsonObject, pcBuffer, &uBufferSize); pl_write_json(ptRootJsonObject, *ppcBuffer, &uBufferSize);
pl_unload_json(&tRootJsonObject); pl_unload_json(&ptRootJsonObject);
} }
// read json void
read_json_test(void* pData)
{ {
plJsonObject tRootJsonObject = {0}; char** ppcBuffer = pData;
pl_load_json(pcBuffer, &tRootJsonObject);
plJsonObject* ptRootJsonObject = NULL;
pl_load_json(*ppcBuffer, &ptRootJsonObject);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~reading~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~reading~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// check root members // check root members
{ {
int aiScores[3] = {0}; int aiScores[3] = {0};
pl_json_int_array_member(&tRootJsonObject, "scores", aiScores, NULL); pl_json_int_array_member(ptRootJsonObject, "scores", aiScores, NULL);
pl_test_expect_int_equal(aiScores[0], 100, NULL); pl_test_expect_int_equal(aiScores[0], 100, NULL);
pl_test_expect_int_equal(aiScores[1], 86, NULL); pl_test_expect_int_equal(aiScores[1], 86, NULL);
pl_test_expect_int_equal(aiScores[2], 46, NULL); pl_test_expect_int_equal(aiScores[2], 46, NULL);
@ -92,7 +92,7 @@ json_test_0(void* pData)
char acPet2[64] = {0}; char acPet2[64] = {0};
char* aacPets[3] = {acPet0, acPet1, acPet2}; char* aacPets[3] = {acPet0, acPet1, acPet2};
uint32_t auLengths[3] = {64, 64, 64}; uint32_t auLengths[3] = {64, 64, 64};
pl_json_string_array_member(&tRootJsonObject, "pets", aacPets, NULL, auLengths); pl_json_string_array_member(ptRootJsonObject, "pets", aacPets, NULL, auLengths);
pl_test_expect_string_equal(acPet0, "Riley", NULL); pl_test_expect_string_equal(acPet0, "Riley", NULL);
pl_test_expect_string_equal(acPet1, "Luna", NULL); pl_test_expect_string_equal(acPet1, "Luna", NULL);
pl_test_expect_string_equal(acPet2, "Chester", NULL); pl_test_expect_string_equal(acPet2, "Chester", NULL);
@ -100,14 +100,14 @@ json_test_0(void* pData)
char acFirstName[64] = {0}; char acFirstName[64] = {0};
char acLastName[64] = {0}; char acLastName[64] = {0};
pl_test_expect_string_equal(pl_json_string_member(&tRootJsonObject, "first name", acFirstName, 64), "John", NULL); pl_test_expect_string_equal(pl_json_string_member(ptRootJsonObject, "first name", acFirstName, 64), "John", NULL);
pl_test_expect_string_equal(pl_json_string_member(&tRootJsonObject, "last name", acLastName, 64), "Doe", NULL); pl_test_expect_string_equal(pl_json_string_member(ptRootJsonObject, "last name", acLastName, 64), "Doe", NULL);
pl_test_expect_int_equal(pl_json_int_member(&tRootJsonObject, "age", 0), 40, NULL); pl_test_expect_int_equal(pl_json_int_member(ptRootJsonObject, "age", 0), 40, NULL);
pl_test_expect_false(pl_json_bool_member(&tRootJsonObject, "tall", false), NULL); pl_test_expect_false(pl_json_bool_member(ptRootJsonObject, "tall", false), NULL);
pl_test_expect_true(pl_json_bool_member(&tRootJsonObject, "hungry", false), NULL); pl_test_expect_true(pl_json_bool_member(ptRootJsonObject, "hungry", false), NULL);
// check child members // check child members
plJsonObject* ptBestFriend = pl_json_member(&tRootJsonObject, "best friend"); plJsonObject* ptBestFriend = pl_json_member(ptRootJsonObject, "best friend");
{ {
int aiScores[3] = {0}; int aiScores[3] = {0};
pl_json_int_array_member(ptBestFriend, "scores", aiScores, NULL); pl_json_int_array_member(ptBestFriend, "scores", aiScores, NULL);
@ -134,10 +134,10 @@ json_test_0(void* pData)
pl_test_expect_true(pl_json_bool_member(ptBestFriend, "hungry", false), NULL); pl_test_expect_true(pl_json_bool_member(ptBestFriend, "hungry", false), NULL);
uint32_t uFriendCount = 0; uint32_t uFriendCount = 0;
plJsonObject* sbtFriends = pl_json_array_member(&tRootJsonObject, "friends", &uFriendCount); plJsonObject* ptFriends = pl_json_array_member(ptRootJsonObject, "friends", &uFriendCount);
plJsonObject* ptFriend0 = &sbtFriends[0]; plJsonObject* ptFriend0 = pl_json_member_by_index(ptFriends, 0);
plJsonObject* ptFriend1 = &sbtFriends[1]; plJsonObject* ptFriend1 = pl_json_member_by_index(ptFriends, 1);
{ {
int aiScores[3] = {0}; int aiScores[3] = {0};
pl_json_int_array_member(ptFriend0, "scores", aiScores, NULL); pl_json_int_array_member(ptFriend0, "scores", aiScores, NULL);
@ -166,6 +166,16 @@ json_test_0(void* pData)
pl_test_expect_true(pl_json_bool_member(ptFriend1, "tall", false), NULL); pl_test_expect_true(pl_json_bool_member(ptFriend1, "tall", false), NULL);
pl_test_expect_true(pl_json_bool_member(ptFriend1, "hungry", false), NULL); pl_test_expect_true(pl_json_bool_member(ptFriend1, "hungry", false), NULL);
pl_unload_json(&tRootJsonObject); pl_unload_json(&ptRootJsonObject);
} }
void
pl_json_tests(void* pData)
{
static char* pcBuffer = NULL;
pl_test_register_test(write_json_test, &pcBuffer);
pl_test_register_test(read_json_test, &pcBuffer);
} }

157
tests/pl_memory_tests.h Normal file
View File

@ -0,0 +1,157 @@
#include "pl_test.h"
#include "pl_memory.h"
#include <string.h> // memset
typedef struct _plTestStruct
{
const char* pcName;
int iAge;
} plTestStruct;
void
memory_test_aligned_alloc(void* pData)
{
int* iBuffer0 = pl_aligned_alloc(0, sizeof(int));
pl_test_expect_uint64_equal(((uint64_t)iBuffer0) % 4, 0, NULL);
pl_aligned_free(iBuffer0);
int* iBuffer1 = pl_aligned_alloc(16, sizeof(int));
pl_test_expect_uint64_equal(((uint64_t)iBuffer1) % 16, 0, NULL);
pl_aligned_free(iBuffer1);
}
void
memory_test_pool_allocator_0(void* pData)
{
// here we are testing standard usage
plPoolAllocator tAllocator = {0};
// let library tell use required buffer size
size_t szRequiredBufferSize = 0;
pl_pool_allocator_init(&tAllocator, 5, sizeof(int), 0, &szRequiredBufferSize, NULL);
int* iBuffer = malloc(szRequiredBufferSize);
memset(iBuffer, 0, szRequiredBufferSize);
pl_pool_allocator_init(&tAllocator, 5, sizeof(int), 0, &szRequiredBufferSize, iBuffer);
int* iItem0 = pl_pool_allocator_alloc(&tAllocator);
int* iItem1 = pl_pool_allocator_alloc(&tAllocator);
int* iItem2 = pl_pool_allocator_alloc(&tAllocator);
int* iItem3 = pl_pool_allocator_alloc(&tAllocator);
int* iItem4 = pl_pool_allocator_alloc(&tAllocator);
int* iItem5 = pl_pool_allocator_alloc(&tAllocator);
*iItem0 = 0;
*iItem1 = 1;
*iItem2 = 2;
*iItem3 = 3;
*iItem4 = 4;
pl_test_expect_int_equal(*iItem0, 0, NULL);
pl_test_expect_int_equal(*iItem1, 1, NULL);
pl_test_expect_int_equal(*iItem2, 2, NULL);
pl_test_expect_int_equal(*iItem3, 3, NULL);
pl_test_expect_int_equal(*iItem4, 4, NULL);
pl_test_expect_uint64_equal(((uint64_t)iItem5), 0, NULL);
free(iBuffer);
}
void
memory_test_pool_allocator_1(void* pData)
{
// here we are testing usage with stack allocated memory
plPoolAllocator tAllocator = {0};
plTestStruct atData[5] = {0};
// let library tell use required buffer size
size_t szRequiredBufferSize = sizeof(atData);
size_t szItemCount = pl_pool_allocator_init(&tAllocator, 0, sizeof(plTestStruct), 0, &szRequiredBufferSize, atData);
pl_pool_allocator_init(&tAllocator, szItemCount, sizeof(plTestStruct), 0, &szRequiredBufferSize, atData);
pl_test_expect_int_equal((int)szItemCount, 4, NULL);
plTestStruct* ptData0 = pl_pool_allocator_alloc(&tAllocator);
plTestStruct* ptData1 = pl_pool_allocator_alloc(&tAllocator);
plTestStruct* ptData2 = pl_pool_allocator_alloc(&tAllocator);
plTestStruct* ptData3 = pl_pool_allocator_alloc(&tAllocator);
plTestStruct* ptData4 = pl_pool_allocator_alloc(&tAllocator);
ptData0->iAge = 0;
ptData1->iAge = 1;
ptData2->iAge = 2;
ptData3->iAge = 3;
ptData0->pcName = "John";
ptData1->pcName = "James";
ptData2->pcName = "Mark";
ptData3->pcName = "Matt";
pl_test_expect_int_equal(ptData0->iAge, 0, NULL);
pl_test_expect_int_equal(ptData1->iAge, 1, NULL);
pl_test_expect_int_equal(ptData2->iAge, 2, NULL);
pl_test_expect_int_equal(ptData3->iAge, 3, NULL);
pl_test_expect_string_equal(ptData0->pcName, "John", NULL);
pl_test_expect_string_equal(ptData1->pcName, "James", NULL);
pl_test_expect_string_equal(ptData2->pcName, "Mark", NULL);
pl_test_expect_string_equal(ptData3->pcName, "Matt", NULL);
pl_test_expect_uint64_equal(((uint64_t)ptData4), 0, NULL);
pl_pool_allocator_free(&tAllocator, ptData1);
plTestStruct* ptData5 = pl_pool_allocator_alloc(&tAllocator);
pl_test_expect_uint64_not_equal(((uint64_t)ptData5), 0, NULL);
}
void
memory_test_stack_allocator_0(void* pData)
{
char acBuffer[1024] = {0};
plStackAllocator tAllocator = {0};
pl_stack_allocator_init(&tAllocator, 1024, acBuffer);
plTestStruct* ptData0 = pl_stack_allocator_alloc(&tAllocator, sizeof(plTestStruct));
ptData0->pcName = "John";
ptData0->iAge = 31;
plStackAllocatorMarker tMarker0 = pl_stack_allocator_marker(&tAllocator);
plTestStruct* ptData1 = pl_stack_allocator_alloc(&tAllocator, sizeof(plTestStruct));
ptData0->pcName = "Rachael";
ptData0->iAge = 32;
pl_stack_allocator_free_to_marker(&tAllocator, tMarker0);
plTestStruct* ptData2 = pl_stack_allocator_alloc(&tAllocator, sizeof(plTestStruct));
ptData0->pcName = "Charlie";
ptData0->iAge = 4;
pl_test_expect_uint64_equal((uint64_t)ptData1, (uint64_t)ptData2, NULL);
}
void
memory_test_temp_allocator_0(void* pData)
{
plTempAllocator tAllocator = {0};
char* pcBuffer0 = pl_temp_allocator_alloc(&tAllocator, 256);
char* pcBuffer1 = pl_temp_allocator_alloc(&tAllocator, 256);
char* pcBuffer2 = pl_temp_allocator_alloc(&tAllocator, 256);
char* pcBuffer3 = pl_temp_allocator_alloc(&tAllocator, 256);
char* pcBuffer4 = pl_temp_allocator_alloc(&tAllocator, 256);
pl_temp_allocator_free(&tAllocator);
}
void
pl_memory_tests(void* pData)
{
pl_test_register_test(memory_test_aligned_alloc, NULL);
pl_test_register_test(memory_test_pool_allocator_0, NULL);
pl_test_register_test(memory_test_pool_allocator_1, NULL);
pl_test_register_test(memory_test_stack_allocator_0, NULL);
pl_test_register_test(memory_test_temp_allocator_0, NULL);
}

78
tests/pl_string_tests.h Normal file
View File

@ -0,0 +1,78 @@
#include "pl_test.h"
#include "pl_string.h"
void
string_test_0(void* pData)
{
const char* pcFilePath0 = "C:/Users/hoffstadt/file1.txt";
const char* pcFilePath1 = "C:\\Users\\hoffstadt\\file1.txt";
const char* pcFilePath2 = "C:\\Users/hoffstadt\\file1.txt";
const char* pcFilePath3 = "file1.txt";
const char* pcFilePath4 = "file1";
const char* pcExt0 = pl_str_get_file_extension(pcFilePath0, NULL, 0);
const char* pcExt1 = pl_str_get_file_extension(pcFilePath1, NULL, 0);
const char* pcExt2 = pl_str_get_file_extension(pcFilePath2, NULL, 0);
const char* pcExt3 = pl_str_get_file_extension(pcFilePath3, NULL, 0);
const char* pcExt4 = pl_str_get_file_extension(pcFilePath4, NULL, 0);
pl_test_expect_string_equal(pcExt0, "txt", NULL);
pl_test_expect_string_equal(pcExt1, "txt", NULL);
pl_test_expect_string_equal(pcExt2, "txt", NULL);
pl_test_expect_string_equal(pcExt3, "txt", NULL);
pl_test_expect_uint64_equal(((uint64_t)pcExt4), 0, NULL);
const char* pcFile0 = pl_str_get_file_name(pcFilePath0, NULL, 0);
const char* pcFile1 = pl_str_get_file_name(pcFilePath1, NULL, 0);
const char* pcFile2 = pl_str_get_file_name(pcFilePath2, NULL, 0);
const char* pcFile3 = pl_str_get_file_name(pcFilePath3, NULL, 0);
const char* pcFile4 = pl_str_get_file_name(pcFilePath4, NULL, 0);
pl_test_expect_string_equal(pcFile0, "file1.txt", "pl_str_get_file_name");
pl_test_expect_string_equal(pcFile1, "file1.txt", "pl_str_get_file_name");
pl_test_expect_string_equal(pcFile2, "file1.txt", "pl_str_get_file_name");
pl_test_expect_string_equal(pcFile3, "file1.txt", "pl_str_get_file_name");
pl_test_expect_string_equal(pcFile4, "file1", "pl_str_get_file_name");
char acFileName0[256] = {0};
char acFileName1[256] = {0};
char acFileName2[256] = {0};
char acFileName3[256] = {0};
char acFileName4[256] = {0};
pl_str_get_file_name_only(pcFilePath0, acFileName0, 256);
pl_str_get_file_name_only(pcFilePath1, acFileName1, 256);
pl_str_get_file_name_only(pcFilePath2, acFileName2, 256);
pl_str_get_file_name_only(pcFilePath3, acFileName3, 256);
pl_str_get_file_name_only(pcFilePath4, acFileName4, 256);
pl_test_expect_string_equal(acFileName0, "file1", "pl_str_get_file_name_only");
pl_test_expect_string_equal(acFileName1, "file1", "pl_str_get_file_name_only");
pl_test_expect_string_equal(acFileName2, "file1", "pl_str_get_file_name_only");
pl_test_expect_string_equal(acFileName3, "file1", "pl_str_get_file_name_only");
pl_test_expect_string_equal(acFileName4, "file1", "pl_str_get_file_name_only");
char acDirectory0[128] = {0};
char acDirectory1[128] = {0};
char acDirectory2[128] = {0};
char acDirectory3[128] = {0};
char acDirectory4[128] = {0};
pl_str_get_directory(pcFilePath0, acDirectory0, 128);
pl_str_get_directory(pcFilePath1, acDirectory1, 128);
pl_str_get_directory(pcFilePath2, acDirectory2, 128);
pl_str_get_directory(pcFilePath3, acDirectory3, 128);
pl_str_get_directory(pcFilePath4, acDirectory4, 128);
pl_test_expect_string_equal(acDirectory0, "C:/Users/hoffstadt/", NULL);
pl_test_expect_string_equal(acDirectory1, "C:\\Users\\hoffstadt\\", NULL);
pl_test_expect_string_equal(acDirectory2, "C:\\Users/hoffstadt\\", NULL);
pl_test_expect_string_equal(acDirectory3, "./", NULL);
pl_test_expect_string_equal(acDirectory4, "./", NULL);
}
void
pl_string_tests(void* pData)
{
pl_test_register_test(string_test_0, NULL);
}