diff options
| -rw-r--r-- | Makefile | 88 | ||||
| -rw-r--r-- | config.mk | 26 | ||||
| -rw-r--r-- | pkmacros.h | 216 | ||||
| -rw-r--r-- | pkmem-types.h | 65 | ||||
| -rw-r--r-- | pkmem.h | 556 | ||||
| -rw-r--r-- | test/pkmacros.c | 55 | ||||
| -rw-r--r-- | test/pkmacros.cpp | 191 | ||||
| -rw-r--r-- | test/pkmem-types.c | 42 | ||||
| -rw-r--r-- | test/pkmem-types.cpp | 65 | ||||
| -rw-r--r-- | test/pkmem.c | 17 | ||||
| -rw-r--r-- | test/pkmem.cpp | 17 |
11 files changed, 1338 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..bf99592 --- /dev/null +++ b/Makefile @@ -0,0 +1,88 @@ +# pkh - header-only library +# See LICENSE file for copyright and license details. + +include config.mk + +.PHONY: pkmem-types pkmem + +SRC = \ + pkmacros.h \ + pkmem-types.h \ + pkmem.h \ + test/pkmacros.c \ + test/pkmacros.cpp \ + test/pkmem-types.c \ + test/pkmem-types.cpp \ + test/pkmem.c \ + test/pkmem.cpp \ + +OBJ = $(SRC:%.c=.o) +PPOBJ = $(SRC:%.cpp=.so) +HOBJ = $(SRC:%.h=.gch) +HPPOBJ = $(SRC:%.h=.gchpp) + +all: options .WAIT clean .WAIT \ + pkmacros pkmem-types pkmem \ + test-pkmem test-pkmem-cpp \ + test-types-pkmem test-types-pkmem-cpp \ + test-pkmacros test-pkmacros-cpp \ + +options: + @echo at-suite build options: + @echo "CFLAGS = $(CFLAGS)" + @echo "LDFLAGS = $(LDFLAGS)" + @echo "CC = $(CC)" + +%.gch: %.h + $(CC) -std=c2x $(CFLAGS) -c $< -o $@ +%.gchpp: %.h + $(CXX) -std=c++23 $(CPPFLAGS) -x c++-header -c $< -o $@ +%.o: %.c + $(CC) -std=c2x $(CFLAGS) -g -O0 -c $< -o $@ +%.so: %.cpp + $(CXX) -std=c++23 $(CPPFLAGS) -g -O0 -c $< -o $@ + +$(OBJ): config.mk +$(PPOBJ): config.mk +$(HOBJ): config.mk +$(HPPOBJ): config.mk + +pkmacros: pkmacros.gch pkmacros.gchpp + +pkmem-types: pkmacros pkmem-types.gch pkmem-types.gchpp + +pkmem: pkmem-types pkmem.gch pkmem.gchpp + +test-pkmacros: test/pkmacros.o + $(CC) -g -O0 -std=c2x $(CFLAGS) -o test/$@ $^ $(LDFLAGS) + +test-pkmacros-cpp: test/pkmacros.so + $(CXX) -g -O0 -std=c++23 $(CPPFLAGS) -o test/$@ $^ $(LDFLAGS) + +test-pkmem-types: test/pkmem-types.o + $(CC) -g -O0 -std=c2x $(CFLAGS) -o test/$@ $^ $(LDFLAGS) + +test-pkmem-types-cpp: test/pkmem-types.so + $(CXX) -g -O0 -std=c++23 $(CPPFLAGS) -o test/$@ $^ $(LDFLAGS) + +test-pkmem: test/pkmem.o + $(CC) -g -O0 -std=c2x $(CFLAGS) -o test/$@ $^ $(LDFLAGS) + +test-pkmem-cpp: test/pkmem.so + $(CXX) -g -O0 -std=c++23 $(CPPFLAGS) -o test/$@ $^ $(LDFLAGS) + +test: pkmacros pkmem-types pkmem +test: test-pkmacros test-pkmacros-cpp +test: test-pkmem-types test-pkmem-types-cpp +test: test-pkmem test-pkmem-cpp +test: + @echo "" + ./test/test-pkmacros ; echo Result: $$? "\n" + ./test/test-pkmacros-cpp ; echo Result: $$? "\n" + ./test/test-pkmem-types ; echo Result: $$? "\n" + ./test/test-pkmem-types-cpp ; echo Result: $$? "\n" + ./test/test-pkmem ; echo Result: $$? "\n" + ./test/test-pkmem-cpp ; echo Result: $$? "\n" + +clean: + rm -f *.plist *.gch *.gchpp *.o *.so test/*.o test/*.so test/test-* diff --git a/config.mk b/config.mk new file mode 100644 index 0000000..cf3ab50 --- /dev/null +++ b/config.mk @@ -0,0 +1,26 @@ +# pkh version +VERSION = 0.0.1 + +# paths +PREFIX = /usr/local +MANPREFIX = $(PREFIX)/share/man + +PKG_CONFIG = pkg-config + +# includes and libs +INCS = \ + +LIBS = -lm \ + +# flags +# -pedantic +SHARED_FLAGS = -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200809L \ + -DVERSION=\"$(VERSION)\" -DPK_MEMORY_DEBUGGER -DPK_IMPLEMENTATION \ + +CPPFLAGS += -Wall $(INCS) $(SHARED_FLAGS) +CFLAGS += -Wall $(INCS) $(SHARED_FLAGS) +LDFLAGS = $(LIBS) + +# compiler and linker +CC ?= /usr/bin/clang +CXX ?= /usr/bin/clang++ diff --git a/pkmacros.h b/pkmacros.h new file mode 100644 index 0000000..0bda595 --- /dev/null +++ b/pkmacros.h @@ -0,0 +1,216 @@ +#ifndef PK_MACROS_H +#define PK_MACROS_H + +#ifndef PK_LOG_OVERRIDE +# ifdef NDEBUG +# define PK_LOG_ERR(str) (void)str +# define PK_LOG_INF(str) (void)str +# define PK_LOGV_ERR(str, ...) (void)str +# define PK_LOGV_INF(str, ...) (void)str +# else +# define PK_LOG_ERR(str, ...) fprintf(stderr, str) +# define PK_LOG_INF(str, ...) fprintf(stdout, str) +# define PK_LOGV_ERR(str, ...) fprintf(stderr, str, __VA_ARGS__) +# define PK_LOGV_INF(str, ...) fprintf(stdout, str, __VA_ARGS__) +# endif +#endif + +#define PK_Q(x) #x +#define PK_QUOTE(x) PK_Q(x) +#define PK_CONCAT2(x, y) x##y +#define PK_CONCAT(x, y) PK_CONCAT2(x, y) + +#define PK_HAS_FLAG(val, flag) ((val & flag) == flag) +#define PK_CLAMP(val, min, max) (val < min ? min : val > max ? max : val) +#define PK_MIN(val, min) (val < min ? val : min) +#define PK_MAX(val, max) (val > max ? val : max) + +#define PK_TO_BIN_PAT PK_Q(%c%c%c%c%c%c%c%c) +#define PK_TO_BIN_PAT_8 PK_TO_BIN_PAT +#define PK_TO_BIN_PAT_16 PK_TO_BIN_PAT PK_TO_BIN_PAT +#define PK_TO_BIN_PAT_32 PK_TO_BIN_PAT_16 PK_TO_BIN_PAT_16 +#define PK_TO_BIN_PAT_64 PK_TO_BIN_PAT_32 PK_TO_BIN_PAT_32 +#define PK_TO_BIN(byte) \ + ((byte) & 0x80 ? '1' : '0'), \ + ((byte) & 0x40 ? '1' : '0'), \ + ((byte) & 0x20 ? '1' : '0'), \ + ((byte) & 0x10 ? '1' : '0'), \ + ((byte) & 0x08 ? '1' : '0'), \ + ((byte) & 0x04 ? '1' : '0'), \ + ((byte) & 0x02 ? '1' : '0'), \ + ((byte) & 0x01 ? '1' : '0') +#define PK_TO_BIN_8(u8) PK_TO_BIN(u8) +#define PK_TO_BIN_16(u16) PK_TO_BIN((u16 >> 8)), PK_TO_BIN(u16 & 0x00FF) +#define PK_TO_BIN_32(u32) PK_TO_BIN_16((u32 >> 16)), PK_TO_BIN_16(u32 & 0x0000FFFF) +#define PK_TO_BIN_64(u64) PK_TO_BIN_32((u64 >> 32)), PK_TO_BIN_32(u64 & 0x00000000FFFFFFFF) + +#if defined(__cplusplus) +# define CAFE_BABE(T) reinterpret_cast<T *>(0xCAFEBABE) +#else +# define CAFE_BABE(T) (T *)(0xCAFEBABE) +#endif + +#define NULL_CHAR_ARR(v, len) char v[len]; v[0] = '\0'; v[len-1] = '\0'; + +#define IS_CONSTRUCTIBLE(T) constexpr(std::is_default_constructible<T>::value && !std::is_integral<T>::value && !std::is_floating_point<T>::value) +#define IS_DESTRUCTIBLE(T) constexpr(std::is_destructible<T>::value && !std::is_integral<T>::value && !std::is_floating_point<T>::value && !std::is_array<T>::value) + +#define TypeSafeInt2_H(TypeName, Type, Max, TypeName_T, TypeName_MAX, TypeName_T_MAX) \ + using TypeName_T = Type; \ + enum class TypeName : TypeName_T; \ + constexpr TypeName_T TypeName_T_MAX = TypeName_T{Max}; \ + constexpr TypeName TypeName_MAX = TypeName{TypeName_T_MAX}; \ + TypeName operator+(const TypeName& a, const TypeName& b); \ + TypeName operator-(const TypeName& a, const TypeName& b); \ + TypeName operator&(const TypeName& a, const TypeName& b); \ + TypeName operator|(const TypeName& a, const TypeName& b); \ + TypeName operator^(const TypeName& a, const TypeName& b); \ + TypeName& operator++(TypeName& a); \ + TypeName& operator--(TypeName& a); \ + TypeName operator++(TypeName& a, int); \ + TypeName operator--(TypeName& a, int); \ + TypeName operator<<(const TypeName& a, const TypeName& b); \ + TypeName operator>>(const TypeName& a, const TypeName& b); \ + TypeName operator+=(TypeName& a, const TypeName& b); \ + TypeName operator-=(TypeName& a, const TypeName& b); \ + TypeName operator&=(TypeName& a, const TypeName& b); \ + TypeName operator|=(TypeName& a, const TypeName& b); \ + TypeName operator^=(TypeName& a, const TypeName& b); \ + TypeName operator~(TypeName& a); +#define TypeSafeInt2_B(TypeName, TypeName_T) \ + inline TypeName operator+(const TypeName& a, const TypeName& b) { \ + return TypeName(static_cast<TypeName_T>(a) + static_cast<TypeName_T>(b)); \ + } \ + inline TypeName operator-(const TypeName& a, const TypeName& b) { \ + return TypeName(static_cast<TypeName_T>(a) - static_cast<TypeName_T>(b)); \ + } \ + inline TypeName operator&(const TypeName& a, const TypeName& b) { \ + return TypeName(static_cast<TypeName_T>(a) & static_cast<TypeName_T>(b)); \ + } \ + inline TypeName operator|(const TypeName& a, const TypeName& b) { \ + return TypeName(static_cast<TypeName_T>(a) | static_cast<TypeName_T>(b)); \ + } \ + inline TypeName operator^(const TypeName& a, const TypeName& b) { \ + return TypeName(static_cast<TypeName_T>(a) ^ static_cast<TypeName_T>(b)); \ + } \ + inline TypeName& operator++(TypeName& a) { \ + a = a + TypeName{1}; \ + return a; \ + } \ + inline TypeName& operator--(TypeName& a) { \ + a = a - TypeName{1}; \ + return a; \ + }; \ + inline TypeName operator++(TypeName& a, int) { \ + a = a + TypeName{1}; \ + return a; \ + } \ + inline TypeName operator--(TypeName& a, int) { \ + a = a - TypeName{1}; \ + return a; \ + }; \ + inline TypeName operator<<(const TypeName& a, const TypeName& b) { \ + return TypeName(static_cast<TypeName_T>(a) << static_cast<TypeName_T>(b)); \ + }; \ + inline TypeName operator>>(const TypeName& a, const TypeName& b) { \ + return TypeName(static_cast<TypeName_T>(a) >> static_cast<TypeName_T>(b)); \ + }; \ + inline TypeName operator+=(TypeName& a, const TypeName& b) { \ + a = TypeName{a + b}; \ + return a; \ + }; \ + inline TypeName operator-=(TypeName& a, const TypeName& b) { \ + a = TypeName{a - b}; \ + return a; \ + }; \ + inline TypeName operator&=(TypeName& a, const TypeName& b) { \ + a = TypeName{a & b}; \ + return a; \ + }; \ + inline TypeName operator|=(TypeName& a, const TypeName& b) { \ + a = TypeName{a | b}; \ + return a; \ + }; \ + inline TypeName operator^=(TypeName& a, const TypeName& b) { \ + a = TypeName{a ^ b}; \ + return a; \ + }; \ + inline TypeName operator~(TypeName& a) { \ + a = static_cast<TypeName>(~static_cast<TypeName_T>(a)); \ + return a; \ + }; +#define TypeSafeInt_H(TypeName, Type, Max) \ + TypeSafeInt2_H(TypeName, Type, Max, PK_CONCAT(TypeName, _T), PK_CONCAT(TypeName, _MAX), PK_CONCAT(TypeName, _T_MAX)) +#define TypeSafeInt_B(TypeName) \ + TypeSafeInt2_B(TypeName, PK_CONCAT(TypeName, _T)) + +#define TypeSafeInt2_H_constexpr(TypeName, Type, Max, TypeName_T, TypeName_MAX, TypeName_T_MAX) \ + using TypeName_T = Type; \ + enum class TypeName : TypeName_T; \ + constexpr TypeName_T TypeName_T_MAX = TypeName_T{Max}; \ + constexpr TypeName TypeName_MAX = TypeName{TypeName_T_MAX}; \ + constexpr TypeName operator+(const TypeName& a, const TypeName& b) { \ + return TypeName(static_cast<TypeName_T>(a) + static_cast<TypeName_T>(b)); \ + } \ + constexpr TypeName operator-(const TypeName& a, const TypeName& b) { \ + return TypeName(static_cast<TypeName_T>(a) - static_cast<TypeName_T>(b)); \ + } \ + constexpr TypeName operator&(const TypeName& a, const TypeName& b) { \ + return TypeName(static_cast<TypeName_T>(a) & static_cast<TypeName_T>(b)); \ + } \ + constexpr TypeName operator|(const TypeName& a, const TypeName& b) { \ + return TypeName(static_cast<TypeName_T>(a) | static_cast<TypeName_T>(b)); \ + } \ + constexpr TypeName operator^(const TypeName& a, const TypeName& b) { \ + return TypeName(static_cast<TypeName_T>(a) ^ static_cast<TypeName_T>(b)); \ + } \ + constexpr TypeName& operator++(TypeName& a) { \ + a = a + TypeName{1}; \ + return a; \ + } \ + constexpr TypeName& operator--(TypeName& a) { \ + a = a - TypeName{1}; \ + return a; \ + }; \ + constexpr TypeName operator++(TypeName& a, int) { \ + a = a + TypeName{1}; \ + return a; \ + } \ + constexpr TypeName operator--(TypeName& a, int) { \ + a = a - TypeName{1}; \ + return a; \ + }; \ + constexpr TypeName operator<<(const TypeName& a, const TypeName& b) { \ + return TypeName(static_cast<TypeName_T>(a) << static_cast<TypeName_T>(b)); \ + }; \ + constexpr TypeName operator>>(const TypeName& a, const TypeName& b) { \ + return TypeName(static_cast<TypeName_T>(a) >> static_cast<TypeName_T>(b)); \ + }; \ + constexpr TypeName operator+=(TypeName& a, const TypeName& b) { \ + a = TypeName{a + b}; \ + return a; \ + }; \ + constexpr TypeName operator-=(TypeName& a, const TypeName& b) { \ + a = TypeName{a - b}; \ + return a; \ + }; \ + constexpr TypeName operator&=(TypeName& a, const TypeName& b) { \ + a = TypeName{a & b}; \ + return a; \ + }; \ + constexpr TypeName operator|=(TypeName& a, const TypeName& b) { \ + a = TypeName{a | b}; \ + return a; \ + }; \ + constexpr TypeName operator^=(TypeName& a, const TypeName& b) { \ + a = TypeName{a ^ b}; \ + return a; \ + }; \ + constexpr TypeName operator~(const TypeName& a) { \ + return static_cast<TypeName>(~static_cast<TypeName_T>(a)); \ + }; +#define TypeSafeInt_constexpr(TypeName, Type, Max) \ + TypeSafeInt2_H_constexpr(TypeName, Type, Max, PK_CONCAT(TypeName, _T), PK_CONCAT(TypeName, _MAX), PK_CONCAT(TypeName, _T_MAX)) + +#endif /* PK_MACROS_H */ +// vim: ts=2:sw=2:expandtab diff --git a/pkmem-types.h b/pkmem-types.h new file mode 100644 index 0000000..27f6f50 --- /dev/null +++ b/pkmem-types.h @@ -0,0 +1,65 @@ +#ifndef PK_MEM_TYPES_H +#define PK_MEM_TYPES_H + +#include <stdint.h> + +typedef uint32_t pk_handle_bucket_index_T; +typedef uint32_t pk_handle_item_index_T; + +enum PK_HANDLE_VALIDATION : uint8_t { + PK_HANDLE_VALIDATION_VALID = 0, + PK_HANDLE_VALIDATION_BUCKET_INDEX_TOO_HIGH = 1, + PK_HANDLE_VALIDATION_ITEM_INDEX_TOO_HIGH = 2, + PK_HANDLE_VALIDATION_VALUE_MAX = 3, +}; + +struct pk_handle { + pk_handle_bucket_index_T bucketIndex; + pk_handle_item_index_T itemIndex; +}; + +const struct pk_handle pk_handle_MAX = (struct pk_handle){ .bucketIndex = 0xFFFFFFFF, .itemIndex = 0xFFFFFFFF }; + +static inline enum PK_HANDLE_VALIDATION +pk_handle_validate(const struct pk_handle handle, const struct pk_handle bucketHandle, const uint64_t maxItems) +{ + if (handle.bucketIndex == pk_handle_MAX.bucketIndex && handle.itemIndex == pk_handle_MAX.itemIndex) + return PK_HANDLE_VALIDATION_VALUE_MAX; + if (handle.bucketIndex > bucketHandle.bucketIndex) + return PK_HANDLE_VALIDATION_BUCKET_INDEX_TOO_HIGH; + if (handle.itemIndex > maxItems) + return PK_HANDLE_VALIDATION_ITEM_INDEX_TOO_HIGH; + if (handle.bucketIndex == bucketHandle.bucketIndex && handle.itemIndex > bucketHandle.itemIndex) + return PK_HANDLE_VALIDATION_ITEM_INDEX_TOO_HIGH; + return PK_HANDLE_VALIDATION_VALID; +} + +#if defined(__cplusplus) + +constexpr struct pk_handle pk_handle_MAX_constexpr = (struct pk_handle){ .bucketIndex = 0xFFFFFFFF, .itemIndex = 0xFFFFFFFF }; + +inline constexpr bool +operator==(const pk_handle& lhs, const pk_handle& rhs) +{ + return lhs.bucketIndex == rhs.bucketIndex && lhs.itemIndex == rhs.itemIndex; +} + +template<const pk_handle handle, const pk_handle bucketHandle, const uint64_t maxItems> +inline constexpr enum PK_HANDLE_VALIDATION +pk_handle_validate_constexpr() +{ + if constexpr (handle == pk_handle_MAX_constexpr) + return PK_HANDLE_VALIDATION_VALUE_MAX; + if constexpr (handle.bucketIndex > bucketHandle.bucketIndex) + return PK_HANDLE_VALIDATION_BUCKET_INDEX_TOO_HIGH; + if constexpr (handle.itemIndex > maxItems) + return PK_HANDLE_VALIDATION_ITEM_INDEX_TOO_HIGH; + if constexpr (handle.bucketIndex == bucketHandle.bucketIndex && handle.itemIndex > bucketHandle.itemIndex) + return PK_HANDLE_VALIDATION_ITEM_INDEX_TOO_HIGH; + return PK_HANDLE_VALIDATION_VALID; +} +#endif /* __cplusplus */ + +struct pk_membucket; + +#endif /* PK_MEM_TYPES_H */ @@ -0,0 +1,556 @@ +#ifndef PK_MEM_H +#define PK_MEM_H + +#include "pkmem-types.h" +#include "pkmacros.h" + +#include <string.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +#ifndef PK_DEFAULT_BUCKET_SIZE +# define PK_DEFAULT_BUCKET_SIZE (1ULL * 1024ULL * 1024ULL * 256ULL) +#endif +#ifndef PK_MINIMUM_ALIGNMENT +# define PK_MINIMUM_ALIGNMENT 1 +#endif +#ifndef PK_MAXIMUM_ALIGNMENT +# define PK_MAXIMUM_ALIGNMENT 64 +#endif + +struct pk_membucket* pk_bucket_create(const char* description, int64_t sz, bool transient); +void pk_bucket_destroy(struct pk_membucket* bkt); +void pk_bucket_reset(struct pk_membucket* bkt); + +void pk_memory_debug_print(); +void pk_memory_flush(); +void pk_memory_teardown_all(); +bool pk_memory_is_in_bucket(const void* ptr, const struct pk_membucket* bkt); + +void* pk_new_base(size_t sz, size_t alignment); +void* pk_new_bkt(size_t sz, size_t alignment, struct pk_membucket* bkt); +void pk_delete_base(const void* ptr, size_t sz); +void pk_delete_bkt(const void* ptr, size_t sz, struct pk_membucket* bkt); + +static inline void stupid_header_warnings() { (void)stdout; } + +#if defined(__cplusplus) + +#include <type_traits> + +static inline void stupid_header_warnings_cpp() { (void)std::is_const<void>::value; } + +template <typename T> +inline T* +pk_new(pk_membucket* bucket = nullptr) +{ + void* ptr = nullptr; + if (bucket) { + ptr = pk_new_bkt(sizeof(T), alignof(T), bucket); + } else { + ptr = pk_new_base(sizeof(T), alignof(T)); + } + if IS_CONSTRUCTIBLE(T) { + return new (ptr) T{}; + } + return reinterpret_cast<T*>(ptr); +} + +template <typename T> +inline T* +pk_new(long count, pk_membucket* bucket = nullptr) +{ + char* ptr = nullptr; + if (bucket) { + ptr = static_cast<char*>(pk_new_bkt(sizeof(T) * count, alignof(T), bucket)); + } else { + ptr = static_cast<char*>(pk_new_base(sizeof(T) * count, alignof(T))); + } + if IS_CONSTRUCTIBLE(T) { + for (long i = 0; i < count; ++i) { + new (ptr + (i * sizeof(T))) T{}; + } + } + return reinterpret_cast<T*>(ptr); +} + +template <typename T> +inline void +pk_delete(const T* ptr, pk_membucket* bucket = nullptr) +{ + if IS_DESTRUCTIBLE(T) { + reinterpret_cast<const T*>(ptr)->~T(); + } + if (bucket) { + return pk_delete_bkt(static_cast<const void*>(ptr), sizeof(T), bucket); + } else { + return pk_delete_base(static_cast<const void*>(ptr), sizeof(T)); + } +} + +template <typename T> +inline void +pk_delete(const T* ptr, long count, pk_membucket* bucket = nullptr) +{ + if IS_DESTRUCTIBLE(T) { + for (long i = 0; i < count; ++i) { + reinterpret_cast<const T*>(reinterpret_cast<const char*>(ptr) + (i * sizeof(T)))->~T(); + } + } + if (bucket) { + return pk_delete_bkt(static_cast<const void*>(ptr), sizeof(T) * count, bucket); + } else { + return pk_delete_base(static_cast<const void*>(ptr), sizeof(T) * count); + } +} + +#endif /* __cplusplus */ + +#endif /* PK_MEM */ + +#ifdef PK_IMPLEMENTATION + +#include <threads.h> +#include <assert.h> + +#if defined(PK_MEMORY_DEBUGGER) +/* + * Note that certain aspects of this expect that you only have one non-transient bucket. + * If you need to track multiple non-transient buckets, these sections will need a refactor. + */ +#endif + +struct pk_memblock { + char* data; + size_t size; +}; + +struct pk_membucket { + // the total size of the bucket, `blocks+ptr` + int64_t size; + // the current head of the bucket: byte offset from `ptr`. + // All currently alloc'd data is before this offset + int64_t head; + // amount of lost bytes in this membucket, hopefully zero + int64_t lostBytes; + // the number of active allocations from this bucket + int64_t allocs; + // the index of the last empty block. + // Should always point to `pk_memblock{ .data = ptr+head, .size=size-head }` + int64_t lastEmptyBlockIndex; + // number of pk_memblocks in the `*blocks` array + int64_t maxBlockCount; + // ptr to an array of pk_memblock to track ALL free space between ptr and ptr+sz + struct pk_memblock* blocks; + // starting point for alloc'd data + union { + char* ptr; + void* raw; + }; + const char* description; + mtx_t mtx; + bool transient; +}; + +static struct pk_membucket pk_buckets[8]; +static int64_t pk_bucket_head = 0; + +#ifdef PK_MEMORY_DEBUGGER +static struct pk_memblock debug_all_allocs[1024 * 1024]; +static int64_t debug_alloc_head = 0; +static bool has_init_debug = false; +#endif + +bool +pk_memory_is_in_bucket(const void* ptr, const struct pk_membucket* bkt) +{ + if (ptr >= bkt->raw && (const char*)ptr < bkt->ptr + bkt->size) return true; + return false; +} + +void +pk_memory_debug_print() +{ + PK_LOGV_INF("Memory Manager printout:\nBucket count: %li\n", pk_bucket_head); + for (long i = 0; i < pk_bucket_head; ++i) { + PK_LOGV_INF("- bucket #%li\n", i); + PK_LOGV_INF("\tdescription: %s\n", pk_buckets[i].description); + PK_LOGV_INF("\tsize: %li\n", pk_buckets[i].size); + PK_LOGV_INF("\thead: %li\n", pk_buckets[i].head); + PK_LOGV_INF("\tlostBytes: %li\n", pk_buckets[i].lostBytes); + PK_LOGV_INF("\tallocs: %li\n", pk_buckets[i].allocs); + PK_LOGV_INF("\tlastEmptyBlockIndex: %li\n", pk_buckets[i].lastEmptyBlockIndex); + PK_LOGV_INF("\tmaxBlockCount: %li\n", pk_buckets[i].maxBlockCount); + PK_LOGV_INF("\tblocks: %p\n", pk_buckets[i].blocks); + PK_LOGV_INF("\tptr: %p\n", pk_buckets[i].ptr); + PK_LOGV_INF("\ttransient: %i\n", pk_buckets[i].transient); +#ifdef PK_MEMORY_DEBUGGER + uint64_t count = 0; + for (int64_t i = 0; i < debug_alloc_head; ++i) { + if (debug_all_allocs[i].size > 0) { + count += 1; + } + } + PK_LOGV_INF("\tdebug alloc count: %lu\n", count); + PK_LOGV_INF("\tdebug alloc last: %lu\n", debug_alloc_head); +#endif + } +} + +void +pk_memory_flush() +{ + for (long i = pk_bucket_head - 2; i > -1; --i) { + if (pk_buckets[i].head != 0) break; + if (pk_buckets[i+1].head != 0) break; + if (pk_buckets[i].transient == true) break; + if (pk_buckets[i+1].transient == true) break; + pk_bucket_head--; + pk_bucket_destroy(&pk_buckets[i + 1]); + } +} + +void +pk_memory_teardown_all() +{ + for (int64_t i = pk_bucket_head - 1; i > 0; --i) { + if (pk_buckets[i].ptr == nullptr) continue; + pk_bucket_destroy(&pk_buckets[i]); + } + pk_bucket_head = 0; +} + +static int64_t +pk_bucket_create_inner(int64_t sz, bool transient, const char* description) +{ +#ifdef PK_MEMORY_DEBUGGER + if (has_init_debug == false) { + has_init_debug = true; + memset(debug_all_allocs, 0, sizeof(struct pk_memblock) * 1024 * 1024); + } +#endif + int64_t blockCount = sz * 0.01; + struct pk_membucket* bkt = &pk_buckets[pk_bucket_head]; + bkt->size = sz; + bkt->head = 0; + bkt->lostBytes = 0; + bkt->allocs = 0; + bkt->lastEmptyBlockIndex = 0; + bkt->maxBlockCount = blockCount < 10 ? 10 : blockCount; + bkt->blocks = (struct pk_memblock*)malloc(sz); + assert(bkt->blocks != nullptr && "failed to allocate memory"); +#if 1 + memset(bkt->blocks, 0, sz); +#endif + bkt->ptr = ((char*)(bkt->blocks)) + (sizeof(struct pk_memblock) * bkt->maxBlockCount); + size_t misalignment = (uint64_t)(bkt->ptr) % PK_MAXIMUM_ALIGNMENT; + if (misalignment != 0) { + size_t moreBlocks = misalignment / sizeof(struct pk_memblock); + bkt->maxBlockCount += moreBlocks; + bkt->ptr += (PK_MAXIMUM_ALIGNMENT - misalignment); + } + bkt->description = description; + bkt->transient = transient; + struct pk_memblock* memBlock = (struct pk_memblock*)(bkt->blocks); + memBlock->data = bkt->ptr; + memBlock->size = sz - (sizeof(struct pk_memblock) * bkt->maxBlockCount); + return pk_bucket_head++; +} + +struct pk_membucket* +pk_bucket_create(const char* description, int64_t sz, bool transient) +{ + return &pk_buckets[pk_bucket_create_inner(sz, transient, description)]; +} + +void +pk_bucket_destroy(struct pk_membucket* bkt) +{ + for (int64_t i = 0; i < pk_bucket_head; ++i) { + if (&pk_buckets[i] == bkt) { + if (pk_bucket_head == i) + pk_bucket_head--; + break; + } + } + free(bkt->blocks); + bkt->size = 0; + bkt->head = 0; + bkt->lostBytes = 0; + bkt->allocs = 0; + bkt->lastEmptyBlockIndex = -1; + bkt->maxBlockCount = 0; + bkt->blocks = CAFE_BABE(struct pk_memblock); + bkt->ptr = CAFE_BABE(char); + bkt->transient = false; +} + +void +pk_bucket_reset(struct pk_membucket* bkt) +{ + if (bkt->transient != true) { + PK_LOG_ERR("WARNING: pk_bucket_reset called on non-transient pk_membucket\n"); + } + bkt->head = 0; + bkt->lostBytes = 0; + bkt->allocs = 0; + bkt->lastEmptyBlockIndex = 0; + bkt->blocks->data = bkt->ptr; + bkt->blocks->size = bkt->size - (sizeof(struct pk_memblock) * bkt->maxBlockCount); +} + +void +pk_bucket_insert_block(struct pk_membucket* bkt, const struct pk_memblock* block) +{ + int64_t index = bkt->lastEmptyBlockIndex; + while (index >= 0) { + struct pk_memblock* b = &bkt->blocks[index]; + struct pk_memblock* nb = &bkt->blocks[index + 1]; + if (b->data < block->data) { + break; + } + nb->data = b->data; + nb->size = b->size; + index -= 1; + } + struct pk_memblock *b = &bkt->blocks[index + 1]; + b->data = block->data; + b->size = block->size; + bkt->lastEmptyBlockIndex += 1; +} + +void +pk_bucket_collapse_empty_blocks(struct pk_membucket* bkt) { + for (int64_t i = bkt->lastEmptyBlockIndex; i > -1; --i) { + struct pk_memblock* block = &bkt->blocks[i]; + if (block->size == 0 && i == bkt->lastEmptyBlockIndex) { + block->data = nullptr; + bkt->lastEmptyBlockIndex -= 1; + continue; + } + if (block->size > 0) { + continue; + } + for (int64_t k = i; k < bkt->lastEmptyBlockIndex; ++k) { + bkt->blocks[k].data = bkt->blocks[k + 1].data; + bkt->blocks[k].size = bkt->blocks[k + 1].size; + } + bkt->lastEmptyBlockIndex -= 1; + } +} + +void* +pk_new_bkt(size_t sz, size_t alignment, struct pk_membucket* bkt) +{ +#ifdef PK_MEMORY_FORCE_MALLOC + return malloc(sz); +#endif + if (sz == 0) return nullptr; + size_t calculatedAlignment = alignment < PK_MINIMUM_ALIGNMENT ? PK_MINIMUM_ALIGNMENT : alignment; + size_t misalignment = 0; + struct pk_memblock* prevBlock = nullptr; + struct pk_memblock* block = nullptr; + struct pk_memblock* nextBlock = nullptr; + void* data = nullptr; + mtx_lock(&bkt->mtx); + for (int64_t i = 0; i <= bkt->lastEmptyBlockIndex; ++i) { + struct pk_memblock* blk = &bkt->blocks[i]; + misalignment = (size_t)(blk->data) % calculatedAlignment; + misalignment = (calculatedAlignment - misalignment) % calculatedAlignment; + if (blk->size >= sz + misalignment) { + block = blk; + if (i < bkt->lastEmptyBlockIndex && bkt->blocks[i + 1].data == block->data + block->size) { + nextBlock = &bkt->blocks[i + 1]; + } + if (i > 0 && i != bkt->lastEmptyBlockIndex && (bkt->blocks[i-1].data + bkt->blocks[i-1].size) == block->data) { + prevBlock = &bkt->blocks[i - 1]; + } + break; + } + } + assert(block != nullptr && "memory corruption: failed to find bucket with enough space"); + data = block->data + misalignment; +#ifdef PK_MEMORY_DEBUGGER + bool handled = bkt->transient; + if (handled == false) { + for (int64_t i = 0; i < debug_alloc_head; ++i) { + struct pk_memblock* mb = &debug_all_allocs[i]; + assert((mb->size == 0 || (void*)(mb->data) != data) && "mem address alloc'd twice!"); + if (mb->size == 0) { + mb->data = (char*)(data); + mb->size = sz; + handled = true; + break; + } + } + } + if (handled == false) { + debug_all_allocs[debug_alloc_head++] = (struct pk_memblock){ + .data = (char*)(data), + .size = sz, + }; + } +#endif + int64_t afterSize = block->size - (misalignment + sz); + if (block->data == bkt->ptr + bkt->head) { + bkt->head += (sz + misalignment); + } + if (afterSize > 0 && nextBlock == nullptr) { + struct pk_memblock newBlock; + memset(&newBlock, 0, sizeof(struct pk_memblock)); + newBlock.data = block->data + misalignment + sz; + newBlock.size = afterSize; + pk_bucket_insert_block(bkt, &newBlock); + } + if (prevBlock == nullptr && nextBlock == nullptr) { + block->size = misalignment; + } else if (nextBlock != nullptr) { + block->size = misalignment; + nextBlock->data -= afterSize; + nextBlock->size += afterSize; + } else if (prevBlock != nullptr) { + prevBlock->size += misalignment; + block->data += misalignment + sz; + block->size = 0; // if you make it here, afterSize has already been handled + } + bkt->allocs++; + assert(data >= bkt->raw && "allocated data is before bucket data"); + assert((char*)data <= bkt->ptr + bkt->size && "allocated data is after bucket data"); + pk_bucket_collapse_empty_blocks(bkt); +#ifdef PK_MEMORY_DEBUGGER + if (!bkt->transient) { + int64_t debug_tracked_alloc_size = 0; + int64_t debug_bucket_alloc_size = bkt->size - (sizeof(struct pk_memblock) * bkt->maxBlockCount); + for (int64_t i = 0; i < debug_alloc_head; ++i) { + debug_tracked_alloc_size += debug_all_allocs[i].size; + } + for (int64_t i = 0; i <= bkt->lastEmptyBlockIndex; ++i) { + debug_bucket_alloc_size -= bkt->blocks[i].size; + } + assert(debug_tracked_alloc_size == debug_bucket_alloc_size && "allocation size mismatch!"); + } +#endif + mtx_unlock(&bkt->mtx); + return data; +} + +void* +pk_new_base(size_t sz, size_t alignment) +{ + struct pk_membucket* bkt = nullptr; + for (long i = 0; i < pk_bucket_head; ++i) { + if (pk_buckets[i].transient == false && pk_buckets[i].size - pk_buckets[i].head > sz + PK_MAXIMUM_ALIGNMENT) { + bkt = &pk_buckets[i]; + break; + } + } + if (bkt == nullptr) { + bkt = &pk_buckets[pk_bucket_create_inner(PK_DEFAULT_BUCKET_SIZE, false, "pk_bucket internally created")]; + } + return pk_new_bkt(sz, alignment, bkt); +} + +void +pk_delete_bkt(const void* ptr, size_t sz, struct pk_membucket* bkt) +{ +#ifdef PK_MEMORY_FORCE_MALLOC + return std::free(const_cast<void*>(ptr)); +#endif + assert(ptr >= bkt->raw && (char*)ptr < bkt->ptr + bkt->size && "pointer not in memory bucket range"); + assert(sz > 0 && "attempted to free pointer of size 0"); +#ifdef PK_MEMORY_DEBUGGER + bool found = bkt->transient; + if (found == false) { + for (int64_t i = debug_alloc_head - 1; i > -1; --i) { + struct pk_memblock* mb = &debug_all_allocs[i]; + if (mb->size == 0) continue; + if ((void*)(mb->data) == ptr) { + assert(mb->size == sz && "[pk_MEMORY_HPP] incorrect free size"); + mb->size = 0; + found = true; + if (i == (debug_alloc_head - 1)) { + debug_alloc_head--; + } + break; + } + } + } + assert(found && "[pk_MEMORY_HPP] double free or invalid ptr"); +#endif + bkt->allocs--; + if (bkt->allocs == 0) { + bkt->head = 0; + bkt->lastEmptyBlockIndex = 0; + bkt->blocks[0].data = bkt->ptr; + bkt->blocks[0].size = bkt->size - (sizeof(struct pk_memblock) * bkt->maxBlockCount); + return; + } + char* afterPtr = ((char*)(ptr))+sz; + struct pk_memblock* beforeBlk = nullptr; + struct pk_memblock* afterBlk = nullptr; + for (int64_t i = bkt->lastEmptyBlockIndex; i > 0; --i) { + if (bkt->blocks[i-1].data + bkt->blocks[i-1].size == ptr) { + beforeBlk = &bkt->blocks[i-1]; + } + if (bkt->blocks[i].data == afterPtr) { + afterBlk = &bkt->blocks[i]; + break; + } + if (bkt->blocks[i-1].data < (char*)ptr) { + break; + } + } + if (ptr == bkt->ptr && afterBlk == nullptr && bkt->blocks[0].data == afterPtr) { + afterBlk = &bkt->blocks[0]; + } + if (afterBlk != nullptr && afterBlk->data == bkt->ptr + bkt->head) { + bkt->head -= sz; + if (beforeBlk != nullptr) { + bkt->head -= beforeBlk->size; + } + } + if (beforeBlk == nullptr && afterBlk == nullptr) { + struct pk_memblock newBlock; + memset(&newBlock, 0, sizeof(struct pk_memblock)); + newBlock.data = (char*)ptr; + newBlock.size = sz; + pk_bucket_insert_block(bkt, &newBlock); + } else if (beforeBlk != nullptr && afterBlk != nullptr) { + beforeBlk->size += sz + afterBlk->size; + afterBlk->size = 0; + } else if (beforeBlk != nullptr) { + beforeBlk->size += sz; + } else if (afterBlk != nullptr) { + afterBlk->data -= sz; + afterBlk->size += sz; + } + pk_bucket_collapse_empty_blocks(bkt); +#ifdef PK_MEMORY_DEBUGGER + if (!bkt->transient) { + int64_t debug_tracked_alloc_size = 0; + int64_t debug_bucket_alloc_size = bkt->size - (sizeof(struct pk_memblock) * bkt->maxBlockCount); + for (int64_t i = 0; i < debug_alloc_head; ++i) { + debug_tracked_alloc_size += debug_all_allocs[i].size; + } + for (int64_t i = 0; i <= bkt->lastEmptyBlockIndex; ++i) { + debug_bucket_alloc_size -= bkt->blocks[i].size; + } + assert(debug_tracked_alloc_size == debug_bucket_alloc_size && "allocation size mismatch!"); + } +#endif +} + +void +pk_delete_base(const void* ptr, size_t sz) +{ + struct pk_membucket* bkt = nullptr; + for (long i = 0; i < pk_bucket_head; ++i) { + bkt = &pk_buckets[i]; + if (ptr >= bkt->raw && (char*)ptr < bkt->ptr + bkt->size) break; + } + assert(bkt != nullptr && "failed to determine correct memory bucket"); + pk_delete_bkt(ptr, sz, bkt); +} + +#endif /* PK_IMPLEMENTATION */ diff --git a/test/pkmacros.c b/test/pkmacros.c new file mode 100644 index 0000000..2a1f626 --- /dev/null +++ b/test/pkmacros.c @@ -0,0 +1,55 @@ + +#include "../pkmacros.h" + +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +int main(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + (void)stdout; + + // MISC + { + PK_LOGV_INF("PK_HAS_FLAG 000: %b\n", PK_HAS_FLAG(0xFF, 5)); + PK_LOGV_INF("PK_HAS_FLAG 001: %b\n", PK_HAS_FLAG(0x0F, 5)); + PK_LOGV_INF("PK_CLAMP 000: %i\n", PK_CLAMP(0, -10, 10)); + PK_LOGV_INF("PK_CLAMP 001: %i\n", PK_CLAMP(-20, -10, 10)); + PK_LOGV_INF("PK_CLAMP 002: %i\n", PK_CLAMP(20, -10, 10)); + PK_LOGV_INF("PK_MIN 000: %i\n", PK_MIN(0, 10)); + PK_LOGV_INF("PK_MIN 001: %i\n", PK_MIN(0, -10)); + PK_LOGV_INF("PK_MAX 000: %i\n", PK_MAX(0, -10)); + PK_LOGV_INF("PK_MAX 001: %i\n", PK_MAX(0, 10)); + PK_LOGV_INF("CAFEBABE 000: %p\n", CAFE_BABE(void)); + NULL_CHAR_ARR(c, 16); + PK_LOGV_INF("NULL_CHAR_ARR 000: '%s' '%lu'\n", c, strlen(c)); + } + + // PK_TO_BIN printing + { + uint8_t u8 = 0x55; // 01010101 + uint16_t u16 = 0x5555; + uint32_t u32 = 0x55555555; + uint64_t u64 = 0x5555555555555555; + PK_LOGV_INF(PK_TO_BIN_PAT_8 "\n", PK_TO_BIN_8(u8)); + PK_LOGV_INF(PK_TO_BIN_PAT_16"\n", PK_TO_BIN_16(u16)); + PK_LOGV_INF(PK_TO_BIN_PAT_32"\n", PK_TO_BIN_32(u32)); + PK_LOGV_INF(PK_TO_BIN_PAT_64"\n", PK_TO_BIN_64(u64)); + u8 = 0xAA; // 10101010 + u16 = 0xAAAA; + u32 = 0xAAAAAAAA; + u64 = 0xAAAAAAAAAAAAAAAA; + PK_LOGV_INF(PK_TO_BIN_PAT_8 "\n", PK_TO_BIN_8(u8)); + PK_LOGV_INF(PK_TO_BIN_PAT_16"\n", PK_TO_BIN_16(u16)); + PK_LOGV_INF(PK_TO_BIN_PAT_32"\n", PK_TO_BIN_32(u32)); + PK_LOGV_INF(PK_TO_BIN_PAT_64"\n", PK_TO_BIN_64(u64)); + u64 = 0xFFFFFFFF00000000; + PK_LOGV_INF(PK_TO_BIN_PAT_64"\n", PK_TO_BIN_64(u64)); + u64 = 0x00000000FFFFFFFF; + PK_LOGV_INF(PK_TO_BIN_PAT_64"\n", PK_TO_BIN_64(u64)); + } + + return 0; +} diff --git a/test/pkmacros.cpp b/test/pkmacros.cpp new file mode 100644 index 0000000..5e5377f --- /dev/null +++ b/test/pkmacros.cpp @@ -0,0 +1,191 @@ + +#include "../pkmacros.h" + +#include <cstdint> +#include <cstdio> +#include <cstring> +#include <type_traits> + +TypeSafeInt_H(MyTSI_8, uint8_t, 0xFF); +TypeSafeInt_H(MyTSI_16, uint16_t, 0xFFFF); +TypeSafeInt_H(MyTSI_32, uint32_t, 0xFFFFFFFF); +TypeSafeInt_H(MyTSI_64, uint64_t, 0xFFFFFFFFFFFFFFFF); + +TypeSafeInt_B(MyTSI_8); +TypeSafeInt_B(MyTSI_16); +TypeSafeInt_B(MyTSI_32); +TypeSafeInt_B(MyTSI_64); + +TypeSafeInt_constexpr(MyConstexprTSI_8, uint8_t, 0xFF); +TypeSafeInt_constexpr(MyConstexprTSI_16, uint16_t, 0xFFFF); +TypeSafeInt_constexpr(MyConstexprTSI_32, uint32_t, 0xFFFFFFFF); +TypeSafeInt_constexpr(MyConstexprTSI_64, uint64_t, 0xFFFFFFFFFFFFFFFF); + +template<typename T, typename T_T> +bool +tsi_test_operators() +{ + T mtsi0F {0x0F}; + T mtsiF0 {0xF0}; + T r; + /* + r = mtsi0F + T_T{static_cast<T_T>(mtsiF0)}; + if (r == T{0}) return false; + r = mtsi0F - T_T{static_cast<T_T>(mtsiF0)}; + if (r == T{0}) return false; + */ + r = mtsi0F + mtsiF0; + if (r == T{0}) return false; + r = mtsi0F - mtsiF0; + if (r == T{0}) return false; + r = mtsi0F & mtsiF0; + if (r != T{0}) return false; + r = mtsi0F | mtsiF0; + if (r == T{0}) return false; + r = mtsi0F ^ mtsiF0; + if (r == T{0}) return false; + r = mtsi0F++; + if (r == T{0}) return false; + r = mtsi0F--; + if (r == T{0}) return false; + r = ++mtsi0F; + if (r == T{0}) return false; + r = --mtsi0F; + if (r == T{0}) return false; + r = mtsi0F << T{1}; + if (r == T{0}) return false; + r = mtsi0F >> T{1}; + if (r == T{0}) return false; + r = mtsi0F += mtsiF0; + if (r == T{0}) return false; + r = mtsi0F -= mtsiF0; + if (r == T{0}) return false; + r = mtsi0F &= mtsiF0; + if (r != T{0}) return false; + r = mtsi0F |= mtsiF0; + if (r == T{0}) return false; + r = mtsi0F ^= mtsiF0; + if (r != T{0}) return false; + r = mtsi0F = ~mtsiF0; + if (r == T{0}) return false; + return true; +} + +template<typename T, typename T_T> +constexpr bool +tsi_test_operators_constexpr() +{ + constexpr T mtsi0F {0x0F}; + constexpr T mtsiF0 {0xF0}; + constexpr T mtsi00 {0x00}; + /* + constexpr T r01 = mtsi0F + T_T{static_cast<T_T>(mtsiF0)}; + if constexpr (r01 == mtsi00) return false; + constexpr T r02 = mtsi0F - T_T{static_cast<T_T>(mtsiF0)}; + if constexpr (r02 == mtsi00) return false; + */ + constexpr T r03 = mtsi0F + mtsiF0; + if constexpr (r03 == mtsi00) return false; + constexpr T r04 = mtsi0F - mtsiF0; + if constexpr (r04 == mtsi00) return false; + constexpr T r05 = mtsi0F & mtsiF0; + if constexpr (r05 != mtsi00) return false; + constexpr T r06 = mtsi0F | mtsiF0; + if constexpr (r06 == mtsi00) return false; + constexpr T r07 = mtsi0F ^ mtsiF0; + if constexpr (r07 == mtsi00) return false; + /* + constexpr T r08 = mtsi0F++; + if constexpr (r08 == mtsi00) return false; + constexpr T r09 = mtsi0F--; + if constexpr (r09 == mtsi00) return false; + constexpr T r10 = ++mtsi0F; + if constexpr (r10 == mtsi00) return false; + constexpr T r11 = --mtsi0F; + if constexpr (r11 == mtsi00) return false; + */ + constexpr T r12 = mtsi0F << T{1}; + if constexpr (r12 == mtsi00) return false; + constexpr T r13 = mtsi0F >> T{1}; + if constexpr (r13 == mtsi00) return false; + /* + constexpr T r14 = mtsi0F += mtsiF0; + if constexpr (r14 == mtsi00) return false; + constexpr T r15 = mtsi0F -= mtsiF0; + if constexpr (r15 == mtsi00) return false; + constexpr T r16 = mtsi0F &= mtsiF0; + if constexpr (r16 != mtsi00) return false; + constexpr T r17 = mtsi0F |= mtsiF0; + if constexpr (r17 == mtsi00) return false; + constexpr T r18 = mtsi0F ^= mtsiF0; + if constexpr (r18 != mtsi00) return false; + constexpr T r19 = mtsi0F = ~mtsiF0; + if constexpr (r19 == mtsi00) return false; + */ + return true; +} + +class sdc { +}; + +int main(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + (void)std::is_const<void>::value; + + // MISC + { + PK_LOGV_INF("PK_HAS_FLAG 000: %b\n", PK_HAS_FLAG(0xFF, 5)); + PK_LOGV_INF("PK_HAS_FLAG 001: %b\n", PK_HAS_FLAG(0x0F, 5)); + PK_LOGV_INF("PK_CLAMP 000: %i\n", PK_CLAMP(0, -10, 10)); + PK_LOGV_INF("PK_CLAMP 001: %i\n", PK_CLAMP(-20, -10, 10)); + PK_LOGV_INF("PK_CLAMP 002: %i\n", PK_CLAMP(20, -10, 10)); + PK_LOGV_INF("PK_MIN 000: %i\n", PK_MIN(0, 10)); + PK_LOGV_INF("PK_MIN 001: %i\n", PK_MIN(0, -10)); + PK_LOGV_INF("PK_MAX 000: %i\n", PK_MAX(0, -10)); + PK_LOGV_INF("PK_MAX 001: %i\n", PK_MAX(0, 10)); + PK_LOGV_INF("CAFEBABE 000: %p\n", CAFE_BABE(void)); + NULL_CHAR_ARR(c, 16); + PK_LOGV_INF("NULL_CHAR_ARR 000: '%s' '%lu'\n", c, strlen(c)); + } + + // IS_CONSTRUCTIBLE + { + bool b = false; + if IS_CONSTRUCTIBLE(sdc) b = true; + fprintf(stdout, "class sdc IS_CONSTRUCTIBLE: %b\n", b); + if IS_DESTRUCTIBLE(sdc) b = false; + fprintf(stdout, "class sdc IS_DESTRUCTIBLE: %b\n", b); + } + + // TypeSafeInt + { + PK_LOGV_INF(PK_TO_BIN_PAT_8 "\n", PK_TO_BIN_8 (static_cast<MyTSI_8_T> (MyTSI_8_MAX))); + PK_LOGV_INF(PK_TO_BIN_PAT_16"\n", PK_TO_BIN_16(static_cast<MyTSI_16_T>(MyTSI_16_MAX))); + PK_LOGV_INF(PK_TO_BIN_PAT_32"\n", PK_TO_BIN_32(static_cast<MyTSI_32_T>(MyTSI_32_MAX))); + PK_LOGV_INF(PK_TO_BIN_PAT_64"\n", PK_TO_BIN_64(static_cast<MyTSI_64_T>(MyTSI_64_MAX))); + PK_LOGV_INF(PK_TO_BIN_PAT_8 "\n", PK_TO_BIN_8 (static_cast<MyConstexprTSI_8_T> (MyConstexprTSI_8_MAX))); + PK_LOGV_INF(PK_TO_BIN_PAT_16"\n", PK_TO_BIN_16(static_cast<MyConstexprTSI_16_T>(MyConstexprTSI_16_MAX))); + PK_LOGV_INF(PK_TO_BIN_PAT_32"\n", PK_TO_BIN_32(static_cast<MyConstexprTSI_32_T>(MyConstexprTSI_32_MAX))); + PK_LOGV_INF(PK_TO_BIN_PAT_64"\n", PK_TO_BIN_64(static_cast<MyConstexprTSI_64_T>(MyConstexprTSI_64_MAX))); + PK_LOGV_INF("tsi_test_operators 08: %b\n", tsi_test_operators<MyTSI_8, MyTSI_8_T>()); + PK_LOGV_INF("tsi_test_operators 16: %b\n", tsi_test_operators<MyTSI_16, MyTSI_16_T>()); + PK_LOGV_INF("tsi_test_operators 32: %b\n", tsi_test_operators<MyTSI_32, MyTSI_32_T>()); + PK_LOGV_INF("tsi_test_operators 64: %b\n", tsi_test_operators<MyTSI_64, MyTSI_64_T>()); + PK_LOGV_INF("tsi_test_operators c08: %b\n", tsi_test_operators<MyConstexprTSI_8, MyConstexprTSI_8_T>()); + PK_LOGV_INF("tsi_test_operators c16: %b\n", tsi_test_operators<MyConstexprTSI_16, MyConstexprTSI_16_T>()); + PK_LOGV_INF("tsi_test_operators c32: %b\n", tsi_test_operators<MyConstexprTSI_32, MyConstexprTSI_32_T>()); + PK_LOGV_INF("tsi_test_operators c64: %b\n", tsi_test_operators<MyConstexprTSI_64, MyConstexprTSI_64_T>()); + constexpr bool b1 = tsi_test_operators_constexpr<MyConstexprTSI_8, MyConstexprTSI_8_T>(); + constexpr bool b2 = tsi_test_operators_constexpr<MyConstexprTSI_16, MyConstexprTSI_16_T>(); + constexpr bool b3 = tsi_test_operators_constexpr<MyConstexprTSI_32, MyConstexprTSI_32_T>(); + constexpr bool b4 = tsi_test_operators_constexpr<MyConstexprTSI_64, MyConstexprTSI_64_T>(); + PK_LOGV_INF("TypeSafeInt_constexpr_08: %b\n", b1); + PK_LOGV_INF("TypeSafeInt_constexpr_16: %b\n", b2); + PK_LOGV_INF("TypeSafeInt_constexpr_32: %b\n", b3); + PK_LOGV_INF("TypeSafeInt_constexpr_64: %b\n", b4); + } + + return 0; +} diff --git a/test/pkmem-types.c b/test/pkmem-types.c new file mode 100644 index 0000000..2399308 --- /dev/null +++ b/test/pkmem-types.c @@ -0,0 +1,42 @@ + +#include "../pkmem-types.h" +#include "../pkmacros.h" + +#include <stdio.h> + +int main(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + (void)stdout; + + // pk_handle_validate + { + enum PK_HANDLE_VALIDATION res; + struct pk_handle h, bh; + + bh.bucketIndex = 2; + bh.itemIndex = 2; + + h.bucketIndex = 0; + h.itemIndex = 0; + res = pk_handle_validate(h, bh, 1024); + PK_LOGV_INF("pk_handle_validate 000: %i\n", res); + + h.bucketIndex = 3; + h.itemIndex = 0; + res = pk_handle_validate(h, bh, 1024); + PK_LOGV_INF("pk_handle_validate 001: %i\n", res); + + h.bucketIndex = 2; + h.itemIndex = 3; + res = pk_handle_validate(h, bh, 1024); + PK_LOGV_INF("pk_handle_validate 002: %i\n", res); + + h = pk_handle_MAX; + res = pk_handle_validate(h, bh, 1024); + PK_LOGV_INF("pk_handle_validate 003: %i\n", res); + } + + return 0; +} diff --git a/test/pkmem-types.cpp b/test/pkmem-types.cpp new file mode 100644 index 0000000..b8e19ef --- /dev/null +++ b/test/pkmem-types.cpp @@ -0,0 +1,65 @@ + +#include "../pkmem-types.h" +#include "../pkmacros.h" + +#include <cstdio> + +int main(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + (void)stdout; + + // pk_handle operator== + { + struct pk_handle h, bh; + bool res; + + constexpr struct pk_handle ch1 { .bucketIndex = 0xAAAAAAAA, .itemIndex = 0x55555555 }; + constexpr struct pk_handle cbh1 { .bucketIndex = 0xAAAAAAAA, .itemIndex = 0x55555555 }; + constexpr bool ret1 = (ch1 == cbh1); + PK_LOGV_INF("pk_handle constexpr operator== 000: %b\n", ret1); + + constexpr struct pk_handle ch2 { .bucketIndex = 0x00000000, .itemIndex = 0x00000000 }; + constexpr struct pk_handle cbh2 { .bucketIndex = 0xFFFFFFFF, .itemIndex = 0xFFFFFFFF }; + constexpr bool ret2 = (ch2 == cbh2); + PK_LOGV_INF("pk_handle constexpr operator== 001: %b\n", ret2); + + h.bucketIndex = 0xCAFE; + h.itemIndex = 0xBABE; + bh.bucketIndex = 0xCAFE; + bh.itemIndex = 0xBABE; + res = h == bh; + PK_LOGV_INF("pk_handle operator== 000: %b\n", res); + + h.bucketIndex = 0x00000000; + h.itemIndex = 0x00000000; + bh.bucketIndex = 0xFFFFFFFF; + bh.itemIndex = 0xFFFFFFFF; + res = h == bh; + PK_LOGV_INF("pk_handle operator== 001: %b\n", res); + } + + // pk_handle_validate_constexpr + { + constexpr struct pk_handle cbh { .bucketIndex = 2, .itemIndex = 2 }; + + constexpr struct pk_handle ch1 { .bucketIndex = 0, .itemIndex = 0 }; + constexpr enum PK_HANDLE_VALIDATION ret1 = pk_handle_validate_constexpr<ch1, cbh, 1024ULL>(); + PK_LOGV_INF("pk_handle_validate_constexpr: 000: %i\n", ret1); + + constexpr struct pk_handle ch2 { .bucketIndex = 3, .itemIndex = 0 }; + constexpr enum PK_HANDLE_VALIDATION ret2 = pk_handle_validate_constexpr<ch2, cbh, 1024ULL>(); + PK_LOGV_INF("pk_handle_validate_constexpr: 000: %i\n", ret2); + + constexpr struct pk_handle ch3 { .bucketIndex = 2, .itemIndex = 3 }; + constexpr enum PK_HANDLE_VALIDATION ret3 = pk_handle_validate_constexpr<ch3, cbh, 1024ULL>(); + PK_LOGV_INF("pk_handle_validate_constexpr: 000: %i\n", ret3); + + constexpr struct pk_handle ch4 = pk_handle_MAX_constexpr; + constexpr enum PK_HANDLE_VALIDATION ret4 = pk_handle_validate_constexpr<ch4, cbh, 1024ULL>(); + PK_LOGV_INF("pk_handle_validate_constexpr: 000: %i\n", ret4); + } + + return 0; +} diff --git a/test/pkmem.c b/test/pkmem.c new file mode 100644 index 0000000..b6826a2 --- /dev/null +++ b/test/pkmem.c @@ -0,0 +1,17 @@ + +#include "../pkmem.h" + +int main(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + + // pk_new_base + { + char *some_dang_string = (char*)pk_new_base(64, alignof(char*)); + fprintf(stdout, "some_dang_string: %p\n", some_dang_string); + pk_delete_base(some_dang_string, 64); + } + + return 0; +} diff --git a/test/pkmem.cpp b/test/pkmem.cpp new file mode 100644 index 0000000..cc7cf9c --- /dev/null +++ b/test/pkmem.cpp @@ -0,0 +1,17 @@ + +#include "../pkmem.h" + +int main(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + + // pk_new<T> + { + char *some_dang_string = pk_new<char>(64); + fprintf(stdout, "some_dang_string: %p\n", some_dang_string); + pk_delete<char>(some_dang_string, 64); + } + + return 0; +} |
