From aebd939d7de65fcbdea6027156d739b9f8bee267 Mon Sep 17 00:00:00 2001 From: Jonathan Hoffstadt Date: Mon, 18 Nov 2024 19:54:23 -0600 Subject: [PATCH] build: 1.0 --- README.md | 46 ++ pl_ds.h | 244 ++++---- pl_json.h | 1167 ++++++++++++++++++++------------------- pl_log.h | 987 +++++++++++++++++---------------- pl_math.h | 165 +++--- pl_memory.h | 304 +++++----- pl_profile.h | 200 ++++--- pl_stl.h | 35 +- pl_string.h | 75 ++- pl_test.h | 308 +++++++---- tests/main_tests.c | 49 +- tests/pl_ds_tests.h | 167 +++--- tests/pl_json_tests.h | 310 ++++++----- tests/pl_memory_tests.h | 157 ++++++ tests/pl_string_tests.h | 78 +++ 15 files changed, 2466 insertions(+), 1826 deletions(-) create mode 100644 README.md create mode 100644 tests/pl_memory_tests.h create mode 100644 tests/pl_string_tests.h diff --git a/README.md b/README.md new file mode 100644 index 0000000..063a7b1 --- /dev/null +++ b/README.md @@ -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. \ No newline at end of file diff --git a/pl_ds.h b/pl_ds.h index a5184ad..22d415f 100644 --- a/pl_ds.h +++ b/pl_ds.h @@ -3,9 +3,9 @@ * data structures */ -// library version -#define PL_DS_VERSION "0.5.2" -#define PL_DS_VERSION_NUM 00502 +// library version (format XYYZZ) +#define PL_DS_VERSION "1.0.0" +#define PL_DS_VERSION_NUM 10000 /* Index of this file: @@ -15,8 +15,8 @@ Index of this file: // [SECTION] forward declarations // [SECTION] public api (stretchy buffer) // [SECTION] public api (hashmap) -// [SECTION] internal -// [SECTION] public api implementation (hashmap) +// [SECTION] internal (stretchy buffer) +// [SECTION] internal (hashmap) */ //----------------------------------------------------------------------------- @@ -125,16 +125,16 @@ HASHMAPS uint64_t pl_hm_hash(const void* pData, size_t szDataSize, uint64_t uSeed); Returns the CRC64 hash of some arbitrary data. - pl__hm_resize: - void pl__hm_resize(plHashMap*, uint32_t); + pl_hm_resize: + void pl_hm_resize(plHashMap*, uint32_t); Resizes the hashmap or frees it if zero is used. pl_hm_free: void pl_hm_free(plHashMap*); Frees the hashmap internal memory. - pl__hm_insert: - void pl__hm_insert(plHashMap*, uint64_t ulKey, uint64_t ulValue); + pl_hm_insert: + 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 ulValue is the index into the value array. @@ -158,8 +158,8 @@ HASHMAPS bool pl_hm_has_key(plHashMap*, const char*); Same as pl_hm_has_key but performs the hash for you. - pl__hm_insert_str: - void pl__hm_insert_str(plHashMap*, const char* pcKey, uint64_t ulValue); + pl_hm_insert_str: + void pl_hm_insert_str(plHashMap*, const char* pcKey, uint64_t ulValue); Same as pl__hm_insert but performs the hash for you. pl_hm_lookup_str: @@ -173,10 +173,12 @@ HASHMAPS COMPILE TIME OPTIONS * Change allocators by defining both: - PL_LOG_ALLOC(x) - PL_LOG_FREE(x) + PL_DS_ALLOC(x) + PL_DS_FREE(x) * 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 // uint32_t -#include // malloc, free #include // memset, memmove #include // bool #include // arg vars #include // 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) //----------------------------------------------------------------------------- @@ -312,30 +300,43 @@ typedef struct _plHashMap //----------------------------------------------------------------------------- #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) \ - 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) \ - 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 (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); +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); //----------------------------------------------------------------------------- -// [SECTION] internal +// [SECTION] internal (stretchy buffer) //----------------------------------------------------------------------------- #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 -pl__hm_resize(plHashMap* ptHashMap, uint32_t uBucketCount, const char* pcFile, int iLine) +typedef struct plHashMap { + 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; uint64_t* sbulOldValueIndices = ptHashMap->_aulValueIndices; 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) { @@ -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->_aulKeys, 0xff, sizeof(uint64_t) * ptHashMap->_uBucketCount); + uint64_t mask = uOldBucketCount - 1; + for(uint32_t i = 0; i < uOldBucketCount; 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) - ulOldModKey = (ulOldModKey + 1) % uOldBucketCount; + ulOldModKey = (ulOldModKey + 1) & mask; const uint64_t ulValue = sbulOldValueIndices[ulOldModKey]; ptHashMap->_uItemCount--; - pl__hm_insert(ptHashMap, ulKey, ulValue, pcFile, iLine); + pl__hm_insert(pptHashMap, ulKey, ulValue, pcFile, iLine); } } else @@ -452,6 +498,11 @@ pl__hm_resize(plHashMap* ptHashMap, uint32_t uBucketCount, const char* pcFile, i ptHashMap->_aulKeys = NULL; pl_sb_free(ptHashMap->_sbulFreeIndices); ptHashMap->_uItemCount = 0; + if(ptHashMap->_iMemoryOwned) + { + PL_DS_FREE(ptHashMap); + *pptHashMap = NULL; + } } if(sbulOldValueIndices) @@ -465,18 +516,29 @@ pl__hm_resize(plHashMap* ptHashMap, uint32_t uBucketCount, const char* pcFile, i } 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) - 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); + plHashMap* ptHashMap = *pptHashMap; - 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) { - ulModKey = (ulModKey + 1) % ptHashMap->_uBucketCount; + ulModKey = (ulModKey + 1) & mask; if(ptHashMap->_aulKeys[ulModKey] == UINT64_MAX - 1) break; } @@ -487,14 +549,16 @@ pl__hm_insert(plHashMap* ptHashMap, uint64_t ulKey, uint64_t ulValue, const char } 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"); - 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) - ulModKey = (ulModKey + 1) % ptHashMap->_uBucketCount; + ulModKey = (ulModKey + 1) & mask; const uint64_t ulValue = ptHashMap->_aulValueIndices[ulModKey]; 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 -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) 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) - ulModKey = (ulModKey + 1) % ptHashMap->_uBucketCount; + ulModKey = (ulModKey + 1) & mask; if(ptHashMap->_aulKeys[ulModKey] == UINT64_MAX) return UINT64_MAX; @@ -585,8 +654,12 @@ pl_hm_lookup(plHashMap* ptHashMap, uint64_t ulKey) } 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; if(pl_sb_size(ptHashMap->_sbulFreeIndices) > 0) { @@ -595,43 +668,24 @@ pl_hm_get_free_index(plHashMap* ptHashMap) 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 -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) 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) - ulModKey = (ulModKey + 1) % ptHashMap->_uBucketCount; + ulModKey = (ulModKey + 1) & mask; 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 \ No newline at end of file diff --git a/pl_json.h b/pl_json.h index 477c93e..100e987 100644 --- a/pl_json.h +++ b/pl_json.h @@ -1,6 +1,6 @@ /* pl_json.h - + * simple json library Do this: #define PL_JSON_IMPLEMENTATION before you include this file in *one* C or C++ file to create the implementation. @@ -12,9 +12,9 @@ #include "pl_json.h" */ -// library version -#define PL_JSON_VERSION "0.2.0" -#define PL_JSON_VERSION_NUM 00200 +// library version (format XYYZZ) +#define PL_JSON_VERSION "1.0.0" +#define PL_JSON_VERSION_NUM 10000 /* Index of this file: @@ -22,7 +22,7 @@ Index of this file: // [SECTION] includes // [SECTION] forward declarations // [SECTION] public api -// [SECTION] internal structs +// [SECTION] enums // [SECTION] jsmn.h // [SECTION] c file */ @@ -34,125 +34,111 @@ Index of this file: #ifndef PL_JSON_H #define PL_JSON_H -#ifndef PL_JSON_MAX_NAME_LENGTH - #define PL_JSON_MAX_NAME_LENGTH 256 -#endif - //----------------------------------------------------------------------------- // [SECTION] includes //----------------------------------------------------------------------------- -#include -#include +#include // uint*_t +#include // bool //----------------------------------------------------------------------------- // [SECTION] forward declarations //----------------------------------------------------------------------------- // basic types -typedef struct _plJsonObject plJsonObject; // opaque pointer +typedef struct _plJsonObject plJsonObject; // opaque pointer to json object // enums -typedef int plJsonType; // internal +typedef int plJsonType; //----------------------------------------------------------------------------- // [SECTION] public api //----------------------------------------------------------------------------- // main -bool pl_load_json (const char* cPtrJson, plJsonObject* tPtrJsonOut); -void pl_unload_json (plJsonObject* tPtrJson); -char* pl_write_json (plJsonObject* tPtrJson, char* pcBuffer, uint32_t* puBufferSize); +bool pl_load_json (const char* pcJson, plJsonObject** pptJsonOut); +void pl_unload_json (plJsonObject**); +plJsonObject* pl_json_new_root_object(const char* pcName); // for writing +char* pl_write_json (plJsonObject*, char* pcBuffer, uint32_t* puBufferSize); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~reading~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // members -plJsonObject* pl_json_member_by_name (plJsonObject* tPtrJson, const char* pcName); -plJsonObject* pl_json_member_by_index (plJsonObject* tPtrJson, uint32_t uIndex); -void pl_json_member_list (plJsonObject* tPtrJson, char** cPtrListOut, uint32_t* uPtrSizeOut, uint32_t* uPtrLength); -bool pl_json_member_exist (plJsonObject* tPtrJson, const char* pcName); +plJsonObject* pl_json_member_by_index(plJsonObject*, uint32_t uIndex); +void pl_json_member_list (plJsonObject*, char** pcListOut, uint32_t* puSizeOut, uint32_t* puLength); +bool pl_json_member_exist (plJsonObject*, const char* pcName); +plJsonType pl_json_get_type (plJsonObject*); // retrieve and cast values (default used if member isn't present) -int pl_json_int_member (plJsonObject* tPtrJson, const char* pcName, int iDefaultValue); -uint32_t pl_json_uint_member (plJsonObject* tPtrJson, const char* pcName, uint32_t uDefaultValue); -float pl_json_float_member (plJsonObject* tPtrJson, const char* pcName, float fDefaultValue); -double pl_json_double_member (plJsonObject* tPtrJson, const char* pcName, double dDefaultValue); -char* pl_json_string_member (plJsonObject* tPtrJson, const char* pcName, char* cPtrDefaultValue, uint32_t uLength); -bool pl_json_bool_member (plJsonObject* tPtrJson, const char* pcName, bool bDefaultValue); -plJsonObject* pl_json_member (plJsonObject* tPtrJson, const char* pcName); -plJsonObject* pl_json_array_member (plJsonObject* tPtrJson, const char* pcName, uint32_t* uPtrSizeOut); +int pl_json_int_member (plJsonObject*, const char* pcName, int iDefaultValue); +uint32_t pl_json_uint_member (plJsonObject*, const char* pcName, uint32_t uDefaultValue); +float pl_json_float_member (plJsonObject*, const char* pcName, float fDefaultValue); +double pl_json_double_member(plJsonObject*, const char* pcName, double dDefaultValue); +char* pl_json_string_member(plJsonObject*, const char* pcName, char* pcDefaultValue, uint32_t uLength); +bool pl_json_bool_member (plJsonObject*, const char* pcName, bool bDefaultValue); +plJsonObject* pl_json_member (plJsonObject*, const char* pcName); +plJsonObject* pl_json_array_member (plJsonObject*, const char* pcName, uint32_t* puSizeOut); // retrieve and cast array values (default used if member isn't present) -void pl_json_int_array_member (plJsonObject* tPtrJson, const char* pcName, int* iPtrOut, uint32_t* uPtrSizeOut); -void pl_json_uint_array_member (plJsonObject* tPtrJson, const char* pcName, uint32_t* uPtrOut, uint32_t* uPtrSizeOut); -void pl_json_float_array_member (plJsonObject* tPtrJson, const char* pcName, float* fPtrOut, uint32_t* uPtrSizeOut); -void pl_json_double_array_member(plJsonObject* tPtrJson, const char* pcName, double* dPtrOut, uint32_t* uPtrSizeOut); -void pl_json_bool_array_member (plJsonObject* tPtrJson, const char* pcName, bool* bPtrOut, uint32_t* uPtrSizeOut); -void pl_json_string_array_member(plJsonObject* tPtrJson, const char* pcName, char** cPtrOut, uint32_t* uPtrSizeOut, uint32_t* uPtrLength); +void pl_json_int_array_member (plJsonObject*, const char* pcName, int* piOut, uint32_t* puSizeOut); +void pl_json_uint_array_member (plJsonObject*, const char* pcName, uint32_t* puOut, uint32_t* puSizeOut); +void pl_json_float_array_member (plJsonObject*, const char* pcName, float* pfOut, uint32_t* puSizeOut); +void pl_json_double_array_member(plJsonObject*, const char* pcName, double* pdOut, uint32_t* puSizeOut); +void pl_json_bool_array_member (plJsonObject*, const char* pcName, bool* pbOut, uint32_t* puSizeOut); +void pl_json_string_array_member(plJsonObject*, const char* pcName, char** pcOut, uint32_t* puSizeOut, uint32_t* puLength); // cast values -int pl_json_as_int (plJsonObject* tPtrJson); -uint32_t pl_json_as_uint (plJsonObject* tPtrJson); -float pl_json_as_float (plJsonObject* tPtrJson); -double pl_json_as_double (plJsonObject* tPtrJson); -const char* pl_json_as_string (plJsonObject* tPtrJson); -bool pl_json_as_bool (plJsonObject* tPtrJson); +int pl_json_as_int (plJsonObject*); +uint32_t pl_json_as_uint (plJsonObject*); +float pl_json_as_float (plJsonObject*); +double pl_json_as_double(plJsonObject*); +const char* pl_json_as_string(plJsonObject*); +bool pl_json_as_bool (plJsonObject*); // cast array values -void pl_json_as_int_array (plJsonObject* tPtrJson, int* iPtrOut, uint32_t* uPtrSizeOut); -void pl_json_as_uint_array (plJsonObject* tPtrJson, uint32_t* uPtrOut, uint32_t* uPtrSizeOut); -void pl_json_as_float_array (plJsonObject* tPtrJson, float* fPtrOut, uint32_t* uPtrSizeOut); -void pl_json_as_double_array (plJsonObject* tPtrJson, double* dPtrOut, uint32_t* uPtrSizeOut); -void pl_json_as_bool_array (plJsonObject* tPtrJson, bool* bPtrOut, uint32_t* uPtrSizeOut); -void pl_json_as_string_array (plJsonObject* tPtrJson, char** cPtrOut, uint32_t* uPtrSizeOut, uint32_t* uPtrLength); +void pl_json_as_int_array (plJsonObject*, int* piOut, uint32_t* puSizeOut); +void pl_json_as_uint_array (plJsonObject*, uint32_t* puOut, uint32_t* puSizeOut); +void pl_json_as_float_array (plJsonObject*, float* pfOut, uint32_t* puSizeOut); +void pl_json_as_double_array(plJsonObject*, double* pdOut, uint32_t* puSizeOut); +void pl_json_as_bool_array (plJsonObject*, bool* bpOut, uint32_t* puSizeOut); +void pl_json_as_string_array(plJsonObject*, char** pcOut, uint32_t* puSizeOut, uint32_t* puLength); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~writing~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -void pl_json_add_int_member (plJsonObject* tPtrJson, const char* pcName, int iValue); -void pl_json_add_uint_member (plJsonObject* tPtrJson, const char* pcName, uint32_t uValue); -void pl_json_add_float_member (plJsonObject* tPtrJson, const char* pcName, float fValue); -void pl_json_add_double_member (plJsonObject* tPtrJson, const char* pcName, double dValue); -void pl_json_add_bool_member (plJsonObject* tPtrJson, const char* pcName, bool bValue); -void pl_json_add_string_member (plJsonObject* tPtrJson, const char* pcName, const char* pcValue); -void pl_json_add_member (plJsonObject* tPtrJson, const char* pcName, plJsonObject* ptValue); -void pl_json_add_member_array (plJsonObject* tPtrJson, const char* pcName, plJsonObject* ptValues, uint32_t uSize); -void pl_json_add_int_array (plJsonObject* tPtrJson, const char* pcName, int* piValues, uint32_t uSize); -void pl_json_add_uint_array (plJsonObject* tPtrJson, const char* pcName, uint32_t* puValues, uint32_t uSize); -void pl_json_add_float_array (plJsonObject* tPtrJson, const char* pcName, float* pfValues, uint32_t uSize); -void pl_json_add_double_array (plJsonObject* tPtrJson, const char* pcName, double* pdValues, uint32_t uSize); -void pl_json_add_bool_array (plJsonObject* tPtrJson, const char* pcName, bool* pbValues, uint32_t uSize); -void pl_json_add_string_array (plJsonObject* tPtrJson, const char* pcName, char** ppcBuffer, uint32_t uSize); +// simple +void pl_json_add_int_member (plJsonObject*, const char* pcName, int); +void pl_json_add_uint_member (plJsonObject*, const char* pcName, uint32_t); +void pl_json_add_float_member (plJsonObject*, const char* pcName, float); +void pl_json_add_double_member(plJsonObject*, const char* pcName, double); +void pl_json_add_bool_member (plJsonObject*, const char* pcName, bool); +void pl_json_add_string_member(plJsonObject*, const char* pcName, const char*); + +// arrays +void pl_json_add_int_array (plJsonObject*, const char* pcName, int*, uint32_t uCount); +void pl_json_add_uint_array (plJsonObject*, const char* pcName, uint32_t*, uint32_t uCount); +void pl_json_add_float_array (plJsonObject*, const char* pcName, float*, uint32_t uCount); +void pl_json_add_double_array(plJsonObject*, const char* pcName, double*, uint32_t uCount); +void pl_json_add_bool_array (plJsonObject*, const char* pcName, bool*, uint32_t uCount); +void pl_json_add_string_array(plJsonObject*, const char* pcName, char**, uint32_t uCount); + +// objects & object arrays +plJsonObject* pl_json_add_member (plJsonObject*, const char* pcName); // returns object to be modified with above commands +plJsonObject* pl_json_add_member_array(plJsonObject*, const char* pcName, uint32_t uCount); // returns array of uCount length //----------------------------------------------------------------------------- -// [SECTION] internal structs +// [SECTION] enums //----------------------------------------------------------------------------- -typedef struct _plJsonObject +enum plJsonType_ { - plJsonType tType; - uint32_t uChildCount; - char acName[PL_JSON_MAX_NAME_LENGTH]; - plJsonObject* sbtChildren; - uint32_t uChildrenFound; - char* sbcBuffer; - char** psbcBuffer; - - union - { - struct - { - uint32_t* sbuValueOffsets; - uint32_t* sbuValueLength; - }; - - struct - { - uint32_t uValueOffset; - uint32_t uValueLength; - }; - }; - -} plJsonObject; + PL_JSON_TYPE_UNSPECIFIED, + PL_JSON_TYPE_STRING, + PL_JSON_TYPE_ARRAY, + PL_JSON_TYPE_NUMBER, + PL_JSON_TYPE_BOOL, + PL_JSON_TYPE_OBJECT, + PL_JSON_TYPE_NULL, +}; #endif //PL_JSON_H @@ -535,9 +521,10 @@ jsmn_init(jsmn_parser* parser) /* Index of this file: // [SECTION] includes +// [SECTION] defines +// [SECTION] internal types // [SECTION] stretchy buffer // [SECTION] internal api -// [SECTION] internal enums // [SECTION] public api implementation // [SECTION] internal api implementation */ @@ -546,9 +533,13 @@ Index of this file: // [SECTION] includes //----------------------------------------------------------------------------- -#include -#include -#include +#include // memset +#include // FLT_MAX +#include // sprintf + +//----------------------------------------------------------------------------- +// [SECTION] defines +//----------------------------------------------------------------------------- #ifndef PL_ASSERT #include @@ -569,6 +560,41 @@ Index of this file: #define PL_JSON_FREE(x) free((x)) #endif +#ifndef PL_JSON_MAX_NAME_LENGTH + #define PL_JSON_MAX_NAME_LENGTH 256 +#endif + +//----------------------------------------------------------------------------- +// [SECTION] internal types +//----------------------------------------------------------------------------- + +typedef struct _plJsonObject +{ + plJsonType tType; + uint32_t uChildCount; + plJsonObject* ptRootObject; + char acName[PL_JSON_MAX_NAME_LENGTH]; + plJsonObject* sbtChildren; + uint32_t uChildrenFound; + char* sbcBuffer; + + union + { + struct + { + uint32_t* sbuValueOffsets; + uint32_t* sbuValueLength; + }; + + struct + { + uint32_t uValueOffset; + uint32_t uValueLength; + }; + }; + +} plJsonObject; + //----------------------------------------------------------------------------- // [SECTION] stretchy buffer //----------------------------------------------------------------------------- @@ -618,10 +644,10 @@ typedef struct } plSbJsonHeader_; static void -pl__sb_json_grow(void** ptrBuffer, size_t szElementSize, size_t szNewItems) +pl__sb_json_grow(void** pBuffer, size_t szElementSize, size_t szNewItems) { - plSbJsonHeader_* ptOldHeader = pl__sb_json_header(*ptrBuffer); + plSbJsonHeader_* ptOldHeader = pl__sb_json_header(*pBuffer); plSbJsonHeader_* ptNewHeader = (plSbJsonHeader_*)PL_JSON_ALLOC((ptOldHeader->uCapacity + szNewItems) * szElementSize + sizeof(plSbJsonHeader_)); memset(ptNewHeader, 0, (ptOldHeader->uCapacity + szNewItems) * szElementSize + sizeof(plSbJsonHeader_)); @@ -629,21 +655,21 @@ pl__sb_json_grow(void** ptrBuffer, size_t szElementSize, size_t szNewItems) { ptNewHeader->uSize = ptOldHeader->uSize; ptNewHeader->uCapacity = ptOldHeader->uCapacity + (uint32_t)szNewItems; - memcpy(&ptNewHeader[1], *ptrBuffer, ptOldHeader->uSize * szElementSize); + memcpy(&ptNewHeader[1], *pBuffer, ptOldHeader->uSize * szElementSize); PL_JSON_FREE(ptOldHeader); - *ptrBuffer = &ptNewHeader[1]; + *pBuffer = &ptNewHeader[1]; } } static void -pl__sb_json_may_grow_(void** ptrBuffer, size_t szElementSize, size_t szNewItems, size_t szMinCapacity) +pl__sb_json_may_grow_(void** pBuffer, size_t szElementSize, size_t szNewItems, size_t szMinCapacity) { - if(*ptrBuffer) + if(*pBuffer) { - plSbJsonHeader_* ptOriginalHeader = pl__sb_json_header(*ptrBuffer); + plSbJsonHeader_* ptOriginalHeader = pl__sb_json_header(*pBuffer); if(ptOriginalHeader->uSize + szNewItems > ptOriginalHeader->uCapacity) { - pl__sb_json_grow(ptrBuffer, szElementSize, szNewItems); + pl__sb_json_grow(pBuffer, szElementSize, szNewItems); } } else // first run @@ -652,7 +678,7 @@ pl__sb_json_may_grow_(void** ptrBuffer, size_t szElementSize, size_t szNewItems, memset(ptHeader, 0, szMinCapacity * szElementSize + sizeof(plSbJsonHeader_)); if(ptHeader) { - *ptrBuffer = &ptHeader[1]; + *pBuffer = &ptHeader[1]; ptHeader->uSize = 0u; ptHeader->uCapacity = (uint32_t)szMinCapacity; } @@ -684,31 +710,27 @@ pl__sb_json_sprintf(char** ppcBuffer, const char* pcFormat, ...) // [SECTION] internal api //----------------------------------------------------------------------------- -static plJsonType pl__get_json_token_object_type(const char* cPtrJson, jsmntok_t* tPtrToken); +static plJsonType pl__get_json_token_object_type(const char* pcJson, jsmntok_t*); static void pl__write_json_object(plJsonObject* ptJson, char* pcBuffer, uint32_t* puBufferSize, uint32_t* puCursor, uint32_t* puDepth); static void pl__check_json_object(plJsonObject* ptJson, uint32_t* puBufferSize, uint32_t* puCursor, uint32_t* puDepth); -//----------------------------------------------------------------------------- -// [SECTION] internal enums -//----------------------------------------------------------------------------- - -enum plJsonType_ -{ - PL_JSON_TYPE_UNSPECIFIED, - PL_JSON_TYPE_STRING, - PL_JSON_TYPE_ARRAY, - PL_JSON_TYPE_NUMBER, - PL_JSON_TYPE_BOOL, - PL_JSON_TYPE_OBJECT, - PL_JSON_TYPE_NULL, -}; - //----------------------------------------------------------------------------- // [SECTION] public api implementation //----------------------------------------------------------------------------- +plJsonObject* +pl_json_new_root_object(const char* pcName) +{ + plJsonObject* ptJson = PL_JSON_ALLOC(sizeof(plJsonObject)); + memset(ptJson, 0, sizeof(plJsonObject)); + ptJson->tType = PL_JSON_TYPE_OBJECT; + ptJson->ptRootObject = ptJson; + strncpy(ptJson->acName, pcName, 256); + return ptJson; +} + bool -pl_load_json(const char* cPtrJson, plJsonObject* tPtrJsonOut) +pl_load_json(const char* pcJson, plJsonObject** pptJsonOut) { jsmn_parser tP = {0}; jsmntok_t* sbtTokens = NULL; @@ -719,11 +741,14 @@ pl_load_json(const char* cPtrJson, plJsonObject* tPtrJsonOut) int iResult = 0; while(true) { - iResult = jsmn_parse(&tP, cPtrJson, strlen(cPtrJson), sbtTokens, pl_sb_json_size(sbtTokens)); + iResult = jsmn_parse(&tP, pcJson, strlen(pcJson), sbtTokens, pl_sb_json_size(sbtTokens)); if(iResult == JSMN_ERROR_INVAL) { + pl_sb_json_free(sbtTokens); PL_ASSERT(false); + return false; + } else if(iResult == JSMN_ERROR_NOMEM) { @@ -731,7 +756,9 @@ pl_load_json(const char* cPtrJson, plJsonObject* tPtrJsonOut) } else if(iResult == JSMN_ERROR_PART) { + pl_sb_json_free(sbtTokens); PL_ASSERT(false); + return false; } else { @@ -742,13 +769,16 @@ pl_load_json(const char* cPtrJson, plJsonObject* tPtrJsonOut) uint32_t uLayer = 0; uint32_t uCurrentTokenIndex = 0; plJsonObject** sbtObjectStack = NULL; - tPtrJsonOut->tType = PL_JSON_TYPE_OBJECT; - pl_sb_json_reserve(tPtrJsonOut->sbcBuffer, strlen(cPtrJson)); - tPtrJsonOut->psbcBuffer = &tPtrJsonOut->sbcBuffer; - tPtrJsonOut->uChildCount = sbtTokens[uCurrentTokenIndex].size; - strcpy(tPtrJsonOut->acName, "ROOT"); - pl_sb_json_reserve(tPtrJsonOut->sbtChildren, sbtTokens[uCurrentTokenIndex].size); - pl_sb_json_push(sbtObjectStack, tPtrJsonOut); + *pptJsonOut = PL_JSON_ALLOC(sizeof(plJsonObject)); + memset(*pptJsonOut, 0, sizeof(plJsonObject)); + plJsonObject* ptJsonOut = *pptJsonOut; + ptJsonOut->ptRootObject = ptJsonOut; + ptJsonOut->tType = PL_JSON_TYPE_OBJECT; + pl_sb_json_reserve(ptJsonOut->sbcBuffer, strlen(pcJson)); + ptJsonOut->uChildCount = sbtTokens[uCurrentTokenIndex].size; + strcpy(ptJsonOut->acName, "ROOT"); + pl_sb_json_reserve(ptJsonOut->sbtChildren, sbtTokens[uCurrentTokenIndex].size); + pl_sb_json_push(sbtObjectStack, ptJsonOut); while(uCurrentTokenIndex < (uint32_t)iResult) { @@ -757,33 +787,33 @@ pl_load_json(const char* cPtrJson, plJsonObject* tPtrJsonOut) else { - plJsonObject* tPtrParentObject = pl_sb_json_top(sbtObjectStack); + plJsonObject* ptParentObject = pl_sb_json_top(sbtObjectStack); - jsmntok_t* tPtrCurrentToken = &sbtTokens[uCurrentTokenIndex]; - jsmntok_t* tPtrNextToken = &sbtTokens[uCurrentTokenIndex + 1]; + jsmntok_t* ptCurrentToken = &sbtTokens[uCurrentTokenIndex]; + jsmntok_t* ptNextToken = &sbtTokens[uCurrentTokenIndex + 1]; - switch (tPtrCurrentToken->type) + switch (ptCurrentToken->type) { // value case JSMN_PRIMITIVE: - if(tPtrParentObject->tType == PL_JSON_TYPE_ARRAY) + if(ptParentObject->tType == PL_JSON_TYPE_ARRAY) { - const uint32_t uBufferLocation = pl_sb_json_size(tPtrJsonOut->sbcBuffer); - pl_sb_json_resize(tPtrJsonOut->sbcBuffer, uBufferLocation + tPtrCurrentToken->end - tPtrCurrentToken->start + 1); - memcpy(&tPtrJsonOut->sbcBuffer[uBufferLocation], &cPtrJson[tPtrCurrentToken->start], tPtrCurrentToken->end - tPtrCurrentToken->start); - pl_sb_json_push(tPtrParentObject->sbuValueOffsets, uBufferLocation); - pl_sb_json_push(tPtrParentObject->sbuValueLength, tPtrCurrentToken->end - tPtrCurrentToken->start); - tPtrParentObject->uChildrenFound++; + const uint32_t uBufferLocation = pl_sb_json_size(ptJsonOut->sbcBuffer); + pl_sb_json_resize(ptJsonOut->sbcBuffer, uBufferLocation + ptCurrentToken->end - ptCurrentToken->start + 1); + memcpy(&ptJsonOut->sbcBuffer[uBufferLocation], &pcJson[ptCurrentToken->start], ptCurrentToken->end - ptCurrentToken->start); + pl_sb_json_push(ptParentObject->sbuValueOffsets, uBufferLocation); + pl_sb_json_push(ptParentObject->sbuValueLength, ptCurrentToken->end - ptCurrentToken->start); + ptParentObject->uChildrenFound++; } else { - const uint32_t uBufferLocation = pl_sb_json_size(tPtrJsonOut->sbcBuffer); - pl_sb_json_resize(tPtrJsonOut->sbcBuffer, uBufferLocation + tPtrCurrentToken->end - tPtrCurrentToken->start + 1); - memcpy(&tPtrJsonOut->sbcBuffer[uBufferLocation], &cPtrJson[tPtrCurrentToken->start], tPtrCurrentToken->end - tPtrCurrentToken->start); - tPtrParentObject->uValueOffset = uBufferLocation; - tPtrParentObject->uValueLength = tPtrCurrentToken->end - tPtrCurrentToken->start; - tPtrParentObject->uChildrenFound++; + const uint32_t uBufferLocation = pl_sb_json_size(ptJsonOut->sbcBuffer); + pl_sb_json_resize(ptJsonOut->sbcBuffer, uBufferLocation + ptCurrentToken->end - ptCurrentToken->start + 1); + memcpy(&ptJsonOut->sbcBuffer[uBufferLocation], &pcJson[ptCurrentToken->start], ptCurrentToken->end - ptCurrentToken->start); + ptParentObject->uValueOffset = uBufferLocation; + ptParentObject->uValueLength = ptCurrentToken->end - ptCurrentToken->start; + ptParentObject->uChildrenFound++; pl_sb_json_pop(sbtObjectStack); } break; @@ -791,25 +821,25 @@ pl_load_json(const char* cPtrJson, plJsonObject* tPtrJsonOut) case JSMN_STRING: { // value - if(tPtrCurrentToken->size == 0) + if(ptCurrentToken->size == 0) { - if(tPtrParentObject->tType == PL_JSON_TYPE_ARRAY) + if(ptParentObject->tType == PL_JSON_TYPE_ARRAY) { - const uint32_t uBufferLocation = pl_sb_json_size(tPtrJsonOut->sbcBuffer); - pl_sb_json_resize(tPtrJsonOut->sbcBuffer, uBufferLocation + tPtrCurrentToken->end - tPtrCurrentToken->start + 1); - memcpy(&tPtrJsonOut->sbcBuffer[uBufferLocation], &cPtrJson[tPtrCurrentToken->start], tPtrCurrentToken->end - tPtrCurrentToken->start); - pl_sb_json_push(tPtrParentObject->sbuValueOffsets, uBufferLocation); - pl_sb_json_push(tPtrParentObject->sbuValueLength, tPtrCurrentToken->end - tPtrCurrentToken->start); - tPtrParentObject->uChildrenFound++; + const uint32_t uBufferLocation = pl_sb_json_size(ptJsonOut->sbcBuffer); + pl_sb_json_resize(ptJsonOut->sbcBuffer, uBufferLocation + ptCurrentToken->end - ptCurrentToken->start + 1); + memcpy(&ptJsonOut->sbcBuffer[uBufferLocation], &pcJson[ptCurrentToken->start], ptCurrentToken->end - ptCurrentToken->start); + pl_sb_json_push(ptParentObject->sbuValueOffsets, uBufferLocation); + pl_sb_json_push(ptParentObject->sbuValueLength, ptCurrentToken->end - ptCurrentToken->start); + ptParentObject->uChildrenFound++; } else { - const uint32_t uBufferLocation = pl_sb_json_size(tPtrJsonOut->sbcBuffer); - pl_sb_json_resize(tPtrJsonOut->sbcBuffer, uBufferLocation + tPtrCurrentToken->end - tPtrCurrentToken->start + 1); - memcpy(&tPtrJsonOut->sbcBuffer[uBufferLocation], &cPtrJson[tPtrCurrentToken->start], tPtrCurrentToken->end - tPtrCurrentToken->start); - tPtrParentObject->uValueOffset = uBufferLocation; - tPtrParentObject->uValueLength = tPtrCurrentToken->end - tPtrCurrentToken->start; - tPtrParentObject->uChildrenFound++; + const uint32_t uBufferLocation = pl_sb_json_size(ptJsonOut->sbcBuffer); + pl_sb_json_resize(ptJsonOut->sbcBuffer, uBufferLocation + ptCurrentToken->end - ptCurrentToken->start + 1); + memcpy(&ptJsonOut->sbcBuffer[uBufferLocation], &pcJson[ptCurrentToken->start], ptCurrentToken->end - ptCurrentToken->start); + ptParentObject->uValueOffset = uBufferLocation; + ptParentObject->uValueLength = ptCurrentToken->end - ptCurrentToken->start; + ptParentObject->uChildrenFound++; pl_sb_json_pop(sbtObjectStack); } } @@ -818,21 +848,21 @@ pl_load_json(const char* cPtrJson, plJsonObject* tPtrJsonOut) else { plJsonObject tNewJsonObject = { - pl__get_json_token_object_type(cPtrJson, tPtrNextToken), - (uint32_t)tPtrNextToken->size + pl__get_json_token_object_type(pcJson, ptNextToken), + (uint32_t)ptNextToken->size }; - tNewJsonObject.psbcBuffer = &tPtrJsonOut->sbcBuffer; + tNewJsonObject.ptRootObject = ptJsonOut; if(tNewJsonObject.uChildCount == 0) { tNewJsonObject.uChildrenFound--; } - tPtrParentObject->uChildrenFound++; - strncpy(tNewJsonObject.acName, &cPtrJson[tPtrCurrentToken->start], tPtrCurrentToken->end - tPtrCurrentToken->start); - pl_sb_json_push(tPtrParentObject->sbtChildren, tNewJsonObject); - pl_sb_json_reserve(pl_sb_json_top(tPtrParentObject->sbtChildren).sbtChildren, tPtrNextToken->size); - pl_sb_json_reserve(pl_sb_json_top(tPtrParentObject->sbtChildren).sbuValueOffsets, tPtrNextToken->size); - pl_sb_json_reserve(pl_sb_json_top(tPtrParentObject->sbtChildren).sbuValueLength, tPtrNextToken->size); - pl_sb_json_push(sbtObjectStack, &pl_sb_json_top(tPtrParentObject->sbtChildren)); + ptParentObject->uChildrenFound++; + strncpy(tNewJsonObject.acName, &pcJson[ptCurrentToken->start], ptCurrentToken->end - ptCurrentToken->start); + pl_sb_json_push(ptParentObject->sbtChildren, tNewJsonObject); + pl_sb_json_reserve(pl_sb_json_top(ptParentObject->sbtChildren).sbtChildren, ptNextToken->size); + pl_sb_json_reserve(pl_sb_json_top(ptParentObject->sbtChildren).sbuValueOffsets, ptNextToken->size); + pl_sb_json_reserve(pl_sb_json_top(ptParentObject->sbtChildren).sbuValueLength, ptNextToken->size); + pl_sb_json_push(sbtObjectStack, &pl_sb_json_top(ptParentObject->sbtChildren)); if(tNewJsonObject.tType == PL_JSON_TYPE_ARRAY) { @@ -844,59 +874,61 @@ pl_load_json(const char* cPtrJson, plJsonObject* tPtrJsonOut) case JSMN_OBJECT: { - if(tPtrParentObject->tType == PL_JSON_TYPE_ARRAY) + if(ptParentObject->tType == PL_JSON_TYPE_ARRAY) { plJsonObject tNewJsonObject = { - pl__get_json_token_object_type(cPtrJson, tPtrCurrentToken), - (uint32_t)tPtrCurrentToken->size + pl__get_json_token_object_type(pcJson, ptCurrentToken), + (uint32_t)ptCurrentToken->size }; - tNewJsonObject.psbcBuffer = &tPtrJsonOut->sbcBuffer; + tNewJsonObject.ptRootObject = ptJsonOut; strcpy(tNewJsonObject.acName, "UNNAMED OBJECT"); - pl_sb_json_push(tPtrParentObject->sbtChildren, tNewJsonObject); - pl_sb_json_reserve(pl_sb_json_top(tPtrParentObject->sbtChildren).sbtChildren, tPtrCurrentToken->size); - pl_sb_json_reserve(pl_sb_json_top(tPtrParentObject->sbtChildren).sbuValueOffsets, tPtrCurrentToken->size); - pl_sb_json_reserve(pl_sb_json_top(tPtrParentObject->sbtChildren).sbuValueLength, tPtrCurrentToken->size); - pl_sb_json_push(sbtObjectStack, &pl_sb_json_top(tPtrParentObject->sbtChildren)); - tPtrParentObject->uChildrenFound++; + pl_sb_json_push(ptParentObject->sbtChildren, tNewJsonObject); + pl_sb_json_reserve(pl_sb_json_top(ptParentObject->sbtChildren).sbtChildren, ptCurrentToken->size); + pl_sb_json_reserve(pl_sb_json_top(ptParentObject->sbtChildren).sbuValueOffsets, ptCurrentToken->size); + pl_sb_json_reserve(pl_sb_json_top(ptParentObject->sbtChildren).sbuValueLength, ptCurrentToken->size); + pl_sb_json_push(sbtObjectStack, &pl_sb_json_top(ptParentObject->sbtChildren)); + ptParentObject->uChildrenFound++; } - else if(tPtrParentObject->tType == PL_JSON_TYPE_OBJECT) + else if(ptParentObject->tType == PL_JSON_TYPE_OBJECT) { // combining key/pair - // tPtrParentObject->uChildrenFound++; + // ptParentObject->uChildrenFound++; } else - { - + { + pl_sb_json_free(sbtTokens); PL_ASSERT(false); // shouldn't be possible + return false; } break; } case JSMN_ARRAY: { - if(tPtrParentObject->tType == PL_JSON_TYPE_ARRAY) + if(ptParentObject->tType == PL_JSON_TYPE_ARRAY) { plJsonObject tNewJsonObject = { - pl__get_json_token_object_type(cPtrJson, tPtrCurrentToken), - (uint32_t)tPtrCurrentToken->size + pl__get_json_token_object_type(pcJson, ptCurrentToken), + (uint32_t)ptCurrentToken->size }; - tNewJsonObject.psbcBuffer = &tPtrJsonOut->sbcBuffer; + tNewJsonObject.ptRootObject = ptJsonOut; strcpy(tNewJsonObject.acName, "UNNAMED ARRAY"); - pl_sb_json_push(tPtrParentObject->sbtChildren, tNewJsonObject); - pl_sb_json_reserve(pl_sb_json_top(tPtrParentObject->sbtChildren).sbtChildren, tPtrCurrentToken->size); - pl_sb_json_reserve(pl_sb_json_top(tPtrParentObject->sbtChildren).sbuValueOffsets, tPtrCurrentToken->size); - pl_sb_json_reserve(pl_sb_json_top(tPtrParentObject->sbtChildren).sbuValueLength, tPtrCurrentToken->size); - pl_sb_json_push(sbtObjectStack, &pl_sb_json_top(tPtrParentObject->sbtChildren)); - tPtrParentObject->uChildrenFound++; + pl_sb_json_push(ptParentObject->sbtChildren, tNewJsonObject); + pl_sb_json_reserve(pl_sb_json_top(ptParentObject->sbtChildren).sbtChildren, ptCurrentToken->size); + pl_sb_json_reserve(pl_sb_json_top(ptParentObject->sbtChildren).sbuValueOffsets, ptCurrentToken->size); + pl_sb_json_reserve(pl_sb_json_top(ptParentObject->sbtChildren).sbuValueLength, ptCurrentToken->size); + pl_sb_json_push(sbtObjectStack, &pl_sb_json_top(ptParentObject->sbtChildren)); + ptParentObject->uChildrenFound++; } - else if(tPtrParentObject->tType == PL_JSON_TYPE_STRING) + else if(ptParentObject->tType == PL_JSON_TYPE_STRING) { // combining key/pair } else { - // shouldn't be possible - PL_ASSERT(false); + pl_sb_json_free(sbtTokens); + PL_ASSERT(false); // shouldn't be possible + return false; } break; } @@ -913,583 +945,629 @@ pl_load_json(const char* cPtrJson, plJsonObject* tPtrJsonOut) return true; } -void -pl_unload_json(plJsonObject* tPtrJson) +static void +pl__free_json(plJsonObject* ptJson) { - for(uint32_t i = 0; i < pl_sb_json_size(tPtrJson->sbtChildren); i++) - pl_unload_json(&tPtrJson->sbtChildren[i]); + for(uint32_t i = 0; i < pl_sb_json_size(ptJson->sbtChildren); i++) + pl__free_json(&ptJson->sbtChildren[i]); - if(tPtrJson->tType == PL_JSON_TYPE_ARRAY) + if(ptJson->tType == PL_JSON_TYPE_ARRAY) { - pl_sb_json_free(tPtrJson->sbuValueOffsets); - pl_sb_json_free(tPtrJson->sbtChildren); - pl_sb_json_free(tPtrJson->sbuValueLength); + pl_sb_json_free(ptJson->sbuValueOffsets); + pl_sb_json_free(ptJson->sbtChildren); + pl_sb_json_free(ptJson->sbuValueLength); } else { - tPtrJson->uValueOffset = 0; - tPtrJson->uValueLength = 0; + ptJson->uValueOffset = 0; + ptJson->uValueLength = 0; } - tPtrJson->uChildCount = 0; - tPtrJson->uChildrenFound = 0; + ptJson->uChildCount = 0; + ptJson->uChildrenFound = 0; - pl_sb_json_free(tPtrJson->sbcBuffer); + pl_sb_json_free(ptJson->sbcBuffer); - memset(tPtrJson->acName, 0, PL_JSON_MAX_NAME_LENGTH); - tPtrJson->tType = PL_JSON_TYPE_UNSPECIFIED; + memset(ptJson->acName, 0, PL_JSON_MAX_NAME_LENGTH); + ptJson->tType = PL_JSON_TYPE_UNSPECIFIED; +} + +void +pl_unload_json(plJsonObject** pptJson) +{ + plJsonObject* ptJson = *pptJson; + for(uint32_t i = 0; i < pl_sb_json_size(ptJson->sbtChildren); i++) + pl__free_json(&ptJson->sbtChildren[i]); + + if(ptJson->tType == PL_JSON_TYPE_ARRAY) + { + pl_sb_json_free(ptJson->sbuValueOffsets); + pl_sb_json_free(ptJson->sbtChildren); + pl_sb_json_free(ptJson->sbuValueLength); + } + else + { + ptJson->uValueOffset = 0; + ptJson->uValueLength = 0; + } + + ptJson->uChildCount = 0; + ptJson->uChildrenFound = 0; + + pl_sb_json_free(ptJson->sbcBuffer); + + memset(ptJson->acName, 0, PL_JSON_MAX_NAME_LENGTH); + ptJson->tType = PL_JSON_TYPE_UNSPECIFIED; + PL_JSON_FREE(ptJson); + *pptJson = NULL; } char* -pl_write_json(plJsonObject* tPtrJson, char* pcBuffer, uint32_t* puBufferSize) +pl_write_json(plJsonObject* ptJson, char* pcBuffer, uint32_t* puBufferSize) { uint32_t uCursorPosition = 0; uint32_t uDepth = 0; if(pcBuffer) - pl__write_json_object(tPtrJson, pcBuffer, puBufferSize, &uCursorPosition, &uDepth); + pl__write_json_object(ptJson, pcBuffer, puBufferSize, &uCursorPosition, &uDepth); else - pl__check_json_object(tPtrJson, puBufferSize, &uCursorPosition, &uDepth); + pl__check_json_object(ptJson, puBufferSize, &uCursorPosition, &uDepth); *puBufferSize = uCursorPosition; return pcBuffer; } plJsonObject* -pl_json_member_by_name(plJsonObject* tPtrJson, const char* pcName) +pl_json_member_by_name(plJsonObject* ptJson, const char* pcName) { - for(uint32_t i = 0; i < tPtrJson->uChildCount; i++) + for(uint32_t i = 0; i < ptJson->uChildCount; i++) { - if(strncmp(pcName, tPtrJson->sbtChildren[i].acName, strlen(tPtrJson->sbtChildren[i].acName)) == 0) - return &tPtrJson->sbtChildren[i]; + if(strncmp(pcName, ptJson->sbtChildren[i].acName, strlen(ptJson->sbtChildren[i].acName)) == 0) + return &ptJson->sbtChildren[i]; } return NULL; } plJsonObject* -pl_json_member_by_index(plJsonObject* tPtrJson, uint32_t uIndex) +pl_json_member_by_index(plJsonObject* ptJson, uint32_t uIndex) { - PL_ASSERT(uIndex < tPtrJson->uChildCount); - return &tPtrJson->sbtChildren[uIndex]; + if(uIndex < ptJson->uChildCount) + return &ptJson->sbtChildren[uIndex]; + return NULL; } void -pl_json_member_list(plJsonObject* tPtrJson, char** cPtrListOut, uint32_t* uPtrSizeOut, uint32_t* uPtrLength) +pl_json_member_list(plJsonObject* ptJson, char** ppcListOut, uint32_t* puSizeOut, uint32_t* puLength) { - if(cPtrListOut) + if(ppcListOut) { - for(uint32_t i = 0; i < pl_sb_json_size(tPtrJson->sbtChildren); i++) - strcpy(cPtrListOut[i], tPtrJson->sbtChildren[i].acName); + for(uint32_t i = 0; i < pl_sb_json_size(ptJson->sbtChildren); i++) + strcpy(ppcListOut[i], ptJson->sbtChildren[i].acName); } - if(uPtrSizeOut) - *uPtrSizeOut = pl_sb_json_size(tPtrJson->sbtChildren); + if(puSizeOut) + *puSizeOut = pl_sb_json_size(ptJson->sbtChildren); - if(uPtrLength) + if(puLength) { - for(uint32_t i = 0; i < pl_sb_json_size(tPtrJson->sbtChildren); i++) + for(uint32_t i = 0; i < pl_sb_json_size(ptJson->sbtChildren); i++) { - const uint32_t uLength = (uint32_t)strlen(tPtrJson->sbtChildren[i].acName); - if(uLength > *uPtrLength) *uPtrLength = uLength; + const uint32_t uLength = (uint32_t)strlen(ptJson->sbtChildren[i].acName); + if(uLength > *puLength) *puLength = uLength; } } } -bool -pl_json_member_exist(plJsonObject* tPtrJson, const char* pcName) +plJsonType +pl_json_get_type(plJsonObject* ptJson) { - return pl_json_member_by_name(tPtrJson, pcName) != NULL; + return ptJson->tType; +} + +bool +pl_json_member_exist(plJsonObject* ptJson, const char* pcName) +{ + return pl_json_member_by_name(ptJson, pcName) != NULL; } int -pl_json_int_member(plJsonObject* tPtrJson, const char* pcName, int iDefaultValue) +pl_json_int_member(plJsonObject* ptJson, const char* pcName, int iDefaultValue) { - plJsonObject* tPtrMember = pl_json_member_by_name(tPtrJson, pcName); + plJsonObject* ptMember = pl_json_member_by_name(ptJson, pcName); - if(tPtrMember) - return pl_json_as_int(tPtrMember); + if(ptMember) + return pl_json_as_int(ptMember); return iDefaultValue; } uint32_t -pl_json_uint_member(plJsonObject* tPtrJson, const char* pcName, uint32_t uDefaultValue) +pl_json_uint_member(plJsonObject* ptJson, const char* pcName, uint32_t uDefaultValue) { - plJsonObject* tPtrMember = pl_json_member_by_name(tPtrJson, pcName); + plJsonObject* ptMember = pl_json_member_by_name(ptJson, pcName); - if(tPtrMember) - return pl_json_as_uint(tPtrMember); + if(ptMember) + return pl_json_as_uint(ptMember); return uDefaultValue; } float -pl_json_float_member(plJsonObject* tPtrJson, const char* pcName, float fDefaultValue) +pl_json_float_member(plJsonObject* ptJson, const char* pcName, float fDefaultValue) { - plJsonObject* tPtrMember = pl_json_member_by_name(tPtrJson, pcName); + plJsonObject* ptMember = pl_json_member_by_name(ptJson, pcName); - if(tPtrMember) - return pl_json_as_float(tPtrMember); + if(ptMember) + return pl_json_as_float(ptMember); return fDefaultValue; } double -pl_json_double_member(plJsonObject* tPtrJson, const char* pcName, double dDefaultValue) +pl_json_double_member(plJsonObject* ptJson, const char* pcName, double dDefaultValue) { - plJsonObject* tPtrMember = pl_json_member_by_name(tPtrJson, pcName); + plJsonObject* ptMember = pl_json_member_by_name(ptJson, pcName); - if(tPtrMember) - return pl_json_as_double(tPtrMember); + if(ptMember) + return pl_json_as_double(ptMember); return dDefaultValue; } char* -pl_json_string_member(plJsonObject* tPtrJson, const char* pcName, char* cPtrDefaultValue, uint32_t uLength) +pl_json_string_member(plJsonObject* ptJson, const char* pcName, char* pcDefaultValue, uint32_t uLength) { - plJsonObject* tPtrMember = pl_json_member_by_name(tPtrJson, pcName); + plJsonObject* ptMember = pl_json_member_by_name(ptJson, pcName); - if(tPtrMember) + if(ptMember) { - PL_ASSERT(uLength >= tPtrMember->uValueLength); - memset(cPtrDefaultValue, 0, uLength); - strncpy(cPtrDefaultValue, &(*tPtrMember->psbcBuffer)[tPtrMember->uValueOffset], tPtrMember->uValueLength); + if(uLength < ptMember->uValueLength) + return NULL; + memset(pcDefaultValue, 0, uLength); + strncpy(pcDefaultValue, &ptMember->ptRootObject->sbcBuffer[ptMember->uValueOffset], ptMember->uValueLength); } - return cPtrDefaultValue; + return pcDefaultValue; } bool -pl_json_bool_member(plJsonObject* tPtrJson, const char* pcName, bool bDefaultValue) +pl_json_bool_member(plJsonObject* ptJson, const char* pcName, bool bDefaultValue) { - plJsonObject* tPtrMember = pl_json_member_by_name(tPtrJson, pcName); + plJsonObject* ptMember = pl_json_member_by_name(ptJson, pcName); - if(tPtrMember) - return pl_json_as_bool(tPtrMember); + if(ptMember) + return pl_json_as_bool(ptMember); return bDefaultValue; } plJsonObject* -pl_json_member(plJsonObject* tPtrJson, const char* pcName) +pl_json_member(plJsonObject* ptJson, const char* pcName) { - plJsonObject* tPtrMember = pl_json_member_by_name(tPtrJson, pcName); + plJsonObject* ptMember = pl_json_member_by_name(ptJson, pcName); - if(tPtrMember) + if(ptMember) { - PL_ASSERT(tPtrMember->tType == PL_JSON_TYPE_OBJECT); - return tPtrMember; + PL_ASSERT(ptMember->tType == PL_JSON_TYPE_OBJECT); + if(ptMember->tType == PL_JSON_TYPE_OBJECT) + return ptMember; } return NULL; } plJsonObject* -pl_json_array_member(plJsonObject* tPtrJson, const char* pcName, uint32_t* uPtrSizeOut) +pl_json_array_member(plJsonObject* ptJson, const char* pcName, uint32_t* puSizeOut) { - plJsonObject* tPtrMember = pl_json_member_by_name(tPtrJson, pcName); - if(uPtrSizeOut) - *uPtrSizeOut = 0; + plJsonObject* ptMember = pl_json_member_by_name(ptJson, pcName); + if(puSizeOut) + *puSizeOut = 0; - if(tPtrMember) + if(ptMember) { - PL_ASSERT(tPtrMember->tType == PL_JSON_TYPE_ARRAY); - if(uPtrSizeOut) - *uPtrSizeOut = tPtrMember->uChildCount; - return tPtrMember->sbtChildren; + PL_ASSERT(ptMember->tType == PL_JSON_TYPE_ARRAY); + if(ptMember->tType == PL_JSON_TYPE_ARRAY) + { + if(puSizeOut) + *puSizeOut = ptMember->uChildCount; + return ptMember; + } } return NULL; } void -pl_json_int_array_member(plJsonObject* tPtrJson, const char* pcName, int* iPtrOut, uint32_t* uPtrSizeOut) +pl_json_int_array_member(plJsonObject* ptJson, const char* pcName, int* piOut, uint32_t* puSizeOut) { - plJsonObject* tPtrMember = pl_json_member_by_name(tPtrJson, pcName); + plJsonObject* ptMember = pl_json_member_by_name(ptJson, pcName); - if(tPtrMember) - pl_json_as_int_array(tPtrMember, iPtrOut, uPtrSizeOut); + if(ptMember) + pl_json_as_int_array(ptMember, piOut, puSizeOut); } void -pl_json_uint_array_member(plJsonObject* tPtrJson, const char* pcName, uint32_t* uPtrOut, uint32_t* uPtrSizeOut) +pl_json_uint_array_member(plJsonObject* ptJson, const char* pcName, uint32_t* puOut, uint32_t* puSizeOut) { - plJsonObject* tPtrMember = pl_json_member_by_name(tPtrJson, pcName); + plJsonObject* ptMember = pl_json_member_by_name(ptJson, pcName); - if(tPtrMember) - pl_json_as_uint_array(tPtrMember, uPtrOut, uPtrSizeOut); + if(ptMember) + pl_json_as_uint_array(ptMember, puOut, puSizeOut); } void -pl_json_float_array_member(plJsonObject* tPtrJson, const char* pcName, float* fPtrOut, uint32_t* uPtrSizeOut) +pl_json_float_array_member(plJsonObject* ptJson, const char* pcName, float* pfOut, uint32_t* puSizeOut) { - plJsonObject* tPtrMember = pl_json_member_by_name(tPtrJson, pcName); + plJsonObject* ptMember = pl_json_member_by_name(ptJson, pcName); - if(tPtrMember) - pl_json_as_float_array(tPtrMember, fPtrOut, uPtrSizeOut); + if(ptMember) + pl_json_as_float_array(ptMember, pfOut, puSizeOut); } void -pl_json_double_array_member(plJsonObject* tPtrJson, const char* pcName, double* dPtrOut, uint32_t* uPtrSizeOut) +pl_json_double_array_member(plJsonObject* ptJson, const char* pcName, double* pdOut, uint32_t* puSizeOut) { - plJsonObject* tPtrMember = pl_json_member_by_name(tPtrJson, pcName); + plJsonObject* ptMember = pl_json_member_by_name(ptJson, pcName); - if(tPtrMember) - pl_json_as_double_array(tPtrMember, dPtrOut, uPtrSizeOut); + if(ptMember) + pl_json_as_double_array(ptMember, pdOut, puSizeOut); } void -pl_json_string_array_member(plJsonObject* tPtrJson, const char* pcName, char** cPtrOut, uint32_t* uPtrSizeOut, uint32_t* uPtrLength) +pl_json_string_array_member(plJsonObject* ptJson, const char* pcName, char** pcOut, uint32_t* puSizeOut, uint32_t* puLength) { - plJsonObject* tPtrMember = pl_json_member_by_name(tPtrJson, pcName); + plJsonObject* ptMember = pl_json_member_by_name(ptJson, pcName); - if(tPtrMember) - pl_json_as_string_array(tPtrMember, cPtrOut, uPtrSizeOut, uPtrLength); + if(ptMember) + pl_json_as_string_array(ptMember, pcOut, puSizeOut, puLength); } void -pl_json_bool_array_member(plJsonObject* tPtrJson, const char* pcName, bool* bPtrOut, uint32_t* uPtrSizeOut) +pl_json_bool_array_member(plJsonObject* ptJson, const char* pcName, bool* pbOut, uint32_t* puSizeOut) { - plJsonObject* tPtrMember = pl_json_member_by_name(tPtrJson, pcName); + plJsonObject* ptMember = pl_json_member_by_name(ptJson, pcName); - if(tPtrMember) - pl_json_as_bool_array(tPtrMember, bPtrOut, uPtrSizeOut); + if(ptMember) + pl_json_as_bool_array(ptMember, pbOut, puSizeOut); } int -pl_json_as_int(plJsonObject* tPtrJson) +pl_json_as_int(plJsonObject* ptJson) { - PL_ASSERT(tPtrJson->tType == PL_JSON_TYPE_NUMBER); - return (int)strtod(&(*tPtrJson->psbcBuffer)[tPtrJson->uValueOffset], NULL); + PL_ASSERT(ptJson->tType == PL_JSON_TYPE_NUMBER); + if(ptJson->tType == PL_JSON_TYPE_NUMBER) + return (int)strtod(&ptJson->ptRootObject->sbcBuffer[ptJson->uValueOffset], NULL); + return 0; } uint32_t -pl_json_as_uint(plJsonObject* tPtrJson) +pl_json_as_uint(plJsonObject* ptJson) { - PL_ASSERT(tPtrJson->tType == PL_JSON_TYPE_NUMBER); - return (uint32_t)strtod(&(*tPtrJson->psbcBuffer)[tPtrJson->uValueOffset], NULL); + PL_ASSERT(ptJson->tType == PL_JSON_TYPE_NUMBER); + if(ptJson->tType == PL_JSON_TYPE_NUMBER) + return (uint32_t)strtod(&ptJson->ptRootObject->sbcBuffer[ptJson->uValueOffset], NULL); + return UINT32_MAX; } float -pl_json_as_float(plJsonObject* tPtrJson) +pl_json_as_float(plJsonObject* ptJson) { - PL_ASSERT(tPtrJson->tType == PL_JSON_TYPE_NUMBER); - return (float)strtod(&(*tPtrJson->psbcBuffer)[tPtrJson->uValueOffset], NULL); + PL_ASSERT(ptJson->tType == PL_JSON_TYPE_NUMBER); + if(ptJson->tType == PL_JSON_TYPE_NUMBER) + return (float)strtod(&ptJson->ptRootObject->sbcBuffer[ptJson->uValueOffset], NULL); + return FLT_MAX; } double -pl_json_as_double(plJsonObject* tPtrJson) +pl_json_as_double(plJsonObject* ptJson) { - PL_ASSERT(tPtrJson->tType == PL_JSON_TYPE_NUMBER); - return strtod(&(*tPtrJson->psbcBuffer)[tPtrJson->uValueOffset], NULL); + PL_ASSERT(ptJson->tType == PL_JSON_TYPE_NUMBER); + if(ptJson->tType == PL_JSON_TYPE_NUMBER) + return strtod(&ptJson->ptRootObject->sbcBuffer[ptJson->uValueOffset], NULL); + return DBL_MAX; } const char* -pl_json_as_string(plJsonObject* tPtrJson) +pl_json_as_string(plJsonObject* ptJson) { - PL_ASSERT(tPtrJson->tType == PL_JSON_TYPE_STRING); - return &(*tPtrJson->psbcBuffer)[tPtrJson->uValueOffset]; + PL_ASSERT(ptJson->tType == PL_JSON_TYPE_STRING); + if(ptJson->tType == PL_JSON_TYPE_STRING) + return &ptJson->ptRootObject->sbcBuffer[ptJson->uValueOffset]; + return NULL; } bool -pl_json_as_bool(plJsonObject* tPtrJson) +pl_json_as_bool(plJsonObject* ptJson) { - PL_ASSERT(tPtrJson->tType == PL_JSON_TYPE_BOOL); - return (&(*tPtrJson->psbcBuffer)[tPtrJson->uValueOffset])[0] == 't'; + PL_ASSERT(ptJson->tType == PL_JSON_TYPE_BOOL); + if(ptJson->tType == PL_JSON_TYPE_BOOL) + return (&ptJson->ptRootObject->sbcBuffer[ptJson->uValueOffset])[0] == 't'; + return false; } void -pl_json_as_int_array(plJsonObject* tPtrJson, int* iPtrOut, uint32_t* uPtrSizeOut) +pl_json_as_int_array(plJsonObject* ptJson, int* piOut, uint32_t* puSizeOut) { - PL_ASSERT(tPtrJson->tType == PL_JSON_TYPE_ARRAY); + PL_ASSERT(ptJson->tType == PL_JSON_TYPE_ARRAY); - if(uPtrSizeOut) - *uPtrSizeOut = tPtrJson->uChildCount; + if(ptJson->tType != PL_JSON_TYPE_ARRAY) + return; - if(iPtrOut) + if(puSizeOut) + *puSizeOut = ptJson->uChildCount; + + if(piOut) { - for(uint32_t i = 0; i < tPtrJson->uChildCount; i++) - iPtrOut[i] = (int)strtod(&(*tPtrJson->psbcBuffer)[tPtrJson->sbuValueOffsets[i]], NULL); + for(uint32_t i = 0; i < ptJson->uChildCount; i++) + piOut[i] = (int)strtod(&ptJson->ptRootObject->sbcBuffer[ptJson->sbuValueOffsets[i]], NULL); } } void -pl_json_as_uint_array(plJsonObject* tPtrJson, uint32_t* uPtrOut, uint32_t* uPtrSizeOut) +pl_json_as_uint_array(plJsonObject* ptJson, uint32_t* puOut, uint32_t* puSizeOut) { - PL_ASSERT(tPtrJson->tType == PL_JSON_TYPE_ARRAY); + PL_ASSERT(ptJson->tType == PL_JSON_TYPE_ARRAY); - if(uPtrSizeOut) - *uPtrSizeOut = tPtrJson->uChildCount; + if(ptJson->tType != PL_JSON_TYPE_ARRAY) + return; - if(uPtrOut) + if(puSizeOut) + *puSizeOut = ptJson->uChildCount; + + if(puOut) { - for(uint32_t i = 0; i < tPtrJson->uChildCount; i++) - uPtrOut[i] = (uint32_t)strtod(&(*tPtrJson->psbcBuffer)[tPtrJson->sbuValueOffsets[i]], NULL); + for(uint32_t i = 0; i < ptJson->uChildCount; i++) + puOut[i] = (uint32_t)strtod(&ptJson->ptRootObject->sbcBuffer[ptJson->sbuValueOffsets[i]], NULL); } } void -pl_json_as_float_array(plJsonObject* tPtrJson, float* fPtrOut, uint32_t* uPtrSizeOut) +pl_json_as_float_array(plJsonObject* ptJson, float* pfOut, uint32_t* puSizeOut) { - PL_ASSERT(tPtrJson->tType == PL_JSON_TYPE_ARRAY); + PL_ASSERT(ptJson->tType == PL_JSON_TYPE_ARRAY); - if(uPtrSizeOut) - { - *uPtrSizeOut = tPtrJson->uChildCount; - } + if(ptJson->tType != PL_JSON_TYPE_ARRAY) + return; - if(fPtrOut) + if(puSizeOut) + *puSizeOut = ptJson->uChildCount; + + if(pfOut) { - for(uint32_t i = 0; i < tPtrJson->uChildCount; i++) - fPtrOut[i] = (float)strtod(&(*tPtrJson->psbcBuffer)[tPtrJson->sbuValueOffsets[i]], NULL); + for(uint32_t i = 0; i < ptJson->uChildCount; i++) + pfOut[i] = (float)strtod(&ptJson->ptRootObject->sbcBuffer[ptJson->sbuValueOffsets[i]], NULL); } } void -pl_json_as_double_array(plJsonObject* tPtrJson, double* dPtrOut, uint32_t* uPtrSizeOut) +pl_json_as_double_array(plJsonObject* ptJson, double* pdOut, uint32_t* puSizeOut) { - PL_ASSERT(tPtrJson->tType == PL_JSON_TYPE_ARRAY); + PL_ASSERT(ptJson->tType == PL_JSON_TYPE_ARRAY); - if(uPtrSizeOut) - *uPtrSizeOut = tPtrJson->uChildCount; + if(ptJson->tType != PL_JSON_TYPE_ARRAY) + return; - if(dPtrOut) + if(puSizeOut) + *puSizeOut = ptJson->uChildCount; + + if(pdOut) { - for(uint32_t i = 0; i < tPtrJson->uChildCount; i++) - dPtrOut[i] = strtod(&(*tPtrJson->psbcBuffer)[tPtrJson->sbuValueOffsets[i]], NULL); + for(uint32_t i = 0; i < ptJson->uChildCount; i++) + pdOut[i] = strtod(&ptJson->ptRootObject->sbcBuffer[ptJson->sbuValueOffsets[i]], NULL); } } void -pl_json_as_string_array(plJsonObject* tPtrJson, char** cPtrOut, uint32_t* uPtrSizeOut, uint32_t* uPtrLength) +pl_json_as_string_array(plJsonObject* ptJson, char** pcOut, uint32_t* puSizeOut, uint32_t* puLength) { - PL_ASSERT(tPtrJson->tType == PL_JSON_TYPE_ARRAY); + PL_ASSERT(ptJson->tType == PL_JSON_TYPE_ARRAY); - if(cPtrOut) + if(ptJson->tType != PL_JSON_TYPE_ARRAY) + return; + + if(pcOut) { - for(uint32_t i = 0; i < tPtrJson->uChildCount; i++) + for(uint32_t i = 0; i < ptJson->uChildCount; i++) { - PL_ASSERT(*uPtrLength >= tPtrJson->sbuValueLength[i]); - memset(cPtrOut[i], 0, *uPtrLength); - strncpy(cPtrOut[i],&(*tPtrJson->psbcBuffer)[tPtrJson->sbuValueOffsets[i]], tPtrJson->sbuValueLength[i]); + PL_ASSERT(*puLength >= ptJson->sbuValueLength[i]); + memset(pcOut[i], 0, *puLength); + strncpy(pcOut[i],&ptJson->ptRootObject->sbcBuffer[ptJson->sbuValueOffsets[i]], ptJson->sbuValueLength[i]); } } - else if(uPtrSizeOut) - *uPtrSizeOut = tPtrJson->uChildCount; + else if(puSizeOut) + *puSizeOut = ptJson->uChildCount; - if(uPtrLength) + if(puLength) { - for(uint32_t i = 0; i < tPtrJson->uChildCount; i++) + for(uint32_t i = 0; i < ptJson->uChildCount; i++) { - if(tPtrJson->sbuValueLength[i] > *uPtrLength) - *uPtrLength = tPtrJson->sbuValueLength[i]; + if(ptJson->sbuValueLength[i] > *puLength) + *puLength = ptJson->sbuValueLength[i]; } } } void -pl_json_as_bool_array(plJsonObject* tPtrJson, bool* bPtrOut, uint32_t* uPtrSizeOut) +pl_json_as_bool_array(plJsonObject* ptJson, bool* pbOut, uint32_t* puSizeOut) { - PL_ASSERT(tPtrJson->tType == PL_JSON_TYPE_ARRAY); + PL_ASSERT(ptJson->tType == PL_JSON_TYPE_ARRAY); - if(uPtrSizeOut) - *uPtrSizeOut = tPtrJson->uChildCount; + if(ptJson->tType != PL_JSON_TYPE_ARRAY) + return; - if(bPtrOut) + if(puSizeOut) + *puSizeOut = ptJson->uChildCount; + + if(pbOut) { - for(uint32_t i = 0; i < tPtrJson->uChildCount; i++) - bPtrOut[i] = (&(*tPtrJson->psbcBuffer)[tPtrJson->sbuValueOffsets[i]])[0] == 't'; + for(uint32_t i = 0; i < ptJson->uChildCount; i++) + pbOut[i] = (&ptJson->ptRootObject->sbcBuffer[ptJson->sbuValueOffsets[i]])[0] == 't'; } } void -pl_json_add_int_member(plJsonObject* tPtrJson, const char* pcName, int iValue) +pl_json_add_int_member(plJsonObject* ptJson, const char* pcName, int iValue) { - tPtrJson->uChildCount++; - tPtrJson->uChildrenFound++; - tPtrJson->tType = PL_JSON_TYPE_OBJECT; + ptJson->uChildCount++; + ptJson->uChildrenFound++; + ptJson->tType = PL_JSON_TYPE_OBJECT; - if(tPtrJson->psbcBuffer == NULL) - tPtrJson->psbcBuffer = &tPtrJson->sbcBuffer; - plJsonObject tNewJsonObject = {0}; tNewJsonObject.tType = PL_JSON_TYPE_NUMBER; + tNewJsonObject.ptRootObject = ptJson->ptRootObject; snprintf(tNewJsonObject.acName, PL_JSON_MAX_NAME_LENGTH, "%s", pcName); tNewJsonObject.sbcBuffer = NULL; - tNewJsonObject.psbcBuffer = tPtrJson->psbcBuffer; - tNewJsonObject.uValueOffset = pl_sb_json_size(*tPtrJson->psbcBuffer); + tNewJsonObject.uValueOffset = pl_sb_json_size(ptJson->ptRootObject->sbcBuffer); tNewJsonObject.uValueLength = snprintf(NULL, 0, "%i", iValue); - pl_sb_json_resize(*tPtrJson->psbcBuffer, tNewJsonObject.uValueOffset + tNewJsonObject.uValueLength); - snprintf(&(*tPtrJson->psbcBuffer)[tNewJsonObject.uValueOffset], tNewJsonObject.uValueLength + 1, "%i", iValue); + pl_sb_json_resize(ptJson->ptRootObject->sbcBuffer, tNewJsonObject.uValueOffset + tNewJsonObject.uValueLength); + snprintf(&ptJson->ptRootObject->sbcBuffer[tNewJsonObject.uValueOffset], tNewJsonObject.uValueLength + 1, "%i", iValue); - pl_sb_json_push(tPtrJson->sbtChildren, tNewJsonObject); + pl_sb_json_push(ptJson->sbtChildren, tNewJsonObject); } void -pl_json_add_uint_member(plJsonObject* tPtrJson, const char* pcName, uint32_t uValue) +pl_json_add_uint_member(plJsonObject* ptJson, const char* pcName, uint32_t uValue) { - tPtrJson->uChildCount++; - tPtrJson->uChildrenFound++; - tPtrJson->tType = PL_JSON_TYPE_OBJECT; - - if(tPtrJson->psbcBuffer == NULL) - tPtrJson->psbcBuffer = &tPtrJson->sbcBuffer; + ptJson->uChildCount++; + ptJson->uChildrenFound++; + ptJson->tType = PL_JSON_TYPE_OBJECT; plJsonObject tNewJsonObject = {0}; tNewJsonObject.tType = PL_JSON_TYPE_NUMBER; + tNewJsonObject.ptRootObject = ptJson->ptRootObject; snprintf(tNewJsonObject.acName, PL_JSON_MAX_NAME_LENGTH, "%s", pcName); tNewJsonObject.sbcBuffer = NULL; - tNewJsonObject.psbcBuffer = tPtrJson->psbcBuffer; - tNewJsonObject.uValueOffset = pl_sb_json_size(*tPtrJson->psbcBuffer); + tNewJsonObject.uValueOffset = pl_sb_json_size(ptJson->ptRootObject->sbcBuffer); tNewJsonObject.uValueLength = snprintf(NULL, 0, "%u", uValue); - pl_sb_json_resize(*tPtrJson->psbcBuffer, tNewJsonObject.uValueOffset + tNewJsonObject.uValueLength); - snprintf(&(*tPtrJson->psbcBuffer)[tNewJsonObject.uValueOffset], tNewJsonObject.uValueLength, "%u", uValue); + pl_sb_json_resize(ptJson->ptRootObject->sbcBuffer, tNewJsonObject.uValueOffset + tNewJsonObject.uValueLength); + snprintf(&ptJson->ptRootObject->sbcBuffer[tNewJsonObject.uValueOffset], tNewJsonObject.uValueLength, "%u", uValue); - pl_sb_json_push(tPtrJson->sbtChildren, tNewJsonObject); + pl_sb_json_push(ptJson->sbtChildren, tNewJsonObject); } void -pl_json_add_float_member(plJsonObject* tPtrJson, const char* pcName, float fValue) +pl_json_add_float_member(plJsonObject* ptJson, const char* pcName, float fValue) { - tPtrJson->uChildCount++; - tPtrJson->uChildrenFound++; - tPtrJson->tType = PL_JSON_TYPE_OBJECT; - - if(tPtrJson->psbcBuffer == NULL) - tPtrJson->psbcBuffer = &tPtrJson->sbcBuffer; + ptJson->uChildCount++; + ptJson->uChildrenFound++; + ptJson->tType = PL_JSON_TYPE_OBJECT; plJsonObject tNewJsonObject = {0}; tNewJsonObject.tType = PL_JSON_TYPE_NUMBER; + tNewJsonObject.ptRootObject = ptJson->ptRootObject; snprintf(tNewJsonObject.acName, PL_JSON_MAX_NAME_LENGTH, "%s", pcName); tNewJsonObject.sbcBuffer = NULL; - tNewJsonObject.psbcBuffer = tPtrJson->psbcBuffer; - tNewJsonObject.uValueOffset = pl_sb_json_size(*tPtrJson->psbcBuffer); + tNewJsonObject.uValueOffset = pl_sb_json_size(ptJson->ptRootObject->sbcBuffer); tNewJsonObject.uValueLength = snprintf(NULL, 0, "%0.7f", fValue); - pl_sb_json_resize(*tPtrJson->psbcBuffer, tNewJsonObject.uValueOffset + tNewJsonObject.uValueLength); - snprintf(&(*tPtrJson->psbcBuffer)[tNewJsonObject.uValueOffset], tNewJsonObject.uValueLength, "%0.7f", fValue); + pl_sb_json_resize(ptJson->ptRootObject->sbcBuffer, tNewJsonObject.uValueOffset + tNewJsonObject.uValueLength); + snprintf(&ptJson->ptRootObject->sbcBuffer[tNewJsonObject.uValueOffset], tNewJsonObject.uValueLength, "%0.7f", fValue); - pl_sb_json_push(tPtrJson->sbtChildren, tNewJsonObject); + pl_sb_json_push(ptJson->sbtChildren, tNewJsonObject); } void -pl_json_add_double_member(plJsonObject* tPtrJson, const char* pcName, double dValue) +pl_json_add_double_member(plJsonObject* ptJson, const char* pcName, double dValue) { - tPtrJson->uChildCount++; - tPtrJson->uChildrenFound++; - tPtrJson->tType = PL_JSON_TYPE_OBJECT; - - if(tPtrJson->psbcBuffer == NULL) - tPtrJson->psbcBuffer = &tPtrJson->sbcBuffer; + ptJson->uChildCount++; + ptJson->uChildrenFound++; + ptJson->tType = PL_JSON_TYPE_OBJECT; plJsonObject tNewJsonObject = {0}; tNewJsonObject.tType = PL_JSON_TYPE_NUMBER; + tNewJsonObject.ptRootObject = ptJson->ptRootObject; snprintf(tNewJsonObject.acName, PL_JSON_MAX_NAME_LENGTH, "%s", pcName); tNewJsonObject.sbcBuffer = NULL; - tNewJsonObject.psbcBuffer = tPtrJson->psbcBuffer; - tNewJsonObject.uValueOffset = pl_sb_json_size(*tPtrJson->psbcBuffer); + tNewJsonObject.uValueOffset = pl_sb_json_size(ptJson->ptRootObject->sbcBuffer); tNewJsonObject.uValueLength = snprintf(NULL, 0, "%0.15f", dValue); - pl_sb_json_resize(*tPtrJson->psbcBuffer, tNewJsonObject.uValueOffset + tNewJsonObject.uValueLength); - snprintf(&(*tPtrJson->psbcBuffer)[tNewJsonObject.uValueOffset], tNewJsonObject.uValueLength, "%0.15f", dValue); + pl_sb_json_resize(ptJson->ptRootObject->sbcBuffer, tNewJsonObject.uValueOffset + tNewJsonObject.uValueLength); + snprintf(&ptJson->ptRootObject->sbcBuffer[tNewJsonObject.uValueOffset], tNewJsonObject.uValueLength, "%0.15f", dValue); - pl_sb_json_push(tPtrJson->sbtChildren, tNewJsonObject); + pl_sb_json_push(ptJson->sbtChildren, tNewJsonObject); } void -pl_json_add_bool_member(plJsonObject* tPtrJson, const char* pcName, bool bValue) +pl_json_add_bool_member(plJsonObject* ptJson, const char* pcName, bool bValue) { - tPtrJson->uChildCount++; - tPtrJson->uChildrenFound++; - tPtrJson->tType = PL_JSON_TYPE_OBJECT; - - if(tPtrJson->psbcBuffer == NULL) - tPtrJson->psbcBuffer = &tPtrJson->sbcBuffer; + ptJson->uChildCount++; + ptJson->uChildrenFound++; + ptJson->tType = PL_JSON_TYPE_OBJECT; plJsonObject tNewJsonObject = {0}; tNewJsonObject.tType = PL_JSON_TYPE_BOOL; + tNewJsonObject.ptRootObject = ptJson->ptRootObject; snprintf(tNewJsonObject.acName, PL_JSON_MAX_NAME_LENGTH, "%s", pcName); tNewJsonObject.sbcBuffer = NULL; - tNewJsonObject.psbcBuffer = tPtrJson->psbcBuffer; - tNewJsonObject.uValueOffset = pl_sb_json_size(*tPtrJson->psbcBuffer); + tNewJsonObject.uValueOffset = pl_sb_json_size(ptJson->ptRootObject->sbcBuffer); tNewJsonObject.uValueLength = snprintf(NULL, 0, "%s", bValue ? "true" : "false"); - pl_sb_json_resize(*tPtrJson->psbcBuffer, tNewJsonObject.uValueOffset + tNewJsonObject.uValueLength); - snprintf(&(*tPtrJson->psbcBuffer)[tNewJsonObject.uValueOffset], tNewJsonObject.uValueLength, bValue ? "true" : "false"); - - pl_sb_json_push(tPtrJson->sbtChildren, tNewJsonObject); + pl_sb_json_resize(ptJson->ptRootObject->sbcBuffer, tNewJsonObject.uValueOffset + tNewJsonObject.uValueLength); + snprintf(&ptJson->ptRootObject->sbcBuffer[tNewJsonObject.uValueOffset], tNewJsonObject.uValueLength, bValue ? "true" : "false"); + pl_sb_json_push(ptJson->sbtChildren, tNewJsonObject); } void -pl_json_add_string_member(plJsonObject* tPtrJson, const char* pcName, const char* pcValue) +pl_json_add_string_member(plJsonObject* ptJson, const char* pcName, const char* pcValue) { - tPtrJson->uChildCount++; - tPtrJson->uChildrenFound++; - tPtrJson->tType = PL_JSON_TYPE_OBJECT; - - if(tPtrJson->psbcBuffer == NULL) - tPtrJson->psbcBuffer = &tPtrJson->sbcBuffer; + ptJson->uChildCount++; + ptJson->uChildrenFound++; + ptJson->tType = PL_JSON_TYPE_OBJECT; plJsonObject tNewJsonObject = {0}; tNewJsonObject.tType = PL_JSON_TYPE_STRING; + tNewJsonObject.ptRootObject = ptJson->ptRootObject; snprintf(tNewJsonObject.acName, PL_JSON_MAX_NAME_LENGTH, "%s", pcName); tNewJsonObject.sbcBuffer = NULL; - tNewJsonObject.psbcBuffer = tPtrJson->psbcBuffer; - tNewJsonObject.uValueOffset = pl_sb_json_size(*tPtrJson->psbcBuffer); + tNewJsonObject.uValueOffset = pl_sb_json_size(ptJson->ptRootObject->sbcBuffer); tNewJsonObject.uValueLength = (uint32_t)strlen(pcValue); - pl_sb_json_resize(*tPtrJson->psbcBuffer, tNewJsonObject.uValueOffset + tNewJsonObject.uValueLength + 1); - strncpy(&(*tPtrJson->psbcBuffer)[tNewJsonObject.uValueOffset], pcValue, tNewJsonObject.uValueLength); - pl_sb_json_push(tPtrJson->sbtChildren, tNewJsonObject); + pl_sb_json_resize(ptJson->ptRootObject->sbcBuffer, tNewJsonObject.uValueOffset + tNewJsonObject.uValueLength + 1); + strncpy(&ptJson->ptRootObject->sbcBuffer[tNewJsonObject.uValueOffset], pcValue, tNewJsonObject.uValueLength); + pl_sb_json_push(ptJson->sbtChildren, tNewJsonObject); } -void -pl_json_add_member(plJsonObject* tPtrJson, const char* pcName, plJsonObject* ptValue) +plJsonObject* +pl_json_add_member(plJsonObject* ptJson, const char* pcName) { - tPtrJson->uChildCount++; - tPtrJson->uChildrenFound++; - tPtrJson->tType = PL_JSON_TYPE_OBJECT; + ptJson->uChildCount++; + ptJson->uChildrenFound++; + ptJson->tType = PL_JSON_TYPE_OBJECT; - if(tPtrJson->psbcBuffer == NULL) - tPtrJson->psbcBuffer = &tPtrJson->sbcBuffer; - - snprintf(ptValue->acName, PL_JSON_MAX_NAME_LENGTH, "%s", pcName); - pl_sb_json_push(tPtrJson->sbtChildren, *ptValue); + pl_sb_json_add_n(ptJson->sbtChildren, 1); + plJsonObject* ptResult = &pl_sb_json_top(ptJson->sbtChildren); + memset(ptResult, 0, sizeof(plJsonObject)); + snprintf(ptResult->acName, PL_JSON_MAX_NAME_LENGTH, "%s", pcName); + ptResult->tType = PL_JSON_TYPE_OBJECT; + ptResult->ptRootObject = ptJson->ptRootObject; + return ptResult; } -void -pl_json_add_member_array(plJsonObject* tPtrJson, const char* pcName, plJsonObject* ptValues, uint32_t uSize) +plJsonObject* +pl_json_add_member_array(plJsonObject* ptJson, const char* pcName, uint32_t uSize) { - tPtrJson->uChildCount++; - tPtrJson->uChildrenFound++; - tPtrJson->tType = PL_JSON_TYPE_OBJECT; - - if(tPtrJson->psbcBuffer == NULL) - tPtrJson->psbcBuffer = &tPtrJson->sbcBuffer; + ptJson->uChildCount++; + ptJson->uChildrenFound++; + ptJson->tType = PL_JSON_TYPE_OBJECT; plJsonObject tNewJsonObject = {0}; tNewJsonObject.tType = PL_JSON_TYPE_ARRAY; + tNewJsonObject.ptRootObject = ptJson->ptRootObject; snprintf(tNewJsonObject.acName, PL_JSON_MAX_NAME_LENGTH, "%s", pcName); tNewJsonObject.sbcBuffer = NULL; - tNewJsonObject.psbcBuffer = tPtrJson->psbcBuffer; tNewJsonObject.uChildCount = uSize; tNewJsonObject.uChildrenFound = uSize; tNewJsonObject.sbuValueLength = NULL; tNewJsonObject.sbuValueOffsets = NULL; tNewJsonObject.sbtChildren = NULL; pl_sb_json_resize(tNewJsonObject.sbtChildren, uSize); - for(uint32_t i = 0; i < uSize; i++) - tNewJsonObject.sbtChildren[i] = ptValues[i]; - - pl_sb_json_push(tPtrJson->sbtChildren, tNewJsonObject); + tNewJsonObject.sbtChildren[i].ptRootObject = ptJson->ptRootObject; + pl_sb_json_push(ptJson->sbtChildren, tNewJsonObject); + return &pl_sb_json_top(ptJson->sbtChildren); } void -pl_json_add_int_array(plJsonObject* tPtrJson, const char* pcName, int* piValues, uint32_t uSize) +pl_json_add_int_array(plJsonObject* ptJson, const char* pcName, int* piValues, uint32_t uSize) { - tPtrJson->uChildCount++; - tPtrJson->uChildrenFound++; - tPtrJson->tType = PL_JSON_TYPE_OBJECT; - - if(tPtrJson->psbcBuffer == NULL) - tPtrJson->psbcBuffer = &tPtrJson->sbcBuffer; + ptJson->uChildCount++; + ptJson->uChildrenFound++; + ptJson->tType = PL_JSON_TYPE_OBJECT; plJsonObject tNewJsonObject = {0}; tNewJsonObject.tType = PL_JSON_TYPE_ARRAY; + tNewJsonObject.ptRootObject = ptJson->ptRootObject; snprintf(tNewJsonObject.acName, PL_JSON_MAX_NAME_LENGTH, "%s", pcName); tNewJsonObject.sbcBuffer = NULL; - tNewJsonObject.psbcBuffer = tPtrJson->psbcBuffer; tNewJsonObject.uChildCount = uSize; tNewJsonObject.uChildrenFound = uSize; tNewJsonObject.sbuValueLength = NULL; @@ -1499,34 +1577,31 @@ pl_json_add_int_array(plJsonObject* tPtrJson, const char* pcName, int* piValues, for(uint32_t i = 0; i < uSize; i++) { - const uint32_t uValueOffset = pl_sb_json_size(*tPtrJson->psbcBuffer); + const uint32_t uValueOffset = pl_sb_json_size(ptJson->ptRootObject->sbcBuffer); const uint32_t uValueLength = snprintf(NULL, 0, "%i", piValues[i]); tNewJsonObject.sbuValueOffsets[i] = uValueOffset; tNewJsonObject.sbuValueLength[i] = uValueLength; - pl_sb_json_resize(*tPtrJson->psbcBuffer, uValueOffset + uValueLength + 1); - snprintf(&(*tPtrJson->psbcBuffer)[uValueOffset], uValueLength + 1, "%i", piValues[i]); + pl_sb_json_resize(ptJson->ptRootObject->sbcBuffer, uValueOffset + uValueLength + 1); + snprintf(&ptJson->ptRootObject->sbcBuffer[uValueOffset], uValueLength + 1, "%i", piValues[i]); } - pl_sb_json_push(tPtrJson->sbtChildren, tNewJsonObject); + pl_sb_json_push(ptJson->sbtChildren, tNewJsonObject); } void -pl_json_add_uint_array(plJsonObject* tPtrJson, const char* pcName, uint32_t* puValues, uint32_t uSize) +pl_json_add_uint_array(plJsonObject* ptJson, const char* pcName, uint32_t* puValues, uint32_t uSize) { - tPtrJson->uChildCount++; - tPtrJson->uChildrenFound++; - tPtrJson->tType = PL_JSON_TYPE_OBJECT; - - if(tPtrJson->psbcBuffer == NULL) - tPtrJson->psbcBuffer = &tPtrJson->sbcBuffer; + ptJson->uChildCount++; + ptJson->uChildrenFound++; + ptJson->tType = PL_JSON_TYPE_OBJECT; plJsonObject tNewJsonObject = {0}; tNewJsonObject.tType = PL_JSON_TYPE_ARRAY; + tNewJsonObject.ptRootObject = ptJson->ptRootObject; snprintf(tNewJsonObject.acName, PL_JSON_MAX_NAME_LENGTH, "%s", pcName); tNewJsonObject.sbcBuffer = NULL; - tNewJsonObject.psbcBuffer = tPtrJson->psbcBuffer; tNewJsonObject.uChildCount = uSize; tNewJsonObject.uChildrenFound = uSize; tNewJsonObject.sbuValueLength = NULL; @@ -1536,34 +1611,31 @@ pl_json_add_uint_array(plJsonObject* tPtrJson, const char* pcName, uint32_t* puV for(uint32_t i = 0; i < uSize; i++) { - const uint32_t uValueOffset = pl_sb_json_size(*tPtrJson->psbcBuffer); + const uint32_t uValueOffset = pl_sb_json_size(ptJson->ptRootObject->sbcBuffer); const uint32_t uValueLength = snprintf(NULL, 0, "%u", puValues[i]); tNewJsonObject.sbuValueOffsets[i] = uValueOffset; tNewJsonObject.sbuValueLength[i] = uValueLength; - pl_sb_json_resize(*tPtrJson->psbcBuffer, uValueOffset + uValueLength + 1); - snprintf(&(*tPtrJson->psbcBuffer)[uValueOffset], uValueLength + 1, "%u", puValues[i]); + pl_sb_json_resize(ptJson->ptRootObject->sbcBuffer, uValueOffset + uValueLength + 1); + snprintf(&ptJson->ptRootObject->sbcBuffer[uValueOffset], uValueLength + 1, "%u", puValues[i]); } - pl_sb_json_push(tPtrJson->sbtChildren, tNewJsonObject); + pl_sb_json_push(ptJson->sbtChildren, tNewJsonObject); } void -pl_json_add_float_array(plJsonObject* tPtrJson, const char* pcName, float* pfValues, uint32_t uSize) +pl_json_add_float_array(plJsonObject* ptJson, const char* pcName, float* pfValues, uint32_t uSize) { - tPtrJson->uChildCount++; - tPtrJson->uChildrenFound++; - tPtrJson->tType = PL_JSON_TYPE_OBJECT; - - if(tPtrJson->psbcBuffer == NULL) - tPtrJson->psbcBuffer = &tPtrJson->sbcBuffer; + ptJson->uChildCount++; + ptJson->uChildrenFound++; + ptJson->tType = PL_JSON_TYPE_OBJECT; plJsonObject tNewJsonObject = {0}; tNewJsonObject.tType = PL_JSON_TYPE_ARRAY; + tNewJsonObject.ptRootObject = ptJson->ptRootObject; snprintf(tNewJsonObject.acName, PL_JSON_MAX_NAME_LENGTH, "%s", pcName); tNewJsonObject.sbcBuffer = NULL; - tNewJsonObject.psbcBuffer = tPtrJson->psbcBuffer; tNewJsonObject.uChildCount = uSize; tNewJsonObject.uChildrenFound = uSize; tNewJsonObject.sbuValueLength = NULL; @@ -1573,34 +1645,31 @@ pl_json_add_float_array(plJsonObject* tPtrJson, const char* pcName, float* pfVal for(uint32_t i = 0; i < uSize; i++) { - const uint32_t uValueOffset = pl_sb_json_size(*tPtrJson->psbcBuffer); + const uint32_t uValueOffset = pl_sb_json_size(ptJson->ptRootObject->sbcBuffer); const uint32_t uValueLength = snprintf(NULL, 0, "%0.7f", pfValues[i]); tNewJsonObject.sbuValueOffsets[i] = uValueOffset; tNewJsonObject.sbuValueLength[i] = uValueLength; - pl_sb_json_resize(*tPtrJson->psbcBuffer, uValueOffset + uValueLength + 1); - snprintf(&(*tPtrJson->psbcBuffer)[uValueOffset], uValueLength + 1, "%0.7f", pfValues[i]); + pl_sb_json_resize(ptJson->ptRootObject->sbcBuffer, uValueOffset + uValueLength + 1); + snprintf(&ptJson->ptRootObject->sbcBuffer[uValueOffset], uValueLength + 1, "%0.7f", pfValues[i]); } - pl_sb_json_push(tPtrJson->sbtChildren, tNewJsonObject); + pl_sb_json_push(ptJson->sbtChildren, tNewJsonObject); } void -pl_json_add_double_array(plJsonObject* tPtrJson, const char* pcName, double* pdValues, uint32_t uSize) +pl_json_add_double_array(plJsonObject* ptJson, const char* pcName, double* pdValues, uint32_t uSize) { - tPtrJson->uChildCount++; - tPtrJson->uChildrenFound++; - tPtrJson->tType = PL_JSON_TYPE_OBJECT; - - if(tPtrJson->psbcBuffer == NULL) - tPtrJson->psbcBuffer = &tPtrJson->sbcBuffer; + ptJson->uChildCount++; + ptJson->uChildrenFound++; + ptJson->tType = PL_JSON_TYPE_OBJECT; plJsonObject tNewJsonObject = {0}; tNewJsonObject.tType = PL_JSON_TYPE_ARRAY; + tNewJsonObject.ptRootObject = ptJson->ptRootObject; snprintf(tNewJsonObject.acName, PL_JSON_MAX_NAME_LENGTH, "%s", pcName); tNewJsonObject.sbcBuffer = NULL; - tNewJsonObject.psbcBuffer = tPtrJson->psbcBuffer; tNewJsonObject.uChildCount = uSize; tNewJsonObject.uChildrenFound = uSize; tNewJsonObject.sbuValueLength = NULL; @@ -1610,34 +1679,31 @@ pl_json_add_double_array(plJsonObject* tPtrJson, const char* pcName, double* pdV for(uint32_t i = 0; i < uSize; i++) { - const uint32_t uValueOffset = pl_sb_json_size(*tPtrJson->psbcBuffer); + const uint32_t uValueOffset = pl_sb_json_size(ptJson->ptRootObject->sbcBuffer); const uint32_t uValueLength = snprintf(NULL, 0, "%0.15f", pdValues[i]); tNewJsonObject.sbuValueOffsets[i] = uValueOffset; tNewJsonObject.sbuValueLength[i] = uValueLength; - pl_sb_json_resize(*tPtrJson->psbcBuffer, uValueOffset + uValueLength + 1); - snprintf(&(*tPtrJson->psbcBuffer)[uValueOffset], uValueLength + 1, "%0.15f", pdValues[i]); + pl_sb_json_resize(ptJson->ptRootObject->sbcBuffer, uValueOffset + uValueLength + 1); + snprintf(&ptJson->ptRootObject->sbcBuffer[uValueOffset], uValueLength + 1, "%0.15f", pdValues[i]); } - pl_sb_json_push(tPtrJson->sbtChildren, tNewJsonObject); + pl_sb_json_push(ptJson->sbtChildren, tNewJsonObject); } void -pl_json_add_bool_array(plJsonObject* tPtrJson, const char* pcName, bool* pbValues, uint32_t uSize) +pl_json_add_bool_array(plJsonObject* ptJson, const char* pcName, bool* pbValues, uint32_t uSize) { - tPtrJson->uChildCount++; - tPtrJson->uChildrenFound++; - tPtrJson->tType = PL_JSON_TYPE_OBJECT; - - if(tPtrJson->psbcBuffer == NULL) - tPtrJson->psbcBuffer = &tPtrJson->sbcBuffer; + ptJson->uChildCount++; + ptJson->uChildrenFound++; + ptJson->tType = PL_JSON_TYPE_OBJECT; plJsonObject tNewJsonObject = {0}; tNewJsonObject.tType = PL_JSON_TYPE_ARRAY; + tNewJsonObject.ptRootObject = ptJson->ptRootObject; snprintf(tNewJsonObject.acName, PL_JSON_MAX_NAME_LENGTH, "%s", pcName); tNewJsonObject.sbcBuffer = NULL; - tNewJsonObject.psbcBuffer = tPtrJson->psbcBuffer; tNewJsonObject.uChildCount = uSize; tNewJsonObject.uChildrenFound = uSize; tNewJsonObject.sbuValueLength = NULL; @@ -1647,34 +1713,31 @@ pl_json_add_bool_array(plJsonObject* tPtrJson, const char* pcName, bool* pbValue for(uint32_t i = 0; i < uSize; i++) { - const uint32_t uValueOffset = pl_sb_json_size(*tPtrJson->psbcBuffer); + const uint32_t uValueOffset = pl_sb_json_size(ptJson->ptRootObject->sbcBuffer); const uint32_t uValueLength = snprintf(NULL, 0, "%s", pbValues[i] ? "true" : "false"); tNewJsonObject.sbuValueOffsets[i] = uValueOffset; tNewJsonObject.sbuValueLength[i] = uValueLength; - pl_sb_json_resize(*tPtrJson->psbcBuffer, uValueOffset + uValueLength + 1); - snprintf(&(*tPtrJson->psbcBuffer)[uValueOffset], uValueLength + 1, "%s", pbValues[i] ? "true" : "false"); + pl_sb_json_resize(ptJson->ptRootObject->sbcBuffer, uValueOffset + uValueLength + 1); + snprintf(&ptJson->ptRootObject->sbcBuffer[uValueOffset], uValueLength + 1, "%s", pbValues[i] ? "true" : "false"); } - pl_sb_json_push(tPtrJson->sbtChildren, tNewJsonObject); + pl_sb_json_push(ptJson->sbtChildren, tNewJsonObject); } void -pl_json_add_string_array(plJsonObject* tPtrJson, const char* pcName, char** ppcBuffer, uint32_t uSize) +pl_json_add_string_array(plJsonObject* ptJson, const char* pcName, char** ppcBuffer, uint32_t uSize) { - tPtrJson->uChildCount++; - tPtrJson->uChildrenFound++; - tPtrJson->tType = PL_JSON_TYPE_OBJECT; - - if(tPtrJson->psbcBuffer == NULL) - tPtrJson->psbcBuffer = &tPtrJson->sbcBuffer; + ptJson->uChildCount++; + ptJson->uChildrenFound++; + ptJson->tType = PL_JSON_TYPE_OBJECT; plJsonObject tNewJsonObject = {0}; tNewJsonObject.tType = PL_JSON_TYPE_ARRAY; + tNewJsonObject.ptRootObject = ptJson->ptRootObject; snprintf(tNewJsonObject.acName, PL_JSON_MAX_NAME_LENGTH, "%s", pcName); tNewJsonObject.sbcBuffer = NULL; - tNewJsonObject.psbcBuffer = tPtrJson->psbcBuffer; tNewJsonObject.uChildCount = uSize; tNewJsonObject.uChildrenFound = uSize; tNewJsonObject.sbuValueLength = NULL; @@ -1684,17 +1747,17 @@ pl_json_add_string_array(plJsonObject* tPtrJson, const char* pcName, char** ppcB for(uint32_t i = 0; i < uSize; i++) { - const uint32_t uValueOffset = pl_sb_json_size(*tPtrJson->psbcBuffer); + const uint32_t uValueOffset = pl_sb_json_size(ptJson->ptRootObject->sbcBuffer); const uint32_t uValueLength = snprintf(NULL, 0, "\"%s\"", ppcBuffer[i]); tNewJsonObject.sbuValueOffsets[i] = uValueOffset; tNewJsonObject.sbuValueLength[i] = uValueLength; - pl_sb_json_resize(*tPtrJson->psbcBuffer, uValueOffset + uValueLength + 1); - snprintf(&(*tPtrJson->psbcBuffer)[uValueOffset], uValueLength + 1, "\"%s\"", ppcBuffer[i]); + pl_sb_json_resize(ptJson->ptRootObject->sbcBuffer, uValueOffset + uValueLength + 1); + snprintf(&ptJson->ptRootObject->sbcBuffer[uValueOffset], uValueLength + 1, "\"%s\"", ppcBuffer[i]); } - pl_sb_json_push(tPtrJson->sbtChildren, tNewJsonObject); + pl_sb_json_push(ptJson->sbtChildren, tNewJsonObject); } //----------------------------------------------------------------------------- @@ -1702,16 +1765,16 @@ pl_json_add_string_array(plJsonObject* tPtrJson, const char* pcName, char** ppcB //----------------------------------------------------------------------------- static plJsonType -pl__get_json_token_object_type(const char* cPtrJson, jsmntok_t* tPtrToken) +pl__get_json_token_object_type(const char* pcJson, jsmntok_t* ptToken) { - switch (tPtrToken->type) + switch (ptToken->type) { case JSMN_ARRAY: return PL_JSON_TYPE_ARRAY; case JSMN_OBJECT: return PL_JSON_TYPE_OBJECT; case JSMN_STRING: return PL_JSON_TYPE_STRING; case JSMN_PRIMITIVE: - if (cPtrJson[tPtrToken->start] == 'n') { return PL_JSON_TYPE_NULL;} - else if(cPtrJson[tPtrToken->start] == 't' || cPtrJson[tPtrToken->start] == 'f') { return PL_JSON_TYPE_BOOL;} + if (pcJson[ptToken->start] == 'n') { return PL_JSON_TYPE_NULL;} + else if(pcJson[ptToken->start] == 't' || pcJson[ptToken->start] == 'f') { return PL_JSON_TYPE_BOOL;} else { return PL_JSON_TYPE_NUMBER;} default: PL_ASSERT(false); @@ -1739,22 +1802,22 @@ pl__write_json_object(plJsonObject* ptJson, char* pcBuffer, uint32_t* puBufferSi case PL_JSON_TYPE_BOOL: { - int iSizeNeeded = snprintf(NULL, 0, "%s", (&(*ptJson->psbcBuffer)[ptJson->uValueOffset])[0] == 't' ? "true" : "false"); - snprintf(&pcBuffer[uCursorPosition], iSizeNeeded + 1, "%s", (&(*ptJson->psbcBuffer)[ptJson->uValueOffset])[0] == 't' ? "true" : "false"); + int iSizeNeeded = snprintf(NULL, 0, "%s", (&ptJson->ptRootObject->sbcBuffer[ptJson->uValueOffset])[0] == 't' ? "true" : "false"); + snprintf(&pcBuffer[uCursorPosition], iSizeNeeded + 1, "%s", (&ptJson->ptRootObject->sbcBuffer[ptJson->uValueOffset])[0] == 't' ? "true" : "false"); uCursorPosition += iSizeNeeded; break; } case PL_JSON_TYPE_NUMBER: { - memcpy(&pcBuffer[uCursorPosition], &(*ptJson->psbcBuffer)[ptJson->uValueOffset], ptJson->uValueLength); + memcpy(&pcBuffer[uCursorPosition], &ptJson->ptRootObject->sbcBuffer[ptJson->uValueOffset], ptJson->uValueLength); uCursorPosition += ptJson->uValueLength; break; } case PL_JSON_TYPE_STRING: { - int iSizeNeeded = snprintf(&pcBuffer[uCursorPosition], (int)ptJson->uValueLength + 2 + 1, "\"%s\"", &(*ptJson->psbcBuffer)[ptJson->uValueOffset]); + int iSizeNeeded = snprintf(&pcBuffer[uCursorPosition], (int)ptJson->uValueLength + 2 + 1, "\"%s\"", &ptJson->ptRootObject->sbcBuffer[ptJson->uValueOffset]); uCursorPosition += iSizeNeeded; break; } @@ -1817,26 +1880,24 @@ pl__write_json_object(plJsonObject* ptJson, char* pcBuffer, uint32_t* puBufferSi for(uint32_t i = 0; i < ptJson->uChildCount; i++) { - // pl__write_json_object(&ptJson->sbtChildren[i], pcBuffer, &uBufferSize, &uCursorPosition, puDepth); - - const char* cPtrPrevChar = &(*ptJson->psbcBuffer)[ptJson->sbuValueOffsets[i]]; + const char* pcPrevChar = &ptJson->ptRootObject->sbcBuffer[ptJson->sbuValueOffsets[i]]; char cPreviousChar = ' '; - if(cPtrPrevChar) + if(pcPrevChar) { - const char* cPtrPrevCharAddr = cPtrPrevChar - 1; - cPreviousChar = cPtrPrevCharAddr[0]; + const char* pcPrevCharAddr = pcPrevChar - 1; + cPreviousChar = pcPrevCharAddr[0]; } if(cPreviousChar == '\"') { int iSizeNeeded2 = ptJson->sbuValueLength[i] + 2; - snprintf(&pcBuffer[uCursorPosition], iSizeNeeded2 + 1, "\"%s\"", &(*ptJson->psbcBuffer)[ptJson->sbuValueOffsets[i]]); + snprintf(&pcBuffer[uCursorPosition], iSizeNeeded2 + 1, "\"%s\"", &ptJson->ptRootObject->sbcBuffer[ptJson->sbuValueOffsets[i]]); uCursorPosition += iSizeNeeded2; } else { - memcpy(&pcBuffer[uCursorPosition], &(*ptJson->psbcBuffer)[ptJson->sbuValueOffsets[i]], ptJson->sbuValueLength[i]); + memcpy(&pcBuffer[uCursorPosition], &ptJson->ptRootObject->sbcBuffer[ptJson->sbuValueOffsets[i]], ptJson->sbuValueLength[i]); uCursorPosition += ptJson->sbuValueLength[i]; } @@ -1898,7 +1959,7 @@ pl__check_json_object(plJsonObject* ptJson, uint32_t* puBufferSize, uint32_t* pu case PL_JSON_TYPE_BOOL: { - int iSizeNeeded = snprintf(NULL, 0, "%s", (&(*ptJson->psbcBuffer)[ptJson->uValueOffset])[0] == 't' ? "true" : "false"); + int iSizeNeeded = snprintf(NULL, 0, "%s", (&ptJson->ptRootObject->sbcBuffer[ptJson->uValueOffset])[0] == 't' ? "true" : "false"); uCursorPosition += iSizeNeeded; break; } @@ -1959,12 +2020,12 @@ pl__check_json_object(plJsonObject* ptJson, uint32_t* puBufferSize, uint32_t* pu // pl__check_json_object(&ptJson->sbtChildren[i], &uBufferSize, &uCursorPosition, puDepth); - const char* cPtrPrevChar = &(*ptJson->psbcBuffer)[ptJson->sbuValueOffsets[i]]; + const char* pcPrevChar = &ptJson->ptRootObject->sbcBuffer[ptJson->sbuValueOffsets[i]]; char cPreviousChar = ' '; - if(cPtrPrevChar) + if(pcPrevChar) { - const char* cPtrPrevCharAddr = cPtrPrevChar - 1; - cPreviousChar = cPtrPrevCharAddr[0]; + const char* pcPrevCharAddr = pcPrevChar - 1; + cPreviousChar = pcPrevCharAddr[0]; } if(cPreviousChar == '\"') @@ -2003,4 +2064,4 @@ pl__check_json_object(plJsonObject* ptJson, uint32_t* puBufferSize, uint32_t* pu *puCursor = uCursorPosition; } -#endif // PL_JSON_IMPLEMENTATION +#endif // PL_JSON_IMPLEMENTATION \ No newline at end of file diff --git a/pl_log.h b/pl_log.h index 5d8fcdb..13f5fee 100644 --- a/pl_log.h +++ b/pl_log.h @@ -1,5 +1,6 @@ /* - pl_log + pl_log.h + * simple logging library Do this: #define PL_LOG_IMPLEMENTATION before you include this file in *one* C or C++ file to create the implementation. @@ -11,9 +12,9 @@ #include "pl_log.h" */ -// library version -#define PL_LOG_VERSION "0.5.2" -#define PL_LOG_VERSION_NUM 00502 +// library version (format XYYZZ) +#define PL_LOG_VERSION "1.0.0" +#define PL_LOG_VERSION_NUM 10000 /* Index of this file: @@ -23,8 +24,8 @@ Index of this file: // [SECTION] defines // [SECTION] forward declarations & basic types // [SECTION] public api -// [SECTION] enums // [SECTION] structs +// [SECTION] enums // [SECTION] internal api // [SECTION] c file start */ @@ -53,88 +54,68 @@ SETUP Sets the current log context. Mostly used to allow logging across DLL boundaries. - pl_get_log_context: - plLogContext* pl_get_log_context(); - Returns the current log context. - CHANNELS pl_add_log_channel: - uint32_t pl_add_log_channel(const char* pcName, plChannelType tType); + uint64_t pl_add_log_channel(const char* pcName, plLogChannelInit tInfo); Creates a new log channel and returns the ID. pl_set_log_level: void pl_set_log_level(uID, uLevel); Sets the runtime logging level of the uID channel - pl_set_current_log_channel: - void pl_set_current_log_channel(uID); - Sets the current logging channel - - pl_get_current_log_channel: - uint32_t pl_get_current_log_channel(); - Gets the current logging channel - - pl_clear_log_level: - void pl_clear_log_level(uID); + pl_clear_log_channel: + void pl_clear_log_channel(uID); Frees the memory associated with log entries (for buffer channel types). - pl_reset_log_level: - void pl_reset_log_level(uID); + pl_reset_log_channel: + void pl_reset_log_channel(uID); Resets the log channel but does not free the memory. - pl_get_log_entries: - plLogEntry* pl_get_log_entries(uID, uint64_t* puEntryCount); - Returns a pointer to the log entries (or NULL if empty). Fills out puEntryCount - with the count. + pl_get_log_channel_id: + uint64_t pl_get_log_channel_id(const char* pcName); + Returns the ID of the channel with the pcName (or UINT32_MAX if not found) - pl_get_log_channels: - plLogChannel* pl_get_log_channels(uint32_t* puChannelCount); - Returns a pointer to the log channels (or NULL if empty). Fills out puChannelCount - with the count. + pl_get_log_channel_info + bool pl_get_log_channel_info(uint64_t uID, plLogChannelInfo*); + Returns information on a channel (used for visualizing). -SIMPLE LOGGING TO CURRENT CHANNEL + pl_get_log_channel_count: + uint64_t pl_get_log_channel_count(void); + Returns the number of channels (used with the above function to iterate through channel info mostly). + +SIMPLE LOGGING pl_log_trace pl_log_debug pl_log_info pl_log_warn pl_log_error - pl_log_fatal: - void pl_log_*(pcMessage); + pl_log_fatal; + void pl_log_*(uID, pcMessage); Logs at the specified level. No color information. Faster if in a tight loop. -LOGGING TO CURRENT CHANNEL WITH FORMAT SPECIFIERS +LOGGING WITH FORMAT SPECIFIERS pl_log_trace_f pl_log_debug_f pl_log_info_f pl_log_warn_f pl_log_error_f - pl_log_fatal_f: - void pl_log_*_f(pcFormatString, ...); + pl_log_fatal_f; + void pl_log_*_f(uID, pcFormatString, ...); Logs at the specified level. Includes color when console. -SIMPLE LOGGING TO SPECIFIED CHANNEL +CUSTOM LOGGING - pl_log_trace_to - pl_log_debug_to - pl_log_info_to - pl_log_warn_to - pl_log_error_to - pl_log_fatal_to; - void pl_log_*_to(uID, pcMessage); + pl_log; + void pl_log(pcPrefix, iPrefixSize, uLevel, uID, pcMessage); Logs at the specified level. No color information. Faster if in a tight loop. -LOGGING TO SPECIFIED CHANNEL WITH FORMAT SPECIFIERS +CUSTOM LOGGING WITH FORMAT SPECIFIERS - pl_log_trace_to_f - pl_log_debug_to_f - pl_log_info_to_f - pl_log_warn_to_f - pl_log_error_to_f - pl_log_fatal_to_f; - void pl_log_*_to_f(uID, pcFormatString, ...); + pl_log_f; + void pl_log_f(cPrefix, iPrefixSize, uLevel, uID, pcFormatString, ...); Logs at the specified level. Includes color when console. LOG LEVELS @@ -150,23 +131,24 @@ LOG LEVELS COMPILE TIME OPTIONS * Change maximum number of channels, define PL_LOG_MAX_CHANNEL_COUNT. (default is 16) - * Change maximum number of entries for cyclic loggers, define PL_LOG_CYCLIC_BUFFER_SIZE. (default is 256) - * Change initial number of log entries for buffer loggers, define PL_LOG_INITIAL_LOG_SIZE. (default is 1024) + * Change maximum lenght of lines, define PL_LOG_MAX_LINE_SIZE. (default is 1024) * Change the global log level, define PL_GLOBAL_LOG_LEVEL. (default is PL_LOG_LEVEL_ALL) * Change background colors by defining the following: - PL_LOG_TRACE_BG_COLOR - PL_LOG_DEBUG_BG_COLOR - PL_LOG_INFO_BG_COLOR - PL_LOG_WARN_BG_COLOR - PL_LOG_ERROR_BG_COLOR - PL_LOG_FATAL_BG_COLOR + PL_LOG_TRACE_BG_COLOR + PL_LOG_DEBUG_BG_COLOR + PL_LOG_INFO_BG_COLOR + PL_LOG_WARN_BG_COLOR + PL_LOG_ERROR_BG_COLOR + PL_LOG_FATAL_BG_COLOR + PL_LOG_CUSTOM_BG_COLOR * Change foreground colors by defining the following: - PL_LOG_TRACE_FG_COLOR - PL_LOG_DEBUG_FG_COLOR - PL_LOG_INFO_FG_COLOR - PL_LOG_WARN_FG_COLOR - PL_LOG_ERROR_FG_COLOR - PL_LOG_FATAL_FG_COLOR + PL_LOG_TRACE_FG_COLOR + PL_LOG_DEBUG_FG_COLOR + PL_LOG_INFO_FG_COLOR + PL_LOG_WARN_FG_COLOR + PL_LOG_ERROR_FG_COLOR + PL_LOG_FATAL_FG_COLOR + PL_LOG_CUSTOM_FG_COLOR * Use bold by defining the following: PL_LOG_TRACE_BOLD PL_LOG_DEBUG_BOLD @@ -174,6 +156,7 @@ COMPILE TIME OPTIONS PL_LOG_WARN_BOLD PL_LOG_ERROR_BOLD PL_LOG_FATAL_BOLD + PL_LOG_CUSTOM_BOLD * Use underline by defining the following: PL_LOG_TRACE_UNDERLINE PL_LOG_DEBUG_UNDERLINE @@ -181,6 +164,7 @@ COMPILE TIME OPTIONS PL_LOG_WARN_UNDERLINE PL_LOG_ERROR_UNDERLINE PL_LOG_FATAL_UNDERLINE + PL_LOG_CUSTOM_UNDERLINE * Change allocators by defining both: PL_LOG_ALLOC(x) PL_LOG_FREE(x) @@ -232,35 +216,19 @@ BACKGROUND COLOR OPTIONS #ifndef PL_LOG_H #define PL_LOG_H -#ifndef PL_LOG_ALLOC - #include - #define PL_LOG_ALLOC(x) malloc((x)) - #define PL_LOG_FREE(x) free((x)) -#endif - //----------------------------------------------------------------------------- // [SECTION] includes //----------------------------------------------------------------------------- -#include -#include +#include // size_t +#include // uint*_t +#include // var args +#include // bool //----------------------------------------------------------------------------- // [SECTION] defines //----------------------------------------------------------------------------- -#ifndef PL_LOG_MAX_LINE_SIZE - #define PL_LOG_MAX_LINE_SIZE 1024 -#endif - -#ifndef PL_LOG_CYCLIC_BUFFER_SIZE - #define PL_LOG_CYCLIC_BUFFER_SIZE 256 -#endif - -#ifndef PL_LOG_INITIAL_LOG_SIZE - #define PL_LOG_INITIAL_LOG_SIZE 1024 -#endif - #define PL_LOG_LEVEL_ALL 0 #define PL_LOG_LEVEL_TRACE 5000 #define PL_LOG_LEVEL_DEBUG 6000 @@ -284,8 +252,10 @@ BACKGROUND COLOR OPTIONS //----------------------------------------------------------------------------- // forward declarations -typedef struct _plLogContext plLogContext; // opaque struct -typedef struct _plLogEntry plLogEntry; // represents a single entry for "buffer" channel types +typedef struct _plLogContext plLogContext; // opaque struct +typedef struct _plLogChannelInit plLogChannelInit; // information to initialize a channel +typedef struct _plLogEntry plLogEntry; // represents a single entry for "buffer" channel types +typedef struct _plLogChannelInfo plLogChannelInfo; // information about a channel used mostly for visualization // enums typedef int plChannelType; @@ -294,140 +264,120 @@ typedef int plChannelType; // [SECTION] public api //----------------------------------------------------------------------------- +#ifndef PL_LOG_REMOVE_ALL_MACROS + #ifdef PL_LOG_ON // setup/shutdown - #define pl_create_log_context() pl__create_log_context() - #define pl_cleanup_log_context() pl__cleanup_log_context() + #define pl_create_log_context() pl__create_log_context() + #define pl_cleanup_log_context() pl__cleanup_log_context() #define pl_set_log_context(tPContext) pl__set_log_context((tPContext)) - #define pl_get_log_context() pl__get_log_context() // channels - #define pl_add_log_channel(pcName, tType) pl__add_log_channel((pcName), (tType)) - #define pl_set_log_level(uID, uLevel) pl__set_log_level((uID), (uLevel)) - #define pl_set_current_log_channel(uID) pl__set_current_log_channel((uID)) - #define pl_get_current_log_channel() pl__get_current_log_channel() - #define pl_clear_log_channel(uID) pl__clear_log_channel((uID)) - #define pl_reset_log_channel(uID) pl__reset_log_channel((uID)) - #define pl_get_log_entries(uID, puEntryCount) pl__get_log_entries((uID), (puEntryCount)) - #define pl_get_log_channels(puChannelCount) pl__get_log_channels((puChannelCount)) + #define pl_add_log_channel(pcName, tInfo) pl__add_log_channel((pcName), (tInfo)) + #define pl_set_log_level(uID, uLevel) pl__set_log_level((uID), (uLevel)) + #define pl_clear_log_channel(uID) pl__clear_log_channel((uID)) + #define pl_reset_log_channel(uID) pl__reset_log_channel((uID)) + #define pl_get_log_channel_count() pl__get_log_channel_count() + #define pl_get_log_channel_id(pcName) pl__get_log_channel_id((pcName)) + #define pl_get_log_channel_info(uID, ptInfoOut) pl__get_log_channel_info((uID), (ptInfoOut)) + + // custom levels + #define pl_log(pcPrefix, iPrefixSize, uLevel, uID, pcMessage) pl__log(pcPrefix, iPrefixSize, uLevel, uID, pcMessage) + #define pl_log_f(...) pl__log_p(__VA_ARGS__) #endif // PL_LOG_ON #if PL_GLOBAL_LOG_LEVEL < PL_LOG_LEVEL_TRACE + 1 && defined(PL_LOG_ON) - #define pl_log_trace(pcMessage) pl__log_trace(pl__get_current_log_channel(), (pcMessage)) - #define pl_log_trace_f(...) pl__log_trace_p(pl__get_current_log_channel(), __VA_ARGS__) - #define pl_log_trace_to(uID, pcMessage) pl__log_trace((uID), (pcMessage)) - #define pl_log_trace_to_f(...) pl__log_trace_p(__VA_ARGS__) + #define pl_log_trace(uID, pcMessage) pl__log_trace((uID), (pcMessage)) + #define pl_log_trace_f(...) pl__log_trace_p(__VA_ARGS__) #else - #define pl_log_trace(pcMessage) // + #define pl_log_trace(uID, pcMessage) // #define pl_log_trace_f(...) // - #define pl_log_trace_to(uID, pcMessage) // - #define pl_log_trace_to_f(...) // #endif #if PL_GLOBAL_LOG_LEVEL < PL_LOG_LEVEL_DEBUG + 1 && defined(PL_LOG_ON) - #define pl_log_debug(pcMessage) pl__log_debug(pl__get_current_log_channel(), (pcMessage)) - #define pl_log_debug_f(...) pl__log_debug_p(pl__get_current_log_channel(), __VA_ARGS__) - #define pl_log_debug_to(uID, pcMessage) pl__log_debug((uID), (pcMessage)) - #define pl_log_debug_to_f(...) pl__log_debug_p(__VA_ARGS__) + #define pl_log_debug(uID, pcMessage) pl__log_debug((uID), (pcMessage)) + #define pl_log_debug_f(...) pl__log_debug_p(__VA_ARGS__) #else - #define pl_log_debug(pcMessage) // + #define pl_log_debug(uID, pcMessage) // #define pl_log_debug_f(...) // - #define pl_log_debug_to(uID, pcMessage) // - #define pl_log_debug_to_f(...) // #endif #if PL_GLOBAL_LOG_LEVEL < PL_LOG_LEVEL_INFO + 1 && defined(PL_LOG_ON) - #define pl_log_info(pcMessage) pl__log_info(pl__get_current_log_channel(), (pcMessage)) - #define pl_log_info_f(...) pl__log_info_p(pl__get_current_log_channel(), __VA_ARGS__) - #define pl_log_info_to(uID, pcMessage) pl__log_info((uID), (pcMessage)) - #define pl_log_info_to_f(...) pl__log_info_p(__VA_ARGS__) + #define pl_log_info(uID, pcMessage) pl__log_info((uID), (pcMessage)) + #define pl_log_info_f(...) pl__log_info_p(__VA_ARGS__) #else - #define pl_log_info(pcMessage) // + #define pl_log_info(uID, pcMessage) // #define pl_log_info_f(...) // - #define pl_log_info_to(uID, pcMessage) // - #define pl_log_info_to_f(...) // #endif #if PL_GLOBAL_LOG_LEVEL < PL_LOG_LEVEL_WARN + 1 && defined(PL_LOG_ON) - #define pl_log_warn(pcMessage) pl__log_warn(pl__get_current_log_channel(), (pcMessage)) - #define pl_log_warn_f(...) pl__log_warn_p(pl__get_current_log_channel(), __VA_ARGS__) - #define pl_log_warn_to(uID, pcMessage) pl__log_warn((uID), (pcMessage)) - #define pl_log_warn_to_f(...) pl__log_warn_p(__VA_ARGS__) + #define pl_log_warn(uID, pcMessage) pl__log_warn((uID), (pcMessage)) + #define pl_log_warn_f(...) pl__log_warn_p(__VA_ARGS__) #else - #define pl_log_warn(pcMessage) // + #define pl_log_warn(tPContext, uID) // #define pl_log_warn_f(...) // - #define pl_log_warn_to(tPContext, uID) // - #define pl_log_warn_to_f(...) // #endif #if PL_GLOBAL_LOG_LEVEL < PL_LOG_LEVEL_ERROR + 1 && defined(PL_LOG_ON) - #define pl_log_error(pcMessage) pl__log_error(pl__get_current_log_channel(), (pcMessage)) - #define pl_log_error_f(...) pl__log_error_p(pl__get_current_log_channel(), __VA_ARGS__) - #define pl_log_error_to(uID, pcMessage) pl__log_error((uID), (pcMessage)) - #define pl_log_error_to_f(...) pl__log_error_p(__VA_ARGS__) + #define pl_log_error(uID, pcMessage) pl__log_error((uID), (pcMessage)) + #define pl_log_error_f(...) pl__log_error_p(__VA_ARGS__) #else - #define pl_log_error(pcMessage) // + #define pl_log_error(tPContext, uID) // #define pl_log_error_f(...) // - #define pl_log_error_to(tPContext, uID) // - #define pl_log_error_to_f(...) // #endif #if PL_GLOBAL_LOG_LEVEL < PL_LOG_LEVEL_FATAL + 1 && defined(PL_LOG_ON) - #define pl_log_fatal(pcMessage) pl__log_fatal(pl__get_current_log_channel(), (pcMessage)) - #define pl_log_fatal_f(...) pl__log_fatal_p(pl__get_current_log_channel(), __VA_ARGS__) - #define pl_log_fatal_to(uID, pcMessage) pl__log_fatal((uID), (pcMessage)) - #define pl_log_fatal_to_f(...) pl__log_fatal_p(__VA_ARGS__) + #define pl_log_fatal(uID, pcMessage) pl__log_fatal((uID), (pcMessage)) + #define pl_log_fatal_f(...) pl__log_fatal_p(__VA_ARGS__) #else - #define pl_log_fatal(pcMessage) // + #define pl_log_fatal(uID, pcMessage) // #define pl_log_fatal_f(...) // - #define pl_log_fatal_to(uID, pcMessage) // - #define pl_log_fatal_to_f(...) // #endif +#endif // PL_LOG_REMOVE_ALL_MACROS + +//----------------------------------------------------------------------------- +// [SECTION] structs +//----------------------------------------------------------------------------- + +typedef struct _plLogChannelInit +{ + plChannelType tType; + uint64_t uEntryCount; // default: 1024 +} plLogChannelInit; + +typedef struct _plLogEntry +{ + uint64_t uLevel; + uint64_t uOffset; +} plLogEntry; + +typedef struct _plLogChannelInfo +{ + uint64_t uID; + plChannelType tType; + const char* pcName; + size_t szBufferSize; + char* pcBuffer; + uint64_t uEntryCount; + uint64_t uEntryCapacity; + plLogEntry* ptEntries; +} plLogChannelInfo; + //----------------------------------------------------------------------------- // [SECTION] enums //----------------------------------------------------------------------------- enum plChannelType_ { - PL_CHANNEL_TYPE_DEFAULT = 0, - PL_CHANNEL_TYPE_CONSOLE = 1 << 0, - PL_CHANNEL_TYPE_BUFFER = 1 << 1, - PL_CHANNEL_TYPE_CYCLIC_BUFFER = 1 << 2 + PL_CHANNEL_TYPE_DEFAULT = 0, + PL_CHANNEL_TYPE_CONSOLE = 1 << 0, + PL_CHANNEL_TYPE_BUFFER = 1 << 1, + PL_CHANNEL_TYPE_CYCLIC_BUFFER = 1 << 2 }; -//----------------------------------------------------------------------------- -// [SECTION] structs -//----------------------------------------------------------------------------- - -typedef struct _plLogEntry -{ - uint32_t uLevel; - uint64_t uOffset; - uint64_t uGeneration; -} plLogEntry; - -typedef struct _plLogChannel -{ - const char* pcName; - bool bOverflowInUse; - char* pcBuffer0; - char* pcBuffer1; - uint64_t uGeneration; - uint64_t uBufferSize; - uint64_t uBufferCapacity; - plLogEntry atEntries[PL_LOG_CYCLIC_BUFFER_SIZE]; - plLogEntry* pEntries; - uint64_t uEntryCount; - uint64_t uEntryCapacity; - uint64_t uNextEntry; - uint32_t uLevel; - plChannelType tType; - uint32_t uID; -} plLogChannel; - //----------------------------------------------------------------------------- // [SECTION] internal api //----------------------------------------------------------------------------- @@ -435,55 +385,58 @@ typedef struct _plLogChannel // setup/shutdown plLogContext* pl__create_log_context (void); void pl__cleanup_log_context(void); -void pl__set_log_context (plLogContext* tPContext); -plLogContext* pl__get_log_context (void); +void pl__set_log_context (plLogContext*); // channels -uint32_t pl__add_log_channel (const char* pcName, plChannelType tType); -uint32_t pl__get_current_log_channel(void); -void pl__set_current_log_channel(uint32_t uID); -void pl__set_log_level (uint32_t uID, uint32_t uLevel); -void pl__clear_log_channel (uint32_t uID); -void pl__reset_log_channel (uint32_t uID); -plLogEntry* pl__get_log_entries (uint32_t uID, uint64_t* puEntryCount); -plLogChannel* pl__get_log_channels (uint32_t* puChannelCount); +uint64_t pl__add_log_channel (const char* pcName, plLogChannelInit); +void pl__set_log_level (uint64_t uID, uint64_t uLevel); +void pl__clear_log_channel (uint64_t uID); +void pl__reset_log_channel (uint64_t uID); +uint64_t pl__get_log_channel_id (const char* pcName); +bool pl__get_log_channel_info (uint64_t uID, plLogChannelInfo*); +uint64_t pl__get_log_channel_count(void); // logging -void pl__log_trace(uint32_t uID, const char* pcMessage); -void pl__log_debug(uint32_t uID, const char* pcMessage); -void pl__log_info (uint32_t uID, const char* pcMessage); -void pl__log_warn (uint32_t uID, const char* pcMessage); -void pl__log_error(uint32_t uID, const char* pcMessage); -void pl__log_fatal(uint32_t uID, const char* pcMessage); +void pl__log (const char* pcPrefix, int iPrefixSize, uint64_t uLevel, uint64_t uID, const char* pcMessage); +void pl__log_trace(uint64_t uID, const char* pcMessage); +void pl__log_debug(uint64_t uID, const char* pcMessage); +void pl__log_info (uint64_t uID, const char* pcMessage); +void pl__log_warn (uint64_t uID, const char* pcMessage); +void pl__log_error(uint64_t uID, const char* pcMessage); +void pl__log_fatal(uint64_t uID, const char* pcMessage); -void pl__log_trace_p(uint32_t uID, const char* cPFormat, ...); -void pl__log_debug_p(uint32_t uID, const char* cPFormat, ...); -void pl__log_info_p (uint32_t uID, const char* cPFormat, ...); -void pl__log_warn_p (uint32_t uID, const char* cPFormat, ...); -void pl__log_error_p(uint32_t uID, const char* cPFormat, ...); -void pl__log_fatal_p(uint32_t uID, const char* cPFormat, ...); +void pl__log_p (const char* pcPrefix, int iPrefixSize, uint64_t uLevel, uint64_t uID, const char* cPFormat, ...); +void pl__log_trace_p(uint64_t uID, const char* cPFormat, ...); +void pl__log_debug_p(uint64_t uID, const char* cPFormat, ...); +void pl__log_info_p (uint64_t uID, const char* cPFormat, ...); +void pl__log_warn_p (uint64_t uID, const char* cPFormat, ...); +void pl__log_error_p(uint64_t uID, const char* cPFormat, ...); +void pl__log_fatal_p(uint64_t uID, const char* cPFormat, ...); -void pl__log_trace_va(uint32_t uID, const char* cPFormat, va_list args); -void pl__log_debug_va(uint32_t uID, const char* cPFormat, va_list args); -void pl__log_info_va (uint32_t uID, const char* cPFormat, va_list args); -void pl__log_warn_va (uint32_t uID, const char* cPFormat, va_list args); -void pl__log_error_va(uint32_t uID, const char* cPFormat, va_list args); -void pl__log_fatal_va(uint32_t uID, const char* cPFormat, va_list args); +void pl__log_va (const char* pcPrefix, int iPrefixSize, uint64_t uLevel, uint64_t uID, const char* cPFormat, va_list args); +void pl__log_trace_va(uint64_t uID, const char* cPFormat, va_list args); +void pl__log_debug_va(uint64_t uID, const char* cPFormat, va_list args); +void pl__log_info_va (uint64_t uID, const char* cPFormat, va_list args); +void pl__log_warn_va (uint64_t uID, const char* cPFormat, va_list args); +void pl__log_error_va(uint64_t uID, const char* cPFormat, va_list args); +void pl__log_fatal_va(uint64_t uID, const char* cPFormat, va_list args); +#ifndef PL_LOG_REMOVE_ALL_MACROS #ifndef PL_LOG_ON #define pl_create_log_context() NULL #define pl_cleanup_log_context() // #define pl_set_log_context(ctx) // - #define pl_get_log_context() NULL - #define pl_add_log_channel(pcName, tType) 0u + #define pl_add_log_channel(pcName, tInfo) 0u #define pl_set_log_level(uID, uLevel) // #define pl_clear_log_channel(uID) // #define pl_reset_log_channel(uID) // - #define pl_get_log_entries(uID, puEntryCount) NULL - #define pl_set_current_log_channel(uID) // - #define pl_get_current_log_channel(uID) 0 - #define pl_get_log_channels(puChannelCount) NULL + #define pl_get_log_channel_count() 0 + #define pl_get_log_channel_id(pcName) 0 + #define pl_get_log_channel_info(uID, ptInfo) false + #define pl_log(pcPrefix, iPrefixSize, uLevel, uID, pcMessage) // + #define pl_log_f(...) // #endif +#endif // PL_LOG_REMOVE_ALL_MACROS #endif // PL_LOG_H @@ -499,7 +452,6 @@ Index of this file: // [SECTION] global context // [SECTION] internal api // [SECTION] public api implementation -// [SECTION] internal api implementation */ //----------------------------------------------------------------------------- @@ -508,88 +460,98 @@ Index of this file: #ifdef PL_LOG_IMPLEMENTATION +#ifndef PL_LOG_ALLOC + #include + #define PL_LOG_ALLOC(x) malloc((x)) + #define PL_LOG_FREE(x) free((x)) +#endif + #ifndef PL_LOG_MAX_CHANNEL_COUNT #define PL_LOG_MAX_CHANNEL_COUNT 16 #endif +#ifndef PL_LOG_MAX_LINE_SIZE + #define PL_LOG_MAX_LINE_SIZE 1024 +#endif + #ifdef _WIN32 -#define PL_LOG_BOLD_CODE "" -#define PL_LOG_UNDERLINE_CODE "" -#define PL_LOG_POP_CODE "" + #define PL_LOG_BOLD_CODE "" + #define PL_LOG_UNDERLINE_CODE "" + #define PL_LOG_POP_CODE "" -#define PL_LOG_FG_COLOR_CODE_BLACK "" -#define PL_LOG_FG_COLOR_CODE_RED "" -#define PL_LOG_FG_COLOR_CODE_GREEN "" -#define PL_LOG_FG_COLOR_CODE_YELLOW "" -#define PL_LOG_FG_COLOR_CODE_BLUE "" -#define PL_LOG_FG_COLOR_CODE_MAGENTA "" -#define PL_LOG_FG_COLOR_CODE_CYAN "" -#define PL_LOG_FG_COLOR_CODE_WHITE "" -#define PL_LOG_FG_COLOR_CODE_STRONG_BLACK "" -#define PL_LOG_FG_COLOR_CODE_STRONG_RED "" -#define PL_LOG_FG_COLOR_CODE_STRONG_GREEN "" -#define PL_LOG_FG_COLOR_CODE_STRONG_YELLOW "" -#define PL_LOG_FG_COLOR_CODE_STRONG_BLUE "" -#define PL_LOG_FG_COLOR_CODE_STRONG_MAGENTA "" -#define PL_LOG_FG_COLOR_CODE_STRONG_CYAN "" -#define PL_LOG_FG_COLOR_CODE_STRONG_WHITE "" + #define PL_LOG_FG_COLOR_CODE_BLACK "" + #define PL_LOG_FG_COLOR_CODE_RED "" + #define PL_LOG_FG_COLOR_CODE_GREEN "" + #define PL_LOG_FG_COLOR_CODE_YELLOW "" + #define PL_LOG_FG_COLOR_CODE_BLUE "" + #define PL_LOG_FG_COLOR_CODE_MAGENTA "" + #define PL_LOG_FG_COLOR_CODE_CYAN "" + #define PL_LOG_FG_COLOR_CODE_WHITE "" + #define PL_LOG_FG_COLOR_CODE_STRONG_BLACK "" + #define PL_LOG_FG_COLOR_CODE_STRONG_RED "" + #define PL_LOG_FG_COLOR_CODE_STRONG_GREEN "" + #define PL_LOG_FG_COLOR_CODE_STRONG_YELLOW "" + #define PL_LOG_FG_COLOR_CODE_STRONG_BLUE "" + #define PL_LOG_FG_COLOR_CODE_STRONG_MAGENTA "" + #define PL_LOG_FG_COLOR_CODE_STRONG_CYAN "" + #define PL_LOG_FG_COLOR_CODE_STRONG_WHITE "" -#define PL_LOG_BG_COLOR_CODE_BLACK "" -#define PL_LOG_BG_COLOR_CODE_RED "" -#define PL_LOG_BG_COLOR_CODE_GREEN "" -#define PL_LOG_BG_COLOR_CODE_YELLOW "" -#define PL_LOG_BG_COLOR_CODE_BLUE "" -#define PL_LOG_BG_COLOR_CODE_MAGENTA "" -#define PL_LOG_BG_COLOR_CODE_CYAN "" -#define PL_LOG_BG_COLOR_CODE_WHITE "" -#define PL_LOG_BG_COLOR_CODE_STRONG_BLACK "" -#define PL_LOG_BG_COLOR_CODE_STRONG_RED "" -#define PL_LOG_BG_COLOR_CODE_STRONG_GREEN "" -#define PL_LOG_BG_COLOR_CODE_STRONG_YELLOW "" -#define PL_LOG_BG_COLOR_CODE_STRONG_BLUE "" -#define PL_LOG_BG_COLOR_CODE_STRONG_MAGENTA "" -#define PL_LOG_BG_COLOR_CODE_STRONG_CYAN "" -#define PL_LOG_BG_COLOR_CODE_STRONG_WHITE "" + #define PL_LOG_BG_COLOR_CODE_BLACK "" + #define PL_LOG_BG_COLOR_CODE_RED "" + #define PL_LOG_BG_COLOR_CODE_GREEN "" + #define PL_LOG_BG_COLOR_CODE_YELLOW "" + #define PL_LOG_BG_COLOR_CODE_BLUE "" + #define PL_LOG_BG_COLOR_CODE_MAGENTA "" + #define PL_LOG_BG_COLOR_CODE_CYAN "" + #define PL_LOG_BG_COLOR_CODE_WHITE "" + #define PL_LOG_BG_COLOR_CODE_STRONG_BLACK "" + #define PL_LOG_BG_COLOR_CODE_STRONG_RED "" + #define PL_LOG_BG_COLOR_CODE_STRONG_GREEN "" + #define PL_LOG_BG_COLOR_CODE_STRONG_YELLOW "" + #define PL_LOG_BG_COLOR_CODE_STRONG_BLUE "" + #define PL_LOG_BG_COLOR_CODE_STRONG_MAGENTA "" + #define PL_LOG_BG_COLOR_CODE_STRONG_CYAN "" + #define PL_LOG_BG_COLOR_CODE_STRONG_WHITE "" #else -#define PL_LOG_BOLD_CODE "\033[1m" -#define PL_LOG_UNDERLINE_CODE "\033[4m" -#define PL_LOG_POP_CODE "\033[0m" + #define PL_LOG_BOLD_CODE "\033[1m" + #define PL_LOG_UNDERLINE_CODE "\033[4m" + #define PL_LOG_POP_CODE "\033[0m" -#define PL_LOG_FG_COLOR_CODE_BLACK "\033[30m" -#define PL_LOG_FG_COLOR_CODE_RED "\033[31m" -#define PL_LOG_FG_COLOR_CODE_GREEN "\033[32m" -#define PL_LOG_FG_COLOR_CODE_YELLOW "\033[33m" -#define PL_LOG_FG_COLOR_CODE_BLUE "\033[34m" -#define PL_LOG_FG_COLOR_CODE_MAGENTA "\033[35m" -#define PL_LOG_FG_COLOR_CODE_CYAN "\033[36m" -#define PL_LOG_FG_COLOR_CODE_WHITE "\033[37m" -#define PL_LOG_FG_COLOR_CODE_STRONG_BLACK "\033[90m" -#define PL_LOG_FG_COLOR_CODE_STRONG_RED "\033[91m" -#define PL_LOG_FG_COLOR_CODE_STRONG_GREEN "\033[92m" -#define PL_LOG_FG_COLOR_CODE_STRONG_YELLOW "\033[93m" -#define PL_LOG_FG_COLOR_CODE_STRONG_BLUE "\033[94m" -#define PL_LOG_FG_COLOR_CODE_STRONG_MAGENTA "\033[95m" -#define PL_LOG_FG_COLOR_CODE_STRONG_CYAN "\033[96m" -#define PL_LOG_FG_COLOR_CODE_STRONG_WHITE "\033[97m" + #define PL_LOG_FG_COLOR_CODE_BLACK "\033[30m" + #define PL_LOG_FG_COLOR_CODE_RED "\033[31m" + #define PL_LOG_FG_COLOR_CODE_GREEN "\033[32m" + #define PL_LOG_FG_COLOR_CODE_YELLOW "\033[33m" + #define PL_LOG_FG_COLOR_CODE_BLUE "\033[34m" + #define PL_LOG_FG_COLOR_CODE_MAGENTA "\033[35m" + #define PL_LOG_FG_COLOR_CODE_CYAN "\033[36m" + #define PL_LOG_FG_COLOR_CODE_WHITE "\033[37m" + #define PL_LOG_FG_COLOR_CODE_STRONG_BLACK "\033[90m" + #define PL_LOG_FG_COLOR_CODE_STRONG_RED "\033[91m" + #define PL_LOG_FG_COLOR_CODE_STRONG_GREEN "\033[92m" + #define PL_LOG_FG_COLOR_CODE_STRONG_YELLOW "\033[93m" + #define PL_LOG_FG_COLOR_CODE_STRONG_BLUE "\033[94m" + #define PL_LOG_FG_COLOR_CODE_STRONG_MAGENTA "\033[95m" + #define PL_LOG_FG_COLOR_CODE_STRONG_CYAN "\033[96m" + #define PL_LOG_FG_COLOR_CODE_STRONG_WHITE "\033[97m" -#define PL_LOG_BG_COLOR_CODE_BLACK "\033[40m" -#define PL_LOG_BG_COLOR_CODE_RED "\033[41m" -#define PL_LOG_BG_COLOR_CODE_GREEN "\033[42m" -#define PL_LOG_BG_COLOR_CODE_YELLOW "\033[43m" -#define PL_LOG_BG_COLOR_CODE_BLUE "\033[44m" -#define PL_LOG_BG_COLOR_CODE_MAGENTA "\033[45m" -#define PL_LOG_BG_COLOR_CODE_CYAN "\033[46m" -#define PL_LOG_BG_COLOR_CODE_WHITE "\033[47m" -#define PL_LOG_BG_COLOR_CODE_STRONG_BLACK "\033[100m" -#define PL_LOG_BG_COLOR_CODE_STRONG_RED "\033[101m" -#define PL_LOG_BG_COLOR_CODE_STRONG_GREEN "\033[102m" -#define PL_LOG_BG_COLOR_CODE_STRONG_YELLOW "\033[103m" -#define PL_LOG_BG_COLOR_CODE_STRONG_BLUE "\033[104m" -#define PL_LOG_BG_COLOR_CODE_STRONG_MAGENTA "\033[105m" -#define PL_LOG_BG_COLOR_CODE_STRONG_CYAN "\033[106m" -#define PL_LOG_BG_COLOR_CODE_STRONG_WHITE "\033[107m" + #define PL_LOG_BG_COLOR_CODE_BLACK "\033[40m" + #define PL_LOG_BG_COLOR_CODE_RED "\033[41m" + #define PL_LOG_BG_COLOR_CODE_GREEN "\033[42m" + #define PL_LOG_BG_COLOR_CODE_YELLOW "\033[43m" + #define PL_LOG_BG_COLOR_CODE_BLUE "\033[44m" + #define PL_LOG_BG_COLOR_CODE_MAGENTA "\033[45m" + #define PL_LOG_BG_COLOR_CODE_CYAN "\033[46m" + #define PL_LOG_BG_COLOR_CODE_WHITE "\033[47m" + #define PL_LOG_BG_COLOR_CODE_STRONG_BLACK "\033[100m" + #define PL_LOG_BG_COLOR_CODE_STRONG_RED "\033[101m" + #define PL_LOG_BG_COLOR_CODE_STRONG_GREEN "\033[102m" + #define PL_LOG_BG_COLOR_CODE_STRONG_YELLOW "\033[103m" + #define PL_LOG_BG_COLOR_CODE_STRONG_BLUE "\033[104m" + #define PL_LOG_BG_COLOR_CODE_STRONG_MAGENTA "\033[105m" + #define PL_LOG_BG_COLOR_CODE_STRONG_CYAN "\033[106m" + #define PL_LOG_BG_COLOR_CODE_STRONG_WHITE "\033[107m" #endif @@ -603,10 +565,10 @@ Index of this file: #define PL_LOG_DEBUG_FG_COLOR PL_LOG_FG_COLOR_CODE_CYAN #endif #ifndef PL_LOG_INFO_FG_COLOR - #define PL_LOG_INFO_FG_COLOR PL_LOG_FG_COLOR_CODE_WHITE + #define PL_LOG_INFO_FG_COLOR PL_LOG_FG_COLOR_CODE_WHITE #endif #ifndef PL_LOG_WARN_FG_COLOR - #define PL_LOG_WARN_FG_COLOR PL_LOG_FG_COLOR_CODE_YELLOW + #define PL_LOG_WARN_FG_COLOR PL_LOG_FG_COLOR_CODE_YELLOW #endif #ifndef PL_LOG_ERROR_FG_COLOR #define PL_LOG_ERROR_FG_COLOR PL_LOG_FG_COLOR_CODE_RED @@ -614,6 +576,12 @@ Index of this file: #ifndef PL_LOG_FATAL_FG_COLOR #define PL_LOG_FATAL_FG_COLOR PL_LOG_FG_COLOR_CODE_WHITE #endif +#ifndef PL_LOG_CUSTOM_FG_COLOR + #define PL_LOG_CUSTOM_FG_COLOR PL_LOG_FG_COLOR_CODE_WHITE +#endif +#ifndef PL_LOG_CUSTOM_BG_COLOR + #define PL_LOG_CUSTOM_BG_COLOR PL_LOG_BG_COLOR_CODE_CYAN +#endif //----------------------------------------------------------------------------- // [SECTION] includes @@ -637,38 +605,92 @@ Index of this file: // [SECTION] internal structs //----------------------------------------------------------------------------- +typedef struct _plLogChannel +{ + const char* pcName; + char* pcBuffer; + uint64_t szGeneration; + size_t szBufferSize; + size_t szBufferCapacity; // real capacity is 2x this + plLogEntry* ptEntries; + uint64_t uEntryCount; + uint64_t uEntryCapacity; + uint64_t uNextEntry; + uint64_t uLevel; + plChannelType tType; + uint64_t uID; +} plLogChannel; + typedef struct _plLogContext { plLogChannel atChannels[PL_LOG_MAX_CHANNEL_COUNT]; - uint32_t uChannelCount; - uint32_t uCurrentChannel; + uint64_t uChannelCount; } plLogContext; //----------------------------------------------------------------------------- // [SECTION] global context //----------------------------------------------------------------------------- -plLogContext* gptLogContext = NULL; +static plLogContext* gptLogContext = NULL; //----------------------------------------------------------------------------- // [SECTION] internal api //----------------------------------------------------------------------------- -static plLogEntry* pl__get_new_log_entry(uint32_t uID); - -static inline void pl__log_buffer_may_grow(plLogChannel* ptChannel, int iAdditionalSize) +static plLogEntry* +pl__get_new_log_entry(uint64_t uID) { - if(ptChannel->uBufferSize + iAdditionalSize > ptChannel->uBufferCapacity) // grow + plLogChannel* tPChannel = &gptLogContext->atChannels[uID]; + + plLogEntry* ptEntry = NULL; + + if(tPChannel->tType & PL_CHANNEL_TYPE_CYCLIC_BUFFER) { - char* pcOldBuffer = ptChannel->pcBuffer0; - uint64_t uNewCapacity = ptChannel->uBufferCapacity * 2; - if(uNewCapacity < ptChannel->uBufferSize + iAdditionalSize) - uNewCapacity = (ptChannel->uBufferSize + (uint64_t)iAdditionalSize) * 2; - ptChannel->pcBuffer0 = (char*)PL_LOG_ALLOC(uNewCapacity * 2); - memset(ptChannel->pcBuffer0, 0, uNewCapacity * 2); - memcpy(ptChannel->pcBuffer0, pcOldBuffer, ptChannel->uBufferCapacity); - ptChannel->uBufferCapacity = uNewCapacity; - ptChannel->pcBuffer1 = &ptChannel->pcBuffer0[uNewCapacity]; + ptEntry = &tPChannel->ptEntries[tPChannel->uNextEntry]; + tPChannel->uNextEntry++; + tPChannel->uNextEntry = tPChannel->uNextEntry % tPChannel->uEntryCapacity; + tPChannel->uEntryCount++; + if(tPChannel->uNextEntry == 0) + { + tPChannel->szBufferSize = 0; + tPChannel->szGeneration++; + } + } + else if(tPChannel->tType & PL_CHANNEL_TYPE_BUFFER) + { + + // check if overflow reallocation is needed + if(tPChannel->uEntryCount == tPChannel->uEntryCapacity) + { + plLogEntry* sbtOldEntries = tPChannel->ptEntries; + tPChannel->ptEntries = (plLogEntry*)PL_LOG_ALLOC(sizeof(plLogEntry) * tPChannel->uEntryCapacity * 2); + memset(tPChannel->ptEntries, 0, sizeof(plLogEntry) * tPChannel->uEntryCapacity * 2); + + // copy old values + memcpy(tPChannel->ptEntries, sbtOldEntries, sizeof(plLogEntry) * tPChannel->uEntryCapacity); + tPChannel->uEntryCapacity *= 2; + + PL_LOG_FREE(sbtOldEntries); + } + ptEntry = &tPChannel->ptEntries[tPChannel->uEntryCount]; + tPChannel->uEntryCount++; + } + return ptEntry; +} + +static inline void +pl__log_buffer_may_grow(plLogChannel* ptChannel, int iAdditionalSize) +{ + if(ptChannel->szBufferSize + iAdditionalSize > ptChannel->szBufferCapacity) // grow + { + char* pcOldBuffer = ptChannel->pcBuffer; + size_t uNewCapacity = ptChannel->szBufferCapacity * 2; + if(uNewCapacity < ptChannel->szBufferSize + iAdditionalSize) + uNewCapacity = (ptChannel->szBufferSize + (size_t)iAdditionalSize) * 2; + ptChannel->pcBuffer = (char*)PL_LOG_ALLOC(uNewCapacity * 2); + memset(ptChannel->pcBuffer, 0, uNewCapacity * 2); + memcpy(ptChannel->pcBuffer, pcOldBuffer, ptChannel->szBufferCapacity); + ptChannel->szBufferCapacity = uNewCapacity; PL_LOG_FREE(pcOldBuffer); } } @@ -680,22 +702,36 @@ static inline void pl__log_buffer_may_grow(plLogChannel* ptChannel, int iAdditio plLogContext* pl__create_log_context(void) { - plLogContext* tPContext = (plLogContext*)PL_LOG_ALLOC(sizeof(plLogContext)); - memset(tPContext, 0, sizeof(plLogContext)); - tPContext->uChannelCount = 0; - gptLogContext = tPContext; + static plLogContext gtContext = {0}; + gptLogContext = >Context; // setup log channels - pl_add_log_channel("Default", PL_CHANNEL_TYPE_CONSOLE | PL_CHANNEL_TYPE_BUFFER); + plLogChannelInit tLogInit = { + .tType = PL_CHANNEL_TYPE_CONSOLE | PL_CHANNEL_TYPE_BUFFER, + .uEntryCount = 1024 + }; + pl__add_log_channel("Default", tLogInit); - pl_log_trace_f("<- global enabled"); - pl_log_debug_f("<- global enabled"); - pl_log_info_f("<- global enabled"); - pl_log_warn_f("<- global enabled"); - pl_log_error_f("<- global enabled"); - pl_log_fatal_f("<- global enabled"); + #if PL_GLOBAL_LOG_LEVEL < PL_LOG_LEVEL_TRACE + 1 && defined(PL_LOG_ON) + pl__log_trace_p(0, "<- global enabled"); + #endif + #if PL_GLOBAL_LOG_LEVEL < PL_LOG_LEVEL_DEBUG + 1 && defined(PL_LOG_ON) + pl__log_debug_p(0, "<- global enabled"); + #endif + #if PL_GLOBAL_LOG_LEVEL < PL_LOG_LEVEL_INFO + 1 && defined(PL_LOG_ON) + pl__log_info_p(0, "<- global enabled"); + #endif + #if PL_GLOBAL_LOG_LEVEL < PL_LOG_LEVEL_WARN + 1 && defined(PL_LOG_ON) + pl__log_warn_p(0, "<- global enabled"); + #endif + #if PL_GLOBAL_LOG_LEVEL < PL_LOG_LEVEL_ERROR + 1 && defined(PL_LOG_ON) + pl__log_error_p(0, "<- global enabled"); + #endif + #if PL_GLOBAL_LOG_LEVEL < PL_LOG_LEVEL_FATAL + 1 && defined(PL_LOG_ON) + pl__log_fatal_p(0, "<- global enabled"); + #endif - return tPContext; + return gptLogContext; } void @@ -704,26 +740,27 @@ pl__cleanup_log_context(void) PL_ASSERT(gptLogContext && "no global log context set"); if(gptLogContext) { - for(uint32_t i = 0; i < gptLogContext->uChannelCount; i++) + for(uint64_t i = 0; i < gptLogContext->uChannelCount; i++) { plLogChannel* ptChannel = &gptLogContext->atChannels[i]; - if(ptChannel->pcBuffer0) - PL_LOG_FREE(ptChannel->pcBuffer0); - if(ptChannel->bOverflowInUse) - PL_LOG_FREE(ptChannel->pEntries); - ptChannel->pEntries = NULL; - ptChannel->pcBuffer0 = NULL; - ptChannel->uBufferCapacity = 0; - ptChannel->uBufferSize = 0; - ptChannel->uEntryCapacity = 0; - ptChannel->uEntryCount = 0; - ptChannel->uLevel = 0; - ptChannel->tType = 0; - ptChannel->uID = 0; + if(ptChannel->pcBuffer) + PL_LOG_FREE(ptChannel->pcBuffer); + if(ptChannel->ptEntries) + { + PL_LOG_FREE(ptChannel->ptEntries); + } + ptChannel->ptEntries = NULL; + ptChannel->pcBuffer = NULL; + ptChannel->szBufferCapacity = 0; + ptChannel->szBufferSize = 0; + ptChannel->uEntryCapacity = 0; + ptChannel->uEntryCount = 0; + ptChannel->uLevel = 0; + ptChannel->tType = 0; + ptChannel->uID = 0; } memset(gptLogContext->atChannels, 0, sizeof(plLogChannel) * PL_LOG_MAX_CHANNEL_COUNT); gptLogContext->uChannelCount = 0; - PL_LOG_FREE(gptLogContext); } gptLogContext = NULL; } @@ -735,39 +772,35 @@ pl__set_log_context(plLogContext* tPContext) gptLogContext = tPContext; } -plLogContext* -pl__get_log_context(void) +uint64_t +pl__add_log_channel(const char* pcName, plLogChannelInit tInit) { - PL_ASSERT(gptLogContext && "no global log context set"); - return gptLogContext; -} + uint64_t uID = gptLogContext->uChannelCount; -uint32_t -pl__add_log_channel(const char* pcName, plChannelType tType) -{ - uint32_t uID = gptLogContext->uChannelCount; + if(tInit.uEntryCount == 0) + tInit.uEntryCount = 1024; - if((tType & PL_CHANNEL_TYPE_BUFFER) && (tType & PL_CHANNEL_TYPE_CYCLIC_BUFFER)) + if((tInit.tType & PL_CHANNEL_TYPE_BUFFER) && (tInit.tType & PL_CHANNEL_TYPE_CYCLIC_BUFFER)) { PL_ASSERT(false && "Can't have PL_CHANNEL_TYPE_BUFFER and PL_CHANNEL_TYPE_CYCLIC_BUFFER together"); } plLogChannel* ptChannel = &gptLogContext->atChannels[uID]; ptChannel->pcName = pcName; - if(tType & PL_CHANNEL_TYPE_BUFFER) + if(tInit.tType & PL_CHANNEL_TYPE_BUFFER) { - ptChannel->pEntries = (plLogEntry*)PL_LOG_ALLOC(PL_LOG_INITIAL_LOG_SIZE * sizeof(plLogEntry)); - ptChannel->uEntryCapacity = PL_LOG_INITIAL_LOG_SIZE; + ptChannel->ptEntries = (plLogEntry*)PL_LOG_ALLOC(tInit.uEntryCount * sizeof(plLogEntry)); + ptChannel->uEntryCapacity = tInit.uEntryCount; + memset(ptChannel->ptEntries, 0, tInit.uEntryCount * sizeof(plLogEntry)); } - else if(tType & PL_CHANNEL_TYPE_CYCLIC_BUFFER) + else if(tInit.tType & PL_CHANNEL_TYPE_CYCLIC_BUFFER) { - ptChannel->pEntries = NULL; - ptChannel->uEntryCapacity = PL_LOG_CYCLIC_BUFFER_SIZE; - pl__log_buffer_may_grow(ptChannel, PL_LOG_MAX_LINE_SIZE); + ptChannel->ptEntries = (plLogEntry*)PL_LOG_ALLOC(tInit.uEntryCount * sizeof(plLogEntry)); + ptChannel->uEntryCapacity = tInit.uEntryCount; } else { - ptChannel->pEntries = NULL; + ptChannel->ptEntries = NULL; ptChannel->uEntryCapacity = 0; pl__log_buffer_may_grow(ptChannel, PL_LOG_MAX_LINE_SIZE); } @@ -775,139 +808,153 @@ pl__add_log_channel(const char* pcName, plChannelType tType) ptChannel->uEntryCount = 0; ptChannel->uNextEntry = 0; ptChannel->uLevel = 0; - ptChannel->tType = tType; + ptChannel->tType = tInit.tType; ptChannel->uID = uID; gptLogContext->uChannelCount++; return uID; } -uint32_t -pl__get_current_log_channel(void) -{ - return gptLogContext->uCurrentChannel; -} - void -pl__set_current_log_channel(uint32_t uID) -{ - PL_ASSERT(uID < gptLogContext->uChannelCount && "channel ID is not valid"); - gptLogContext->uCurrentChannel = uID; -} - -void -pl__set_log_level(uint32_t uID, uint32_t uLevel) +pl__set_log_level(uint64_t uID, uint64_t uLevel) { PL_ASSERT(uID < gptLogContext->uChannelCount && "channel ID is not valid"); gptLogContext->atChannels[uID].uLevel = uLevel; } void -pl__clear_log_channel(uint32_t uID) +pl__clear_log_channel(uint64_t uID) { PL_ASSERT(uID < gptLogContext->uChannelCount && "channel ID is not valid"); gptLogContext->atChannels[uID].uEntryCount = 0u; gptLogContext->atChannels[uID].uNextEntry = 0u; - if(gptLogContext->atChannels[uID].tType & PL_CHANNEL_TYPE_CYCLIC_BUFFER) - memset(gptLogContext->atChannels[uID].atEntries, 0, sizeof(plLogEntry) * PL_LOG_CYCLIC_BUFFER_SIZE); - else if(gptLogContext->atChannels[uID].tType & PL_CHANNEL_TYPE_BUFFER) + if(gptLogContext->atChannels[uID].tType & PL_CHANNEL_TYPE_CYCLIC_BUFFER || gptLogContext->atChannels[uID].tType & PL_CHANNEL_TYPE_BUFFER) { - PL_LOG_FREE(gptLogContext->atChannels[uID].pEntries); - gptLogContext->atChannels[uID].pEntries = NULL; + PL_LOG_FREE(gptLogContext->atChannels[uID].ptEntries); + gptLogContext->atChannels[uID].ptEntries = NULL; gptLogContext->atChannels[uID].uEntryCapacity = 0; } } void -pl__reset_log_channel(uint32_t uID) +pl__reset_log_channel(uint64_t uID) { PL_ASSERT(uID < gptLogContext->uChannelCount && "channel ID is not valid"); gptLogContext->atChannels[uID].uEntryCount = 0u; gptLogContext->atChannels[uID].uNextEntry = 0u; - if(gptLogContext->atChannels[uID].tType & PL_CHANNEL_TYPE_CYCLIC_BUFFER) - memset(gptLogContext->atChannels[uID].atEntries, 0, sizeof(plLogEntry) * PL_LOG_CYCLIC_BUFFER_SIZE); - else if(gptLogContext->atChannels[uID].tType & PL_CHANNEL_TYPE_BUFFER) - memset(gptLogContext->atChannels[uID].pEntries, 0, sizeof(plLogEntry) * gptLogContext->atChannels[uID].uEntryCapacity); + if(gptLogContext->atChannels[uID].tType & PL_CHANNEL_TYPE_CYCLIC_BUFFER || gptLogContext->atChannels[uID].tType & PL_CHANNEL_TYPE_BUFFER) + memset(gptLogContext->atChannels[uID].ptEntries, 0, sizeof(plLogEntry) * gptLogContext->atChannels[uID].uEntryCapacity); } -plLogEntry* -pl__get_log_entries(uint32_t uID, uint64_t* puEntryCount) +bool +pl__get_log_channel_info(uint64_t uID, plLogChannelInfo* ptOut) { - PL_ASSERT(uID < gptLogContext->uChannelCount && "channel ID is not valid"); - plLogChannel* tPChannel = &gptLogContext->atChannels[uID]; - if(puEntryCount) - *puEntryCount = tPChannel->uEntryCount; - return tPChannel->pEntries; + if(uID >= gptLogContext->uChannelCount) + return false; + + ptOut->uID = uID; + ptOut->pcName = gptLogContext->atChannels[uID].pcName; + ptOut->tType = gptLogContext->atChannels[uID].tType; + ptOut->pcBuffer = gptLogContext->atChannels[uID].pcBuffer; + ptOut->uEntryCount = gptLogContext->atChannels[uID].uEntryCount; + ptOut->ptEntries = gptLogContext->atChannels[uID].ptEntries; + ptOut->uEntryCapacity = gptLogContext->atChannels[uID].uEntryCapacity; + return true; } -plLogChannel* -pl__get_log_channels(uint32_t* puChannelCount) +uint64_t +pl__get_log_channel_count(void) { - if(puChannelCount) - *puChannelCount = gptLogContext->uChannelCount; - return gptLogContext->atChannels; + return gptLogContext->uChannelCount; +} + +uint64_t +pl__get_log_channel_id(const char* pcName) +{ + for(uint64_t i = 0; i < gptLogContext->uChannelCount; i++) + { + if(strcmp(gptLogContext->atChannels[i].pcName, pcName) == 0) + return i; + } + return SIZE_MAX; } #define PL__LOG_LEVEL_MACRO(level, prefix, prefixSize) \ plLogChannel* tPChannel = &gptLogContext->atChannels[uID]; \ - plLogEntry* ptEntry = pl__get_new_log_entry(uID); \ if(tPChannel->uLevel < level + 1) \ { \ if(tPChannel->tType & PL_CHANNEL_TYPE_CONSOLE) \ - printf(prefix " (%s) %s\n", tPChannel->pcName, pcMessage); \ + printf("%s (%s) %s\n", prefix, tPChannel->pcName, pcMessage); \ if((tPChannel->tType & PL_CHANNEL_TYPE_CYCLIC_BUFFER) || (tPChannel->tType & PL_CHANNEL_TYPE_BUFFER)) \ { \ - const size_t szNewSize = strlen(pcMessage) + 10; \ + plLogEntry* ptEntry = pl__get_new_log_entry(uID); \ + const size_t szNewSize = strlen(pcMessage) + prefixSize + 2; \ pl__log_buffer_may_grow(tPChannel, (int)szNewSize); \ - ptEntry->uOffset = tPChannel->uBufferSize; \ - char* cPDest = &tPChannel->pcBuffer0[tPChannel->uBufferSize + tPChannel->uBufferCapacity * (ptEntry->uGeneration % 2)]; \ + char* cPDest = &tPChannel->pcBuffer[tPChannel->szBufferSize + tPChannel->szBufferCapacity * (tPChannel->szGeneration % 2)]; \ + ptEntry->uOffset = tPChannel->szBufferSize + tPChannel->szBufferCapacity * (tPChannel->szGeneration % 2); \ ptEntry->uLevel = level; \ - tPChannel->uBufferSize += szNewSize; \ + tPChannel->szBufferSize += szNewSize; \ strcpy(cPDest, prefix); \ - cPDest += prefixSize; \ + cPDest[prefixSize] = ' '; \ + cPDest += prefixSize + 1; \ strcpy(cPDest, pcMessage); \ } \ } void -pl__log_trace(uint32_t uID, const char* pcMessage) +pl__log(const char* pcPrefix, int iPrefixSize, uint64_t uLevel, uint64_t uID, const char* pcMessage) { - PL__LOG_LEVEL_MACRO(PL_LOG_LEVEL_TRACE, "[TRACE] ", 8) + PL__LOG_LEVEL_MACRO(uLevel, pcPrefix, iPrefixSize) } void -pl__log_debug(uint32_t uID, const char* pcMessage) +pl__log_trace(uint64_t uID, const char* pcMessage) { - PL__LOG_LEVEL_MACRO(PL_LOG_LEVEL_DEBUG, "[DEBUG] ", 8) + PL__LOG_LEVEL_MACRO(PL_LOG_LEVEL_TRACE, "[TRACE]", 7) } void -pl__log_info(uint32_t uID, const char* pcMessage) +pl__log_debug(uint64_t uID, const char* pcMessage) { - PL__LOG_LEVEL_MACRO(PL_LOG_LEVEL_INFO, "[INFO ] ", 8) + PL__LOG_LEVEL_MACRO(PL_LOG_LEVEL_DEBUG, "[DEBUG]", 7) } void -pl__log_warn(uint32_t uID, const char* pcMessage) +pl__log_info(uint64_t uID, const char* pcMessage) { - PL__LOG_LEVEL_MACRO(PL_LOG_LEVEL_WARN, "[WARN ] ", 8) + PL__LOG_LEVEL_MACRO(PL_LOG_LEVEL_INFO, "[INFO ]", 7) } void -pl__log_error(uint32_t uID, const char* pcMessage) +pl__log_warn(uint64_t uID, const char* pcMessage) { - PL__LOG_LEVEL_MACRO(PL_LOG_LEVEL_ERROR, "[ERROR] ", 8) + PL__LOG_LEVEL_MACRO(PL_LOG_LEVEL_WARN, "[WARN ]", 7) } void -pl__log_fatal(uint32_t uID, const char* pcMessage) +pl__log_error(uint64_t uID, const char* pcMessage) { - PL__LOG_LEVEL_MACRO(PL_LOG_LEVEL_FATAL, "[FATAL] ", 8) + PL__LOG_LEVEL_MACRO(PL_LOG_LEVEL_ERROR, "[ERROR]", 7) } void -pl__log_trace_p(uint32_t uID, const char* cPFormat, ...) +pl__log_fatal(uint64_t uID, const char* pcMessage) +{ + PL__LOG_LEVEL_MACRO(PL_LOG_LEVEL_FATAL, "[FATAL]", 7) +} + +void +pl__log_p(const char* pcPrefix, int iPrefixSize, uint64_t uLevel, uint64_t uID, const char* cPFormat, ...) +{ + va_list argptr; + va_start(argptr, cPFormat); + pl__log_va(pcPrefix, iPrefixSize, uLevel, uID, cPFormat, argptr); + va_end(argptr); +} + +void +pl__log_trace_p(uint64_t uID, const char* cPFormat, ...) { va_list argptr; va_start(argptr, cPFormat); @@ -916,7 +963,7 @@ pl__log_trace_p(uint32_t uID, const char* cPFormat, ...) } void -pl__log_debug_p(uint32_t uID, const char* cPFormat, ...) +pl__log_debug_p(uint64_t uID, const char* cPFormat, ...) { va_list argptr; va_start(argptr, cPFormat); @@ -925,7 +972,7 @@ pl__log_debug_p(uint32_t uID, const char* cPFormat, ...) } void -pl__log_info_p(uint32_t uID, const char* cPFormat, ...) +pl__log_info_p(uint64_t uID, const char* cPFormat, ...) { va_list argptr; va_start(argptr, cPFormat); @@ -934,7 +981,7 @@ pl__log_info_p(uint32_t uID, const char* cPFormat, ...) } void -pl__log_warn_p(uint32_t uID, const char* cPFormat, ...) +pl__log_warn_p(uint64_t uID, const char* cPFormat, ...) { va_list argptr; va_start(argptr, cPFormat); @@ -943,7 +990,7 @@ pl__log_warn_p(uint32_t uID, const char* cPFormat, ...) } void -pl__log_error_p(uint32_t uID, const char* cPFormat, ...) +pl__log_error_p(uint64_t uID, const char* cPFormat, ...) { va_list argptr; va_start(argptr, cPFormat); @@ -952,7 +999,7 @@ pl__log_error_p(uint32_t uID, const char* cPFormat, ...) } void -pl__log_fatal_p(uint32_t uID, const char* cPFormat, ...) +pl__log_fatal_p(uint64_t uID, const char* cPFormat, ...) { va_list argptr; va_start(argptr, cPFormat); @@ -960,20 +1007,20 @@ pl__log_fatal_p(uint32_t uID, const char* cPFormat, ...) va_end(argptr); } -#define PL__LOG_LEVEL_VA_BUFFER_MACRO(level, prefix) \ +#define PL__LOG_LEVEL_VA_BUFFER_MACRO(level, prefix, prefixSize) \ if((tPChannel->tType & PL_CHANNEL_TYPE_CYCLIC_BUFFER) || (tPChannel->tType & PL_CHANNEL_TYPE_BUFFER)) \ { \ va_list parm_copy; \ va_copy(parm_copy, args); \ plLogEntry* ptEntry = pl__get_new_log_entry(uID); \ - const int iNewSize = pl_vsnprintf(NULL, 0, cPFormat, parm_copy) + 9; \ + const int iNewSize = pl_vsnprintf(NULL, 0, cPFormat, parm_copy) + prefixSize + 2; \ va_end(parm_copy); \ pl__log_buffer_may_grow(tPChannel, iNewSize); \ - ptEntry->uOffset = tPChannel->uBufferSize; \ - char* cPDest = &tPChannel->pcBuffer0[tPChannel->uBufferSize + tPChannel->uBufferCapacity * (ptEntry->uGeneration % 2)]; \ - tPChannel->uBufferSize += iNewSize; \ + char* cPDest = &tPChannel->pcBuffer[tPChannel->szBufferSize + tPChannel->szBufferCapacity * (tPChannel->szGeneration % 2)]; \ + ptEntry->uOffset = tPChannel->szBufferSize + tPChannel->szBufferCapacity * (tPChannel->szGeneration % 2); \ + tPChannel->szBufferSize += iNewSize; \ ptEntry->uLevel = level; \ - cPDest += pl_snprintf(cPDest, 9, prefix); \ + cPDest += pl_snprintf(cPDest, prefixSize + 2, "%s ", prefix); \ va_list parm_copy2; \ va_copy(parm_copy2, args); \ pl_vsnprintf(cPDest, iNewSize, cPFormat, parm_copy2); \ @@ -981,7 +1028,44 @@ pl__log_fatal_p(uint32_t uID, const char* cPFormat, ...) } void -pl__log_trace_va(uint32_t uID, const char* cPFormat, va_list args) +pl__log_va(const char* pcPrefix, int iPrefixSize, uint64_t uLevel, uint64_t uID, const char* cPFormat, va_list args) +{ + plLogChannel* tPChannel = &gptLogContext->atChannels[uID]; + + if(tPChannel->uLevel < uLevel + 1) + { + if(tPChannel->tType & PL_CHANNEL_TYPE_CONSOLE) + { + #ifdef PL_LOG_CUSTOM_BOLD + printf(PL_LOG_BOLD_CODE); + #endif + + #ifdef PL_LOG_CUSTOM_UNDERLINE + printf(PL_LOG_UNDERLINE_CODE); + #endif + + #ifdef PL_LOG_CUSTOM_FG_COLOR + printf(PL_LOG_CUSTOM_FG_COLOR); + #endif + + #ifdef PL_LOG_CUSTOM_BG_COLOR + printf(PL_LOG_CUSTOM_BG_COLOR); + #endif + + printf("%s (%s) ", pcPrefix, tPChannel->pcName); + char dest[PL_LOG_MAX_LINE_SIZE]; + va_list parm_copy; + va_copy(parm_copy, args); + pl_vsnprintf(dest, PL_LOG_MAX_LINE_SIZE, cPFormat, parm_copy); + printf("%s%s\n", dest, PL_LOG_POP_CODE); + va_end(parm_copy); + } + PL__LOG_LEVEL_VA_BUFFER_MACRO(uLevel, pcPrefix, iPrefixSize) + } +} + +void +pl__log_trace_va(uint64_t uID, const char* cPFormat, va_list args) { plLogChannel* tPChannel = &gptLogContext->atChannels[uID]; @@ -1008,21 +1092,18 @@ pl__log_trace_va(uint32_t uID, const char* cPFormat, va_list args) printf("[TRACE] (%s) ", tPChannel->pcName); char dest[PL_LOG_MAX_LINE_SIZE]; - va_list parm_copy; va_copy(parm_copy, args); pl_vsnprintf(dest, PL_LOG_MAX_LINE_SIZE, cPFormat, parm_copy); printf("%s%s\n", dest, PL_LOG_POP_CODE); va_end(parm_copy); } - PL__LOG_LEVEL_VA_BUFFER_MACRO(PL_LOG_LEVEL_TRACE, "[TRACE] ") - } - - + PL__LOG_LEVEL_VA_BUFFER_MACRO(PL_LOG_LEVEL_TRACE, "[TRACE]", 7) + } } void -pl__log_debug_va(uint32_t uID, const char* cPFormat, va_list args) +pl__log_debug_va(uint64_t uID, const char* cPFormat, va_list args) { plLogChannel* tPChannel = &gptLogContext->atChannels[uID]; @@ -1055,12 +1136,12 @@ pl__log_debug_va(uint32_t uID, const char* cPFormat, va_list args) printf("%s%s\n", dest, PL_LOG_POP_CODE); va_end(parm_copy); } - PL__LOG_LEVEL_VA_BUFFER_MACRO(PL_LOG_LEVEL_DEBUG, "[DEBUG] ") + PL__LOG_LEVEL_VA_BUFFER_MACRO(PL_LOG_LEVEL_DEBUG, "[DEBUG]", 7) } } void -pl__log_info_va(uint32_t uID, const char* cPFormat, va_list args) +pl__log_info_va(uint64_t uID, const char* cPFormat, va_list args) { plLogChannel* tPChannel = &gptLogContext->atChannels[uID]; @@ -1093,12 +1174,12 @@ pl__log_info_va(uint32_t uID, const char* cPFormat, va_list args) printf("%s%s\n", dest, PL_LOG_POP_CODE); va_end(parm_copy); } - PL__LOG_LEVEL_VA_BUFFER_MACRO(PL_LOG_LEVEL_INFO, "[INFO ] ") + PL__LOG_LEVEL_VA_BUFFER_MACRO(PL_LOG_LEVEL_INFO, "[INFO ]", 7) } } void -pl__log_warn_va(uint32_t uID, const char* cPFormat, va_list args) +pl__log_warn_va(uint64_t uID, const char* cPFormat, va_list args) { plLogChannel* tPChannel = &gptLogContext->atChannels[uID]; @@ -1131,12 +1212,12 @@ pl__log_warn_va(uint32_t uID, const char* cPFormat, va_list args) printf("%s%s\n", dest, PL_LOG_POP_CODE); va_end(parm_copy); } - PL__LOG_LEVEL_VA_BUFFER_MACRO(PL_LOG_LEVEL_WARN, "[WARN ] ") + PL__LOG_LEVEL_VA_BUFFER_MACRO(PL_LOG_LEVEL_WARN, "[WARN ]", 7) } } void -pl__log_error_va(uint32_t uID, const char* cPFormat, va_list args) +pl__log_error_va(uint64_t uID, const char* cPFormat, va_list args) { plLogChannel* tPChannel = &gptLogContext->atChannels[uID]; @@ -1169,12 +1250,12 @@ pl__log_error_va(uint32_t uID, const char* cPFormat, va_list args) printf("%s%s\n", dest, PL_LOG_POP_CODE); va_end(parm_copy); } - PL__LOG_LEVEL_VA_BUFFER_MACRO(PL_LOG_LEVEL_ERROR, "[ERROR] ") + PL__LOG_LEVEL_VA_BUFFER_MACRO(PL_LOG_LEVEL_ERROR, "[ERROR]", 7) } } void -pl__log_fatal_va(uint32_t uID, const char* cPFormat, va_list args) +pl__log_fatal_va(uint64_t uID, const char* cPFormat, va_list args) { plLogChannel* tPChannel = &gptLogContext->atChannels[uID]; @@ -1207,56 +1288,8 @@ pl__log_fatal_va(uint32_t uID, const char* cPFormat, va_list args) printf("%s%s\n", dest, PL_LOG_POP_CODE); va_end(parm_copy); } - PL__LOG_LEVEL_VA_BUFFER_MACRO(PL_LOG_LEVEL_FATAL, "[FATAL] ") + PL__LOG_LEVEL_VA_BUFFER_MACRO(PL_LOG_LEVEL_FATAL, "[FATAL]", 7) } } -//----------------------------------------------------------------------------- -// [SECTION] internal api implementation -//----------------------------------------------------------------------------- - -static plLogEntry* -pl__get_new_log_entry(uint32_t uID) -{ - plLogChannel* tPChannel = &gptLogContext->atChannels[uID]; - - plLogEntry* ptEntry = NULL; - - if(tPChannel->tType & PL_CHANNEL_TYPE_CYCLIC_BUFFER) - { - ptEntry = &tPChannel->atEntries[tPChannel->uNextEntry]; - tPChannel->uNextEntry++; - tPChannel->uNextEntry = tPChannel->uNextEntry % PL_LOG_CYCLIC_BUFFER_SIZE; - tPChannel->uEntryCount++; - if(tPChannel->uNextEntry == 0) - { - tPChannel->uBufferSize = 0; - tPChannel->uGeneration++; - } - } - else if(tPChannel->tType & PL_CHANNEL_TYPE_BUFFER) - { - - // check if overflow reallocation is needed - if(tPChannel->uEntryCount == tPChannel->uEntryCapacity) - { - plLogEntry* sbtOldEntries = tPChannel->pEntries; - tPChannel->pEntries = (plLogEntry*)PL_LOG_ALLOC(sizeof(plLogEntry) * tPChannel->uEntryCapacity * 2); - memset(tPChannel->pEntries, 0, sizeof(plLogEntry) * tPChannel->uEntryCapacity * 2); - - // copy old values - memcpy(tPChannel->pEntries, sbtOldEntries, sizeof(plLogEntry) * tPChannel->uEntryCapacity); - tPChannel->uEntryCapacity *= 2; - - PL_LOG_FREE(sbtOldEntries); - } - - ptEntry = &tPChannel->pEntries[tPChannel->uEntryCount]; - tPChannel->uEntryCount++; - } - - ptEntry->uGeneration = tPChannel->uGeneration; - return ptEntry; -} - -#endif // PL_LOG_IMPLEMENTATION +#endif // PL_LOG_IMPLEMENTATION \ No newline at end of file diff --git a/pl_math.h b/pl_math.h index 95e05b2..8f40bec 100644 --- a/pl_math.h +++ b/pl_math.h @@ -1,5 +1,6 @@ /* - pl_math.h, v0.6 (WIP) + pl_math.h + * simple math library Do this: #define PL_MATH_INCLUDE_FUNCTIONS @@ -12,9 +13,9 @@ #include "pl_math.h" */ -// library version -#define PL_MATH_VERSION "0.7.0" -#define PL_MATH_VERSION_NUM 00700 +// library version (format XYYZZ) +#define PL_MATH_VERSION "1.0.0" +#define PL_MATH_VERSION_NUM 10000 /* Index of this file: @@ -29,6 +30,7 @@ Index of this file: // [SECTION] matrix ops // [SECTION] quaternion ops // [SECTION] rect ops +// [SECTION] colors // [SECTION] implementations */ @@ -187,7 +189,11 @@ typedef struct _plAABB #include #include // bool #include // uint*_t -#include + +#ifndef PL_ASSERT + #include + #define PL_ASSERT(x) assert((x)) +#endif //----------------------------------------------------------------------------- // [SECTION] helpers @@ -239,92 +245,89 @@ 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 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 //----------------------------------------------------------------------------- // unary ops -static inline float pl_length_sqr_vec2 (plVec2 tVec) { return pl_squaref(tVec.x) + pl_squaref(tVec.y); } -static inline float pl_length_sqr_vec3 (plVec3 tVec) { return pl_squaref(tVec.x) + pl_squaref(tVec.y) + pl_squaref(tVec.z); } -static inline float pl_length_sqr_vec4 (plVec4 tVec) { return pl_squaref(tVec.x) + pl_squaref(tVec.y) + pl_squaref(tVec.z) + pl_squaref(tVec.w); } -static inline float pl_length_vec2 (plVec2 tVec) { return sqrtf(pl_length_sqr_vec2(tVec)); } -static inline float pl_length_vec3 (plVec3 tVec) { return sqrtf(pl_length_sqr_vec3(tVec)); } -static inline float pl_length_vec4 (plVec4 tVec) { return sqrtf(pl_length_sqr_vec4(tVec)); } -static inline plVec2 pl_floor_vec2 (plVec2 tVec) { return pl_create_vec2(floorf(tVec.x), floorf(tVec.y));} -static inline plVec3 pl_floor_vec3 (plVec3 tVec) { return pl_create_vec3(floorf(tVec.x), floorf(tVec.y), floorf(tVec.z));} -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 float pl_length_sqr_vec2(plVec2 tVec) { return pl_squaref(tVec.x) + pl_squaref(tVec.y); } +static inline float pl_length_sqr_vec3(plVec3 tVec) { return pl_squaref(tVec.x) + pl_squaref(tVec.y) + pl_squaref(tVec.z); } +static inline float pl_length_sqr_vec4(plVec4 tVec) { return pl_squaref(tVec.x) + pl_squaref(tVec.y) + pl_squaref(tVec.z) + pl_squaref(tVec.w); } +static inline float pl_length_vec2 (plVec2 tVec) { return sqrtf(pl_length_sqr_vec2(tVec)); } +static inline float pl_length_vec3 (plVec3 tVec) { return sqrtf(pl_length_sqr_vec3(tVec)); } +static inline float pl_length_vec4 (plVec4 tVec) { return sqrtf(pl_length_sqr_vec4(tVec)); } +static inline plVec2 pl_floor_vec2 (plVec2 tVec) { return pl_create_vec2(floorf(tVec.x), floorf(tVec.y));} +static inline plVec3 pl_floor_vec3 (plVec3 tVec) { return pl_create_vec3(floorf(tVec.x), floorf(tVec.y), floorf(tVec.z));} +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 +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 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_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 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 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 plVec2 pl_min_vec2(plVec2 tValue0, plVec2 tValue1) { return pl_create_vec2(pl_minf(tValue0.x, tValue1.x), pl_minf(tValue0.y, tValue1.y));} +static inline plVec3 pl_min_vec3(plVec3 tValue0, plVec3 tValue1) { return pl_create_vec3(pl_minf(tValue0.x, tValue1.x), pl_minf(tValue0.y, tValue1.y), pl_minf(tValue0.z, tValue1.z));} +static inline plVec4 pl_min_vec4(plVec4 tValue0, plVec4 tValue1) { return pl_create_vec4(pl_minf(tValue0.x, tValue1.x), pl_minf(tValue0.y, tValue1.y), pl_minf(tValue0.z, tValue1.z), pl_minf(tValue0.w, tValue1.w));} +static inline plVec2 pl_max_vec2(plVec2 tValue0, plVec2 tValue1) { return pl_create_vec2(pl_maxf(tValue0.x, tValue1.x), pl_maxf(tValue0.y, tValue1.y));} +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 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 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 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_min_vec2 (plVec2 tValue0, plVec2 tValue1) { return pl_create_vec2(pl_minf(tValue0.x, tValue1.x), pl_minf(tValue0.y, tValue1.y));} -static inline plVec3 pl_min_vec3 (plVec3 tValue0, plVec3 tValue1) { return pl_create_vec3(pl_minf(tValue0.x, tValue1.x), pl_minf(tValue0.y, tValue1.y), pl_minf(tValue0.z, tValue1.z));} -static inline plVec4 pl_min_vec4 (plVec4 tValue0, plVec4 tValue1) { return pl_create_vec4(pl_minf(tValue0.x, tValue1.x), pl_minf(tValue0.y, tValue1.y), pl_minf(tValue0.z, tValue1.z), pl_minf(tValue0.w, tValue1.w));} -static inline plVec2 pl_max_vec2 (plVec2 tValue0, plVec2 tValue1) { return pl_create_vec2(pl_maxf(tValue0.x, tValue1.x), pl_maxf(tValue0.y, tValue1.y));} -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 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_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_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_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 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 plVec4 pl_add_vec4(plVec4 tVec1, plVec4 tVec2) { return pl_create_vec4(tVec1.x + tVec2.x, tVec1.y + tVec2.y, tVec1.z + tVec2.z, tVec1.w + tVec2.w); } -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 plVec4 pl_add_vec4 (plVec4 tVec1, plVec4 tVec2) { return pl_create_vec4(tVec1.x + tVec2.x, tVec1.y + tVec2.y, tVec1.z + tVec2.z, tVec1.w + tVec2.w); } +static inline plVec2 pl_sub_vec2(plVec2 tVec1, plVec2 tVec2) { return pl_create_vec2(tVec1.x - tVec2.x, tVec1.y - tVec2.y); } +static inline plVec3 pl_sub_vec3(plVec3 tVec1, plVec3 tVec2) { return pl_create_vec3(tVec1.x - tVec2.x, tVec1.y - tVec2.y, tVec1.z - tVec2.z); } +static inline plVec4 pl_sub_vec4(plVec4 tVec1, plVec4 tVec2) { return pl_create_vec4(tVec1.x - tVec2.x, tVec1.y - tVec2.y, tVec1.z - tVec2.z, tVec1.w - tVec2.w) ;} -static inline plVec2 pl_sub_vec2 (plVec2 tVec1, plVec2 tVec2) { return pl_create_vec2(tVec1.x - tVec2.x, tVec1.y - tVec2.y); } -static inline plVec3 pl_sub_vec3 (plVec3 tVec1, plVec3 tVec2) { return pl_create_vec3(tVec1.x - tVec2.x, tVec1.y - tVec2.y, tVec1.z - tVec2.z); } -static inline plVec4 pl_sub_vec4 (plVec4 tVec1, plVec4 tVec2) { return pl_create_vec4(tVec1.x - tVec2.x, tVec1.y - tVec2.y, tVec1.z - tVec2.z, tVec1.w - tVec2.w) ;} +static inline plVec2 pl_mul_vec2(plVec2 tVec1, plVec2 tVec2) { return pl_create_vec2(tVec1.x * tVec2.x, tVec1.y * tVec2.y); } +static inline plVec3 pl_mul_vec3(plVec3 tVec1, plVec3 tVec2) { return pl_create_vec3(tVec1.x * tVec2.x, tVec1.y * tVec2.y, tVec1.z * tVec2.z); } +static inline plVec4 pl_mul_vec4(plVec4 tVec1, plVec4 tVec2) { return pl_create_vec4(tVec1.x * tVec2.x, tVec1.y * tVec2.y, tVec1.z * tVec2.z, tVec1.w * tVec2.w); } -static inline plVec2 pl_mul_vec2 (plVec2 tVec1, plVec2 tVec2) { return pl_create_vec2(tVec1.x * tVec2.x, tVec1.y * tVec2.y); } -static inline plVec3 pl_mul_vec3 (plVec3 tVec1, plVec3 tVec2) { return pl_create_vec3(tVec1.x * tVec2.x, tVec1.y * tVec2.y, tVec1.z * tVec2.z); } -static inline plVec4 pl_mul_vec4 (plVec4 tVec1, plVec4 tVec2) { return pl_create_vec4(tVec1.x * tVec2.x, tVec1.y * tVec2.y, tVec1.z * tVec2.z, tVec1.w * tVec2.w); } +static inline plVec2 pl_div_vec2(plVec2 tVec1, plVec2 tVec2) { return pl_create_vec2(tVec1.x / tVec2.x, tVec1.y / tVec2.y); } +static inline plVec3 pl_div_vec3(plVec3 tVec1, plVec3 tVec2) { return pl_create_vec3(tVec1.x / tVec2.x, tVec1.y / tVec2.y, tVec1.z / tVec2.z); } +static inline plVec4 pl_div_vec4(plVec4 tVec1, plVec4 tVec2) { return pl_create_vec4(tVec1.x / tVec2.x, tVec1.y / tVec2.y, tVec1.z / tVec2.z, tVec1.w / tVec2.w); } -static inline plVec2 pl_div_vec2 (plVec2 tVec1, plVec2 tVec2) { return pl_create_vec2(tVec1.x / tVec2.x, tVec1.y / tVec2.y); } -static inline plVec3 pl_div_vec3 (plVec3 tVec1, plVec3 tVec2) { return pl_create_vec3(tVec1.x / tVec2.x, tVec1.y / tVec2.y, tVec1.z / tVec2.z); } -static inline plVec4 pl_div_vec4 (plVec4 tVec1, plVec4 tVec2) { return pl_create_vec4(tVec1.x / tVec2.x, tVec1.y / tVec2.y, tVec1.z / tVec2.z, tVec1.w / tVec2.w); } +static inline plVec2 pl_mul_vec2_scalarf(plVec2 tVec, float fValue) { return pl_create_vec2(fValue * tVec.x, fValue * tVec.y); } +static inline plVec3 pl_mul_vec3_scalarf(plVec3 tVec, float fValue) { return pl_create_vec3(fValue * tVec.x, fValue * tVec.y, fValue * tVec.z); } +static inline plVec4 pl_mul_vec4_scalarf(plVec4 tVec, float fValue) { return pl_create_vec4(fValue * tVec.x, fValue * tVec.y, fValue * tVec.z, fValue * tVec.w); } -static inline plVec2 pl_mul_vec2_scalarf(plVec2 tVec, float fValue) { return pl_create_vec2(fValue * tVec.x, fValue * tVec.y); } -static inline plVec3 pl_mul_vec3_scalarf(plVec3 tVec, float fValue) { return pl_create_vec3(fValue * tVec.x, fValue * tVec.y, fValue * tVec.z); } -static inline plVec4 pl_mul_vec4_scalarf(plVec4 tVec, float fValue) { return pl_create_vec4(fValue * tVec.x, fValue * tVec.y, fValue * tVec.z, fValue * tVec.w); } +static inline plVec2 pl_div_vec2_scalarf(plVec2 tVec, float fValue) { return pl_create_vec2(tVec.x / fValue, tVec.y / fValue); } +static inline plVec3 pl_div_vec3_scalarf(plVec3 tVec, float fValue) { return pl_create_vec3(tVec.x / fValue, tVec.y / fValue, tVec.z / fValue); } +static inline plVec4 pl_div_vec4_scalarf(plVec4 tVec, float fValue) { return pl_create_vec4(tVec.x / fValue, tVec.y / fValue, tVec.z / fValue, tVec.w / fValue); } -static inline plVec2 pl_div_vec2_scalarf(plVec2 tVec, float fValue) { return pl_create_vec2(tVec.x / fValue, tVec.y / fValue); } -static inline plVec3 pl_div_vec3_scalarf(plVec3 tVec, float fValue) { return pl_create_vec3(tVec.x / fValue, tVec.y / fValue, tVec.z / fValue); } -static inline plVec4 pl_div_vec4_scalarf(plVec4 tVec, float fValue) { return pl_create_vec4(tVec.x / fValue, tVec.y / fValue, tVec.z / fValue, tVec.w / fValue); } +static inline plVec2 pl_div_scalarf_vec2(float fValue, plVec2 tVec) { return pl_create_vec2(fValue / tVec.x, fValue / tVec.y); } +static inline plVec3 pl_div_scalarf_vec3(float fValue, plVec3 tVec) { return pl_create_vec3(fValue / tVec.x, fValue / tVec.y, fValue / tVec.z); } +static inline plVec4 pl_div_scalarf_vec4(float fValue, plVec4 tVec) { return pl_create_vec4(fValue / tVec.x, fValue / tVec.y, fValue / tVec.z, fValue / tVec.w); } -static inline plVec2 pl_div_scalarf_vec2(float fValue, plVec2 tVec) { return pl_create_vec2(fValue / tVec.x, fValue / tVec.y); } -static inline plVec3 pl_div_scalarf_vec3(float fValue, plVec3 tVec) { return pl_create_vec3(fValue / tVec.x, fValue / tVec.y, fValue / tVec.z); } -static inline plVec4 pl_div_scalarf_vec4(float fValue, plVec4 tVec) { return pl_create_vec4(fValue / tVec.x, fValue / tVec.y, fValue / tVec.z, fValue / tVec.w); } - -static inline plVec2 pl_norm_vec2 (plVec2 tVec) { float fLength = pl_length_vec2(tVec); if(fLength > 0) fLength = 1.0f / fLength; return pl_mul_vec2_scalarf(tVec, fLength); } -static inline plVec3 pl_norm_vec3 (plVec3 tVec) { float fLength = pl_length_vec3(tVec); if(fLength > 0) fLength = 1.0f / fLength; return pl_mul_vec3_scalarf(tVec, fLength); } -static inline plVec4 pl_norm_vec4 (plVec4 tVec) { float fLength = pl_length_vec4(tVec); if(fLength > 0) fLength = 1.0f / fLength; return pl_mul_vec4_scalarf(tVec, fLength); } +static inline plVec2 pl_norm_vec2(plVec2 tVec) { float fLength = pl_length_vec2(tVec); if(fLength > 0) fLength = 1.0f / fLength; return pl_mul_vec2_scalarf(tVec, fLength); } +static inline plVec3 pl_norm_vec3(plVec3 tVec) { float fLength = pl_length_vec3(tVec); if(fLength > 0) fLength = 1.0f / fLength; return pl_mul_vec3_scalarf(tVec, fLength); } +static inline plVec4 pl_norm_vec4(plVec4 tVec) { float fLength = pl_length_vec4(tVec); if(fLength > 0) fLength = 1.0f / fLength; return pl_mul_vec4_scalarf(tVec, fLength); } //----------------------------------------------------------------------------- // [SECTION] matrix ops //----------------------------------------------------------------------------- // general ops -static inline float pl_mat4_get (const plMat4* ptMat, int iRow, int iCol) { return ptMat->col[iCol].d[iRow];} -static inline void pl_mat4_set (plMat4* ptMat, int iRow, int iCol, float fValue) { ptMat->col[iCol].d[iRow] = fValue;} -static inline plMat4 pl_identity_mat4 (void) { return pl_create_mat4_diag(1.0f, 1.0f, 1.0f, 1.0f);} -static inline plMat4 pl_mat4_transpose (const plMat4* ptMat) { plMat4 tResult = {0}; for (int i = 0; i < 4; i++) for (int j = 0; j < 4; j++) pl_mat4_set(&tResult, i, j, pl_mat4_get(ptMat, j, i)); return tResult;} -static inline plMat4 pl_mat4_invert (const plMat4* ptMat); -static inline plMat4 pl_mul_scalarf_mat4 (float fLeft, const plMat4* ptRight) { plMat4 tResult = {0}; for (int i = 0; i < 4; i++) for (int j = 0; j < 4; j++) pl_mat4_set(&tResult, i, j, fLeft * pl_mat4_get(ptRight, j, i)); return tResult;} -static inline plVec3 pl_mul_mat4_vec3 (const plMat4* ptLeft, plVec3 tRight); -static inline plVec4 pl_mul_mat4_vec4 (const plMat4* ptLeft, plVec4 tRight); -static inline plMat4 pl_mul_mat4 (const plMat4* ptLeft, const plMat4* ptRight); +static inline float pl_mat4_get (const plMat4* ptMat, int iRow, int iCol) { return ptMat->col[iCol].d[iRow];} +static inline void pl_mat4_set (plMat4* ptMat, int iRow, int iCol, float fValue) { ptMat->col[iCol].d[iRow] = fValue;} +static inline plMat4 pl_identity_mat4 (void) { return pl_create_mat4_diag(1.0f, 1.0f, 1.0f, 1.0f);} +static inline plMat4 pl_mat4_transpose (const plMat4* ptMat) { plMat4 tResult = {0}; for (int i = 0; i < 4; i++) for (int j = 0; j < 4; j++) pl_mat4_set(&tResult, i, j, pl_mat4_get(ptMat, j, i)); return tResult;} +static inline plMat4 pl_mat4_invert (const plMat4* ptMat); +static inline plMat4 pl_mul_scalarf_mat4(float fLeft, const plMat4* ptRight) { plMat4 tResult = {0}; for (int i = 0; i < 4; i++) for (int j = 0; j < 4; j++) pl_mat4_set(&tResult, i, j, fLeft * pl_mat4_get(ptRight, j, i)); return tResult;} +static inline plVec3 pl_mul_mat4_vec3 (const plMat4* ptLeft, plVec3 tRight); +static inline plVec4 pl_mul_mat4_vec4 (const plMat4* ptLeft, plVec4 tRight); +static inline plMat4 pl_mul_mat4 (const plMat4* ptLeft, const plMat4* ptRight); // translation, rotation, scaling static inline plMat4 pl_mat4_translate_xyz (float fX, float fY, float fZ) { plMat4 tResult = pl_create_mat4_diag(1.0f, 1.0f, 1.0f, 1.0f); tResult.x14 = fX; tResult.x24 = fY; tResult.x34 = fZ; return tResult;} @@ -337,8 +340,8 @@ static inline plMat4 pl_mat4_rotate_quat (plVec4 tQ); static inline plMat4 pl_rotation_translation_scale(plVec4 tQ, plVec3 tV, plVec3 tS); // transforms (optimized for orthogonal matrices) -static inline plMat4 pl_mat4t_invert (const plMat4* ptMat); -static inline plMat4 pl_mul_mat4t (const plMat4* ptLeft, const plMat4* ptRight); +static inline plMat4 pl_mat4t_invert(const plMat4* ptMat); +static inline plMat4 pl_mul_mat4t (const plMat4* ptLeft, const plMat4* ptRight); //----------------------------------------------------------------------------- // [SECTION] quaternion ops @@ -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_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 //----------------------------------------------------------------------------- @@ -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 @@ -795,4 +820,4 @@ pl_quat_slerp(plVec4 tQ1, plVec4 tQ2, float fT) return tResult; } -#endif // PL_MATH_INCLUDE_FUNCTIONS +#endif // PL_MATH_INCLUDE_FUNCTIONS \ No newline at end of file diff --git a/pl_memory.h b/pl_memory.h index fc181b3..719aeda 100644 --- a/pl_memory.h +++ b/pl_memory.h @@ -1,7 +1,7 @@ /* - pl_memory + pl_memory.h * no dependencies - * simple + * simple memory allocators Do this: #define PL_MEMORY_IMPLEMENTATION @@ -19,9 +19,9 @@ * override assert by defining PL_ASSERT(x) */ -// library version -#define PL_MEMORY_VERSION "0.5.0" -#define PL_MEMORY_VERSION_NUM 00500 +// library version (format XYYZZ) +#define PL_MEMORY_VERSION "1.0.0" +#define PL_MEMORY_VERSION_NUM 10000 /* Index of this file: @@ -53,18 +53,16 @@ Index of this file: // [SECTION] includes //----------------------------------------------------------------------------- -#include // uint*_t #include // size_t -#include // bool //----------------------------------------------------------------------------- // [SECTION] forward declarations & basic types //----------------------------------------------------------------------------- -typedef struct _plTempAllocator plTempAllocator; -typedef struct _plStackAllocator plStackAllocator; -typedef struct _plPoolAllocator plPoolAllocator; -typedef struct _plPoolAllocatorNode plPoolAllocatorNode; +// basic types +typedef struct _plTempAllocator plTempAllocator; +typedef struct _plStackAllocator plStackAllocator; +typedef struct _plPoolAllocator plPoolAllocator; typedef size_t plStackAllocatorMarker; @@ -74,65 +72,57 @@ typedef size_t plStackAllocatorMarker; //~~~~~~~~~~~~~~~~~~~~~~~~~general purpose allocation~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -void* pl_aligned_alloc(size_t szAlignment, size_t szSize); -void pl_aligned_free (void* pBuffer); - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~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()" +void* pl_aligned_alloc(size_t szAlignment, size_t); +void pl_aligned_free (void*); //~~~~~~~~~~~~~~~~~~~~~~~~~~~temporary allocator~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -void* pl_temp_allocator_alloc (plTempAllocator* ptAllocator, size_t szSize); -void pl_temp_allocator_reset (plTempAllocator* ptAllocator); -void pl_temp_allocator_free (plTempAllocator* ptAllocator); -char* pl_temp_allocator_sprintf(plTempAllocator* ptAllocator, const char* cPFormat, ...); +void* pl_temp_allocator_alloc (plTempAllocator*, size_t); +void pl_temp_allocator_reset (plTempAllocator*); +void pl_temp_allocator_free (plTempAllocator*); +char* pl_temp_allocator_sprintf(plTempAllocator*, const char* cPFormat, ...); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~stack allocators~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // common -void pl_stack_allocator_init (plStackAllocator* ptAllocator, size_t szSize, void* pBuffer); +void pl_stack_allocator_init(plStackAllocator*, size_t, void*); // single stack -void* pl_stack_allocator_alloc (plStackAllocator* ptAllocator, size_t szSize); -void* pl_stack_allocator_aligned_alloc (plStackAllocator* ptAllocator, size_t szSize, size_t szAlignment); -plStackAllocatorMarker pl_stack_allocator_marker (plStackAllocator* ptAllocator); -void pl_stack_allocator_free_to_marker(plStackAllocator* ptAllocator, plStackAllocatorMarker tMarker); -void pl_stack_allocator_reset (plStackAllocator* ptAllocator); +void* pl_stack_allocator_alloc (plStackAllocator*, size_t); +void* pl_stack_allocator_aligned_alloc (plStackAllocator*, size_t, size_t szAlignment); +plStackAllocatorMarker pl_stack_allocator_marker (plStackAllocator*); +void pl_stack_allocator_free_to_marker(plStackAllocator*, plStackAllocatorMarker); +void pl_stack_allocator_reset (plStackAllocator*); // double sided stack -void* pl_stack_allocator_aligned_alloc_bottom (plStackAllocator* ptAllocator, size_t szSize, size_t szAlignment); -plStackAllocatorMarker pl_stack_allocator_top_marker (plStackAllocator* ptAllocator); -plStackAllocatorMarker pl_stack_allocator_bottom_marker (plStackAllocator* ptAllocator); -void* pl_stack_allocator_alloc_bottom (plStackAllocator* ptAllocator, size_t szSize); -void* pl_stack_allocator_alloc_top (plStackAllocator* ptAllocator, size_t szSize); -void pl_stack_allocator_free_top_to_marker (plStackAllocator* ptAllocator, plStackAllocatorMarker tMarker); -void pl_stack_allocator_free_bottom_to_marker(plStackAllocator* ptAllocator, plStackAllocatorMarker tMarker); +void* pl_stack_allocator_aligned_alloc_bottom (plStackAllocator*, size_t, size_t szAlignment); +plStackAllocatorMarker pl_stack_allocator_top_marker (plStackAllocator*); +plStackAllocatorMarker pl_stack_allocator_bottom_marker (plStackAllocator*); +void* pl_stack_allocator_alloc_bottom (plStackAllocator*, size_t); +void* pl_stack_allocator_alloc_top (plStackAllocator*, size_t); +void pl_stack_allocator_free_top_to_marker (plStackAllocator*, plStackAllocatorMarker); +void pl_stack_allocator_free_bottom_to_marker(plStackAllocator*, plStackAllocatorMarker); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~pool allocator~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -void pl_pool_allocator_init (plPoolAllocator* ptAllocator, size_t szItemCount, size_t szItemSize, size_t szItemAlignment, size_t* pszBufferSize, void* pBuffer); -void* pl_pool_allocator_alloc(plPoolAllocator* ptAllocator); -void pl_pool_allocator_free (plPoolAllocator* ptAllocator, void* pItem); +// Notes +// - setting pBuffer to NULL, will set pszBufferSize to required buffer size +// 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 //----------------------------------------------------------------------------- +// 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 { size_t szSize; @@ -142,6 +132,8 @@ typedef struct _plTempAllocator char** ppcMemoryBlocks; size_t szMemoryBlockCount; size_t szMemoryBlockCapacity; + size_t szCurrentBlockSizes; + size_t szNextBlockSizes; } plTempAllocator; typedef struct _plStackAllocator @@ -152,6 +144,7 @@ typedef struct _plStackAllocator size_t szTopOffset; } plStackAllocator; +typedef struct _plPoolAllocatorNode plPoolAllocatorNode; typedef struct _plPoolAllocatorNode { plPoolAllocatorNode* ptNextNode; @@ -179,7 +172,6 @@ Index of this file: // [SECTION] defines // [SECTION] internal api // [SECTION] public api implementation -// [SECTION] internal api implementation */ //----------------------------------------------------------------------------- @@ -198,40 +190,23 @@ Index of this file: #ifndef PL_MEMORY_ALLOC #include - #define PL_MEMORY_ALLOC(x) malloc(x) - #define PL_MEMORY_FREE(x) free(x) + #define PL_MEMORY_ALLOC(x) malloc(x) + #define PL_MEMORY_FREE(x) free(x) #endif - #ifndef PL_ASSERT -#include -#define PL_ASSERT(x) assert((x)) -#endif - -#ifndef PL_MEMORY_TEMP_STACK_BLOCK_SIZE - #define PL_MEMORY_TEMP_BLOCK_SIZE 4194304 -#endif - -#ifdef _WIN32 - #define WIN32_LEAN_AND_MEAN - #include // VirtualAlloc, VirtualFree - #include // page size -#elif defined(__APPLE__) - #include - #include -#else // linux - #include - #include + #include + #define PL_ASSERT(x) assert((x)) #endif #define PL__ALIGN_UP(num, align) (((num) + ((align)-1)) & ~((align)-1)) #ifndef pl_vnsprintf -#include -#define pl_vnsprintf vnsprintf + #include + #define pl_vnsprintf vsnprintf #endif -#include +#include // varargs //----------------------------------------------------------------------------- // [SECTION] internal api @@ -270,96 +245,18 @@ pl__align_forward_size(size_t szPtr, size_t szAlign) return p; } - //----------------------------------------------------------------------------- // [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* pl_aligned_alloc(size_t szAlignment, size_t szSize) { void* pBuffer = NULL; + if(szAlignment == 0) + szAlignment = pl__get_next_power_of_2(szSize); + // ensure 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->pcBuffer = ptAllocator->acStackBuffer; 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); } @@ -414,7 +313,6 @@ pl_temp_allocator_alloc(plTempAllocator* ptAllocator, size_t szSize) // not enough room is available if(szSize > ptAllocator->szSize - ptAllocator->szOffset) { - PL_ASSERT(szSize < PL_MEMORY_TEMP_BLOCK_SIZE); if(ptAllocator->szMemoryBlockCapacity == 0) // first overflow { // 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); memset(ptAllocator->ppcMemoryBlocks, 0, (sizeof(char*) * ptAllocator->szMemoryBlockCapacity)); + size_t szNewBlockSize = ptAllocator->szCurrentBlockSizes; + if(szSize > szNewBlockSize) + { + ptAllocator->szNextBlockSizes = szSize; + szNewBlockSize = szSize; + } + // allocate first block - ptAllocator->ppcMemoryBlocks[0] = (char*)PL_MEMORY_ALLOC(PL_MEMORY_TEMP_BLOCK_SIZE); - ptAllocator->szSize = PL_MEMORY_TEMP_BLOCK_SIZE; + ptAllocator->ppcMemoryBlocks[0] = (char*)PL_MEMORY_ALLOC(szNewBlockSize); + ptAllocator->szSize = szNewBlockSize; ptAllocator->szOffset = 0; ptAllocator->pcBuffer = ptAllocator->ppcMemoryBlocks[0]; } 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; 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(PL_MEMORY_TEMP_BLOCK_SIZE); - ptAllocator->szSize = PL_MEMORY_TEMP_BLOCK_SIZE; + ptAllocator->ppcMemoryBlocks[ptAllocator->szMemoryBlockCount] = (char*)PL_MEMORY_ALLOC(szNewBlockSize); + ptAllocator->szSize = szNewBlockSize; ptAllocator->pcBuffer = ptAllocator->ppcMemoryBlocks[ptAllocator->szMemoryBlockCount]; 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->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++; } @@ -462,6 +391,17 @@ pl_temp_allocator_reset(plTempAllocator* ptAllocator) ptAllocator->szOffset = 0; ptAllocator->szMemoryBlockCount = 0; 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 @@ -530,7 +470,8 @@ pl_stack_allocator_alloc(plStackAllocator* ptAllocator, size_t szSize) { size_t szOffset = ptAllocator->szBottomOffset + szSize; - PL_ASSERT(szOffset < ptAllocator->szTopOffset && "stack allocator full"); + if(szOffset >= ptAllocator->szTopOffset) + return NULL; // update offset 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); 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 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); 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 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; - PL_ASSERT(szOffset > ptAllocator->szBottomOffset && szOffset < ptAllocator->szTopOffset && "stack allocator full"); + if(szOffset < ptAllocator->szBottomOffset || szOffset > ptAllocator->szTopOffset) + return NULL; // update offset void* pBuffer = ptAllocator->pucBuffer + szOffset; @@ -674,24 +618,36 @@ pl_stack_allocator_reset(plStackAllocator* ptAllocator) #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_ASSERT(ptAllocator); - PL_ASSERT(szItemCount > 0); PL_ASSERT(szItemSize > 0); 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); + + // 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) { size_t szAlignedItemSize = pl__align_forward_size(szItemSize, szItemAlignment); *pszBufferSize = szAlignedItemSize * szItemCount + szItemAlignment; - return; + return 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); 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"); unsigned char* pUsableBuffer = (unsigned char*)pStart; @@ -716,6 +671,7 @@ pl_pool_allocator_init(plPoolAllocator* ptAllocator, size_t szItemCount, size_t pNode0->ptNextNode = pNode1; } ptAllocator->pFreeList = (plPoolAllocatorNode*)pUsableBuffer; + return szItemCount; } void* @@ -740,4 +696,4 @@ pl_pool_allocator_free(plPoolAllocator* ptAllocator, void* pItem) ptAllocator->pFreeList->ptNextNode = pOldFreeNode; } -#endif +#endif // PL_MEMORY_IMPLEMENTATION \ No newline at end of file diff --git a/pl_profile.h b/pl_profile.h index bca019e..29cfe7d 100644 --- a/pl_profile.h +++ b/pl_profile.h @@ -1,5 +1,6 @@ /* - pl_profile + pl_profile.h + * simple profiling library Do this: #define PL_PROFILE_IMPLEMENTATION before you include this file in *one* C or C++ file to create the implementation. @@ -11,9 +12,9 @@ #include "pl_profile.h" */ -// library version -#define PL_PROFILE_VERSION "0.2.0" -#define PL_PROFILE_VERSION_NUM 00200 +// library version (format XYYZZ) +#define PL_PROFILE_VERSION "1.0.0" +#define PL_PROFILE_VERSION_NUM 10000 /* Index of this file: @@ -76,7 +77,7 @@ SAMPLING RETRIEVING RESULTS 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". @@ -105,8 +106,9 @@ COMPILE TIME OPTIONS //----------------------------------------------------------------------------- // forward declarations -typedef struct _plProfileSample plProfileSample; -typedef struct _plProfileContext plProfileContext; +typedef struct _plProfileSample plProfileSample; // single sample result +typedef struct _plProfileInit plProfileInit; // profile context init info +typedef struct _plProfileContext plProfileContext; // opaque type //----------------------------------------------------------------------------- // [SECTION] public api @@ -115,19 +117,19 @@ typedef struct _plProfileContext plProfileContext; #ifdef PL_PROFILE_ON // setup/shutdown -#define pl_create_profile_context(ptContext) pl__create_profile_context() -#define pl_cleanup_profile_context() pl__cleanup_profile_context() -#define pl_set_profile_context(ptContext) pl__set_profile_context((ptContext)) -#define pl_get_profile_context() pl__get_profile_context() +#define pl_create_profile_context(tInit) pl__create_profile_context((tInit)) +#define pl_cleanup_profile_context() pl__cleanup_profile_context() +#define pl_set_profile_context(ptContext) pl__set_profile_context((ptContext)) +#define pl_get_profile_context() pl__get_profile_context() // frames -#define pl_begin_profile_frame() pl__begin_profile_frame() -#define pl_end_profile_frame() pl__end_profile_frame() +#define pl_begin_profile_frame() pl__begin_profile_frame() +#define pl_end_profile_frame() pl__end_profile_frame() // samples -#define pl_begin_profile_sample(pcName) pl__begin_profile_sample((pcName)) -#define pl_end_profile_sample() pl__end_profile_sample() -#define pl_get_last_frame_samples(puSize) pl__get_last_frame_samples((puSize)) +#define pl_begin_profile_sample(uThreadIndex, pcName) pl__begin_profile_sample((uThreadIndex), (pcName)) +#define pl_end_profile_sample(uThreadIndex) pl__end_profile_sample((uThreadIndex)) +#define pl_get_last_frame_samples(uThreadIndex, puSize) pl__get_last_frame_samples((uThreadIndex), (puSize)) #endif // PL_PROFILE_ON @@ -143,35 +145,41 @@ typedef struct _plProfileSample uint32_t uDepth; } plProfileSample; +typedef struct _plProfileInit +{ + uint32_t uThreadCount; +} plProfileInit; + //----------------------------------------------------------------------------- // [SECTION] internal api //----------------------------------------------------------------------------- // setup/shutdown -plProfileContext* pl__create_profile_context (void); +plProfileContext* pl__create_profile_context (plProfileInit); 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); // frames -void pl__begin_profile_frame(void); -void pl__end_profile_frame (void); +void pl__begin_profile_frame (void); +void pl__end_profile_frame (void); // samples -void pl__begin_profile_sample(const char* pcName); -void pl__end_profile_sample (void); -plProfileSample* pl__get_last_frame_samples(uint32_t* puSize); +void pl__begin_profile_sample(uint32_t uThreadIndex, const char* pcName); +void pl__end_profile_sample (uint32_t uThreadIndex); +plProfileSample* pl__get_last_frame_samples(uint32_t uThreadIndex, uint32_t* puSizeOut); #ifndef PL_PROFILE_ON #define pl_create_profile_context(ptContext) NULL #define pl_cleanup_profile_context() // #define pl_set_profile_context(ptContext) // #define pl_get_profile_context() NULL - #define pl_begin_profile_frame(ulFrame) // + #define pl_begin_profile_frame() // #define pl_end_profile_frame() // - #define pl_begin_profile_sample(pcName) // - #define pl_end_profile_sample() // - #define pl_get_last_frame_samples(puSize) NULL + #define pl_begin_profile_sampleuThreadIndex(uThreadIndex, pcName) // + #define pl_end_profile_sample(uThreadIndex) // + #define pl_get_last_frame_samples(uThreadIndex, puSize) NULL + #define pl_get_profile_overhead() 0.0 #endif #endif // PL_PROFILE_H @@ -212,8 +220,11 @@ Index of this file: // [SECTION] includes //----------------------------------------------------------------------------- +#include // bool +#include // memset + #ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN #include #elif defined(__APPLE__) #include // clock_gettime_nsec_np @@ -225,7 +236,7 @@ Index of this file: // [SECTION] global context //----------------------------------------------------------------------------- -plProfileContext* gTPProfileContext = NULL; +static plProfileContext* gptProfileContext = NULL; //----------------------------------------------------------------------------- // [SECTION] internal structs @@ -257,14 +268,20 @@ typedef struct _plProfileFrame uint32_t uOverflowSampleCapacity; } plProfileFrame; -typedef struct _plProfileContext +typedef struct _plProfileThreadData { - double dStartTime; - uint64_t ulFrame; plProfileFrame atFrames[2]; plProfileFrame* ptCurrentFrame; plProfileFrame* ptLastFrame; - void* pInternal; +} plProfileThreadData; + +typedef struct _plProfileContext +{ + double dStartTime; + uint64_t ulFrame; + plProfileThreadData* ptThreadData; + uint32_t uThreadCount; + void* pInternal; } plProfileContext; //----------------------------------------------------------------------------- @@ -286,7 +303,7 @@ pl__get_wall_clock(void) { double dResult = 0; #ifdef _WIN32 - INT64 slPerfFrequency = *(INT64*)gTPProfileContext->pInternal; + INT64 slPerfFrequency = *(INT64*)gptProfileContext->pInternal; INT64 slPerfCounter; QueryPerformanceCounter((LARGE_INTEGER*)&slPerfCounter); dResult = (double)slPerfCounter / (double)slPerfFrequency; @@ -296,7 +313,7 @@ pl__get_wall_clock(void) struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); 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 return dResult; } @@ -306,17 +323,23 @@ pl__get_wall_clock(void) //----------------------------------------------------------------------------- plProfileContext* -pl__create_profile_context(void) +pl__create_profile_context(plProfileInit tInit) { // allocate context plProfileContext* ptContext = (plProfileContext*)PL_PROFILE_ALLOC(sizeof(plProfileContext)); memset(ptContext, 0, sizeof(plProfileContext)); - gTPProfileContext = ptContext; + gptProfileContext = ptContext; // clock setup #ifdef _WIN32 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; #elif defined(__APPLE__) // no setup required @@ -324,7 +347,10 @@ pl__create_profile_context(void) static struct timespec ts; 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; @@ -333,73 +359,97 @@ pl__create_profile_context(void) #endif ptContext->dStartTime = pl__get_wall_clock(); - ptContext->ptCurrentFrame = &ptContext->atFrames[0]; - ptContext->atFrames[0].uSampleCapacity = 256; - ptContext->atFrames[0].uSampleStackCapacity = 256; - ptContext->atFrames[1].uSampleCapacity = 256; - ptContext->atFrames[1].uSampleStackCapacity = 256; - ptContext->atFrames[0].ptSamples = ptContext->atFrames[0].atSamples; - ptContext->atFrames[1].ptSamples = ptContext->atFrames[1].atSamples; - ptContext->atFrames[0].puSampleStack = ptContext->atFrames[0].auSampleStack; - ptContext->atFrames[1].puSampleStack = ptContext->atFrames[1].auSampleStack; - ptContext->ptLastFrame = &ptContext->atFrames[0]; + ptContext->uThreadCount = tInit.uThreadCount; + ptContext->ptThreadData = (plProfileThreadData*)PL_PROFILE_ALLOC(sizeof(plProfileThreadData) * tInit.uThreadCount); + memset(ptContext->ptThreadData, 0, sizeof(plProfileThreadData) * tInit.uThreadCount); + for(uint32_t i = 0; i < tInit.uThreadCount; i++) + { + ptContext->ptThreadData[i].ptCurrentFrame = &ptContext->ptThreadData[i].atFrames[0]; + ptContext->ptThreadData[i].atFrames[0].uSampleCapacity = 256; + ptContext->ptThreadData[i].atFrames[0].uSampleStackCapacity = 256; + ptContext->ptThreadData[i].atFrames[1].uSampleCapacity = 256; + 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; } void pl__cleanup_profile_context(void) { - - for(uint32_t i = 0; i < 2; i++) + for(uint32_t i = 0; i < gptProfileContext->uThreadCount; i++) { - if(gTPProfileContext->atFrames[i].bOverflowInUse) - PL_PROFILE_FREE(gTPProfileContext->atFrames[i].ptSamples); + for(uint32_t j = 0; j < 2; j++) + { + + if(gptProfileContext->ptThreadData[i].atFrames[j].bOverflowInUse) + PL_PROFILE_FREE(gptProfileContext->ptThreadData[i].atFrames[j].ptSamples); - if(gTPProfileContext->atFrames[i].bSampleStackOverflowInUse) - PL_PROFILE_FREE(gTPProfileContext->atFrames[i].puSampleStack); + if(gptProfileContext->ptThreadData[i].atFrames[j].bSampleStackOverflowInUse) + PL_PROFILE_FREE(gptProfileContext->ptThreadData[i].atFrames[j].puSampleStack); + } } - PL_PROFILE_FREE(gTPProfileContext); - gTPProfileContext = NULL; + PL_PROFILE_FREE(gptProfileContext->ptThreadData); + PL_PROFILE_FREE(gptProfileContext); + gptProfileContext = NULL; } void pl__set_profile_context(plProfileContext* ptContext) { - PL_ASSERT(ptContext && "profile context is NULL"); - gTPProfileContext = ptContext; + gptProfileContext = ptContext; } plProfileContext* pl__get_profile_context(void) { - PL_ASSERT(gTPProfileContext && "no global log context set"); - return gTPProfileContext; + return gptProfileContext; } void pl__begin_profile_frame(void) { - gTPProfileContext->ulFrame++; - gTPProfileContext->ptCurrentFrame = &gTPProfileContext->atFrames[gTPProfileContext->ulFrame % 2]; - gTPProfileContext->ptCurrentFrame->dDuration = 0.0; - gTPProfileContext->ptCurrentFrame->dInternalDuration = 0.0; - gTPProfileContext->ptCurrentFrame->dStartTime = pl__get_wall_clock(); - gTPProfileContext->ptCurrentFrame->uTotalSampleSize = 0; + + if(gptProfileContext == NULL) + { + plProfileInit tInit = { + .uThreadCount = 1 + }; + 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 pl__end_profile_frame(void) { - gTPProfileContext->ptCurrentFrame->dDuration = pl__get_wall_clock() - gTPProfileContext->ptCurrentFrame->dStartTime; - gTPProfileContext->ptLastFrame = gTPProfileContext->ptCurrentFrame; + for(uint32_t i = 0; i < gptProfileContext->uThreadCount; i++) + { + gptProfileContext->ptThreadData[i].ptCurrentFrame->dDuration = pl__get_wall_clock() - gptProfileContext->ptThreadData[i].ptCurrentFrame->dStartTime; + gptProfileContext->ptThreadData[i].ptLastFrame = gptProfileContext->ptThreadData[i].ptCurrentFrame; + } } 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(); - plProfileFrame* ptCurrentFrame = gTPProfileContext->ptCurrentFrame; + plProfileFrame* ptCurrentFrame = gptProfileContext->ptThreadData[uThreadIndex].ptCurrentFrame; uint32_t uSampleIndex = ptCurrentFrame->uTotalSampleSize; plProfileSample* ptSample = pl__get_sample(ptCurrentFrame); @@ -414,10 +464,10 @@ pl__begin_profile_sample(const char* pcName) } void -pl__end_profile_sample(void) +pl__end_profile_sample(uint32_t uThreadIndex) { 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)]; PL_ASSERT(ptLastSample && "Begin/end profile sample mismatch"); ptLastSample->dDuration = pl__get_wall_clock() - ptLastSample->dStartTime; @@ -426,9 +476,9 @@ pl__end_profile_sample(void) } 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) *puSize = ptFrame->uTotalSampleSize; diff --git a/pl_stl.h b/pl_stl.h index ed332f2..f6e51b0 100644 --- a/pl_stl.h +++ b/pl_stl.h @@ -1,15 +1,26 @@ /* 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 -#define PL_STL_VERSION "0.2.0" -#define PL_STL_VERSION_NUM 00200 +// library version (format XYYZZ) +#define PL_STL_VERSION "1.0.0" +#define PL_STL_VERSION_NUM 10000 /* Index of this file: // [SECTION] header mess -// [SECTION] includes // [SECTION] forward declarations & basic types // [SECTION] public api // [SECTION] structs @@ -23,12 +34,6 @@ Index of this file: #ifndef PL_STL_H #define PL_STL_H -//----------------------------------------------------------------------------- -// [SECTION] includes -//----------------------------------------------------------------------------- - -#include - //----------------------------------------------------------------------------- // [SECTION] forward declarations & basic types //----------------------------------------------------------------------------- @@ -50,7 +55,7 @@ typedef struct _plStlInfo size_t szPositionStreamSize; size_t szNormalStreamSize; size_t szIndexBufferSize; - bool bPreloaded; + int iPreloaded; } plStlInfo; #endif // PL_STL_H @@ -104,11 +109,11 @@ pl_load_stl(const char* pcData, size_t szDataSize, float* afPositionStream, floa ptInfoOut = &_tInternalInfo; 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 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 @@ -131,7 +136,7 @@ pl_load_stl(const char* pcData, size_t szDataSize, float* afPositionStream, floa szVertexCount = szFacetCount * 3; } - ptInfoOut->bPreloaded = true; + ptInfoOut->iPreloaded = 1; } ptInfoOut->szIndexBufferSize = szFacetCount * 3; diff --git a/pl_string.h b/pl_string.h index a4cb663..c2f14ad 100644 --- a/pl_string.h +++ b/pl_string.h @@ -1,5 +1,8 @@ /* - pl_string + pl_string.h + * no dependencies + * simple string ops + Do this: #define PL_STRING_IMPLEMENTATION before you include this file in *one* C or C++ file to create the implementation. @@ -11,9 +14,9 @@ #include "pl_string.h" */ -// library version -#define PL_STRING_VERSION "0.2.0" -#define PL_STRING_VERSION_NUM 00200 +// library version (format XYYZZ) +#define PL_STRING_VERSION "1.0.0" +#define PL_STRING_VERSION_NUM 10000 /* 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); // file/path string ops -const char* pl_str_get_file_extension(const char* pcFilePath, char* pcExtensionOut); -const char* pl_str_get_file_name (const char* pcFilePath, char* pcFileOut); -const char* pl_str_get_file_name_only(const char* pcFilePath, char* pcFileOut); -void pl_str_get_directory (const char* pcFilePath, char* pcDirectoryOut); +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, size_t szOutSize); +bool pl_str_get_file_name_only(const char* pcFilePath, char* pcFileOut, size_t szOutSize); +bool pl_str_get_directory (const char* pcFilePath, char* pcDirectoryOut, size_t szOutSize); // misc. opts 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* -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 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]; if(c == '.') { - if(pcExtensionOut) strcpy(pcExtensionOut, &pcFilePath[szLen - i]); + if(pcExtensionOut) + strncpy(pcExtensionOut, &pcFilePath[szLen - i], szOutSize); pcResult = &pcFilePath[szLen - i]; break; } @@ -202,14 +206,15 @@ pl_str_get_file_extension(const char* pcFilePath, char* pcExtensionOut) } else { - if(pcExtensionOut) memset(pcExtensionOut, 0, 1); + if(pcExtensionOut) + memset(pcExtensionOut, 0, szOutSize); } return pcResult; } 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 size_t szLen = strlen(pcFilePath); @@ -233,7 +238,8 @@ pl_str_get_file_name(const char* pcFilePath, char* pcFileOut) if(uSlashCount == 0) { - if(pcFileOut) strcpy(pcFileOut, &pcFilePath[i + 1]); + if(pcFileOut) + strncpy(pcFileOut, &pcFilePath[i + 1], szOutSize); pcResult = &pcFilePath[i + 1]; break; } @@ -241,16 +247,26 @@ pl_str_get_file_name(const char* pcFilePath, char* pcFileOut) } 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; } -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) { - 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); // check if string includes directory @@ -272,19 +288,20 @@ pl_str_get_file_name_only(const char* pcFilePath, char* pcFileOut) if(uSlashCount == 0) { - if(pcFileOut) strcpy(pcFileOut, &pcFilePath[i + 1]); - pcResult = &pcFilePath[i + 1]; + strncpy(pcFileOut, &pcFilePath[i + 1], szOutSize); break; } } } 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; 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; } } - - return pcResult; + return true; } -void -pl_str_get_directory(const char* pcFilePath, char* pcDirectoryOut) +bool +pl_str_get_directory(const char* pcFilePath, char* pcDirectoryOut, size_t szOutSize) { size_t szLen = strlen(pcFilePath); - strcpy(pcDirectoryOut, pcFilePath); + strncpy(pcDirectoryOut, pcFilePath, szOutSize); + + if(szLen > szOutSize || szOutSize < 2) + return false; while(szLen > 0) { @@ -323,6 +342,7 @@ pl_str_get_directory(const char* pcFilePath, char* pcDirectoryOut) pcDirectoryOut[0] = '.'; pcDirectoryOut[1] = '/'; } + return true; } bool @@ -333,7 +353,6 @@ pl_str_concatenate(const char* pcStr0, const char* pcStr1, char* pcStringOut, si if(szLen0 + szLen1 > szDataSize) { - PL_ASSERT(false && "buffer provided not big enough"); return false; } diff --git a/pl_test.h b/pl_test.h index 30d70a3..25f9aa9 100644 --- a/pl_test.h +++ b/pl_test.h @@ -1,5 +1,7 @@ /* - pl_test + pl_test.h + * simple test librsry + Do this: #define PL_TEST_IMPLEMENTATION before you include this file in *one* C or C++ file to create the implementation. @@ -9,17 +11,22 @@ #include ... #define PL_TEST_IMPLEMENTATION #include "pl_test.h" + Notes: + * for console color output on windows, define "PL_TEST_WIN32_COLOR" before + including the implementation */ -// library version -#define PL_TEST_VERSION "0.1.0" -#define PL_TEST_VERSION_NUM 00100 +// library version (format XYYZZ) +#define PL_TEST_VERSION "1.0.0" +#define PL_TEST_VERSION_NUM 10000 /* Index of this file: // [SECTION] header mess // [SECTION] includes // [SECTION] public api +// [SECTION] structs +// [SECTION] private // [SECTION] c file */ @@ -34,8 +41,8 @@ Index of this file: // [SECTION] includes //----------------------------------------------------------------------------- -#include -#include +#include // bool +#include // uint32_t //----------------------------------------------------------------------------- // [SECTION] forward declarations & basic types @@ -43,6 +50,7 @@ Index of this file: // forward declarations typedef struct _plTestContext plTestContext; +typedef struct _plTestOptions plTestOptions; 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) - //----------------------------------------------------------------------------- // [SECTION] public api //----------------------------------------------------------------------------- -plTestContext* pl_create_test_context(void); +plTestContext* pl_create_test_context(plTestOptions); // tests -void pl__test_register_test(PL_TEST_FUNCTION tTest, void* pData, const char* pcName); -bool pl_test_run(void); +void pl_test_run_suite(const char* pcSuiteName); +bool pl_test_finish(void); // booleans bool pl_test_expect_true (bool bValue, const char* pcMsg); bool pl_test_expect_false(bool bValue, const char* pcMsg); -// numbers -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_unsigned_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); +// integers +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_uint32_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_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); @@ -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_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 //----------------------------------------------------------------------------- @@ -100,6 +128,14 @@ Index of this file: #ifdef PL_TEST_IMPLEMENTATION +#if defined(PL_TEST_WIN32_COLOR) && defined(_WIN32) + #define WIN32_LEAN_AND_MEAN + #include + static DWORD gtOriginalMode = 0; + static HANDLE gtStdOutHandle = 0; + static bool gbActiveColor = 0; +#endif + //----------------------------------------------------------------------------- // [SECTION] includes //----------------------------------------------------------------------------- @@ -130,12 +166,15 @@ typedef struct _plTest typedef struct _plTestContext { - plTest* atTests; - plTest* ptCurrentTest; - uint32_t uTestSize; - uint32_t uTestCapacity; - uint32_t uFailedTest; - bool bPrintPasses; + plTest* atTests; + plTest* ptCurrentTest; + uint32_t uTestSize; + uint32_t uTestCapacity; + uint32_t uFailedTest; + plTestOptions tOptions; + + uint32_t uTotalPassedTests; + uint32_t uTotalFailedTests; } plTestContext; //----------------------------------------------------------------------------- @@ -149,12 +188,30 @@ plTestContext* gptTestContext = NULL; //----------------------------------------------------------------------------- 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)); memset(gptTestContext, 0, sizeof(plTestContext)); gptTestContext->uTestCapacity = 64; - gptTestContext->bPrintPasses = false; + gptTestContext->tOptions = tOptions; gptTestContext->atTests = (plTest*)malloc(gptTestContext->uTestCapacity * sizeof(plTest)); memset(gptTestContext->atTests, 0, sizeof(gptTestContext->uTestCapacity * sizeof(plTest))); 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; } -bool -pl_test_run(void) +void +pl_test_run_suite(const char* pcSuiteName) { + printf("\n------%s suite------\n\n", pcSuiteName); + for(uint32_t i = 0; i < gptTestContext->uTestSize; i++) { gptTestContext->ptCurrentTest = &gptTestContext->atTests[i]; gptTestContext->ptCurrentTest->bFailureOccured = false; - printf("-----------------------------------\n"); - printf("\"%s\" running...\n\n", gptTestContext->ptCurrentTest->pcName); + printf("running -> \"%s\"\n", gptTestContext->ptCurrentTest->pcName); gptTestContext->ptCurrentTest->tTest(gptTestContext->ptCurrentTest->pData); 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++; } else - printf("\n\n\"%s\" passed\n\n", gptTestContext->ptCurrentTest->pcName); - printf("-----------------------------------\n"); + pl__test_print_green("%s", NULL, " passed"); } - 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 @@ -210,7 +307,8 @@ pl_test_expect_true(bool bValue, const char* pcMsg) { if(bValue) { - pl__test_print_green("Value: true | Expected Value: true", pcMsg); + if(gptTestContext->tOptions.bPrintAllPassedChecks) + pl__test_print_green("Value: true | Expected Value: true", pcMsg); return true; } @@ -229,64 +327,67 @@ pl_test_expect_false(bool bValue, const char* pcMsg) return false; } - pl__test_print_green("Value: false | Expected Value: false", pcMsg); + if(gptTestContext->tOptions.bPrintAllPassedChecks) + pl__test_print_green("Value: false | Expected Value: false", pcMsg); 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 pl_test_expect_int_equal(int iValue0, int iValue1, const char* pcMsg) { - if(iValue0 == iValue1) - { - 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; + pl__test_expect_equal(iValue0, iValue1, pcMsg, "%i"); } bool pl_test_expect_int_not_equal(int iValue0, int iValue1, const char* pcMsg) { - if(iValue0 == iValue1) - { - 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; + pl__test_expect_not_equal(iValue0, iValue1, pcMsg, "%i"); } 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_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; + pl__test_expect_equal(uValue0, uValue1, pcMsg, "%llu"); } 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_print_red("%u equals %u | Equality Not Expected", pcMsg, uValue0, uValue1); - gptTestContext->ptCurrentTest->bFailureOccured = true; - return false; - } + pl__test_expect_not_equal(uValue0, uValue1, pcMsg, "%llu"); +} - pl__test_print_green("%u does not equal %u | Equality Not Expected", pcMsg, uValue0, uValue1); - return true; +bool +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 @@ -306,7 +407,8 @@ pl_test_expect_double_near_equal(double dValue0, double dValue1, double dError, { if(dValue0 >= dValue1 - dError && dValue0 <= dValue1 + dError) { - pl__test_print_green("%0.6f equals %0.6f | Equality Expected within %0.6f", pcMsg, 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); return true; } @@ -325,7 +427,8 @@ pl_test_expect_double_near_not_equal(double dValue0, double dValue1, double dErr return false; } - pl__test_print_green("%0.6f does not equal %0.6f | Equality Not Expected within %0.6f", pcMsg, dValue0, dValue1, dError); + 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); return true; } @@ -334,7 +437,8 @@ pl_test_expect_string_equal(const char* pcValue0, const char* pcValue1, const ch { if(strcmp(pcValue0, pcValue1) == 0) { - pl__test_print_green("\"%s\" equals \"%s\" | Equality Expected", pcMsg, pcValue0, pcValue1); + if(gptTestContext->tOptions.bPrintAllPassedChecks) + pl__test_print_green("\"%s\" equals \"%s\" | Equality Expected", pcMsg, pcValue0, pcValue1); return true; } @@ -348,7 +452,8 @@ pl_test_expect_string_not_equal(const char* pcValue0, const char* pcValue1, cons { if(strcmp(pcValue0, pcValue1) == 0) { - pl__test_print_green("\"%s\" equals \"%s\" | Equality Not Expected", pcMsg, pcValue0, pcValue1); + if(gptTestContext->tOptions.bPrintAllPassedChecks) + pl__test_print_green("\"%s\" equals \"%s\" | Equality Not Expected", pcMsg, pcValue0, pcValue1); gptTestContext->ptCurrentTest->bFailureOccured = true; return false; } @@ -374,11 +479,14 @@ pl__test_print_va(const char* cPFormat, va_list args) void static pl__test_print_red(const char* cPFormat, const char* pcMsg, ...) { - #ifdef _WIN32 - printf(""); - #else - printf("\033[91m"); - #endif + if(gptTestContext->tOptions.bPrintColor) + { + #ifdef _WIN32 + printf(""); + #else + printf("\033[91m"); + #endif + } va_list argptr; va_start(argptr, pcMsg); @@ -390,24 +498,27 @@ pl__test_print_red(const char* cPFormat, const char* pcMsg, ...) else printf("\n"); - #ifdef _WIN32 - printf(""); - #else - printf("\033[0m"); - #endif + if(gptTestContext->tOptions.bPrintColor) + { + #ifdef _WIN32 + printf(""); + #else + printf("\033[0m"); + #endif + } } static void pl__test_print_green(const char* cPFormat, const char* pcMsg, ...) { - if(!gptTestContext->bPrintPasses) - return; - - #ifdef _WIN32 - printf(""); - #else - printf("\033[92m"); - #endif + if(gptTestContext->tOptions.bPrintColor) + { + #ifdef _WIN32 + printf(""); + #else + printf("\033[92m"); + #endif + } va_list argptr; va_start(argptr, pcMsg); @@ -419,11 +530,14 @@ pl__test_print_green(const char* cPFormat, const char* pcMsg, ...) else printf("\n"); - #ifdef _WIN32 - printf(""); - #else - printf("\033[0m"); - #endif + if(gptTestContext->tOptions.bPrintColor) + { + #ifdef _WIN32 + printf(""); + #else + printf("\033[0m"); + #endif + } } #endif // PL_TEST_IMPLEMENTATION \ No newline at end of file diff --git a/tests/main_tests.c b/tests/main_tests.c index 0a3f520..d8e0c56 100644 --- a/tests/main_tests.c +++ b/tests/main_tests.c @@ -1,26 +1,51 @@ #include "pl_ds_tests.h" #include "pl_json_tests.h" +#include "pl_memory_tests.h" +#include "pl_string_tests.h" int main() { - plTestContext* ptTestContext = pl_create_test_context(); - - // data structure tests - pl_test_register_test(hashmap_test_0, NULL); + // create test context + plTestOptions tOptions = { + .bPrintSuiteResults = true, + .bPrintColor = true + }; + plTestContext* ptTestContext = pl_create_test_context(tOptions); - // json tests - pl_test_register_test(json_test_0, NULL); + // pl_json.h tests + pl_json_tests(NULL); + pl_test_run_suite("pl_json.h"); - if(!pl_test_run()) + // pl_memory.h tests + pl_memory_tests(NULL); + pl_test_run_suite("pl_memory.h"); + + // 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); } - return 0; } -#define PL_TEST_IMPLEMENTATION -#include "pl_test.h" - #define PL_JSON_IMPLEMENTATION -#include "pl_json.h" \ No newline at end of file +#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" \ No newline at end of file diff --git a/tests/pl_ds_tests.h b/tests/pl_ds_tests.h index e82e731..49e6e3e 100644 --- a/tests/pl_ds_tests.h +++ b/tests/pl_ds_tests.h @@ -6,97 +6,104 @@ #include #include "pl_ds.h" -static void +void hashmap_test_0(void* pData) { - // hashmap 0 + plHashMap* ptHashMap = NULL; + + int* sbiValues = NULL; + pl_sb_push(sbiValues, 0); + pl_sb_push(sbiValues, 69); + pl_hm_insert(ptHashMap, pl_hm_hash_str("Dirty Number"), pl_sb_size(sbiValues) - 1); + pl_sb_push(sbiValues, 117); + pl_hm_insert(ptHashMap, pl_hm_hash_str("Spartan Number"), pl_sb_size(sbiValues) - 1); + + for(uint32_t i = 0; i < 3000; i++) { - plHashMap tHashMap = {0}; - - int* sbiValues = NULL; - pl_sb_push(sbiValues, 0); - pl_sb_push(sbiValues, 69); - pl_hm_insert(&tHashMap, pl_hm_hash_str("Dirty Number"), pl_sb_size(sbiValues) - 1); - pl_sb_push(sbiValues, 117); - pl_hm_insert(&tHashMap, pl_hm_hash_str("Spartan Number"), pl_sb_size(sbiValues) - 1); - - for(uint32_t i = 0; i < 3000; 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_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(&tHashMap, pl_hm_hash_str("Spartan Number"))], 117, NULL); - - pl_hm_remove(&tHashMap, pl_hm_hash_str("Dirty Number")); - - uint64_t ulFreeIndex = pl_hm_get_free_index(&tHashMap); - if(ulFreeIndex == UINT64_MAX) - { - pl_sb_add(sbiValues); - ulFreeIndex = pl_sb_size(sbiValues) - 1; - } - sbiValues[ulFreeIndex] = 666999; - pl_hm_insert(&tHashMap, 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(&tHashMap, 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_hm_free(&tHashMap); - pl_sb_free(sbiValues); + pl_sb_push(sbiValues, i); + pl_hm_insert(ptHashMap, pl_hm_hash("Spartan Number2", strlen("Spartan Number2"), i), pl_sb_size(sbiValues) - 1); } - // hashmap 1 + 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(ptHashMap, pl_hm_hash_str("Spartan Number"))], 117, NULL); + + pl_hm_remove(ptHashMap, pl_hm_hash_str("Dirty Number")); + + uint64_t ulFreeIndex = pl_hm_get_free_index(ptHashMap); + if(ulFreeIndex == UINT64_MAX) { - plHashMap tHashMap = {0}; + pl_sb_add(sbiValues); + ulFreeIndex = pl_sb_size(sbiValues) - 1; + } + sbiValues[ulFreeIndex] = 666999; + pl_hm_insert(ptHashMap, pl_hm_hash_str("Extra dirty number"), ulFreeIndex); + pl_test_expect_int_equal(sbiValues[pl_hm_lookup(ptHashMap, pl_hm_hash_str("Extra dirty number"))], 666999, NULL); - pl_hm_insert(&tHashMap, pl_hm_hash_str("Dirty Number"), 69); - pl_hm_insert(&tHashMap, pl_hm_hash_str("Spartan Number"), 117); + 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(ptHashMap, pl_hm_hash_str("Spartan Number"))], 117, NULL); - 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(&tHashMap, pl_hm_hash_str("Spartan Number")), 117, NULL); + pl_hm_free(ptHashMap); + pl_sb_free(sbiValues); +} - pl_hm_free(&tHashMap); +void +hashmap_test_1(void* pData) +{ + plHashMap* ptHashMap = NULL; + + pl_hm_insert(ptHashMap, pl_hm_hash_str("Dirty Number"), 69); + pl_hm_insert(ptHashMap, pl_hm_hash_str("Spartan Number"), 117); + + 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(ptHashMap, pl_hm_hash_str("Spartan Number")), 117, NULL); + + pl_hm_free(ptHashMap); +} + +void +hashmap_test_2(void* pData) +{ + plHashMap* ptHashMap = NULL; + + int* sbiValues = NULL; + pl_sb_push(sbiValues, 0); + pl_sb_push(sbiValues, 69); + pl_hm_insert_str(ptHashMap, "Dirty Number", pl_sb_size(sbiValues) - 1); + pl_sb_push(sbiValues, 117); + pl_hm_insert_str(ptHashMap, "Spartan Number", pl_sb_size(sbiValues) - 1); + + for(uint32_t i = 0; i < 79; i++) + { + pl_sb_push(sbiValues, 118); + pl_hm_insert_str(ptHashMap, "Spartan Number2", pl_sb_size(sbiValues) - 1); } - // hashmap 2 + 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(ptHashMap, "Spartan Number")], 117, NULL); + + pl_hm_remove_str(ptHashMap, "Dirty Number"); + + uint64_t ulFreeIndex = pl_hm_get_free_index(ptHashMap); + if(ulFreeIndex == UINT64_MAX) { - plHashMap tHashMap = {0}; - - int* sbiValues = NULL; - pl_sb_push(sbiValues, 0); - pl_sb_push(sbiValues, 69); - pl_hm_insert_str(&tHashMap, "Dirty Number", pl_sb_size(sbiValues) - 1); - pl_sb_push(sbiValues, 117); - pl_hm_insert_str(&tHashMap, "Spartan Number", pl_sb_size(sbiValues) - 1); - - for(uint32_t i = 0; i < 79; i++) - { - pl_sb_push(sbiValues, 118); - pl_hm_insert_str(&tHashMap, "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(&tHashMap, "Spartan Number")], 117, NULL); - - pl_hm_remove_str(&tHashMap, "Dirty Number"); - - uint64_t ulFreeIndex = pl_hm_get_free_index(&tHashMap); - if(ulFreeIndex == UINT64_MAX) - { - pl_sb_add(sbiValues); - ulFreeIndex = pl_sb_size(sbiValues) - 1; - } - sbiValues[ulFreeIndex] = 666999; - pl_hm_insert_str(&tHashMap, "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(&tHashMap, "Extra dirty number")], 666999, NULL); - pl_test_expect_int_equal(sbiValues[pl_hm_lookup_str(&tHashMap, "Spartan Number")], 117, NULL); - - pl_hm_free(&tHashMap); - pl_sb_free(sbiValues); + pl_sb_add(sbiValues); + ulFreeIndex = pl_sb_size(sbiValues) - 1; } + sbiValues[ulFreeIndex] = 666999; + pl_hm_insert_str(ptHashMap, "Extra dirty number", ulFreeIndex); + 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(ptHashMap, "Extra dirty number")], 666999, NULL); + pl_test_expect_int_equal(sbiValues[pl_hm_lookup_str(ptHashMap, "Spartan Number")], 117, NULL); + + pl_hm_free(ptHashMap); + 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); } \ No newline at end of file diff --git a/tests/pl_json_tests.h b/tests/pl_json_tests.h index 94f6ea6..530125e 100644 --- a/tests/pl_json_tests.h +++ b/tests/pl_json_tests.h @@ -6,166 +6,176 @@ #include #include "pl_json.h" -static void -json_test_0(void* pData) +void +write_json_test(void* pData) { - char* pcBuffer = NULL; + char** ppcBuffer = pData; - // write json - { + // root object + plJsonObject* ptRootJsonObject = pl_json_new_root_object("ROOT"); + pl_json_add_string_member(ptRootJsonObject, "first name", "John"); + pl_json_add_string_member(ptRootJsonObject, "last name", "Doe"); + pl_json_add_int_member(ptRootJsonObject, "age", 40); + pl_json_add_bool_member(ptRootJsonObject, "tall", false); + pl_json_add_bool_member(ptRootJsonObject, "hungry", true); + int aScores[] = {100, 86, 46}; + pl_json_add_int_array(ptRootJsonObject, "scores", aScores, 3); - // root object - plJsonObject tRootJsonObject = {0}; - pl_json_add_string_member(&tRootJsonObject, "first name", "John"); - pl_json_add_string_member(&tRootJsonObject, "last name", "Doe"); - pl_json_add_int_member(&tRootJsonObject, "age", 40); - pl_json_add_bool_member(&tRootJsonObject, "tall", false); - pl_json_add_bool_member(&tRootJsonObject, "hungry", true); - int aScores[] = {100, 86, 46}; - pl_json_add_int_array(&tRootJsonObject, "scores", aScores, 3); + char* aPets[] = {"Riley", "Luna", "Chester"}; + pl_json_add_string_array(ptRootJsonObject, "pets", aPets, 3); - char* aPets[] = {"Riley", "Luna", "Chester"}; - pl_json_add_string_array(&tRootJsonObject, "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); + 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); - pl_json_add_member(&tRootJsonObject, "best friend", &tBestFriend); + // friend member object + plJsonObject* ptFriends = pl_json_add_member_array(ptRootJsonObject, "friends", 2); - // friend member object - plJsonObject atFriends[2] = {0}; - int aScores0[] = {88, 86, 100}; - pl_json_add_string_member(&atFriends[0], "first name", "Jacob"); - pl_json_add_string_member(&atFriends[0], "last name", "Smith"); - pl_json_add_int_member(&atFriends[0], "age", 23); - pl_json_add_bool_member(&atFriends[0], "tall", true); - pl_json_add_bool_member(&atFriends[0], "hungry", false); - pl_json_add_int_array(&atFriends[0], "scores", aScores0, 3); + plJsonObject* ptFriend0 = pl_json_member_by_index(ptFriends, 0); + int aScores0[] = {88, 86, 100}; + pl_json_add_string_member(ptFriend0, "first name", "Jacob"); + pl_json_add_string_member(ptFriend0, "last name", "Smith"); + pl_json_add_int_member(ptFriend0, "age", 23); + pl_json_add_bool_member(ptFriend0, "tall", true); + pl_json_add_bool_member(ptFriend0, "hungry", false); + pl_json_add_int_array(ptFriend0, "scores", aScores0, 3); - int aScores1[] = {80, 80, 100}; - pl_json_add_string_member(&atFriends[1], "first name", "Chance"); - pl_json_add_string_member(&atFriends[1], "last name", "Dale"); - pl_json_add_int_member(&atFriends[1], "age", 48); - pl_json_add_bool_member(&atFriends[1], "tall", true); - pl_json_add_bool_member(&atFriends[1], "hungry", true); - pl_json_add_int_array(&atFriends[1], "scores", aScores1, 3); + plJsonObject* ptFriend1 = pl_json_member_by_index(ptFriends, 1); + int aScores1[] = {80, 80, 100}; + pl_json_add_string_member(ptFriend1, "first name", "Chance"); + pl_json_add_string_member(ptFriend1, "last name", "Dale"); + pl_json_add_int_member(ptFriend1, "age", 48); + pl_json_add_bool_member(ptFriend1, "tall", true); + pl_json_add_bool_member(ptFriend1, "hungry", true); + pl_json_add_int_array(ptFriend1, "scores", aScores1, 3); - pl_json_add_member_array(&tRootJsonObject, "friends", atFriends, 2); + uint32_t uBufferSize = 0; + pl_write_json(ptRootJsonObject, NULL, &uBufferSize); - uint32_t uBufferSize = 0; - pl_write_json(&tRootJsonObject, NULL, &uBufferSize); + *ppcBuffer = malloc(uBufferSize + 1); + memset(*ppcBuffer, 0, uBufferSize + 1); + pl_write_json(ptRootJsonObject, *ppcBuffer, &uBufferSize); - pcBuffer = malloc(uBufferSize + 1); - memset(pcBuffer, 0, uBufferSize + 1); - pl_write_json(&tRootJsonObject, pcBuffer, &uBufferSize); - - pl_unload_json(&tRootJsonObject); - } - - // read json - { - - plJsonObject tRootJsonObject = {0}; - pl_load_json(pcBuffer, &tRootJsonObject); - - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~reading~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - // check root members - { - int aiScores[3] = {0}; - pl_json_int_array_member(&tRootJsonObject, "scores", aiScores, 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[2], 46, NULL); - } - { - char acPet0[64] = {0}; - char acPet1[64] = {0}; - char acPet2[64] = {0}; - char* aacPets[3] = {acPet0, acPet1, acPet2}; - uint32_t auLengths[3] = {64, 64, 64}; - pl_json_string_array_member(&tRootJsonObject, "pets", aacPets, NULL, auLengths); - pl_test_expect_string_equal(acPet0, "Riley", NULL); - pl_test_expect_string_equal(acPet1, "Luna", NULL); - pl_test_expect_string_equal(acPet2, "Chester", NULL); - } - - char acFirstName[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(&tRootJsonObject, "last name", acLastName, 64), "Doe", NULL); - pl_test_expect_int_equal(pl_json_int_member(&tRootJsonObject, "age", 0), 40, NULL); - pl_test_expect_false(pl_json_bool_member(&tRootJsonObject, "tall", false), NULL); - pl_test_expect_true(pl_json_bool_member(&tRootJsonObject, "hungry", false), NULL); - - // check child members - plJsonObject* ptBestFriend = pl_json_member(&tRootJsonObject, "best friend"); - { - int aiScores[3] = {0}; - pl_json_int_array_member(ptBestFriend, "scores", aiScores, 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[2], 46, NULL); - } - { - char acPet0[64] = {0}; - char acPet1[64] = {0}; - char acPet2[64] = {0}; - char* aacPets[3] = {acPet0, acPet1, acPet2}; - uint32_t auLengths[3] = {64, 64, 64}; - pl_json_string_array_member(ptBestFriend, "pets", aacPets, NULL, auLengths); - pl_test_expect_string_equal(acPet0, "Riley", NULL); - pl_test_expect_string_equal(acPet1, "Luna", NULL); - pl_test_expect_string_equal(acPet2, "Chester", NULL); - } - - pl_test_expect_string_equal(pl_json_string_member(ptBestFriend, "first name", acFirstName, 64), "John", NULL); - pl_test_expect_string_equal(pl_json_string_member(ptBestFriend, "last name", acLastName, 64), "Doe", NULL); - pl_test_expect_int_equal(pl_json_int_member(ptBestFriend, "age", 0), 40, NULL); - pl_test_expect_false(pl_json_bool_member(ptBestFriend, "tall", false), NULL); - pl_test_expect_true(pl_json_bool_member(ptBestFriend, "hungry", false), NULL); - - uint32_t uFriendCount = 0; - plJsonObject* sbtFriends = pl_json_array_member(&tRootJsonObject, "friends", &uFriendCount); - - plJsonObject* ptFriend0 = &sbtFriends[0]; - plJsonObject* ptFriend1 = &sbtFriends[1]; - { - int aiScores[3] = {0}; - pl_json_int_array_member(ptFriend0, "scores", aiScores, NULL); - pl_test_expect_int_equal(aiScores[0], 88, NULL); - pl_test_expect_int_equal(aiScores[1], 86, NULL); - pl_test_expect_int_equal(aiScores[2], 100, NULL); - } - - { - int aiScores[3] = {0}; - pl_json_int_array_member(ptFriend1, "scores", aiScores, NULL); - pl_test_expect_int_equal(aiScores[0], 80, NULL); - pl_test_expect_int_equal(aiScores[1], 80, NULL); - pl_test_expect_int_equal(aiScores[2], 100, NULL); - } - - pl_test_expect_string_equal(pl_json_string_member(ptFriend0, "first name", acFirstName, 64), "Jacob", NULL); - pl_test_expect_string_equal(pl_json_string_member(ptFriend0, "last name", acLastName, 64), "Smith", NULL); - pl_test_expect_int_equal(pl_json_int_member(ptFriend0, "age", 0), 23, NULL); - pl_test_expect_true(pl_json_bool_member(ptFriend0, "tall", false), NULL); - pl_test_expect_false(pl_json_bool_member(ptFriend0, "hungry", false), NULL); - - pl_test_expect_string_equal(pl_json_string_member(ptFriend1, "first name", acFirstName, 64), "Chance", NULL); - pl_test_expect_string_equal(pl_json_string_member(ptFriend1, "last name", acLastName, 64), "Dale", NULL); - pl_test_expect_int_equal(pl_json_int_member(ptFriend1, "age", 0), 48, 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_unload_json(&tRootJsonObject); - } + pl_unload_json(&ptRootJsonObject); } + +void +read_json_test(void* pData) +{ + + char** ppcBuffer = pData; + + plJsonObject* ptRootJsonObject = NULL; + pl_load_json(*ppcBuffer, &ptRootJsonObject); + + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~reading~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + // check root members + { + int aiScores[3] = {0}; + pl_json_int_array_member(ptRootJsonObject, "scores", aiScores, 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[2], 46, NULL); + } + { + char acPet0[64] = {0}; + char acPet1[64] = {0}; + char acPet2[64] = {0}; + char* aacPets[3] = {acPet0, acPet1, acPet2}; + uint32_t auLengths[3] = {64, 64, 64}; + pl_json_string_array_member(ptRootJsonObject, "pets", aacPets, NULL, auLengths); + pl_test_expect_string_equal(acPet0, "Riley", NULL); + pl_test_expect_string_equal(acPet1, "Luna", NULL); + pl_test_expect_string_equal(acPet2, "Chester", NULL); + } + + char acFirstName[64] = {0}; + char acLastName[64] = {0}; + 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(ptRootJsonObject, "last name", acLastName, 64), "Doe", NULL); + pl_test_expect_int_equal(pl_json_int_member(ptRootJsonObject, "age", 0), 40, NULL); + pl_test_expect_false(pl_json_bool_member(ptRootJsonObject, "tall", false), NULL); + pl_test_expect_true(pl_json_bool_member(ptRootJsonObject, "hungry", false), NULL); + + // check child members + plJsonObject* ptBestFriend = pl_json_member(ptRootJsonObject, "best friend"); + { + int aiScores[3] = {0}; + pl_json_int_array_member(ptBestFriend, "scores", aiScores, 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[2], 46, NULL); + } + { + char acPet0[64] = {0}; + char acPet1[64] = {0}; + char acPet2[64] = {0}; + char* aacPets[3] = {acPet0, acPet1, acPet2}; + uint32_t auLengths[3] = {64, 64, 64}; + pl_json_string_array_member(ptBestFriend, "pets", aacPets, NULL, auLengths); + pl_test_expect_string_equal(acPet0, "Riley", NULL); + pl_test_expect_string_equal(acPet1, "Luna", NULL); + pl_test_expect_string_equal(acPet2, "Chester", NULL); + } + + pl_test_expect_string_equal(pl_json_string_member(ptBestFriend, "first name", acFirstName, 64), "John", NULL); + pl_test_expect_string_equal(pl_json_string_member(ptBestFriend, "last name", acLastName, 64), "Doe", NULL); + pl_test_expect_int_equal(pl_json_int_member(ptBestFriend, "age", 0), 40, NULL); + pl_test_expect_false(pl_json_bool_member(ptBestFriend, "tall", false), NULL); + pl_test_expect_true(pl_json_bool_member(ptBestFriend, "hungry", false), NULL); + + uint32_t uFriendCount = 0; + plJsonObject* ptFriends = pl_json_array_member(ptRootJsonObject, "friends", &uFriendCount); + + plJsonObject* ptFriend0 = pl_json_member_by_index(ptFriends, 0); + plJsonObject* ptFriend1 = pl_json_member_by_index(ptFriends, 1); + { + int aiScores[3] = {0}; + pl_json_int_array_member(ptFriend0, "scores", aiScores, NULL); + pl_test_expect_int_equal(aiScores[0], 88, NULL); + pl_test_expect_int_equal(aiScores[1], 86, NULL); + pl_test_expect_int_equal(aiScores[2], 100, NULL); + } + + { + int aiScores[3] = {0}; + pl_json_int_array_member(ptFriend1, "scores", aiScores, NULL); + pl_test_expect_int_equal(aiScores[0], 80, NULL); + pl_test_expect_int_equal(aiScores[1], 80, NULL); + pl_test_expect_int_equal(aiScores[2], 100, NULL); + } + + pl_test_expect_string_equal(pl_json_string_member(ptFriend0, "first name", acFirstName, 64), "Jacob", NULL); + pl_test_expect_string_equal(pl_json_string_member(ptFriend0, "last name", acLastName, 64), "Smith", NULL); + pl_test_expect_int_equal(pl_json_int_member(ptFriend0, "age", 0), 23, NULL); + pl_test_expect_true(pl_json_bool_member(ptFriend0, "tall", false), NULL); + pl_test_expect_false(pl_json_bool_member(ptFriend0, "hungry", false), NULL); + + pl_test_expect_string_equal(pl_json_string_member(ptFriend1, "first name", acFirstName, 64), "Chance", NULL); + pl_test_expect_string_equal(pl_json_string_member(ptFriend1, "last name", acLastName, 64), "Dale", NULL); + pl_test_expect_int_equal(pl_json_int_member(ptFriend1, "age", 0), 48, 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_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); +} \ No newline at end of file diff --git a/tests/pl_memory_tests.h b/tests/pl_memory_tests.h new file mode 100644 index 0000000..e22b278 --- /dev/null +++ b/tests/pl_memory_tests.h @@ -0,0 +1,157 @@ +#include "pl_test.h" +#include "pl_memory.h" +#include // 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); +} \ No newline at end of file diff --git a/tests/pl_string_tests.h b/tests/pl_string_tests.h new file mode 100644 index 0000000..9582320 --- /dev/null +++ b/tests/pl_string_tests.h @@ -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); +} \ No newline at end of file