mongory 0.6.2 → 0.7.0

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 (87) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +2 -0
  3. data/CHANGELOG.md +42 -0
  4. data/README.md +82 -176
  5. data/Rakefile +77 -0
  6. data/SUBMODULE_INTEGRATION.md +325 -0
  7. data/docs/advanced_usage.md +40 -0
  8. data/docs/clang_bridge.md +69 -0
  9. data/docs/field_names.md +30 -0
  10. data/docs/migration.md +30 -0
  11. data/docs/performance.md +61 -0
  12. data/examples/benchmark.rb +98 -19
  13. data/ext/mongory_ext/extconf.rb +91 -0
  14. data/ext/mongory_ext/mongory-core/LICENSE +3 -0
  15. data/ext/mongory_ext/mongory-core/include/mongory-core/foundations/array.h +105 -0
  16. data/ext/mongory_ext/mongory-core/include/mongory-core/foundations/config.h +206 -0
  17. data/ext/mongory_ext/mongory-core/include/mongory-core/foundations/error.h +82 -0
  18. data/ext/mongory_ext/mongory-core/include/mongory-core/foundations/memory_pool.h +95 -0
  19. data/ext/mongory_ext/mongory-core/include/mongory-core/foundations/table.h +108 -0
  20. data/ext/mongory_ext/mongory-core/include/mongory-core/foundations/value.h +175 -0
  21. data/ext/mongory_ext/mongory-core/include/mongory-core/matchers/matcher.h +76 -0
  22. data/ext/mongory_ext/mongory-core/include/mongory-core.h +12 -0
  23. data/ext/mongory_ext/mongory-core/src/foundations/array.c +246 -0
  24. data/ext/mongory_ext/mongory-core/src/foundations/array_private.h +18 -0
  25. data/ext/mongory_ext/mongory-core/src/foundations/config.c +406 -0
  26. data/ext/mongory_ext/mongory-core/src/foundations/config_private.h +30 -0
  27. data/ext/mongory_ext/mongory-core/src/foundations/error.c +30 -0
  28. data/ext/mongory_ext/mongory-core/src/foundations/memory_pool.c +298 -0
  29. data/ext/mongory_ext/mongory-core/src/foundations/string_buffer.c +65 -0
  30. data/ext/mongory_ext/mongory-core/src/foundations/string_buffer.h +49 -0
  31. data/ext/mongory_ext/mongory-core/src/foundations/table.c +458 -0
  32. data/ext/mongory_ext/mongory-core/src/foundations/value.c +459 -0
  33. data/ext/mongory_ext/mongory-core/src/matchers/array_record_matcher.c +309 -0
  34. data/ext/mongory_ext/mongory-core/src/matchers/array_record_matcher.h +47 -0
  35. data/ext/mongory_ext/mongory-core/src/matchers/base_matcher.c +161 -0
  36. data/ext/mongory_ext/mongory-core/src/matchers/base_matcher.h +115 -0
  37. data/ext/mongory_ext/mongory-core/src/matchers/compare_matcher.c +210 -0
  38. data/ext/mongory_ext/mongory-core/src/matchers/compare_matcher.h +83 -0
  39. data/ext/mongory_ext/mongory-core/src/matchers/composite_matcher.c +539 -0
  40. data/ext/mongory_ext/mongory-core/src/matchers/composite_matcher.h +125 -0
  41. data/ext/mongory_ext/mongory-core/src/matchers/existance_matcher.c +144 -0
  42. data/ext/mongory_ext/mongory-core/src/matchers/existance_matcher.h +48 -0
  43. data/ext/mongory_ext/mongory-core/src/matchers/external_matcher.c +121 -0
  44. data/ext/mongory_ext/mongory-core/src/matchers/external_matcher.h +46 -0
  45. data/ext/mongory_ext/mongory-core/src/matchers/inclusion_matcher.c +199 -0
  46. data/ext/mongory_ext/mongory-core/src/matchers/inclusion_matcher.h +46 -0
  47. data/ext/mongory_ext/mongory-core/src/matchers/literal_matcher.c +334 -0
  48. data/ext/mongory_ext/mongory-core/src/matchers/literal_matcher.h +97 -0
  49. data/ext/mongory_ext/mongory-core/src/matchers/matcher.c +196 -0
  50. data/ext/mongory_ext/mongory-core/src/matchers/matcher_explainable.c +107 -0
  51. data/ext/mongory_ext/mongory-core/src/matchers/matcher_explainable.h +50 -0
  52. data/ext/mongory_ext/mongory-core/src/matchers/matcher_traversable.c +55 -0
  53. data/ext/mongory_ext/mongory-core/src/matchers/matcher_traversable.h +23 -0
  54. data/ext/mongory_ext/mongory_ext.c +635 -0
  55. data/lib/mongory/c_query_builder.rb +44 -0
  56. data/lib/mongory/converters/converted.rb +2 -2
  57. data/lib/mongory/matchers/abstract_matcher.rb +4 -0
  58. data/lib/mongory/matchers/abstract_multi_matcher.rb +44 -0
  59. data/lib/mongory/matchers/and_matcher.rb +2 -23
  60. data/lib/mongory/matchers/array_record_matcher.rb +2 -23
  61. data/lib/mongory/matchers/elem_match_matcher.rb +4 -0
  62. data/lib/mongory/matchers/eq_matcher.rb +4 -0
  63. data/lib/mongory/matchers/every_matcher.rb +4 -0
  64. data/lib/mongory/matchers/exists_matcher.rb +4 -0
  65. data/lib/mongory/matchers/field_matcher.rb +4 -0
  66. data/lib/mongory/matchers/gt_matcher.rb +4 -0
  67. data/lib/mongory/matchers/gte_matcher.rb +4 -0
  68. data/lib/mongory/matchers/hash_condition_matcher.rb +2 -23
  69. data/lib/mongory/matchers/in_matcher.rb +13 -4
  70. data/lib/mongory/matchers/literal_matcher.rb +4 -0
  71. data/lib/mongory/matchers/lt_matcher.rb +4 -0
  72. data/lib/mongory/matchers/lte_matcher.rb +4 -0
  73. data/lib/mongory/matchers/ne_matcher.rb +4 -0
  74. data/lib/mongory/matchers/nin_matcher.rb +14 -5
  75. data/lib/mongory/matchers/not_matcher.rb +4 -0
  76. data/lib/mongory/matchers/or_matcher.rb +2 -23
  77. data/lib/mongory/matchers/present_matcher.rb +4 -0
  78. data/lib/mongory/matchers/regex_matcher.rb +4 -0
  79. data/lib/mongory/matchers/size_matcher.rb +4 -0
  80. data/lib/mongory/query_builder.rb +8 -0
  81. data/lib/mongory/utils/context.rb +7 -0
  82. data/lib/mongory/utils.rb +1 -1
  83. data/lib/mongory/version.rb +1 -1
  84. data/lib/mongory.rb +7 -0
  85. data/mongory.gemspec +10 -4
  86. data/scripts/build_with_core.sh +292 -0
  87. metadata +70 -5
@@ -0,0 +1,246 @@
1
+ /**
2
+ * @file array.c
3
+ * @brief Implements the mongory_array dynamic array.
4
+ *
5
+ * This file contains the internal implementation details for the mongory_array,
6
+ * including memory management, resizing, and the core array operations.
7
+ * It uses a private structure `mongory_array_private` which extends
8
+ * `mongory_array` with capacity information and the actual item storage.
9
+ */
10
+
11
+ #include <string.h>
12
+ #include "array_private.h"
13
+ #include <mongory-core/foundations/array.h>
14
+ #include <mongory-core/foundations/memory_pool.h>
15
+ #include <mongory-core/foundations/value.h>
16
+
17
+ /**
18
+ * @def MONGORY_ARRAY_INIT_SIZE
19
+ * @brief Initial capacity of a newly created mongory_array.
20
+ */
21
+ #define MONGORY_ARRAY_INIT_SIZE 4
22
+
23
+ /**
24
+ * @brief Resizes the internal storage of the array.
25
+ *
26
+ * Allocates a new block of memory for items and copies existing items to it.
27
+ * The old item storage is not explicitly freed here as it's managed by the
28
+ * memory pool; this function assumes the new allocation replaces the old one
29
+ * in terms of where `internal->items` points.
30
+ *
31
+ * @param self Pointer to the mongory_array instance.
32
+ * @param size The new capacity (number of elements) for the array.
33
+ * @return true if resizing was successful, false otherwise (e.g., memory
34
+ * allocation failure).
35
+ */
36
+ bool mongory_array_resize(mongory_array *self, size_t size) {
37
+ mongory_array_private *internal = (mongory_array_private *)self;
38
+
39
+ // Allocate a new, larger block of memory for the items.
40
+ mongory_value **new_items = MG_ALLOC_ARY(self->pool, mongory_value*, size);
41
+ if (!new_items) {
42
+ // TODO: Propagate error via self->pool->error.
43
+ return false;
44
+ }
45
+
46
+ // Copy existing item pointers to the new memory block.
47
+ memcpy(new_items, internal->items, sizeof(mongory_value *) * self->count);
48
+
49
+ internal->items = new_items;
50
+ internal->capacity = size;
51
+ return true;
52
+ }
53
+
54
+ /**
55
+ * @brief Ensures the array has enough capacity for a given size, growing it if
56
+ * necessary.
57
+ *
58
+ * If the required size is smaller than the current capacity, this function does
59
+ * nothing. Otherwise, it calculates a new capacity (typically double the
60
+ * current, or more if needed to fit `size`) and calls mongory_array_resize.
61
+ *
62
+ * @param self Pointer to the mongory_array instance.
63
+ * @param size The minimum number of elements the array needs to accommodate.
64
+ * @return true if the array has sufficient capacity (or was successfully
65
+ * grown), false otherwise.
66
+ */
67
+ // ============================================================================
68
+ // Static Helper Functions
69
+ // ============================================================================
70
+ static inline bool mongory_array_grow_if_needed(mongory_array *self, size_t size) {
71
+ mongory_array_private *internal = (mongory_array_private *)self;
72
+ if (size < internal->capacity) {
73
+ return true;
74
+ }
75
+
76
+ // Calculate new capacity, typically doubling, until it's sufficient.
77
+ size_t new_capacity = internal->capacity * 2;
78
+ while (new_capacity <= size) {
79
+ new_capacity *= 2;
80
+ }
81
+
82
+ return mongory_array_resize(self, new_capacity);
83
+ }
84
+
85
+ /**
86
+ * @brief Internal implementation for iterating over array elements.
87
+ * @param self Pointer to the mongory_array instance.
88
+ * @param acc Accumulator/context passed to the callback.
89
+ * @param func Callback function executed for each item.
90
+ * @return true if iteration completed, false if callback stopped it.
91
+ */
92
+ static inline bool mongory_array_each(mongory_array *self, void *acc, mongory_array_callback_func func) {
93
+ mongory_array_private *internal = (mongory_array_private *)self;
94
+ for (size_t i = 0; i < self->count; i++) {
95
+ mongory_value *item = internal->items[i];
96
+ if (!func(item, acc)) {
97
+ return false; // Callback requested to stop iteration.
98
+ }
99
+ }
100
+ return true;
101
+ }
102
+
103
+ /**
104
+ * @brief Internal implementation for adding an element to the end of the array.
105
+ * Grows the array if necessary.
106
+ * @param self Pointer to the mongory_array instance.
107
+ * @param value The mongory_value to add.
108
+ * @return true if successful, false on failure (e.g., memory allocation).
109
+ */
110
+ static inline bool mongory_array_push(mongory_array *self, mongory_value *value) {
111
+ mongory_array_private *internal = (mongory_array_private *)self;
112
+ // Ensure there's space for one more element (current count).
113
+ if (!mongory_array_grow_if_needed(self, self->count)) {
114
+ return false;
115
+ }
116
+
117
+ internal->items[self->count++] = value;
118
+ return true;
119
+ }
120
+
121
+ /**
122
+ * @brief Internal implementation for retrieving an element by index.
123
+ * @param self Pointer to the mongory_array instance.
124
+ * @param index The index of the element.
125
+ * @return Pointer to the mongory_value, or NULL if index is out of bounds.
126
+ */
127
+ static inline mongory_value *mongory_array_get(mongory_array *self, size_t index) {
128
+ mongory_array_private *internal = (mongory_array_private *)self;
129
+ if (index >= self->count) {
130
+ return NULL; // Index out of bounds.
131
+ }
132
+ return internal->items[index];
133
+ }
134
+
135
+ /**
136
+ * @brief Internal implementation for setting an element at a specific index.
137
+ *
138
+ * Grows the array if necessary. If the index is beyond the current count,
139
+ * intermediate elements are set to NULL, and the array's count is updated.
140
+ *
141
+ * @param self Pointer to the mongory_array instance.
142
+ * @param index The index at which to set the value.
143
+ * @param value The mongory_value to set.
144
+ * @return true if successful, false on failure (e.g., memory allocation).
145
+ */
146
+ static inline bool mongory_array_set(mongory_array *self, size_t index, mongory_value *value) {
147
+ mongory_array_private *internal = (mongory_array_private *)self;
148
+ // Ensure capacity for the given index (index + 1 elements).
149
+ if (!mongory_array_grow_if_needed(self, index + 1)) {
150
+ return false;
151
+ }
152
+
153
+ // If setting beyond the current count, fill intermediate spots with NULL.
154
+ if (index >= self->count) {
155
+ for (size_t i = self->count; i < index; i++) {
156
+ internal->items[i] = NULL;
157
+ }
158
+ self->count = index + 1; // Update count to include the new element.
159
+ }
160
+
161
+ internal->items[index] = value;
162
+ return true;
163
+ }
164
+
165
+ /**
166
+ * @brief Creates and initializes a new mongory_array.
167
+ *
168
+ * Allocates memory for the array structure itself and its initial item storage
169
+ * using the provided memory pool. Assigns function pointers for array
170
+ * operations.
171
+ *
172
+ * @param pool The memory pool to use for allocations.
173
+ * @return Pointer to the new mongory_array, or NULL on allocation failure.
174
+ */
175
+ mongory_array *mongory_array_new(mongory_memory_pool *pool) {
176
+ // First, allocate the private structure that holds all array metadata.
177
+ mongory_array_private *internal = MG_ALLOC_PTR(pool, mongory_array_private);
178
+ if (!internal) {
179
+ // TODO: Propagate error via pool->error (if pool is not NULL)
180
+ return NULL;
181
+ }
182
+
183
+ // Then, allocate the initial block of memory for the array items.
184
+ mongory_value **items = MG_ALLOC_ARY(pool, mongory_value*, MONGORY_ARRAY_INIT_SIZE);
185
+ if (!items) {
186
+ // If this fails, the 'internal' struct allocated above will be cleaned up
187
+ // by the pool, assuming it's a tracing pool.
188
+ // TODO: Propagate error via pool->error (if pool is not NULL)
189
+ return NULL;
190
+ }
191
+
192
+ // Initialize the public part of the array structure.
193
+ internal->base.pool = pool;
194
+ internal->base.count = 0;
195
+ internal->base.each = mongory_array_each;
196
+ internal->base.get = mongory_array_get;
197
+ internal->base.push = mongory_array_push;
198
+ internal->base.set = mongory_array_set;
199
+
200
+ // Initialize the private part of the array structure.
201
+ internal->items = items;
202
+ internal->capacity = MONGORY_ARRAY_INIT_SIZE;
203
+
204
+ return &internal->base; // Return pointer to the public structure.
205
+ }
206
+
207
+ static mongory_value** mongory_array_merge(mongory_memory_pool *pool, mongory_value **left, mongory_value **right, size_t count, void *ctx, size_t(*callback)(mongory_value *value, void *ctx)) {
208
+ mongory_value **result = MG_ALLOC_ARY(pool, mongory_value*, count);
209
+ size_t i = 0, j = 0, k = 0;
210
+ while (i < count / 2 && j < count - count / 2) {
211
+ if (callback(left[i], ctx) < callback(right[j], ctx)) {
212
+ result[k++] = left[i++];
213
+ } else {
214
+ result[k++] = right[j++];
215
+ }
216
+ }
217
+ while (i < count / 2) {
218
+ result[k++] = left[i++];
219
+ }
220
+ while (j < count - count / 2) {
221
+ result[k++] = right[j++];
222
+ }
223
+ return result;
224
+ }
225
+
226
+ static mongory_value** mongory_array_merge_sort(mongory_memory_pool *pool, mongory_value **origin_items, size_t count, void *ctx, size_t(*callback)(mongory_value *value, void *ctx)) {
227
+ if (count <= 1) {
228
+ return origin_items;
229
+ }
230
+ size_t mid = count / 2;
231
+ mongory_value **left = mongory_array_merge_sort(pool, origin_items, mid, ctx, callback);
232
+ mongory_value **right = mongory_array_merge_sort(pool, origin_items + mid, count - mid, ctx, callback);
233
+ return mongory_array_merge(pool, left, right, count, ctx, callback);
234
+ }
235
+
236
+ mongory_array *mongory_array_sort_by(mongory_array *self, mongory_memory_pool *temp_pool, void *ctx, size_t(*callback)(mongory_value *value, void *ctx)) {
237
+ mongory_array_private *internal = (mongory_array_private *)self;
238
+
239
+ mongory_value **new_items = mongory_array_merge_sort(temp_pool, internal->items, self->count, ctx, callback);
240
+ mongory_array_private *new_array = (mongory_array_private *)mongory_array_new(self->pool);
241
+ new_array->capacity = internal->capacity;
242
+ new_array->base.count = self->count;
243
+ new_array->items = MG_ALLOC_ARY(self->pool, mongory_value*, new_array->capacity);
244
+ memcpy(new_array->items, new_items, sizeof(mongory_value *) * self->count);
245
+ return &new_array->base;
246
+ }
@@ -0,0 +1,18 @@
1
+ #ifndef MONGORY_ARRAY_PRIVATE_H
2
+ #define MONGORY_ARRAY_PRIVATE_H
3
+ #include "mongory-core/foundations/array.h"
4
+ #include "mongory-core/foundations/memory_pool.h"
5
+ #include "mongory-core/foundations/value.h"
6
+ #include <stdbool.h>
7
+
8
+ bool mongory_array_resize(mongory_array *self, size_t size); // resize array
9
+
10
+ typedef struct mongory_array_private {
11
+ mongory_array base; // public array
12
+ mongory_value **items; // items pointer
13
+ size_t capacity; // capacity
14
+ } mongory_array_private;
15
+
16
+ mongory_array *mongory_array_sort_by(mongory_array *self, mongory_memory_pool *temp_pool, void *ctx, size_t(*callback)(mongory_value *value, void *ctx));
17
+
18
+ #endif // MONGORY_ARRAY_PRIVATE_H
@@ -0,0 +1,406 @@
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
+ #include <stdarg.h> // For va_list, va_start, va_end, vsnprintf
24
+ #include <stdio.h> // For snprintf
25
+ #include <string.h> // For strlen, strcpy
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 = NULL;
31
+ // Global table mapping matcher names (e.g., "$eq") to their build functions.
32
+ mongory_table *mongory_matcher_mapping = NULL;
33
+ // Global converter for handling external data types.
34
+ mongory_value_converter *mongory_internal_value_converter = NULL;
35
+ // Global adapter for custom matchers.
36
+ mongory_matcher_custom_adapter *mongory_custom_matcher_adapter = NULL;
37
+
38
+ /**
39
+ * @brief Initializes the internal memory pool if it hasn't been already.
40
+ * This pool is used for allocations by various library components.
41
+ */
42
+ static inline void mongory_internal_pool_init() {
43
+ if (mongory_internal_pool != NULL) {
44
+ return; // Already initialized.
45
+ }
46
+ mongory_internal_pool = mongory_memory_pool_new();
47
+ // TODO: Add error handling if mongory_memory_pool_new returns NULL.
48
+ }
49
+
50
+ /**
51
+ * @brief Default regex function that always returns false.
52
+ * Used if no custom regex function is set via mongory_regex_func_set.
53
+ * @param pool Unused.
54
+ * @param pattern Unused.
55
+ * @param value Unused.
56
+ * @return Always false.
57
+ */
58
+ static inline bool mongory_regex_default_func(mongory_memory_pool *pool, mongory_value *pattern, mongory_value *value) {
59
+ (void)pool; // Mark as unused to prevent compiler warnings.
60
+ (void)pattern; // Mark as unused.
61
+ (void)value; // Mark as unused.
62
+ return false; // Default behavior is no match.
63
+ }
64
+
65
+ static inline char *mongory_regex_default_stringify_func(mongory_memory_pool *pool, mongory_value *pattern) {
66
+ (void)pool; // Mark as unused to prevent compiler warnings.
67
+ (void)pattern; // Mark as unused.
68
+ return "//"; // Default behavior is no stringification.
69
+ }
70
+
71
+ /**
72
+ * @brief Initializes the internal regex adapter if it hasn't been already.
73
+ * Allocates the adapter structure from the internal pool and sets the default
74
+ * regex function.
75
+ */
76
+ static inline void mongory_internal_regex_adapter_init() {
77
+ if (mongory_internal_regex_adapter != NULL) {
78
+ return; // Already initialized.
79
+ }
80
+
81
+ // Ensure the internal pool is initialized first.
82
+ mongory_internal_pool_init();
83
+ if (mongory_internal_pool == NULL) {
84
+ // Cannot proceed if pool initialization failed.
85
+ return;
86
+ }
87
+
88
+ mongory_internal_regex_adapter = MG_ALLOC_PTR(mongory_internal_pool, mongory_regex_adapter);
89
+ if (mongory_internal_regex_adapter == NULL) {
90
+ // TODO: Set error state (e.g., in mongory_internal_pool->error).
91
+ return;
92
+ }
93
+
94
+ mongory_internal_regex_adapter->match_func = mongory_regex_default_func;
95
+ mongory_internal_regex_adapter->stringify_func = mongory_regex_default_stringify_func;
96
+ }
97
+
98
+ /**
99
+ * @brief Sets the global regex matching function.
100
+ * Initializes the regex adapter if it's not already.
101
+ * @param func The custom regex function to use.
102
+ */
103
+ void mongory_regex_func_set(mongory_regex_func func) {
104
+ if (mongory_internal_regex_adapter == NULL) {
105
+ mongory_internal_regex_adapter_init();
106
+ }
107
+ if (mongory_internal_regex_adapter != NULL) {
108
+ mongory_internal_regex_adapter->match_func = func;
109
+ }
110
+ // TODO: What if mongory_internal_regex_adapter is still NULL after init?
111
+ // (e.g. pool alloc failed)
112
+ }
113
+
114
+ /**
115
+ * @brief Sets the global regex stringify function.
116
+ * Initializes the regex adapter if it's not already.
117
+ * @param func The custom regex stringify function to use.
118
+ */
119
+ void mongory_regex_stringify_func_set(mongory_regex_stringify_func func) {
120
+ if (mongory_internal_regex_adapter == NULL) {
121
+ mongory_internal_regex_adapter_init();
122
+ }
123
+ if (mongory_internal_regex_adapter != NULL) {
124
+ mongory_internal_regex_adapter->stringify_func = func;
125
+ }
126
+ }
127
+ /**
128
+ * @brief Initializes the matcher mapping table if it hasn't been already.
129
+ * This table stores registrations of matcher names to their constructor
130
+ * functions.
131
+ */
132
+ static inline void mongory_matcher_mapping_init() {
133
+ if (mongory_matcher_mapping != NULL) {
134
+ return; // Already initialized.
135
+ }
136
+
137
+ // Ensure the internal pool is initialized first.
138
+ mongory_internal_pool_init();
139
+ if (mongory_internal_pool == NULL) {
140
+ return; // Cannot proceed if pool initialization failed.
141
+ }
142
+
143
+ mongory_matcher_mapping = mongory_table_new(mongory_internal_pool);
144
+ if (mongory_matcher_mapping == NULL) {
145
+ // TODO: Set error state.
146
+ return;
147
+ }
148
+ }
149
+
150
+ /**
151
+ * @brief Registers a matcher build function with a given name.
152
+ * The build function is stored in the global matcher mapping table.
153
+ * @param name The name of the matcher (e.g., "$eq", "$in").
154
+ * @param build_func A function pointer to the matcher's constructor.
155
+ */
156
+ void mongory_matcher_register(char *name, mongory_matcher_build_func build_func) {
157
+ // Ensure mapping is initialized.
158
+ if (mongory_matcher_mapping == NULL) {
159
+ mongory_matcher_mapping_init();
160
+ if (mongory_matcher_mapping == NULL) {
161
+ // TODO: Set error: Cannot register if mapping init failed.
162
+ return;
163
+ }
164
+ }
165
+
166
+ // Wrap the function pointer in a mongory_value to store in the table.
167
+ mongory_value *value = mongory_value_wrap_ptr(mongory_internal_pool, build_func);
168
+ if (value == NULL) {
169
+ // TODO: Set error: Failed to wrap pointer.
170
+ return;
171
+ }
172
+
173
+ mongory_matcher_mapping->set(mongory_matcher_mapping, name, value);
174
+ // TODO: Check return value of set?
175
+ }
176
+
177
+ /**
178
+ * @brief Retrieves a matcher build function by its name from the global
179
+ * mapping.
180
+ * @param name The name of the matcher to retrieve.
181
+ * @return mongory_matcher_build_func A function pointer to the matcher's
182
+ * constructor, or NULL if not found.
183
+ */
184
+ mongory_matcher_build_func mongory_matcher_build_func_get(char *name) {
185
+ if (mongory_matcher_mapping == NULL) {
186
+ return NULL; // Mapping not initialized or init failed.
187
+ }
188
+
189
+ mongory_value *value = mongory_matcher_mapping->get(mongory_matcher_mapping, name);
190
+ if (value == NULL || value->type != MONGORY_TYPE_POINTER) {
191
+ return NULL; // Not found or not a pointer type as expected.
192
+ }
193
+
194
+ return (mongory_matcher_build_func)value->data.ptr;
195
+ }
196
+
197
+ /**
198
+ * @brief Initializes the internal value converter if it hasn't been already.
199
+ * This converter holds function pointers for custom data type conversions.
200
+ */
201
+ static inline void mongory_internal_value_converter_init() {
202
+ if (mongory_internal_value_converter != NULL) {
203
+ return; // Already initialized.
204
+ }
205
+
206
+ mongory_internal_pool_init();
207
+ if (mongory_internal_pool == NULL) {
208
+ return; // Cannot proceed if pool init failed.
209
+ }
210
+
211
+ mongory_internal_value_converter = MG_ALLOC_PTR(mongory_internal_pool, mongory_value_converter);
212
+ if (mongory_internal_value_converter == NULL) {
213
+ // TODO: Set error state.
214
+ return;
215
+ }
216
+ // Initialize function pointers to NULL or default no-op functions if desired.
217
+ mongory_internal_value_converter->deep_convert = NULL;
218
+ mongory_internal_value_converter->shallow_convert = NULL;
219
+ mongory_internal_value_converter->recover = NULL;
220
+ }
221
+
222
+ /**
223
+ * @brief Sets the function for deep conversion of external values.
224
+ * Initializes the value converter if necessary.
225
+ * @param deep_convert The deep conversion function.
226
+ */
227
+ void mongory_value_converter_deep_convert_set(mongory_deep_convert_func deep_convert) {
228
+ if (mongory_internal_value_converter == NULL) {
229
+ mongory_internal_value_converter_init();
230
+ }
231
+ if (mongory_internal_value_converter != NULL) {
232
+ mongory_internal_value_converter->deep_convert = deep_convert;
233
+ }
234
+ // TODO: Handle case where converter is still NULL after init.
235
+ }
236
+
237
+ /**
238
+ * @brief Sets the function for shallow conversion of external values.
239
+ * Initializes the value converter if necessary.
240
+ * @param shallow_convert The shallow conversion function.
241
+ */
242
+ void mongory_value_converter_shallow_convert_set(mongory_shallow_convert_func shallow_convert) {
243
+ if (mongory_internal_value_converter == NULL) {
244
+ mongory_internal_value_converter_init();
245
+ }
246
+ if (mongory_internal_value_converter != NULL) {
247
+ mongory_internal_value_converter->shallow_convert = shallow_convert;
248
+ }
249
+ // TODO: Handle case where converter is still NULL after init.
250
+ }
251
+
252
+ /**
253
+ * @brief Sets the function for recovering external values from mongory_value.
254
+ * Initializes the value converter if necessary.
255
+ * @param recover The recovery function.
256
+ */
257
+ void mongory_value_converter_recover_set(mongory_recover_func recover) {
258
+ if (mongory_internal_value_converter == NULL) {
259
+ mongory_internal_value_converter_init();
260
+ }
261
+ if (mongory_internal_value_converter != NULL) {
262
+ mongory_internal_value_converter->recover = recover;
263
+ }
264
+ // TODO: Handle case where converter is still NULL after init.
265
+ }
266
+
267
+ /**
268
+ * @brief Initializes the custom matcher adapter if it hasn't been already.
269
+ * This adapter holds function pointers for custom matchers.
270
+ */
271
+ static void mongory_custom_matcher_adapter_init() {
272
+ if (mongory_custom_matcher_adapter != NULL) {
273
+ return; // Already initialized.
274
+ }
275
+ mongory_custom_matcher_adapter = MG_ALLOC_PTR(mongory_internal_pool, mongory_matcher_custom_adapter);
276
+ if (mongory_custom_matcher_adapter == NULL) {
277
+ // TODO: Set error state.
278
+ return;
279
+ }
280
+ mongory_custom_matcher_adapter->build = NULL;
281
+ mongory_custom_matcher_adapter->lookup = NULL;
282
+ mongory_custom_matcher_adapter->match = NULL;
283
+ }
284
+
285
+ void mongory_custom_matcher_match_func_set(bool (*match)(void *external_matcher, mongory_value *value)) {
286
+ if (mongory_custom_matcher_adapter == NULL) {
287
+ mongory_custom_matcher_adapter_init();
288
+ }
289
+ mongory_custom_matcher_adapter->match = match;
290
+ }
291
+
292
+ void mongory_custom_matcher_build_func_set(mongory_matcher_custom_context *(*build)(char *key, mongory_value *condition, void *extern_ctx)) {
293
+ if (mongory_custom_matcher_adapter == NULL) {
294
+ mongory_custom_matcher_adapter_init();
295
+ }
296
+ mongory_custom_matcher_adapter->build = build;
297
+ }
298
+
299
+ void mongory_custom_matcher_lookup_func_set(bool (*lookup)(char *key)) {
300
+ if (mongory_custom_matcher_adapter == NULL) {
301
+ mongory_custom_matcher_adapter_init();
302
+ }
303
+ mongory_custom_matcher_adapter->lookup = lookup;
304
+ }
305
+
306
+ /**
307
+ * @brief Creates a copy of a string using the specified memory pool.
308
+ * @param pool The memory pool to use for allocation.
309
+ * @param str The null-terminated string to copy.
310
+ * @return A pointer to the newly allocated copy, or NULL if str is NULL or
311
+ * allocation fails.
312
+ */
313
+ char *mongory_string_cpy(mongory_memory_pool *pool, char *str) {
314
+ if (str == NULL) {
315
+ return NULL;
316
+ }
317
+
318
+ size_t len = strlen(str);
319
+ char *new_str = (char *)MG_ALLOC(pool, len + 1); // +1 for null terminator.
320
+ if (new_str == NULL) {
321
+ pool->error = &MONGORY_ALLOC_ERROR;
322
+ return NULL;
323
+ }
324
+
325
+ strcpy(new_str, str);
326
+ return new_str;
327
+ }
328
+
329
+ char *mongory_string_cpyf(mongory_memory_pool *pool, char *format, ...) {
330
+ va_list args;
331
+ va_start(args, format);
332
+ int len = vsnprintf(NULL, 0, format, args);
333
+ va_end(args);
334
+ char *new_str = (char *)MG_ALLOC(pool, len + 1);
335
+ if (new_str == NULL) {
336
+ pool->error = &MONGORY_ALLOC_ERROR;
337
+ return NULL;
338
+ }
339
+ va_start(args, format);
340
+ vsnprintf(new_str, len + 1, format, args);
341
+ va_end(args);
342
+ new_str[len] = '\0';
343
+ return new_str;
344
+ }
345
+
346
+ /**
347
+ * @brief Initializes all core Mongory library components.
348
+ * This includes the internal memory pool, regex adapter, matcher mapping table,
349
+ * and value converter. It then registers all standard matcher types.
350
+ * This function MUST be called before using most other library features.
351
+ */
352
+ void mongory_init() {
353
+ // Initialize all global components. Order can be important if one init
354
+ // depends on another (e.g., most depend on the pool).
355
+ mongory_internal_pool_init();
356
+ mongory_internal_regex_adapter_init();
357
+ mongory_matcher_mapping_init();
358
+ mongory_internal_value_converter_init();
359
+ mongory_custom_matcher_adapter_init();
360
+
361
+ // Register all standard matchers.
362
+ // Note: These registrations rely on mongory_internal_pool and
363
+ // mongory_matcher_mapping being successfully initialized.
364
+ // TODO: Add checks to ensure initializations were successful before
365
+ // proceeding.
366
+ mongory_matcher_register("$in", mongory_matcher_in_new);
367
+ mongory_matcher_register("$nin", mongory_matcher_not_in_new);
368
+ mongory_matcher_register("$eq", mongory_matcher_equal_new);
369
+ mongory_matcher_register("$ne", mongory_matcher_not_equal_new);
370
+ mongory_matcher_register("$gt", mongory_matcher_greater_than_new);
371
+ mongory_matcher_register("$gte", mongory_matcher_greater_than_or_equal_new);
372
+ mongory_matcher_register("$lt", mongory_matcher_less_than_new);
373
+ mongory_matcher_register("$lte", mongory_matcher_less_than_or_equal_new);
374
+ mongory_matcher_register("$exists", mongory_matcher_exists_new);
375
+ mongory_matcher_register("$present", mongory_matcher_present_new);
376
+ mongory_matcher_register("$regex", mongory_matcher_regex_new);
377
+ mongory_matcher_register("$and", mongory_matcher_and_new);
378
+ mongory_matcher_register("$or", mongory_matcher_or_new);
379
+ mongory_matcher_register("$elemMatch", mongory_matcher_elem_match_new);
380
+ mongory_matcher_register("$every", mongory_matcher_every_new);
381
+ mongory_matcher_register("$not", mongory_matcher_not_new);
382
+ mongory_matcher_register("$size", mongory_matcher_size_new);
383
+ }
384
+
385
+ /**
386
+ * @brief Cleans up all resources allocated by the Mongory library.
387
+ * This primarily involves freeing the internal memory pool, which should, in
388
+ * turn, release all memory allocated from it. It also resets global pointers
389
+ * to NULL. This should be called when the library is no longer needed to
390
+ * prevent memory leaks.
391
+ */
392
+ void mongory_cleanup() {
393
+ if (mongory_internal_pool != NULL) {
394
+ // Freeing the pool should handle all allocations made from it,
395
+ // including the regex_adapter, matcher_mapping table (and its contents if
396
+ // they were allocated from this pool), and value_converter.
397
+ mongory_internal_pool->free(mongory_internal_pool);
398
+ mongory_internal_pool = NULL;
399
+ }
400
+
401
+ // Set other global pointers to NULL to indicate they are no longer valid.
402
+ // The memory they pointed to should have been managed by the internal pool.
403
+ mongory_internal_regex_adapter = NULL;
404
+ mongory_matcher_mapping = NULL; // The table itself and its nodes.
405
+ mongory_internal_value_converter = NULL;
406
+ }