1#pragma once
 2
 3#include <stdatomic.h>
 4
 5#ifdef __cplusplus
 6extern "C" {
 7#endif
 8
 9/*
10 * Pussy allocator functions reallocate() and release()
11 * require the number of bytes argument for allocated block.
12 *
13 * This is different from traditional allocators that store
14 * the size of allocated block.
15 *
16 * The approach is more error-prone.
17 * However, it is more efficient for small blocks.
18 *
19 *
20 * Caveat: unlike other types, the compiler sees no difference
21 * between void* and void**.
22 * This makes use of release() extremely error prone.
23 */
24
25typedef void  (*FnInitAllocator)();
26typedef void* (*FnAllocate)  (unsigned nbytes, bool clean);
27typedef bool  (*FnReallocate)(void** addr_ptr, unsigned old_nbytes, unsigned new_nbytes, bool clean, bool* addr_changed);
28typedef void  (*FnRelease)   (void** addr_ptr, unsigned nbytes);
29typedef void  (*FnDump)();
30
31typedef struct {
32    atomic_size_t blocks_allocated;
33} AllocatorStats;
34
35typedef struct {
36    FnInitAllocator init;  // optional, can be nullptr
37    FnAllocate   allocate;
38    FnReallocate reallocate;
39    FnRelease    release;
40    FnDump       dump;
41
42    AllocatorStats* stats;
43
44    // optionally supported:
45    bool verbose;
46    bool trace;
47
48} Allocator;
49
50/****************************************************************
51 * Allocators.
52 */
53
54extern Allocator pet_allocator;
55extern Allocator stdlib_allocator;
56extern Allocator debug_allocator;  // checks if memory was damaged around the block
57
58/****************************************************************
59 * Default allocator and shorthand wrappers.
60 */
61
62extern Allocator default_allocator;  // uninitialized by default, use init_allocator at startup
63
64static inline void init_allocator(Allocator* allocator)
65{
66    if (allocator->init) {
67        allocator->init();
68    }
69    default_allocator = *allocator;
70}
71
72static inline void* allocate(unsigned nbytes, bool clean)
73{
74    return default_allocator.allocate(nbytes, clean);
75}
76
77static inline bool reallocate(void** addr_ptr, unsigned old_nbytes, unsigned new_nbytes, bool clean, bool* addr_changed)
78{
79    return default_allocator.reallocate(addr_ptr, old_nbytes, new_nbytes, clean, addr_changed);
80}
81
82static inline void release(void** addr_ptr, unsigned nbytes)
83{
84    default_allocator.release(addr_ptr, nbytes);
85}
86
87#ifdef __cplusplus
88}
89#endif