mongory 0.7.5 → 0.7.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +0 -14
  3. data/ext/mongory_ext/mongory-core/include/mongory-core/foundations/array.h +122 -0
  4. data/ext/mongory_ext/mongory-core/include/mongory-core/foundations/config.h +161 -0
  5. data/ext/mongory_ext/mongory-core/include/mongory-core/foundations/error.h +79 -0
  6. data/ext/mongory_ext/mongory-core/include/mongory-core/foundations/memory_pool.h +95 -0
  7. data/ext/mongory_ext/mongory-core/include/mongory-core/foundations/table.h +127 -0
  8. data/ext/mongory_ext/mongory-core/include/mongory-core/foundations/value.h +175 -0
  9. data/ext/mongory_ext/mongory-core/include/mongory-core/matchers/matcher.h +76 -0
  10. data/ext/mongory_ext/mongory-core/include/mongory-core.h +12 -0
  11. data/ext/mongory_ext/mongory-core/src/foundations/array.c +287 -0
  12. data/ext/mongory_ext/mongory-core/src/foundations/array_private.h +19 -0
  13. data/ext/mongory_ext/mongory-core/src/foundations/config.c +270 -0
  14. data/ext/mongory_ext/mongory-core/src/foundations/config_private.h +48 -0
  15. data/ext/mongory_ext/mongory-core/src/foundations/error.c +38 -0
  16. data/ext/mongory_ext/mongory-core/src/foundations/memory_pool.c +298 -0
  17. data/ext/mongory_ext/mongory-core/src/foundations/string_buffer.c +65 -0
  18. data/ext/mongory_ext/mongory-core/src/foundations/string_buffer.h +49 -0
  19. data/ext/mongory_ext/mongory-core/src/foundations/table.c +498 -0
  20. data/ext/mongory_ext/mongory-core/src/foundations/utils.c +210 -0
  21. data/ext/mongory_ext/mongory-core/src/foundations/utils.h +70 -0
  22. data/ext/mongory_ext/mongory-core/src/foundations/value.c +500 -0
  23. data/ext/mongory_ext/mongory-core/src/matchers/array_record_matcher.c +164 -0
  24. data/ext/mongory_ext/mongory-core/src/matchers/array_record_matcher.h +47 -0
  25. data/ext/mongory_ext/mongory-core/src/matchers/base_matcher.c +122 -0
  26. data/ext/mongory_ext/mongory-core/src/matchers/base_matcher.h +100 -0
  27. data/ext/mongory_ext/mongory-core/src/matchers/compare_matcher.c +217 -0
  28. data/ext/mongory_ext/mongory-core/src/matchers/compare_matcher.h +83 -0
  29. data/ext/mongory_ext/mongory-core/src/matchers/composite_matcher.c +573 -0
  30. data/ext/mongory_ext/mongory-core/src/matchers/composite_matcher.h +125 -0
  31. data/ext/mongory_ext/mongory-core/src/matchers/existance_matcher.c +147 -0
  32. data/ext/mongory_ext/mongory-core/src/matchers/existance_matcher.h +48 -0
  33. data/ext/mongory_ext/mongory-core/src/matchers/external_matcher.c +124 -0
  34. data/ext/mongory_ext/mongory-core/src/matchers/external_matcher.h +46 -0
  35. data/ext/mongory_ext/mongory-core/src/matchers/inclusion_matcher.c +126 -0
  36. data/ext/mongory_ext/mongory-core/src/matchers/inclusion_matcher.h +46 -0
  37. data/ext/mongory_ext/mongory-core/src/matchers/literal_matcher.c +314 -0
  38. data/ext/mongory_ext/mongory-core/src/matchers/literal_matcher.h +97 -0
  39. data/ext/mongory_ext/mongory-core/src/matchers/matcher.c +252 -0
  40. data/ext/mongory_ext/mongory-core/src/matchers/matcher_explainable.c +79 -0
  41. data/ext/mongory_ext/mongory-core/src/matchers/matcher_explainable.h +23 -0
  42. data/ext/mongory_ext/mongory-core/src/matchers/matcher_traversable.c +60 -0
  43. data/ext/mongory_ext/mongory-core/src/matchers/matcher_traversable.h +23 -0
  44. data/lib/mongory/version.rb +1 -1
  45. metadata +43 -2
@@ -0,0 +1,270 @@
1
+ /**
2
+ * @file config.c
3
+ * @brief Implements global configuration and initialization for the Mongory
4
+ * library.
5
+ *
6
+ * This file manages the lifecycle of global resources such as the internal
7
+ * memory pool, regex adapter, matcher registration table, and value converters.
8
+ * It provides the `mongory_init` and `mongory_cleanup` functions, as well as
9
+ * setters for customizable components and a string copy utility.
10
+ */
11
+ #include "mongory-core/foundations/config.h"
12
+ #include "../matchers/base_matcher.h" // For mongory_matcher_build_func
13
+ #include "../matchers/compare_matcher.h" // For specific matcher constructors
14
+ #include "../matchers/composite_matcher.h" // For specific matcher constructors
15
+ #include "../matchers/existance_matcher.h" // For specific matcher constructors
16
+ #include "../matchers/inclusion_matcher.h" // For specific matcher constructors
17
+ #include "../matchers/literal_matcher.h" // For specific matcher constructors
18
+ #include "../matchers/external_matcher.h" // For specific matcher constructors
19
+ #include "config_private.h" // For mongory_regex_adapter, mongory_value_converter, etc.
20
+ #include "mongory-core/foundations/memory_pool.h"
21
+ #include "mongory-core/foundations/table.h"
22
+ #include "mongory-core/foundations/value.h"
23
+
24
+ static bool mongory_regex_default_func(mongory_memory_pool *pool, mongory_value *pattern, mongory_value *value);
25
+ static char *mongory_regex_default_stringify_func(mongory_memory_pool *pool, mongory_value *pattern);
26
+
27
+ // Global internal memory pool for the library.
28
+ mongory_memory_pool *mongory_internal_pool = NULL;
29
+ // Global adapter for regex operations.
30
+ mongory_regex_adapter mongory_internal_regex_adapter = {
31
+ .match_func = mongory_regex_default_func,
32
+ .stringify_func = mongory_regex_default_stringify_func,
33
+ };
34
+ // Global table mapping matcher names (e.g., "$eq") to their build functions.
35
+ mongory_table *mongory_matcher_mapping = NULL;
36
+ // Global converter for handling external data types.
37
+ mongory_value_converter mongory_internal_value_converter = {
38
+ .deep_convert = NULL,
39
+ .shallow_convert = NULL,
40
+ .recover = NULL,
41
+ };
42
+ // Global adapter for custom matchers.
43
+ mongory_matcher_custom_adapter mongory_custom_matcher_adapter = {
44
+ .build = NULL,
45
+ .lookup = NULL,
46
+ .match = NULL,
47
+ };
48
+
49
+ bool mongory_matcher_trace_result_colorful = true;
50
+
51
+ /**
52
+ * @brief Initializes the internal memory pool if it hasn't been already.
53
+ * This pool is used for allocations by various library components.
54
+ */
55
+ static inline void mongory_internal_pool_init() {
56
+ if (mongory_internal_pool != NULL) {
57
+ return; // Already initialized.
58
+ }
59
+ mongory_internal_pool = mongory_memory_pool_new();
60
+ // TODO: Add error handling if mongory_memory_pool_new returns NULL.
61
+ }
62
+
63
+ /**
64
+ * @brief Default regex function that always returns false.
65
+ * Used if no custom regex function is set via mongory_regex_func_set.
66
+ * @param pool Unused.
67
+ * @param pattern Unused.
68
+ * @param value Unused.
69
+ * @return Always false.
70
+ */
71
+ static bool mongory_regex_default_func(mongory_memory_pool *pool, mongory_value *pattern, mongory_value *value) {
72
+ (void)pool; // Mark as unused to prevent compiler warnings.
73
+ (void)pattern; // Mark as unused.
74
+ (void)value; // Mark as unused.
75
+ return false; // Default behavior is no match.
76
+ }
77
+
78
+ static char *mongory_regex_default_stringify_func(mongory_memory_pool *pool, mongory_value *pattern) {
79
+ (void)pool; // Mark as unused to prevent compiler warnings.
80
+ (void)pattern; // Mark as unused.
81
+ return "//"; // Default behavior is no stringification.
82
+ }
83
+
84
+ /**
85
+ * @brief Sets the global regex matching function.
86
+ * Initializes the regex adapter if it's not already.
87
+ * @param func The custom regex function to use.
88
+ */
89
+ void mongory_regex_func_set(mongory_regex_func func) {
90
+ mongory_internal_regex_adapter.match_func = func;
91
+ }
92
+
93
+ /**
94
+ * @brief Sets the global regex stringify function.
95
+ * Initializes the regex adapter if it's not already.
96
+ * @param func The custom regex stringify function to use.
97
+ */
98
+ void mongory_regex_stringify_func_set(mongory_regex_stringify_func func) {
99
+ mongory_internal_regex_adapter.stringify_func = func;
100
+ }
101
+ /**
102
+ * @brief Initializes the matcher mapping table if it hasn't been already.
103
+ * This table stores registrations of matcher names to their constructor
104
+ * functions.
105
+ */
106
+ static inline void mongory_matcher_mapping_init() {
107
+ if (mongory_matcher_mapping != NULL) {
108
+ return; // Already initialized.
109
+ }
110
+
111
+ // Ensure the internal pool is initialized first.
112
+ mongory_internal_pool_init();
113
+ if (mongory_internal_pool == NULL) {
114
+ return; // Cannot proceed if pool initialization failed.
115
+ }
116
+
117
+ mongory_matcher_mapping = mongory_table_new(mongory_internal_pool);
118
+ if (mongory_matcher_mapping == NULL) {
119
+ // TODO: Set error state.
120
+ return;
121
+ }
122
+ }
123
+
124
+ /**
125
+ * @brief Registers a matcher build function with a given name.
126
+ * The build function is stored in the global matcher mapping table.
127
+ * @param name The name of the matcher (e.g., "$eq", "$in").
128
+ * @param build_func A function pointer to the matcher's constructor.
129
+ */
130
+ void mongory_matcher_register(char *name, mongory_matcher_build_func build_func) {
131
+ // Ensure mapping is initialized.
132
+ if (mongory_matcher_mapping == NULL) {
133
+ mongory_matcher_mapping_init();
134
+ if (mongory_matcher_mapping == NULL) {
135
+ // TODO: Set error: Cannot register if mapping init failed.
136
+ return;
137
+ }
138
+ }
139
+
140
+ // Wrap the function pointer in a mongory_value to store in the table.
141
+ mongory_value *value = mongory_value_wrap_ptr(mongory_internal_pool, build_func);
142
+ if (value == NULL) {
143
+ // TODO: Set error: Failed to wrap pointer.
144
+ return;
145
+ }
146
+
147
+ mongory_matcher_mapping->set(mongory_matcher_mapping, name, value);
148
+ // TODO: Check return value of set?
149
+ }
150
+
151
+ /**
152
+ * @brief Retrieves a matcher build function by its name from the global
153
+ * mapping.
154
+ * @param name The name of the matcher to retrieve.
155
+ * @return mongory_matcher_build_func A function pointer to the matcher's
156
+ * constructor, or NULL if not found.
157
+ */
158
+ mongory_matcher_build_func mongory_matcher_build_func_get(char *name) {
159
+ if (mongory_matcher_mapping == NULL) {
160
+ return NULL; // Mapping not initialized or init failed.
161
+ }
162
+
163
+ mongory_value *value = mongory_matcher_mapping->get(mongory_matcher_mapping, name);
164
+ if (value == NULL || value->type != MONGORY_TYPE_POINTER) {
165
+ return NULL; // Not found or not a pointer type as expected.
166
+ }
167
+
168
+ return (mongory_matcher_build_func)value->data.ptr;
169
+ }
170
+
171
+ /**
172
+ * @brief Sets the function for deep conversion of external values.
173
+ * Initializes the value converter if necessary.
174
+ * @param deep_convert The deep conversion function.
175
+ */
176
+ void mongory_value_converter_deep_convert_set(mongory_deep_convert_func deep_convert) {
177
+ mongory_internal_value_converter.deep_convert = deep_convert;
178
+ }
179
+
180
+ /**
181
+ * @brief Sets the function for shallow conversion of external values.
182
+ * Initializes the value converter if necessary.
183
+ * @param shallow_convert The shallow conversion function.
184
+ */
185
+ void mongory_value_converter_shallow_convert_set(mongory_shallow_convert_func shallow_convert) {
186
+ mongory_internal_value_converter.shallow_convert = shallow_convert;
187
+ }
188
+
189
+ /**
190
+ * @brief Sets the function for recovering external values from mongory_value.
191
+ * Initializes the value converter if necessary.
192
+ * @param recover The recovery function.
193
+ */
194
+ void mongory_value_converter_recover_set(mongory_recover_func recover) {
195
+ mongory_internal_value_converter.recover = recover;
196
+ }
197
+
198
+
199
+ void mongory_custom_matcher_match_func_set(bool (*match)(void *external_matcher, mongory_value *value)) {
200
+ mongory_custom_matcher_adapter.match = match;
201
+ }
202
+
203
+ void mongory_custom_matcher_build_func_set(mongory_matcher_custom_context *(*build)(char *key, mongory_value *condition, void *extern_ctx)) {
204
+ mongory_custom_matcher_adapter.build = build;
205
+ }
206
+
207
+ void mongory_custom_matcher_lookup_func_set(bool (*lookup)(char *key)) {
208
+ mongory_custom_matcher_adapter.lookup = lookup;
209
+ }
210
+
211
+ void mongory_matcher_trace_result_colorful_set(bool colorful) {
212
+ mongory_matcher_trace_result_colorful = colorful;
213
+ }
214
+
215
+ /**
216
+ * @brief Initializes all core Mongory library components.
217
+ * This includes the internal memory pool, regex adapter, matcher mapping table,
218
+ * and value converter. It then registers all standard matcher types.
219
+ * This function MUST be called before using most other library features.
220
+ */
221
+ void mongory_init() {
222
+ // Initialize all global components. Order can be important if one init
223
+ // depends on another (e.g., most depend on the pool).
224
+ mongory_internal_pool_init();
225
+ mongory_matcher_mapping_init();
226
+
227
+ // Register all standard matchers.
228
+ // Note: These registrations rely on mongory_internal_pool and
229
+ // mongory_matcher_mapping being successfully initialized.
230
+ // TODO: Add checks to ensure initializations were successful before
231
+ // proceeding.
232
+ mongory_matcher_register("$in", mongory_matcher_in_new);
233
+ mongory_matcher_register("$nin", mongory_matcher_not_in_new);
234
+ mongory_matcher_register("$eq", mongory_matcher_equal_new);
235
+ mongory_matcher_register("$ne", mongory_matcher_not_equal_new);
236
+ mongory_matcher_register("$gt", mongory_matcher_greater_than_new);
237
+ mongory_matcher_register("$gte", mongory_matcher_greater_than_or_equal_new);
238
+ mongory_matcher_register("$lt", mongory_matcher_less_than_new);
239
+ mongory_matcher_register("$lte", mongory_matcher_less_than_or_equal_new);
240
+ mongory_matcher_register("$exists", mongory_matcher_exists_new);
241
+ mongory_matcher_register("$present", mongory_matcher_present_new);
242
+ mongory_matcher_register("$regex", mongory_matcher_regex_new);
243
+ mongory_matcher_register("$and", mongory_matcher_and_new);
244
+ mongory_matcher_register("$or", mongory_matcher_or_new);
245
+ mongory_matcher_register("$elemMatch", mongory_matcher_elem_match_new);
246
+ mongory_matcher_register("$every", mongory_matcher_every_new);
247
+ mongory_matcher_register("$not", mongory_matcher_not_new);
248
+ mongory_matcher_register("$size", mongory_matcher_size_new);
249
+ }
250
+
251
+ /**
252
+ * @brief Cleans up all resources allocated by the Mongory library.
253
+ * This primarily involves freeing the internal memory pool, which should, in
254
+ * turn, release all memory allocated from it. It also resets global pointers
255
+ * to NULL. This should be called when the library is no longer needed to
256
+ * prevent memory leaks.
257
+ */
258
+ void mongory_cleanup() {
259
+ if (mongory_internal_pool != NULL) {
260
+ // Freeing the pool should handle all allocations made from it,
261
+ // including the regex_adapter, matcher_mapping table (and its contents if
262
+ // they were allocated from this pool), and value_converter.
263
+ mongory_internal_pool->free(mongory_internal_pool);
264
+ mongory_internal_pool = NULL;
265
+ }
266
+
267
+ // Set other global pointers to NULL to indicate they are no longer valid.
268
+ // The memory they pointed to should have been managed by the internal pool.
269
+ mongory_matcher_mapping = NULL; // The table itself and its nodes.
270
+ }
@@ -0,0 +1,48 @@
1
+ #ifndef MONGORY_FOUNDATIONS_CONFIG_PRIVATE_H
2
+ #define MONGORY_FOUNDATIONS_CONFIG_PRIVATE_H
3
+ #include "../matchers/base_matcher.h"
4
+ #include "mongory-core/foundations/config.h"
5
+ #include "mongory-core/foundations/table.h"
6
+ #include "mongory-core/matchers/matcher.h"
7
+
8
+ typedef struct mongory_regex_adapter {
9
+ mongory_regex_func match_func;
10
+ mongory_regex_stringify_func stringify_func;
11
+ } mongory_regex_adapter;
12
+
13
+ typedef struct mongory_value_converter {
14
+ mongory_deep_convert_func deep_convert;
15
+ mongory_shallow_convert_func shallow_convert;
16
+ mongory_recover_func recover;
17
+ } mongory_value_converter;
18
+
19
+ /**
20
+ * @brief Function pointer type for matching a value against an external matcher.
21
+ *
22
+ * This function is called when a value needs to be matched against an external
23
+ * matcher.
24
+ *
25
+ * @param external_matcher The external reference to the matcher.
26
+ * @param value The value to match against.
27
+ * @return bool True if the value matches the matcher, false otherwise.
28
+ */
29
+ typedef struct mongory_matcher_custom_adapter {
30
+ bool (*match)(void *external_matcher, mongory_value *value); // Match a value against an external matcher.
31
+ mongory_matcher_custom_context *(*build)(char *key, mongory_value *condition, void *extern_ctx); // Build an external matcher reference.
32
+ bool (*lookup)(char *key); // Lookup a matcher reference by key.
33
+ } mongory_matcher_custom_adapter;
34
+
35
+ extern mongory_memory_pool *mongory_internal_pool;
36
+ extern mongory_regex_adapter mongory_internal_regex_adapter;
37
+ extern mongory_table *mongory_matcher_mapping;
38
+ extern mongory_value_converter mongory_internal_value_converter;
39
+ extern mongory_matcher_custom_adapter mongory_custom_matcher_adapter;
40
+ extern bool mongory_matcher_trace_result_colorful;
41
+
42
+ typedef mongory_matcher *(*mongory_matcher_build_func)(mongory_memory_pool *pool,
43
+ mongory_value *condition,
44
+ void *extern_ctx); // build function
45
+ void mongory_matcher_register(char *name, mongory_matcher_build_func build_func);
46
+ mongory_matcher_build_func mongory_matcher_build_func_get(char *name);
47
+
48
+ #endif
@@ -0,0 +1,38 @@
1
+ #ifndef MONGORY_ERROR_C
2
+ #define MONGORY_ERROR_C
3
+ /**
4
+ * @file error.c
5
+ * @brief Implements error type to string conversion for the Mongory library.
6
+ */
7
+ #include <mongory-core/foundations/error.h>
8
+
9
+ /**
10
+ * @brief Converts a mongory_error_type enum to its human-readable string
11
+ * representation.
12
+ *
13
+ * This function uses the MONGORY_ERROR_TYPE_MACRO to generate a switch
14
+ * statement that maps each error enum to its corresponding string.
15
+ *
16
+ * @param type The mongory_error_type enum value to convert.
17
+ * @return const char* A string literal representing the error type. If the
18
+ * type is not recognized, it returns "Unknown Error Type".
19
+ */
20
+ const char *mongory_error_type_to_string(enum mongory_error_type type) {
21
+ switch (type) {
22
+ // Use the X-Macro to generate case statements for each error type.
23
+ #define DEFINE_ERROR_STRING(name, num, str) \
24
+ case name: \
25
+ return str;
26
+ MONGORY_ERROR_TYPE_MACRO(DEFINE_ERROR_STRING)
27
+ #undef DEFINE_ERROR_STRING // Undefine the macro after use.
28
+ default:
29
+ // Fallback for any undefined or unknown error types.
30
+ return "Unknown Error Type";
31
+ }
32
+ }
33
+
34
+ mongory_error MONGORY_ALLOC_ERROR = {
35
+ .type = MONGORY_ERROR_MEMORY,
36
+ .message = "Memory Allocation Failed",
37
+ };
38
+ #endif
@@ -0,0 +1,298 @@
1
+ /**
2
+ * @file memory_pool.c
3
+ * @brief Implements a memory pool for the Mongory library.
4
+ *
5
+ * This implementation uses a linked list of memory chunks. Allocations are
6
+ * made from the current chunk. If the current chunk is full, a new, larger
7
+ * chunk is allocated and added to the list. Freeing the pool deallocates all
8
+ * chunks. It also supports tracing externally allocated memory.
9
+ */
10
+ #include <mongory-core/foundations/memory_pool.h>
11
+ #include <stdio.h> // For NULL, though stdlib.h or stddef.h is more common
12
+ #include <stdlib.h> // For calloc, free, etc.
13
+ #include <string.h> // For memset
14
+
15
+ /**
16
+ * @def MONGORY_INITIAL_CHUNK_SIZE
17
+ * @brief The initial size in bytes for the first memory chunk allocated by the
18
+ * pool.
19
+ */
20
+ #define MONGORY_INITIAL_CHUNK_SIZE 2048
21
+
22
+ /**
23
+ * @def MONGORY_ALIGN8(size)
24
+ * @brief Macro to align a given size to an 8-byte boundary.
25
+ * This is useful for ensuring that memory allocations are suitably aligned
26
+ * for various data types.
27
+ * @param size The original size.
28
+ * @return The size aligned up to the nearest multiple of 8.
29
+ */
30
+ #define MONGORY_ALIGN8(size) (((size) + 7) & ~((size_t)7))
31
+
32
+ /**
33
+ * @struct mongory_memory_node
34
+ * @brief Represents a node in the linked list of memory chunks within the pool.
35
+ *
36
+ * Each node holds a pointer to a block of memory (`ptr`), its total `size`,
37
+ * how much of it is `used`, and a pointer to the `next` node in the list.
38
+ * This structure is also used by the tracing mechanism to track external
39
+ * allocations.
40
+ */
41
+ typedef struct mongory_memory_node {
42
+ void *ptr; /**< Pointer to the allocated memory block. */
43
+ size_t size; /**< Total size of the memory block. */
44
+ size_t used; /**< Bytes used in this memory block. */
45
+ struct mongory_memory_node *next; /**< Pointer to the next memory node. */
46
+ } mongory_memory_node;
47
+
48
+ /**
49
+ * @struct mongory_memory_pool_ctx
50
+ * @brief Internal context for a mongory_memory_pool.
51
+ *
52
+ * Stores the current `chunk_size` (which doubles on growth), pointers to
53
+ * the `head` and `current` memory nodes for allocations, and a list (`extra`)
54
+ * for traced external allocations.
55
+ */
56
+ typedef struct mongory_memory_pool_ctx {
57
+ size_t chunk_size; /**< Current preferred size for new chunks. */
58
+ mongory_memory_node *head; /**< Head of the list of memory chunks. */
59
+ mongory_memory_node *current; /**< Current chunk to allocate from. */
60
+ mongory_memory_node *extra; /**< Head of list for externally traced memory. */
61
+ } mongory_memory_pool_ctx;
62
+
63
+ /**
64
+ * @brief Allocates a new memory chunk (node and its associated memory block).
65
+ *
66
+ * Uses `calloc` to ensure memory is zero-initialized.
67
+ *
68
+ * @param chunk_size The size of the memory block to allocate for this chunk.
69
+ * @return mongory_memory_node* Pointer to the new memory node, or NULL on
70
+ * failure.
71
+ */
72
+ static inline mongory_memory_node *mongory_memory_chunk_new(size_t chunk_size) {
73
+ mongory_memory_node *node = calloc(1, sizeof(mongory_memory_node));
74
+ if (!node) {
75
+ return NULL; // Failed to allocate node structure.
76
+ }
77
+
78
+ void *mem = calloc(1, chunk_size);
79
+ if (!mem) {
80
+ free(node); // Clean up allocated node structure.
81
+ return NULL; // Failed to allocate memory block for the chunk.
82
+ }
83
+
84
+ node->ptr = mem;
85
+ node->size = chunk_size;
86
+ node->used = 0;
87
+ node->next = NULL;
88
+
89
+ return node;
90
+ }
91
+
92
+ /**
93
+ * @brief Grows the memory pool by adding a new, larger chunk.
94
+ *
95
+ * The new chunk size is at least double the previous chunk size, and large
96
+ * enough to satisfy `request_size`. The new chunk becomes the `current` chunk.
97
+ *
98
+ * @param ctx Pointer to the memory pool's context.
99
+ * @param request_size The minimum size required from the new chunk for an
100
+ * upcoming allocation.
101
+ * @return true if growth was successful, false otherwise.
102
+ */
103
+ static inline bool mongory_memory_pool_grow(mongory_memory_pool_ctx *ctx, size_t request_size) {
104
+ if (ctx->current->next) {
105
+ ctx->current = ctx->current->next;
106
+ return true; // Already have a next chunk.
107
+ }
108
+ // Double the chunk size, ensuring it's at least as large as request_size.
109
+ ctx->chunk_size *= 2;
110
+ while (request_size > ctx->chunk_size) {
111
+ ctx->chunk_size *= 2;
112
+ }
113
+
114
+ mongory_memory_node *new_chunk = mongory_memory_chunk_new(ctx->chunk_size);
115
+ if (!new_chunk) {
116
+ return false; // Failed to create a new chunk.
117
+ }
118
+
119
+ // Link the new chunk and update the current pointer.
120
+ ctx->current->next = new_chunk;
121
+ ctx->current = new_chunk;
122
+
123
+ return true;
124
+ }
125
+
126
+ /**
127
+ * @brief Allocates memory from the pool. Implements `pool->alloc`.
128
+ *
129
+ * Allocates `size` bytes (aligned to 8 bytes) from the `current` chunk.
130
+ * If the current chunk doesn't have enough space, `mongory_memory_pool_grow`
131
+ * is called to add a new chunk.
132
+ *
133
+ * @param pool Pointer to the `mongory_memory_pool`.
134
+ * @param size The number of bytes to allocate.
135
+ * @return void* Pointer to the allocated memory, or NULL on failure.
136
+ */
137
+ static inline void *mongory_memory_pool_alloc(mongory_memory_pool *pool, size_t size) {
138
+ mongory_memory_pool_ctx *pool_ctx = (mongory_memory_pool_ctx *)pool->ctx;
139
+ size = MONGORY_ALIGN8(size); // Ensure 8-byte alignment.
140
+
141
+ size_t balance = pool_ctx->current->size - pool_ctx->current->used;
142
+ if (size > balance) {
143
+ // Not enough space in current chunk, try to grow.
144
+ if (!mongory_memory_pool_grow(pool_ctx, size)) {
145
+ return NULL; // Growth failed.
146
+ }
147
+ // After successful growth, pool_ctx->current points to the new chunk.
148
+ }
149
+
150
+ // Allocate from the current chunk.
151
+ void *ptr = (char *)pool_ctx->current->ptr + pool_ctx->current->used;
152
+ pool_ctx->current->used += size;
153
+
154
+ return ptr;
155
+ }
156
+
157
+ static inline void mongory_memory_pool_reset(mongory_memory_pool *pool) {
158
+ mongory_memory_pool_ctx *pool_ctx = (mongory_memory_pool_ctx *)pool->ctx;
159
+ pool_ctx->current = pool_ctx->head;
160
+ mongory_memory_node *node = pool_ctx->head;
161
+ while (node) {
162
+ node->used = 0;
163
+ node = node->next;
164
+ }
165
+ }
166
+
167
+ /**
168
+ * @brief Frees a linked list of memory nodes.
169
+ *
170
+ * Iterates through the list, freeing the memory block (`node->ptr`) and then
171
+ * the node structure itself for each node. Memory blocks are zeroed out before
172
+ * freeing for security/safety.
173
+ *
174
+ * @param head Pointer to the head of the memory node list to free.
175
+ */
176
+ static inline void mongory_memory_pool_node_list_free(mongory_memory_node *head) {
177
+ mongory_memory_node *node = head;
178
+ while (node) {
179
+ mongory_memory_node *next = node->next;
180
+ if (node->ptr) {
181
+ memset(node->ptr, 0, node->size); // Clear memory for safety.
182
+ free(node->ptr); // Free the actual memory block.
183
+ }
184
+ memset(node, 0,
185
+ sizeof(mongory_memory_node)); // Clear the node structure itself.
186
+ free(node); // Free the node structure.
187
+ node = next;
188
+ }
189
+ }
190
+
191
+ /**
192
+ * @brief Destroys the memory pool and frees all associated memory.
193
+ * Implements `pool->free`.
194
+ *
195
+ * Frees all memory chunks allocated by the pool (`ctx->head` list) and all
196
+ * externally traced memory blocks (`ctx->extra` list). Then frees the pool
197
+ * context and the pool structure itself.
198
+ *
199
+ * @param pool Pointer to the `mongory_memory_pool` to destroy.
200
+ */
201
+ static inline void mongory_memory_pool_destroy(mongory_memory_pool *pool) {
202
+ if (!pool)
203
+ return;
204
+ mongory_memory_pool_ctx *ctx = (mongory_memory_pool_ctx *)pool->ctx;
205
+
206
+ if (ctx) {
207
+ // Free the main list of memory chunks.
208
+ mongory_memory_pool_node_list_free(ctx->head);
209
+ // Free the list of externally traced memory chunks.
210
+ mongory_memory_pool_node_list_free(ctx->extra);
211
+
212
+ memset(ctx, 0,
213
+ sizeof(mongory_memory_pool_ctx)); // Clear the context structure.
214
+ free(ctx); // Free the context structure.
215
+ }
216
+
217
+ memset(pool, 0, sizeof(mongory_memory_pool)); // Clear the pool structure.
218
+ free(pool); // Free the pool structure.
219
+ }
220
+
221
+ /**
222
+ * @brief Traces an externally allocated piece of memory. Implements
223
+ * `pool->trace`.
224
+ *
225
+ * Creates a new `mongory_memory_node` to track the external memory block and
226
+ * adds it to the `extra` list in the pool's context. This memory will be
227
+ * freed when `mongory_memory_pool_destroy` is called if this trace function
228
+ * is used.
229
+ *
230
+ * @param pool Pointer to the `mongory_memory_pool`.
231
+ * @param ptr Pointer to the externally allocated memory.
232
+ * @param size Size of the externally allocated memory.
233
+ */
234
+ static inline void mongory_memory_pool_trace(mongory_memory_pool *pool, void *ptr, size_t size) {
235
+ mongory_memory_pool_ctx *pool_ctx = (mongory_memory_pool_ctx *)pool->ctx;
236
+
237
+ // Create a new node to trace this external allocation.
238
+ mongory_memory_node *extra_alloc_tracer = calloc(1, sizeof(mongory_memory_node));
239
+ if (!extra_alloc_tracer) {
240
+ // Allocation of tracer node failed; cannot trace.
241
+ // This might lead to a leak of 'ptr' if the caller expects the pool to
242
+ // manage it. Consider error reporting.
243
+ return;
244
+ }
245
+ extra_alloc_tracer->ptr = ptr; // This is the externally allocated memory.
246
+ extra_alloc_tracer->size = size; // Its size.
247
+ extra_alloc_tracer->used = size; // Mark as fully "used" in context of tracing.
248
+ extra_alloc_tracer->next = pool_ctx->extra; // Prepend to extra list.
249
+ pool_ctx->extra = extra_alloc_tracer;
250
+ }
251
+
252
+ /**
253
+ * @brief Creates and initializes a new memory pool.
254
+ *
255
+ * Allocates the `mongory_memory_pool` structure, its internal
256
+ * `mongory_memory_pool_ctx`, and the first memory chunk. Sets up the function
257
+ * pointers for `alloc`, `free`, and `trace`.
258
+ *
259
+ * @return mongory_memory_pool* Pointer to the new pool, or NULL on failure.
260
+ */
261
+ mongory_memory_pool *mongory_memory_pool_new() {
262
+ // Allocate the main pool structure.
263
+ mongory_memory_pool *pool = calloc(1, sizeof(mongory_memory_pool));
264
+ if (!pool) {
265
+ return NULL;
266
+ }
267
+
268
+ // Allocate the internal context for the pool.
269
+ mongory_memory_pool_ctx *ctx = calloc(1, sizeof(mongory_memory_pool_ctx));
270
+ if (!ctx) {
271
+ free(pool); // Clean up partially allocated pool.
272
+ return NULL;
273
+ }
274
+
275
+ // Allocate the first memory chunk.
276
+ mongory_memory_node *first_chunk = mongory_memory_chunk_new(MONGORY_INITIAL_CHUNK_SIZE);
277
+ if (!first_chunk) {
278
+ free(ctx); // Clean up context.
279
+ free(pool); // Clean up pool structure.
280
+ return NULL;
281
+ }
282
+
283
+ // Initialize context fields.
284
+ ctx->chunk_size = MONGORY_INITIAL_CHUNK_SIZE;
285
+ ctx->head = first_chunk;
286
+ ctx->current = first_chunk;
287
+ ctx->extra = NULL; // No extra traced allocations initially.
288
+
289
+ // Initialize pool fields.
290
+ pool->ctx = ctx;
291
+ pool->alloc = mongory_memory_pool_alloc;
292
+ pool->reset = mongory_memory_pool_reset;
293
+ pool->free = mongory_memory_pool_destroy;
294
+ pool->trace = mongory_memory_pool_trace;
295
+ pool->error = NULL; // No error initially.
296
+
297
+ return pool;
298
+ }