// vim: tw=80 /******************************************************************************* * PK Single-Header-Library V@@PK_VERSION@@ * * Author: Jonathan Bradley * Copyright: © 2024-@@YEAR@@ Jonathan Bradley * Description: * * A collection of useful programming tools, available for C and C++ as a * single-header file. To enable, in ONE single C or C++ file, declare * PK_IMPL_ALL before including pk.h. * * Example: * * pk.h.include.c * ``` c * #define PK_IMPL_ALL * #include "pk.h" * ``` * * It is also possible to enable modules ad-hoc by defining each IMPL * individually: * * pk.h.include.c * ``` c * # define PK_IMPL_MEM_TYPES * # define PK_IMPL_MEM * # define PK_IMPL_STR * # define PK_IMPL_EV * #include "pk.h" * ``` * ******************************************************************************** * pkmacros.h: * * Provides a set of useful macros for a variety of uses. * * The macros PK_LOG* provide simple logging utilities. These can be overridden * by providing your own implementations of each and defining PK_LOG_OVERRIDE * before including pk.h Note that each of these are no-op'd if NDEBUG is * defined. * * The TypeSafeInt_H and TypeSafeInt_B macros provide a way to define * type-specific integers, implemented via enums. * ******************************************************************************** * pkmem-types.h: def PK_IMPL_MEM_TYPES before including pk.h to enable ad-hoc. * * Provides the types needed by pkmem, as well as a generic pk_handle featuring a * bucket+item indexing system. * ******************************************************************************** * pkmem.h: def PK_IMPL_MEM before including pk.h to enable ad-hoc. * * A bucketed memory manager. Allows for the creation and management of up to a * well-defined number of buckets. * * Thread safety: Bucket creation and destruction is *not* thread-safe. On the * other hand, the "pk_new" and "pk_delete" methods *are* thread-safe, but * thread-safety is implemented per-bucket via a single mutex with long-running * lock times. PRs for a more performant thread-safe strategy are welcome, * complexity and benchmark depending. * * The following definitions (shown with defaults) can be overridden: * PK_DEFAULT_BUCKET_SIZE 256MB (used when bkt is NULL on first call) * PK_MINIMUM_ALIGNMENT 1 * PK_MAXIMUM_ALIGNMENT 64 * PK_MAX_BUCKET_COUNT 8 * * For debugging purposes, define the following: * PK_MEMORY_DEBUGGER : enables a tracking system for all allocs and frees to * ensure bucket validity and consistency. * PK_MEMORY_FORCE_MALLOC : completely disables pkmem and its debugging features * in favor of directly using malloc and free. Useful for out-of-bounds * checking. * ******************************************************************************** * pkstr.h: def PK_IMPL_STR before including pk.h to enable ad-hoc. * * Provides a simple string structure, allowing the user to track the string * length and reserved buffer length. Limits max string length to uint32_t max * size, which is roughly 4GB. * * Tip: set reserved to 0 for compile-time strings as well as for strings alloc'd * in a larger buffer (such as bulk-loaded data). * ******************************************************************************** * pkev.h: def PK_IMPL_EV before including pk.h to enable ad-hoc. * * Provides a simple event callback system. While the _init and _teardown * functions are NOT thread-safe, the _register and _emit functions are. * Note: uses malloc. * * Each mgr is stored contiguously with its data. Consider the following layout: * [[mgr][ev 0][ev 1][..][ev N][ev 1 cb array][ev 2 cb array][..][ev N cb array]] * * The following definitions (shown with defaults) can be overridden: * PK_EV_INIT_MGR_COUNT 1 * PK_EV_INIT_EV_COUNT 16 * PK_EV_INIT_CB_COUNT 8 * PK_EV_GROW_RATIO 1.5 * * The number of evs and cbs (per ev) is stored as a uint8_t, so a hard-limit of * 255 is to be observed for each. The number of mgrs is stored as a uint64_t. * * Note that PK_EV_GROW_RATIO is used in two scenarios: * 1. When registering an ev on a full mgr. * 2. When registering a cb on a full ev. * The grow ratio is applied to the ev count and cb count in their respective * scenarios. This causes a new allocation for the entire mgr. The existing * mgr and its evs and cbs are copied to the new larger buffer space. * Explicitly, the number of mgrs does not grow dynamically. Use * PK_EV_INIT_MGR_COUNT to control the number of mgrs. * * Note that increasing PK_EV_INIT_MGR_COUNT isn't recommended, but you may * consider doing so if you have specific size or contiguity requirements. For * example, you could -DPK_EV_INIT_EV_COUNT=1 to reduce the memory footprint of * each event/mgr, and simply create a new mgr for each needed event. Be aware * that in this provided scenario a given mgr will still grow if a second EV is * registered. * *******************************************************************************/ #define PK_VERSION "@@PK_VERSION@@" #ifdef PK_IMPL_ALL # ifndef PK_IMPL_MEM_TYPES # define PK_IMPL_MEM_TYPES # endif # ifndef PK_IMPL_MEM # define PK_IMPL_MEM # endif # ifndef PK_IMPL_STR # define PK_IMPL_STR # endif # ifndef PK_IMPL_EV # define PK_IMPL_EV # endif #endif