mongory 0.6.3 → 0.7.1
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.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -0
- data/CHANGELOG.md +46 -0
- data/README.md +83 -176
- data/Rakefile +77 -0
- data/SUBMODULE_INTEGRATION.md +325 -0
- data/docs/advanced_usage.md +40 -0
- data/docs/clang_bridge.md +69 -0
- data/docs/field_names.md +30 -0
- data/docs/migration.md +30 -0
- data/docs/performance.md +61 -0
- data/examples/benchmark.rb +98 -19
- data/ext/mongory_ext/extconf.rb +91 -0
- data/ext/mongory_ext/mongory-core/LICENSE +3 -0
- data/ext/mongory_ext/mongory-core/include/mongory-core/foundations/array.h +105 -0
- data/ext/mongory_ext/mongory-core/include/mongory-core/foundations/config.h +206 -0
- data/ext/mongory_ext/mongory-core/include/mongory-core/foundations/error.h +82 -0
- data/ext/mongory_ext/mongory-core/include/mongory-core/foundations/memory_pool.h +95 -0
- data/ext/mongory_ext/mongory-core/include/mongory-core/foundations/table.h +108 -0
- data/ext/mongory_ext/mongory-core/include/mongory-core/foundations/value.h +175 -0
- data/ext/mongory_ext/mongory-core/include/mongory-core/matchers/matcher.h +76 -0
- data/ext/mongory_ext/mongory-core/include/mongory-core.h +12 -0
- data/ext/mongory_ext/mongory-core/src/foundations/array.c +246 -0
- data/ext/mongory_ext/mongory-core/src/foundations/array_private.h +18 -0
- data/ext/mongory_ext/mongory-core/src/foundations/config.c +406 -0
- data/ext/mongory_ext/mongory-core/src/foundations/config_private.h +30 -0
- data/ext/mongory_ext/mongory-core/src/foundations/error.c +30 -0
- data/ext/mongory_ext/mongory-core/src/foundations/memory_pool.c +298 -0
- data/ext/mongory_ext/mongory-core/src/foundations/string_buffer.c +65 -0
- data/ext/mongory_ext/mongory-core/src/foundations/string_buffer.h +49 -0
- data/ext/mongory_ext/mongory-core/src/foundations/table.c +458 -0
- data/ext/mongory_ext/mongory-core/src/foundations/value.c +459 -0
- data/ext/mongory_ext/mongory-core/src/matchers/array_record_matcher.c +309 -0
- data/ext/mongory_ext/mongory-core/src/matchers/array_record_matcher.h +47 -0
- data/ext/mongory_ext/mongory-core/src/matchers/base_matcher.c +161 -0
- data/ext/mongory_ext/mongory-core/src/matchers/base_matcher.h +115 -0
- data/ext/mongory_ext/mongory-core/src/matchers/compare_matcher.c +210 -0
- data/ext/mongory_ext/mongory-core/src/matchers/compare_matcher.h +83 -0
- data/ext/mongory_ext/mongory-core/src/matchers/composite_matcher.c +539 -0
- data/ext/mongory_ext/mongory-core/src/matchers/composite_matcher.h +125 -0
- data/ext/mongory_ext/mongory-core/src/matchers/existance_matcher.c +144 -0
- data/ext/mongory_ext/mongory-core/src/matchers/existance_matcher.h +48 -0
- data/ext/mongory_ext/mongory-core/src/matchers/external_matcher.c +121 -0
- data/ext/mongory_ext/mongory-core/src/matchers/external_matcher.h +46 -0
- data/ext/mongory_ext/mongory-core/src/matchers/inclusion_matcher.c +199 -0
- data/ext/mongory_ext/mongory-core/src/matchers/inclusion_matcher.h +46 -0
- data/ext/mongory_ext/mongory-core/src/matchers/literal_matcher.c +334 -0
- data/ext/mongory_ext/mongory-core/src/matchers/literal_matcher.h +97 -0
- data/ext/mongory_ext/mongory-core/src/matchers/matcher.c +198 -0
- data/ext/mongory_ext/mongory-core/src/matchers/matcher_explainable.c +107 -0
- data/ext/mongory_ext/mongory-core/src/matchers/matcher_explainable.h +50 -0
- data/ext/mongory_ext/mongory-core/src/matchers/matcher_traversable.c +55 -0
- data/ext/mongory_ext/mongory-core/src/matchers/matcher_traversable.h +23 -0
- data/ext/mongory_ext/mongory_ext.c +635 -0
- data/lib/mongory/c_query_builder.rb +44 -0
- data/lib/mongory/query_builder.rb +8 -0
- data/lib/mongory/utils/context.rb +7 -0
- data/lib/mongory/version.rb +1 -1
- data/lib/mongory.rb +7 -0
- data/mongory.gemspec +10 -4
- data/scripts/build_with_core.sh +292 -0
- metadata +69 -4
data/examples/benchmark.rb
CHANGED
@@ -8,12 +8,12 @@ Mongory.register(Array)
|
|
8
8
|
Mongory.enable_symbol_snippets!
|
9
9
|
|
10
10
|
def gc_handler
|
11
|
-
|
11
|
+
GC.disable
|
12
12
|
before = GC.stat
|
13
13
|
yield
|
14
|
+
GC.start
|
14
15
|
after = GC.stat
|
15
|
-
|
16
|
-
|
16
|
+
GC.enable
|
17
17
|
created = after[:total_allocated_objects] - before[:total_allocated_objects]
|
18
18
|
freed = after[:total_freed_objects] - before[:total_freed_objects]
|
19
19
|
alive = after[:heap_live_slots] - before[:heap_live_slots]
|
@@ -29,17 +29,18 @@ end
|
|
29
29
|
# Generate test data
|
30
30
|
records = (1..size).map do |_|
|
31
31
|
{
|
32
|
-
'age' => rand(1..100),
|
32
|
+
'age' => [nil, rand(1..100)].sample,
|
33
33
|
'status' => ['active', 'inactive'].sample
|
34
34
|
}
|
35
35
|
end
|
36
36
|
|
37
|
+
count_of_simple_query = records.count { |r| r['age'].is_a?(Numeric) && r['age'] >= 18 }
|
37
38
|
# Simple query (Plain Ruby) test
|
38
39
|
puts "\nSimple query (Plain Ruby) (#{size} records):"
|
39
40
|
gc_handler do
|
40
41
|
5.times do
|
41
42
|
result = Benchmark.measure do
|
42
|
-
records.select { |r| r.
|
43
|
+
records.select { |r| r['age'].is_a?(Numeric) && r['age'] >= 18 }
|
43
44
|
end
|
44
45
|
puts result
|
45
46
|
end
|
@@ -48,12 +49,40 @@ end
|
|
48
49
|
# Simple query (Mongory) test
|
49
50
|
puts "\nSimple query (Mongory) (#{size} records):"
|
50
51
|
gc_handler do
|
52
|
+
builder = records.mongory.where(:age.gte => 18)
|
53
|
+
5.times do
|
54
|
+
result = Benchmark.measure do
|
55
|
+
builder.to_a
|
56
|
+
end
|
57
|
+
puts result
|
58
|
+
end
|
59
|
+
raise "count mismatch" if builder.to_a.count != count_of_simple_query
|
60
|
+
end
|
61
|
+
|
62
|
+
# Simple query (Mongory::CMatcher) test
|
63
|
+
puts "\nSimple query (Mongory::CMatcher) (#{size} records):"
|
64
|
+
gc_handler do
|
65
|
+
matcher = Mongory::CMatcher.new(:age.gte => 18)
|
51
66
|
5.times do
|
52
67
|
result = Benchmark.measure do
|
53
|
-
records.
|
68
|
+
records.select { |r| matcher.match?(r) }
|
54
69
|
end
|
55
70
|
puts result
|
56
71
|
end
|
72
|
+
raise "count mismatch" if records.count { |r| matcher.match?(r) } != count_of_simple_query
|
73
|
+
end
|
74
|
+
|
75
|
+
# Simple query (Mongory::CQueryBuilder) test
|
76
|
+
puts "\nSimple query (Mongory::CQueryBuilder) (#{size} records):"
|
77
|
+
gc_handler do
|
78
|
+
builder = Mongory::CQueryBuilder.new(records).where(:age.gte => 18)
|
79
|
+
5.times do
|
80
|
+
result = Benchmark.measure do
|
81
|
+
builder.to_a
|
82
|
+
end
|
83
|
+
puts result
|
84
|
+
end
|
85
|
+
raise "count mismatch" if builder.count != count_of_simple_query
|
57
86
|
end
|
58
87
|
|
59
88
|
# Complex query (Plain Ruby) test
|
@@ -64,42 +93,92 @@ end
|
|
64
93
|
records.select do |r|
|
65
94
|
next false unless r.key?('age') && r.key?('status')
|
66
95
|
|
67
|
-
r['age'] >= 18 ||
|
96
|
+
r['age'].is_a?(Numeric) && r['age'] >= 18 || r['status'] == 'active'
|
68
97
|
end
|
69
98
|
end
|
70
99
|
puts result
|
71
100
|
end
|
72
101
|
end
|
73
102
|
|
103
|
+
count_of_complex_query = records.count do |r|
|
104
|
+
r.key?('age') && r.key?('status') && (r['age'].is_a?(Numeric) && r['age'] >= 18 || r['status'] == 'active')
|
105
|
+
end
|
106
|
+
|
74
107
|
# Complex query (Mongory) test
|
75
108
|
puts "\nComplex query (Mongory) (#{size} records):"
|
76
109
|
gc_handler do
|
110
|
+
builder = records.mongory.or(
|
111
|
+
{ :age.gte => 18 },
|
112
|
+
{ status: 'active' }
|
113
|
+
)
|
77
114
|
5.times do
|
78
115
|
result = Benchmark.measure do
|
79
|
-
|
80
|
-
:$or => [
|
81
|
-
{ :age.gte => 18 },
|
82
|
-
{ status: 'active' }
|
83
|
-
]
|
84
|
-
).to_a
|
116
|
+
builder.to_a
|
85
117
|
end
|
86
118
|
puts result
|
87
119
|
end
|
120
|
+
raise "count mismatch" if builder.count != count_of_complex_query
|
88
121
|
end
|
89
122
|
|
90
123
|
# Complex query (Mongory) test
|
91
124
|
puts "\nComplex query (Mongory) fast mode (#{size} records):"
|
92
125
|
gc_handler do
|
126
|
+
builder = records.mongory.or(
|
127
|
+
{ :age.gte => 18 },
|
128
|
+
{ status: 'active' }
|
129
|
+
).fast
|
93
130
|
5.times do
|
94
131
|
result = Benchmark.measure do
|
95
|
-
|
96
|
-
:$or => [
|
97
|
-
{ :age.gte => 18 },
|
98
|
-
{ status: 'active' }
|
99
|
-
]
|
100
|
-
).fast.to_a
|
132
|
+
builder.to_a
|
101
133
|
end
|
102
134
|
puts result
|
103
135
|
end
|
136
|
+
raise "count mismatch" if builder.count != count_of_complex_query
|
137
|
+
end
|
138
|
+
|
139
|
+
puts "\nComplex query (Mongory) use CMatcher (#{size} records):"
|
140
|
+
gc_handler do
|
141
|
+
matcher = Mongory::CMatcher.new(
|
142
|
+
'$or' => [
|
143
|
+
{ :age.gte => 18 },
|
144
|
+
{ status: 'active' }
|
145
|
+
]
|
146
|
+
)
|
147
|
+
5.times do
|
148
|
+
result = Benchmark.measure do
|
149
|
+
records.select { |r| matcher.match?(r) }
|
150
|
+
end
|
151
|
+
puts result
|
152
|
+
end
|
153
|
+
raise "count mismatch" if records.count { |r| matcher.match?(r) } != count_of_complex_query
|
154
|
+
end
|
155
|
+
|
156
|
+
puts "\nComplex query (Mongory) use CQueryBuilder (#{size} records):"
|
157
|
+
gc_handler do
|
158
|
+
builder = records.mongory.c.or(
|
159
|
+
{ :age.gte => 18 },
|
160
|
+
{ status: 'active' }
|
161
|
+
)
|
162
|
+
5.times do
|
163
|
+
result = Benchmark.measure do
|
164
|
+
builder.to_a
|
165
|
+
end
|
166
|
+
puts result
|
167
|
+
end
|
168
|
+
raise "count mismatch" if builder.count != count_of_complex_query
|
169
|
+
end
|
170
|
+
|
171
|
+
puts "\nTest Mongory::CMatcher#trace"
|
172
|
+
matcher = Mongory::CMatcher.new(
|
173
|
+
'$or' => [
|
174
|
+
{ :age.gte => 18 },
|
175
|
+
{ status: 'active' }
|
176
|
+
]
|
177
|
+
)
|
178
|
+
# matcher.enable_trace
|
179
|
+
records.sample(30).each do |r|
|
180
|
+
matcher.trace(r)
|
104
181
|
end
|
182
|
+
# matcher.print_trace
|
183
|
+
# matcher.disable_trace
|
105
184
|
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# rubocop:disable Style/GlobalVars
|
4
|
+
|
5
|
+
require 'mkmf'
|
6
|
+
require 'rbconfig'
|
7
|
+
|
8
|
+
# Set the path to mongory-core
|
9
|
+
core_dir = File.expand_path('mongory-core', __dir__)
|
10
|
+
core_src_dir = File.join(core_dir, 'src')
|
11
|
+
core_include_dir = File.join(core_dir, 'include')
|
12
|
+
|
13
|
+
# Check if mongory-core submodule exists
|
14
|
+
unless Dir.exist?(core_dir)
|
15
|
+
puts "Error: mongory-core submodule not found at #{core_dir}"
|
16
|
+
puts 'Please run: git submodule update --init --recursive'
|
17
|
+
exit 1
|
18
|
+
end
|
19
|
+
|
20
|
+
# mongory-rb does not require cJSON; only mongory-core's tests use it, so we don't check cJSON here
|
21
|
+
|
22
|
+
# Normalize compiler flags across GCC/Clang on CI (Ruby 2.6 on Ubuntu may inject clang-only warn flags)
|
23
|
+
def scrub_flags_from_config!(keys, patterns)
|
24
|
+
[RbConfig::CONFIG, RbConfig::MAKEFILE_CONFIG].uniq.each do |cfg|
|
25
|
+
keys.each do |k|
|
26
|
+
next unless cfg[k]
|
27
|
+
|
28
|
+
patterns.each do |pat|
|
29
|
+
cfg[k] = cfg[k].gsub(/\b#{Regexp.escape(pat)}\b/, '')
|
30
|
+
end
|
31
|
+
cfg[k] = cfg[k].squeeze(' ').strip
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
gcc_like = RbConfig::CONFIG['GCC'] == 'yes' || RbConfig::CONFIG['CC'].to_s =~ /(gcc|cc)/
|
37
|
+
if gcc_like
|
38
|
+
scrub_flags_from_config!(%w(warnflags cflags optflags debugflags), [
|
39
|
+
'-Wno-self-assign',
|
40
|
+
'-Wno-parentheses-equality',
|
41
|
+
'-Wno-constant-logical-operand'
|
42
|
+
])
|
43
|
+
end
|
44
|
+
|
45
|
+
# Add include paths
|
46
|
+
$INCFLAGS << " -I#{core_include_dir}"
|
47
|
+
|
48
|
+
# Collect source files to compile directly into the extension
|
49
|
+
foundations_src = Dir.glob(File.join(core_src_dir, 'foundations', '*.c'))
|
50
|
+
matchers_src = Dir.glob(File.join(core_src_dir, 'matchers', '*.c'))
|
51
|
+
|
52
|
+
$CFLAGS << ' -std=c99 -Wall -Wextra -Wno-incompatible-pointer-types -Wno-int-conversion'
|
53
|
+
# Silence C90-style warnings on older GCC when standard flags are not fully applied by toolchains
|
54
|
+
$CFLAGS << ' -Wno-declaration-after-statement -Wno-discarded-qualifiers'
|
55
|
+
$CFLAGS << ' -O2' unless ENV['DEBUG']
|
56
|
+
$CFLAGS << ' -g -O0 -DDEBUG' if ENV['DEBUG']
|
57
|
+
|
58
|
+
# Let mkmf generate rules by listing all sources and corresponding objects
|
59
|
+
$INCFLAGS << ' -I.'
|
60
|
+
$INCFLAGS << " -I#{File.join(core_src_dir, 'foundations')}"
|
61
|
+
$INCFLAGS << " -I#{File.join(core_src_dir, 'matchers')}"
|
62
|
+
all_sources = ['mongory_ext.c'] + foundations_src + matchers_src
|
63
|
+
$srcs = all_sources
|
64
|
+
$objs = all_sources.map { |src| "#{File.basename(src, '.c')}.o" }
|
65
|
+
|
66
|
+
# Generate Makefile
|
67
|
+
create_makefile('mongory_ext')
|
68
|
+
|
69
|
+
puts 'extconf.rb completed successfully'
|
70
|
+
puts "Found #{foundations_src.length} foundation sources"
|
71
|
+
puts "Found #{matchers_src.length} matcher sources"
|
72
|
+
puts "Use 'make' to build the extension"
|
73
|
+
|
74
|
+
# Append Makefile rules: explicit compilation rules for submodule sources to avoid copying/linking files
|
75
|
+
mk = File.read('Makefile')
|
76
|
+
|
77
|
+
# rubocop:disable Layout/HeredocIndentation
|
78
|
+
rules = +"\n# --- custom rules for mongory-core submodule sources ---\n"
|
79
|
+
(foundations_src + matchers_src).each do |src|
|
80
|
+
obj = "#{File.basename(src, '.c')}.o"
|
81
|
+
rules << <<~MAKE
|
82
|
+
#{obj}: #{src}
|
83
|
+
$(ECHO) compiling $<
|
84
|
+
$(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
|
85
|
+
|
86
|
+
MAKE
|
87
|
+
end
|
88
|
+
|
89
|
+
File.write('Makefile', mk + rules)
|
90
|
+
# rubocop:enable Layout/HeredocIndentation
|
91
|
+
# rubocop:enable Style/GlobalVars
|
@@ -0,0 +1,105 @@
|
|
1
|
+
#ifndef MONGORY_ARRAY
|
2
|
+
#define MONGORY_ARRAY
|
3
|
+
|
4
|
+
/**
|
5
|
+
* @file array.h
|
6
|
+
* @brief Defines the mongory_array structure and its associated operations.
|
7
|
+
*
|
8
|
+
* mongory_array is a dynamic array implementation that stores mongory_value
|
9
|
+
* pointers. It handles its own memory management for the array storage using a
|
10
|
+
* provided mongory_memory_pool. The array can grow automatically as new
|
11
|
+
* elements are added.
|
12
|
+
*/
|
13
|
+
|
14
|
+
#include "mongory-core/foundations/memory_pool.h"
|
15
|
+
#include "mongory-core/foundations/value.h"
|
16
|
+
#include <stdbool.h>
|
17
|
+
|
18
|
+
/**
|
19
|
+
* @brief Forward declaration for the mongory_array structure.
|
20
|
+
*/
|
21
|
+
typedef struct mongory_array mongory_array;
|
22
|
+
|
23
|
+
/**
|
24
|
+
* @brief Callback function type used by mongory_array_each_func.
|
25
|
+
*
|
26
|
+
* This function is called for each item in the array during an iteration.
|
27
|
+
*
|
28
|
+
* @param item A pointer to the current mongory_value item in the array.
|
29
|
+
* @param acc An accumulator or context pointer passed through the iteration.
|
30
|
+
* @return bool Return true to continue iteration, false to stop.
|
31
|
+
*/
|
32
|
+
typedef bool (*mongory_array_callback_func)(mongory_value *item, void *acc);
|
33
|
+
|
34
|
+
/**
|
35
|
+
* @brief Function pointer type for iterating over the array.
|
36
|
+
* @param self A pointer to the mongory_array instance.
|
37
|
+
* @param acc An accumulator or context pointer to be passed to the callback.
|
38
|
+
* @param func The callback function to be executed for each item.
|
39
|
+
* @return bool Returns true if the iteration completed fully, false if it was
|
40
|
+
* stopped by a callback.
|
41
|
+
*/
|
42
|
+
typedef bool (*mongory_array_each_func)(mongory_array *self, void *acc, mongory_array_callback_func func);
|
43
|
+
|
44
|
+
/**
|
45
|
+
* @brief Function pointer type for adding an element to the end of the array.
|
46
|
+
* @param self A pointer to the mongory_array instance.
|
47
|
+
* @param value A pointer to the mongory_value to add.
|
48
|
+
* @return bool Returns true if the value was successfully added, false
|
49
|
+
* otherwise (e.g., memory allocation failure).
|
50
|
+
*/
|
51
|
+
typedef bool (*mongory_array_push_func)(mongory_array *self, mongory_value *value);
|
52
|
+
|
53
|
+
/**
|
54
|
+
* @brief Function pointer type for retrieving an element at a specific index.
|
55
|
+
* @param self A pointer to the mongory_array instance.
|
56
|
+
* @param index The index of the element to retrieve.
|
57
|
+
* @return mongory_value* A pointer to the mongory_value at the given index, or
|
58
|
+
* NULL if the index is out of bounds.
|
59
|
+
*/
|
60
|
+
typedef mongory_value *(*mongory_array_get_func)(mongory_array *self, size_t index);
|
61
|
+
|
62
|
+
/**
|
63
|
+
* @brief Function pointer type for setting or replacing an element at a
|
64
|
+
* specific index.
|
65
|
+
*
|
66
|
+
* If the index is beyond the current count, the array will be grown, and
|
67
|
+
* intermediate elements will be initialized to NULL.
|
68
|
+
*
|
69
|
+
* @param self A pointer to the mongory_array instance.
|
70
|
+
* @param index The index at which to set the value.
|
71
|
+
* @param value A pointer to the mongory_value to set.
|
72
|
+
* @return bool Returns true if the value was successfully set, false otherwise
|
73
|
+
* (e.g., memory allocation failure).
|
74
|
+
*/
|
75
|
+
typedef bool (*mongory_array_set_func)(mongory_array *self, size_t index, mongory_value *value);
|
76
|
+
|
77
|
+
/**
|
78
|
+
* @brief Creates a new mongory_array instance.
|
79
|
+
*
|
80
|
+
* The array is initialized with a default capacity and will use the provided
|
81
|
+
* memory pool for all its internal allocations related to storing elements.
|
82
|
+
*
|
83
|
+
* @param pool A pointer to the mongory_memory_pool to be used for allocations.
|
84
|
+
* @return mongory_array* A pointer to the newly created mongory_array, or NULL
|
85
|
+
* if creation fails (e.g., memory allocation failure).
|
86
|
+
*/
|
87
|
+
mongory_array *mongory_array_new(mongory_memory_pool *pool);
|
88
|
+
|
89
|
+
/**
|
90
|
+
* @struct mongory_array
|
91
|
+
* @brief Represents a dynamic array of mongory_value pointers.
|
92
|
+
*
|
93
|
+
* This structure provides function pointers for common array operations,
|
94
|
+
* allowing for a somewhat object-oriented interface in C.
|
95
|
+
*/
|
96
|
+
struct mongory_array {
|
97
|
+
size_t count; /**< The current number of elements in the array. */
|
98
|
+
mongory_memory_pool *pool; /**< The memory pool used for allocations. */
|
99
|
+
mongory_array_each_func each; /**< Function to iterate over elements in the array. */
|
100
|
+
mongory_array_push_func push; /**< Function to add an element to the end of the array. */
|
101
|
+
mongory_array_get_func get; /**< Function to retrieve an element by index. */
|
102
|
+
mongory_array_set_func set; /**< Function to set or replace an element at an index. */
|
103
|
+
};
|
104
|
+
|
105
|
+
#endif /* MONGORY_ARRAY */
|
@@ -0,0 +1,206 @@
|
|
1
|
+
#ifndef MONGORY_FOUNDATIONS_CONFIG_H
|
2
|
+
#define MONGORY_FOUNDATIONS_CONFIG_H
|
3
|
+
|
4
|
+
/**
|
5
|
+
* @file config.h
|
6
|
+
* @brief Defines global configuration functions and types for the Mongory
|
7
|
+
* library.
|
8
|
+
*
|
9
|
+
* This includes initialization and cleanup routines, as well as functions
|
10
|
+
* for setting up custom behaviors like regex matching and value conversion.
|
11
|
+
* It also provides a string copying utility that uses the library's memory
|
12
|
+
* pool.
|
13
|
+
*/
|
14
|
+
|
15
|
+
#include "mongory-core/foundations/memory_pool.h"
|
16
|
+
#include "mongory-core/foundations/value.h"
|
17
|
+
#include <stdbool.h>
|
18
|
+
|
19
|
+
/**
|
20
|
+
* @brief Function pointer type for custom regex matching.
|
21
|
+
*
|
22
|
+
* This function is called when a regex match is required.
|
23
|
+
*
|
24
|
+
* @param pool The memory pool to use for any allocations during the match.
|
25
|
+
* @param pattern The regex pattern (as a mongory_value, typically a string or
|
26
|
+
* regex type).
|
27
|
+
* @param value The value to match against (as a mongory_value, typically a
|
28
|
+
* string).
|
29
|
+
* @return bool True if the value matches the pattern, false otherwise.
|
30
|
+
*/
|
31
|
+
typedef bool (*mongory_regex_func)(mongory_memory_pool *pool, mongory_value *pattern, mongory_value *value);
|
32
|
+
|
33
|
+
/**
|
34
|
+
* @brief Function pointer type for stringifying a regex pattern.
|
35
|
+
*
|
36
|
+
* This function is called when a regex pattern needs to be stringified.
|
37
|
+
*
|
38
|
+
* @param pool The memory pool to use for any allocations during the
|
39
|
+
* stringification.
|
40
|
+
* @param pattern The regex pattern (as a mongory_value, typically a string or
|
41
|
+
* regex type).
|
42
|
+
* @return char* A stringified representation of the regex pattern, or NULL on failure.
|
43
|
+
*/
|
44
|
+
typedef char* (*mongory_regex_stringify_func)(mongory_memory_pool *pool, mongory_value *pattern);
|
45
|
+
|
46
|
+
/**
|
47
|
+
* @brief Function pointer type for deep conversion of an external value to a
|
48
|
+
* mongory_value.
|
49
|
+
*
|
50
|
+
* "Deep" implies that if the external value is a complex type (e.g., a struct
|
51
|
+
* representing a document or array), its contents should also be converted.
|
52
|
+
*
|
53
|
+
* @param pool The memory pool to use for allocating the new mongory_value and
|
54
|
+
* its data.
|
55
|
+
* @param value A pointer to the external value to convert.
|
56
|
+
* @return mongory_value* A new mongory_value representing the converted data,
|
57
|
+
* or NULL on failure.
|
58
|
+
*/
|
59
|
+
typedef mongory_value *(*mongory_deep_convert_func)(mongory_memory_pool *pool, void *value);
|
60
|
+
|
61
|
+
/**
|
62
|
+
* @brief Function pointer type for shallow conversion of an external value to a
|
63
|
+
* mongory_value.
|
64
|
+
*
|
65
|
+
* "Shallow" implies that if the external value is complex, only a wrapper or
|
66
|
+
* pointer might be stored in the mongory_value, without deeply converting its
|
67
|
+
* contents.
|
68
|
+
*
|
69
|
+
* @param pool The memory pool to use for allocating the new mongory_value.
|
70
|
+
* @param value A pointer to the external value to convert.
|
71
|
+
* @return mongory_value* A new mongory_value, or NULL on failure.
|
72
|
+
*/
|
73
|
+
typedef mongory_value *(*mongory_shallow_convert_func)(mongory_memory_pool *pool, void *value);
|
74
|
+
|
75
|
+
/**
|
76
|
+
* @brief Function pointer type for recovering an external value from a
|
77
|
+
* mongory_value.
|
78
|
+
*
|
79
|
+
* This is the reverse of a conversion, intended to get back the original
|
80
|
+
* external data representation if it was stored or wrapped.
|
81
|
+
*
|
82
|
+
* @param pool The memory pool (can be used if recovery involves allocation,
|
83
|
+
* though often it might just retrieve a stored pointer).
|
84
|
+
* @param value The mongory_value from which to recover the external data.
|
85
|
+
* @return void* A pointer to the recovered external value, or NULL if not
|
86
|
+
* possible.
|
87
|
+
*/
|
88
|
+
typedef void *(*mongory_recover_func)(mongory_memory_pool *pool, mongory_value *value);
|
89
|
+
|
90
|
+
/**
|
91
|
+
* @brief Initializes the Mongory library.
|
92
|
+
*
|
93
|
+
* Sets up internal structures, including the global memory pool,
|
94
|
+
* regex adapter, matcher mapping, and value converter. This function
|
95
|
+
* should be called before any other Mongory library functions are used.
|
96
|
+
* It also registers the default set of matchers (e.g., $in, $eq).
|
97
|
+
*/
|
98
|
+
void mongory_init();
|
99
|
+
|
100
|
+
/**
|
101
|
+
* @brief Cleans up resources used by the Mongory library.
|
102
|
+
*
|
103
|
+
* Frees the internal memory pool and resets global pointers. This should
|
104
|
+
* be called when the library is no longer needed to prevent memory leaks.
|
105
|
+
*/
|
106
|
+
void mongory_cleanup();
|
107
|
+
|
108
|
+
/**
|
109
|
+
* @brief Sets the custom regex matching function.
|
110
|
+
*
|
111
|
+
* If not called, a default function that always returns false is used.
|
112
|
+
*
|
113
|
+
* @param func The custom regex function to use.
|
114
|
+
*/
|
115
|
+
void mongory_regex_func_set(mongory_regex_func func);
|
116
|
+
|
117
|
+
/**
|
118
|
+
* @brief Sets the custom regex stringify function.
|
119
|
+
*
|
120
|
+
* If not called, a default function that always returns NULL is used.
|
121
|
+
*
|
122
|
+
* @param func The custom regex stringify function to use.
|
123
|
+
*/
|
124
|
+
void mongory_regex_stringify_func_set(mongory_regex_stringify_func func);
|
125
|
+
|
126
|
+
/**
|
127
|
+
* @brief Sets the custom deep value conversion function.
|
128
|
+
* @param deep_convert The function to use for deep conversions.
|
129
|
+
*/
|
130
|
+
void mongory_value_converter_deep_convert_set(mongory_deep_convert_func deep_convert);
|
131
|
+
|
132
|
+
/**
|
133
|
+
* @brief Sets the custom shallow value conversion function.
|
134
|
+
* @param shallow_convert The function to use for shallow conversions.
|
135
|
+
*/
|
136
|
+
void mongory_value_converter_shallow_convert_set(mongory_shallow_convert_func shallow_convert);
|
137
|
+
|
138
|
+
/**
|
139
|
+
* @brief Sets the custom value recovery function.
|
140
|
+
* @param recover The function to use for recovering external values.
|
141
|
+
*/
|
142
|
+
void mongory_value_converter_recover_set(mongory_recover_func recover);
|
143
|
+
|
144
|
+
/**
|
145
|
+
* @brief Function pointer type for matching a value against an external matcher.
|
146
|
+
* @param external_matcher The external reference to the matcher.
|
147
|
+
* @param value The value to match against.
|
148
|
+
* @return bool True if the value matches the matcher, false otherwise.
|
149
|
+
*/
|
150
|
+
typedef struct mongory_matcher_custom_context {
|
151
|
+
char *name; // Name of the custom matcher.
|
152
|
+
void *external_matcher; // External reference to the custom matcher.
|
153
|
+
} mongory_matcher_custom_context;
|
154
|
+
|
155
|
+
/**
|
156
|
+
* @brief Function pointer type for matching a value against an external matcher.
|
157
|
+
*
|
158
|
+
* This function is called when a value needs to be matched against an external
|
159
|
+
* matcher.
|
160
|
+
*
|
161
|
+
* @param external_matcher The external reference to the matcher.
|
162
|
+
* @param value The value to match against.
|
163
|
+
* @return bool True if the value matches the matcher, false otherwise.
|
164
|
+
*/
|
165
|
+
typedef struct mongory_matcher_custom_adapter {
|
166
|
+
bool (*match)(void *external_matcher, mongory_value *value); // Match a value against an external matcher.
|
167
|
+
mongory_matcher_custom_context *(*build)(char *key, mongory_value *condition, void *extern_ctx); // Build an external matcher reference.
|
168
|
+
bool (*lookup)(char *key); // Lookup a matcher reference by key.
|
169
|
+
} mongory_matcher_custom_adapter;
|
170
|
+
|
171
|
+
extern mongory_matcher_custom_adapter *mongory_custom_matcher_adapter;
|
172
|
+
|
173
|
+
void mongory_custom_matcher_match_func_set(bool (*match)(void *external_matcher, mongory_value *value));
|
174
|
+
void mongory_custom_matcher_build_func_set(mongory_matcher_custom_context *(*build)(char *key, mongory_value *condition, void *extern_ctx));
|
175
|
+
void mongory_custom_matcher_lookup_func_set(bool (*lookup)(char *key));
|
176
|
+
|
177
|
+
/**
|
178
|
+
* @brief Copies a string using the Mongory library's memory pool.
|
179
|
+
*
|
180
|
+
* Allocates memory from the given pool and copies the source string into it.
|
181
|
+
* The returned string is null-terminated.
|
182
|
+
*
|
183
|
+
* @param pool The memory pool to use for allocating the new string.
|
184
|
+
* @param str The source string to copy. If NULL, returns NULL.
|
185
|
+
* @return char* A pointer to the newly allocated and copied string, or NULL
|
186
|
+
* if allocation fails or str is NULL. The caller does not own this memory
|
187
|
+
* directly; it will be freed when the pool is freed.
|
188
|
+
*/
|
189
|
+
char *mongory_string_cpy(mongory_memory_pool *pool, char *str);
|
190
|
+
|
191
|
+
/**
|
192
|
+
* @brief Copies a formatted string using the Mongory library's memory pool.
|
193
|
+
*
|
194
|
+
* Allocates memory from the given pool and copies the formatted string into it.
|
195
|
+
* The returned string is null-terminated.
|
196
|
+
*
|
197
|
+
* @param pool The memory pool to use for allocating the new string.
|
198
|
+
* @param format The format string to copy.
|
199
|
+
* @param ... The arguments to be formatted into the string.
|
200
|
+
* @return char* A pointer to the newly allocated and copied string, or NULL
|
201
|
+
* if allocation fails or format is NULL. The caller does not own this memory
|
202
|
+
* directly; it will be freed when the pool is freed.
|
203
|
+
*/
|
204
|
+
char *mongory_string_cpyf(mongory_memory_pool *pool, char *format, ...);
|
205
|
+
|
206
|
+
#endif /* MONGORY_FOUNDATIONS_CONFIG_H */
|
@@ -0,0 +1,82 @@
|
|
1
|
+
#ifndef MONGORY_ERROR
|
2
|
+
#define MONGORY_ERROR
|
3
|
+
|
4
|
+
/**
|
5
|
+
* @file error.h
|
6
|
+
* @brief Defines error types and structures for the Mongory library.
|
7
|
+
*
|
8
|
+
* This file provides an enumeration of possible error codes and a structure
|
9
|
+
* for representing error information, typically consisting of an error type
|
10
|
+
* and an associated message.
|
11
|
+
*/
|
12
|
+
|
13
|
+
#include <stdbool.h>
|
14
|
+
|
15
|
+
/**
|
16
|
+
* @def MONGORY_ERROR_TYPE_MAGIC
|
17
|
+
* @brief A magic number used in generating enum values for error types.
|
18
|
+
* Helps in creating somewhat unique integer values for the enums.
|
19
|
+
*/
|
20
|
+
#define MONGORY_ERROR_TYPE_MAGIC 107
|
21
|
+
|
22
|
+
/**
|
23
|
+
* @def MONGORY_ERROR_TYPE_MACRO
|
24
|
+
* @brief X-Macro for defining error types.
|
25
|
+
* This macro allows defining the error enum, string conversion, etc.,
|
26
|
+
* from a single list, promoting consistency.
|
27
|
+
* Each entry takes the enum name, a numeric suffix, and a string description.
|
28
|
+
*/
|
29
|
+
#define MONGORY_ERROR_TYPE_MACRO(_) \
|
30
|
+
_(MONGORY_ERROR_NONE, 10, "No Error") \
|
31
|
+
_(MONGORY_ERROR_MEMORY, 11, "Memory Allocation Error") \
|
32
|
+
_(MONGORY_ERROR_INVALID_TYPE, 12, "Invalid Type Error") \
|
33
|
+
_(MONGORY_ERROR_OUT_OF_BOUNDS, 13, "Out of Bounds Error") \
|
34
|
+
_(MONGORY_ERROR_UNSUPPORTED_OPERATION, 14, "Unsupported Operation Error") \
|
35
|
+
_(MONGORY_ERROR_INVALID_ARGUMENT, 15, "Invalid Argument Error") \
|
36
|
+
_(MONGORY_ERROR_IO, 16, "I/O Error") \
|
37
|
+
_(MONGORY_ERROR_PARSE, 17, "Parse Error") \
|
38
|
+
_(MONGORY_ERROR_UNKNOWN, 99, "Unknown Error")
|
39
|
+
|
40
|
+
/**
|
41
|
+
* @enum mongory_error_type
|
42
|
+
* @brief Enumerates the types of errors that can occur within the Mongory
|
43
|
+
* library. Values are generated using MONGORY_ERROR_TYPE_MACRO and
|
44
|
+
* MONGORY_ERROR_TYPE_MAGIC.
|
45
|
+
*/
|
46
|
+
typedef enum mongory_error_type {
|
47
|
+
#define DEFINE_ERROR_ENUM(name, num, str) name = num * MONGORY_ERROR_TYPE_MAGIC,
|
48
|
+
MONGORY_ERROR_TYPE_MACRO(DEFINE_ERROR_ENUM)
|
49
|
+
#undef DEFINE_ERROR_ENUM
|
50
|
+
} mongory_error_type;
|
51
|
+
|
52
|
+
/**
|
53
|
+
* @brief Converts a mongory_error_type enum to its string representation.
|
54
|
+
*
|
55
|
+
* @param type The error type enum value.
|
56
|
+
* @return const char* A string describing the error type. Returns "Unknown
|
57
|
+
* Error Type" if the type is not recognized.
|
58
|
+
*/
|
59
|
+
const char *mongory_error_type_to_string(enum mongory_error_type type);
|
60
|
+
|
61
|
+
/**
|
62
|
+
* @struct mongory_error
|
63
|
+
* @brief Structure to hold error information.
|
64
|
+
*
|
65
|
+
* Contains the type of error and an optional descriptive message.
|
66
|
+
* The message string is expected to be a literal or have a lifetime
|
67
|
+
* managed elsewhere (e.g., allocated from a memory pool).
|
68
|
+
*/
|
69
|
+
typedef struct mongory_error {
|
70
|
+
mongory_error_type type; /**< The type of the error. */
|
71
|
+
const char *message; /**< A descriptive message for the error. This message
|
72
|
+
might be a string literal or allocated from a
|
73
|
+
memory pool. Its lifetime should be considered
|
74
|
+
carefully. */
|
75
|
+
} mongory_error;
|
76
|
+
|
77
|
+
static mongory_error MONGORY_ALLOC_ERROR = {
|
78
|
+
.type = MONGORY_ERROR_MEMORY,
|
79
|
+
.message = "Memory Allocation Failed",
|
80
|
+
};
|
81
|
+
|
82
|
+
#endif /* MONGORY_ERROR */
|