#pragma once #include #include #ifdef __cplusplus extern "C" { #endif /** Capability flags that describe what a memory allocation needs or prefers. */ enum MemoryCapability { /** Internal memory (non-external/non-PSRAM) memory. */ MEMORY_CAPABILITY_INTERNAL = 1u << 0, /** External memory (e.g. PSRAM/SPIRAM). */ MEMORY_CAPABILITY_EXTERNAL = 1u << 1, /** Usable for code execution. */ MEMORY_CAPABILITY_EXECUTABLE = 1u << 2, /** Usable as a DMA source/destination. */ MEMORY_CAPABILITY_DMA = 1u << 3, /** Usable for SIMD instructions. */ MEMORY_CAPABILITY_SIMD = 1u << 4, }; /** * @brief Describes the constraints an allocation must (or should) satisfy. * * `required` capabilities must all be satisfied or the allocation fails. `desired` * capabilities are attempted alongside `required`, but implementations fall back to * `required`-only if `required | desired` together can't be satisfied. */ struct MemoryPolicy { /** A bitset of MemoryCapability flags that are required during allocation. */ uint16_t required; /** A bitset of MemoryCapability flags that are preferable (but optional) during allocation. */ uint16_t desired; /** Alignment (in bytes) of the returned pointer, or 0 for the platform default. Must be a power of 2. */ size_t alignment; }; /** The default policy: no required/desired capabilities, no alignment requirement. */ extern const struct MemoryPolicy MEMORY_POLICY_DEFAULT; /** * @brief Logs current heap usage (internal and external, when applicable). * No-op on platforms without heap capability tracking. */ void memory_print_stats(); /** * @brief Allocates memory that satisfies the given policy. * @param[in] size number of bytes to allocate * @param[in] policy the allocation constraints * @return the allocated memory, or NULL on failure */ void* memory_alloc_with_policy(size_t size, const struct MemoryPolicy* policy); /** * @brief Resizes a previous allocation, preserving its contents up to the smaller of the old and new size. * @warning policy->alignment is not guaranteed to be preserved across a realloc - it is only * honored on fresh allocations (memory_alloc_with_policy()/memory_calloc_with_policy()). * @param[in] ptr memory previously returned by memory_alloc_with_policy(), memory_calloc_with_policy(), * or memory_realloc_with_policy(), or NULL to allocate a new block * @param[in] size new memory size in bytes * @param[in] policy the policy for the new allocation * @return the (possibly moved) allocated memory, or NULL on failure - in which case ptr is left untouched */ void* memory_realloc_with_policy(void* ptr, size_t size, const struct MemoryPolicy* policy); /** * @brief Allocates zero-initialized memory that satisfies the given policy. * @param[in] count number of elements * @param[in] size size of each element in bytes * @param[in] policy the allocation constraints * @return the allocated memory, or NULL on failure */ void* memory_calloc_with_policy(size_t count, size_t size, const struct MemoryPolicy* policy); /** * @brief Allocates memory using MEMORY_POLICY_DEFAULT. * @param[in] size number of bytes to allocate * @return the allocated memory, or NULL on failure */ inline void* memory_alloc(size_t size) { return memory_alloc_with_policy(size, &MEMORY_POLICY_DEFAULT); } /** * @brief Allocates zero-initialized memory using MEMORY_POLICY_DEFAULT. * @param[in] count number of elements * @param[in] size size of each element in bytes * @return the allocated memory, or NULL on failure */ inline void* memory_calloc(size_t count, size_t size) { return memory_calloc_with_policy(count, size, &MEMORY_POLICY_DEFAULT); } /** * @brief Resizes a previous allocation using MEMORY_POLICY_DEFAULT. See memory_realloc_with_policy(). * @param[in] ptr memory previously returned by one of the memory_* allocation functions, or NULL * @param[in] size new memory size in bytes * @return the (possibly moved) allocated memory, or NULL on failure - in which case ptr is left untouched */ inline void* memory_realloc(void* ptr, size_t size) { return memory_realloc_with_policy(ptr, size, &MEMORY_POLICY_DEFAULT); } /** * @brief Frees memory previously returned by one of the memory_* allocation functions. * @param[in] ptr the memory to free, or NULL (a no-op) */ void memory_free(void* ptr); #ifdef __cplusplus } #endif