yeptris 0.6.18.2-arm-linux-eabihf
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 +7 -0
- data/README.adoc +141 -0
- data/ext/build_windows_native.rb +41 -0
- data/ext/libyeptris/extconf.rb +57 -0
- data/ext/yeptris_native/cbor_ruby.c +193 -0
- data/ext/yeptris_native/extconf.rb +47 -0
- data/ext/yeptris_native/json_ruby.c +354 -0
- data/ext/yeptris_native/yeptris_native.c +497 -0
- data/lib/yeptris/cbor.rb +130 -0
- data/lib/yeptris/document.rb +255 -0
- data/lib/yeptris/ffi.rb +426 -0
- data/lib/yeptris/json/descriptor.rb +266 -0
- data/lib/yeptris/json.rb +394 -0
- data/lib/yeptris/materializer.rb +354 -0
- data/lib/yeptris/native-3.4.so +0 -0
- data/lib/yeptris/node.rb +453 -0
- data/lib/yeptris/psych/class_loader.rb +24 -0
- data/lib/yeptris/psych/coder_shim.rb +55 -0
- data/lib/yeptris/psych/drop_in.rb +63 -0
- data/lib/yeptris/psych/encodable.rb +14 -0
- data/lib/yeptris/psych/handler.rb +90 -0
- data/lib/yeptris/psych/parser.rb +105 -0
- data/lib/yeptris/psych/scalar_scanner.rb +149 -0
- data/lib/yeptris/psych/visitors.rb +545 -0
- data/lib/yeptris/psych.rb +622 -0
- data/lib/yeptris/schema.rb +253 -0
- data/lib/yeptris/valueml.rb +455 -0
- data/lib/yeptris/yaml/descriptor.rb +56 -0
- data/lib/yeptris/yaml.rb +422 -0
- data/lib/yeptris.rb +113 -0
- data/libyeptris.so +0 -0
- data/vendor/libyeptris/CMakeLists.txt +254 -0
- data/vendor/libyeptris/cmake/yeptris-config.cmake.in +5 -0
- data/vendor/libyeptris/cmake/yeptris.pc.in +11 -0
- data/vendor/libyeptris/src/CMakeLists.txt +167 -0
- data/vendor/libyeptris/src/include/yeptris/api.h +32 -0
- data/vendor/libyeptris/src/include/yeptris/cbor.h +101 -0
- data/vendor/libyeptris/src/include/yeptris/dom.h +190 -0
- data/vendor/libyeptris/src/include/yeptris/emit.h +81 -0
- data/vendor/libyeptris/src/include/yeptris/error.h +41 -0
- data/vendor/libyeptris/src/include/yeptris/events.h +157 -0
- data/vendor/libyeptris/src/include/yeptris/json.h +45 -0
- data/vendor/libyeptris/src/include/yeptris/json.hpp +258 -0
- data/vendor/libyeptris/src/include/yeptris/jsonc_compat.h +115 -0
- data/vendor/libyeptris/src/include/yeptris/marshal.h +52 -0
- data/vendor/libyeptris/src/include/yeptris/parse.h +48 -0
- data/vendor/libyeptris/src/include/yeptris/plan.h +100 -0
- data/vendor/libyeptris/src/include/yeptris/resolve.h +71 -0
- data/vendor/libyeptris/src/include/yeptris/schema.h +121 -0
- data/vendor/libyeptris/src/include/yeptris/tape.h +123 -0
- data/vendor/libyeptris/src/include/yeptris/types.h +38 -0
- data/vendor/libyeptris/src/include/yeptris/values.h +102 -0
- data/vendor/libyeptris/src/include/yeptris/version.h.in +29 -0
- data/vendor/libyeptris/src/include/yeptris/visit.h +77 -0
- data/vendor/libyeptris/src/include/yeptris/yajl_compat.h +135 -0
- data/vendor/libyeptris/src/include/yeptris.h +23 -0
- data/vendor/libyeptris/src/yeptris/build.c +376 -0
- data/vendor/libyeptris/src/yeptris/cbor/cbor.h +25 -0
- data/vendor/libyeptris/src/yeptris/cbor/decode.c +981 -0
- data/vendor/libyeptris/src/yeptris/cbor/encode.c +835 -0
- data/vendor/libyeptris/src/yeptris/cbor/sink.h +58 -0
- data/vendor/libyeptris/src/yeptris/common/chartype.c +41 -0
- data/vendor/libyeptris/src/yeptris/common/chartype.h +77 -0
- data/vendor/libyeptris/src/yeptris/common/cpu.c +81 -0
- data/vendor/libyeptris/src/yeptris/common/cpu.h +40 -0
- data/vendor/libyeptris/src/yeptris/common/error.c +65 -0
- data/vendor/libyeptris/src/yeptris/common/error.h +79 -0
- data/vendor/libyeptris/src/yeptris/common/mutex.h +45 -0
- data/vendor/libyeptris/src/yeptris/common/nametab.c +275 -0
- data/vendor/libyeptris/src/yeptris/common/nametab.h +68 -0
- data/vendor/libyeptris/src/yeptris/common/port.h +74 -0
- data/vendor/libyeptris/src/yeptris/common/simd_text.c +49 -0
- data/vendor/libyeptris/src/yeptris/common/simd_text.h +295 -0
- data/vendor/libyeptris/src/yeptris/common/simd_text_avx2.c +534 -0
- data/vendor/libyeptris/src/yeptris/common/simd_text_neon.c +662 -0
- data/vendor/libyeptris/src/yeptris/common/simd_text_scalar.c +298 -0
- data/vendor/libyeptris/src/yeptris/common/string_view.c +34 -0
- data/vendor/libyeptris/src/yeptris/common/string_view.h +93 -0
- data/vendor/libyeptris/src/yeptris/doc.h +56 -0
- data/vendor/libyeptris/src/yeptris/dom/dom.c +1192 -0
- data/vendor/libyeptris/src/yeptris/dom/dom.h +312 -0
- data/vendor/libyeptris/src/yeptris/dom/hpool.c +107 -0
- data/vendor/libyeptris/src/yeptris/dom/mapindex.c +173 -0
- data/vendor/libyeptris/src/yeptris/dom/mapindex.h +61 -0
- data/vendor/libyeptris/src/yeptris/dom/mutate.c +431 -0
- data/vendor/libyeptris/src/yeptris/emit/emit.c +434 -0
- data/vendor/libyeptris/src/yeptris/emit/float/api.h +38 -0
- data/vendor/libyeptris/src/yeptris/emit/float/dragon.c +405 -0
- data/vendor/libyeptris/src/yeptris/emit/float/floatint.h +231 -0
- data/vendor/libyeptris/src/yeptris/emit/float/print.c +396 -0
- data/vendor/libyeptris/src/yeptris/emit/style.c +81 -0
- data/vendor/libyeptris/src/yeptris/emit/style.h +24 -0
- data/vendor/libyeptris/src/yeptris/emit/writer.c +816 -0
- data/vendor/libyeptris/src/yeptris/emit/writer.h +76 -0
- data/vendor/libyeptris/src/yeptris/encoding/bom.c +31 -0
- data/vendor/libyeptris/src/yeptris/encoding/encoding.h +63 -0
- data/vendor/libyeptris/src/yeptris/encoding/transcode.c +148 -0
- data/vendor/libyeptris/src/yeptris/encoding/utf8_validate.c +178 -0
- data/vendor/libyeptris/src/yeptris/events/capture.c +150 -0
- data/vendor/libyeptris/src/yeptris/events/capture.h +39 -0
- data/vendor/libyeptris/src/yeptris/events/iterparse.c +208 -0
- data/vendor/libyeptris/src/yeptris/events/pull.c +97 -0
- data/vendor/libyeptris/src/yeptris/events/push.c +104 -0
- data/vendor/libyeptris/src/yeptris/events/recorder.c +107 -0
- data/vendor/libyeptris/src/yeptris/events/values.c +527 -0
- data/vendor/libyeptris/src/yeptris/events/values_priv.h +51 -0
- data/vendor/libyeptris/src/yeptris/events/yaml_compat.c +86 -0
- data/vendor/libyeptris/src/yeptris/events/yaml_compat.h +90 -0
- data/vendor/libyeptris/src/yeptris/jsonapi/jsonc_compat.c +687 -0
- data/vendor/libyeptris/src/yeptris/jsonapi/yajl_compat.c +728 -0
- data/vendor/libyeptris/src/yeptris/marshal.c +782 -0
- data/vendor/libyeptris/src/yeptris/memory/allocator.c +20 -0
- data/vendor/libyeptris/src/yeptris/memory/allocator.h +43 -0
- data/vendor/libyeptris/src/yeptris/memory/arena.c +134 -0
- data/vendor/libyeptris/src/yeptris/memory/arena.h +52 -0
- data/vendor/libyeptris/src/yeptris/memory/pool.c +122 -0
- data/vendor/libyeptris/src/yeptris/memory/pool.h +36 -0
- data/vendor/libyeptris/src/yeptris/parse/engine.c +3698 -0
- data/vendor/libyeptris/src/yeptris/parse/engine.h +65 -0
- data/vendor/libyeptris/src/yeptris/parse/events.h +124 -0
- data/vendor/libyeptris/src/yeptris/parse/numbers.c +349 -0
- data/vendor/libyeptris/src/yeptris/parse/numbers.h +33 -0
- data/vendor/libyeptris/src/yeptris/parse/scalars.c +416 -0
- data/vendor/libyeptris/src/yeptris/parse/scalars.h +75 -0
- data/vendor/libyeptris/src/yeptris/parse.c +737 -0
- data/vendor/libyeptris/src/yeptris/plan.c +824 -0
- data/vendor/libyeptris/src/yeptris/resolve/compat11.c +334 -0
- data/vendor/libyeptris/src/yeptris/resolve/core12.c +143 -0
- data/vendor/libyeptris/src/yeptris/resolve/resolver.h +56 -0
- data/vendor/libyeptris/src/yeptris/resolve/tags.c +58 -0
- data/vendor/libyeptris/src/yeptris/scan/json.c +792 -0
- data/vendor/libyeptris/src/yeptris/scan/json.h +109 -0
- data/vendor/libyeptris/src/yeptris/scan/scan.c +463 -0
- data/vendor/libyeptris/src/yeptris/scan/scan.h +150 -0
- data/vendor/libyeptris/src/yeptris/schema.c +308 -0
- data/vendor/libyeptris/src/yeptris/tape.c +1308 -0
- data/vendor/libyeptris/src/yeptris/tape_in.h +19 -0
- data/vendor/libyeptris/src/yeptris/version.c +7 -0
- data/vendor/libyeptris/src/yeptris/visit/dom_visit.c +115 -0
- data/vendor/libyeptris/src/yeptris/visit/json_visit.c +293 -0
- data/vendor/libyeptris/src/yeptris/visit/yaml_visit.c +127 -0
- metadata +199 -0
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
/* dom.h — minimal event-built DOM (TODO.impl/11 v1).
|
|
2
|
+
*
|
|
3
|
+
* Nodes are dense records in a pool; children are sibling-linked
|
|
4
|
+
* (first_child/last_child/next_sibling) — safe when parent and child
|
|
5
|
+
* collections interleave. Anchors bind to node ids. The builder is a
|
|
6
|
+
* sink over the engine (MECE: the DOM never parses). v1 deviation from
|
|
7
|
+
* the board (recorded there): one dom.c with a kind enum — per-kind
|
|
8
|
+
* vtables land with mutation + emitter integration, where polymorphic
|
|
9
|
+
* behavior actually appears.
|
|
10
|
+
*
|
|
11
|
+
* Lifetime: borrowed event values (from the caller's input) stay views
|
|
12
|
+
* into that input; engine-pool values (folded/escaped) are copied into
|
|
13
|
+
* the DOM's pool. The input buffer must outlive the document.
|
|
14
|
+
*/
|
|
15
|
+
#ifndef YEP_DOM_H
|
|
16
|
+
#define YEP_DOM_H
|
|
17
|
+
|
|
18
|
+
#include <stdint.h>
|
|
19
|
+
|
|
20
|
+
#include <yeptris/api.h> /* YEPTRIS_CT_ASSERT (the layout gates) */
|
|
21
|
+
#include <yeptris/tape.h> /* yeptris_json_tape (dom_from_tape) */ /* YEPTRIS_CT_ASSERT (the layout gates) */
|
|
22
|
+
|
|
23
|
+
#include "../common/simd_text.h"
|
|
24
|
+
|
|
25
|
+
#include "common/nametab.h"
|
|
26
|
+
#include "dom/mapindex.h"
|
|
27
|
+
#include "memory/allocator.h"
|
|
28
|
+
#include "memory/pool.h"
|
|
29
|
+
#include "parse/events.h"
|
|
30
|
+
|
|
31
|
+
#ifdef __cplusplus
|
|
32
|
+
extern "C" {
|
|
33
|
+
#endif
|
|
34
|
+
|
|
35
|
+
typedef enum {
|
|
36
|
+
YEP_DOM_SCALAR = 0,
|
|
37
|
+
YEP_DOM_SEQUENCE,
|
|
38
|
+
YEP_DOM_MAPPING,
|
|
39
|
+
YEP_DOM_ALIAS,
|
|
40
|
+
} yep_dom_kind;
|
|
41
|
+
|
|
42
|
+
#define YEP_DOM_MAX_DEPTH 1000
|
|
43
|
+
|
|
44
|
+
/* Compact node strings: (region-tagged offset, length) instead of
|
|
45
|
+
* pointers — the node drops to <= 64 B (TODO.impl/11's gate). Two
|
|
46
|
+
* regions: the borrowed parse input (offset from its base) and the
|
|
47
|
+
* DOM's own contiguous string arena (offset from its start; the
|
|
48
|
+
* arena grows by realloc, which MOVES bytes but never invalidates
|
|
49
|
+
* OFFSETS — the leptris arena discipline). Absence = len 0. */
|
|
50
|
+
#define YEP_SV_INPUT 0x80000000u /* region bit: 1 = arena, 0 = input */
|
|
51
|
+
#define YEP_SV_OFF 0x7FFFFFFFu /* 31-bit offsets (2 GiB ceiling) */
|
|
52
|
+
|
|
53
|
+
typedef struct yep_sview {
|
|
54
|
+
uint32_t off; /* YEP_SV_INPUT | byte offset into the region */
|
|
55
|
+
uint32_t len;
|
|
56
|
+
} yep_sview;
|
|
57
|
+
|
|
58
|
+
/* Compact header (TODO.restructure/64-2a): kind/style/flow/implicit
|
|
59
|
+
* pack into one bitfield byte. The mutation-only attached/depth
|
|
60
|
+
* fields left the record — they live in the DOM's lazily-built side
|
|
61
|
+
* tables (parse pays nothing; dom.c owns them). */
|
|
62
|
+
typedef struct yep_dnode {
|
|
63
|
+
uint8_t kind : 2; /* yep_dom_kind (0-3) */
|
|
64
|
+
uint8_t style : 3; /* yep_scalar_style (0-5) */
|
|
65
|
+
uint8_t flow : 1; /* collection opened in flow style */
|
|
66
|
+
uint8_t implicit : 1; /* scalar written without quotes/tag */
|
|
67
|
+
uint8_t tag_id; /* resolved tag (resolve/resolver.h) */
|
|
68
|
+
uint32_t first_child; /* child link (mappings: key,value,key,value…) */
|
|
69
|
+
uint32_t last_child;
|
|
70
|
+
uint32_t next_sibling;
|
|
71
|
+
uint32_t count; /* children (mappings: 2 × pairs) */
|
|
72
|
+
uint32_t target; /* alias: target node id */
|
|
73
|
+
yep_sview value; /* scalar content / alias name */
|
|
74
|
+
yep_sview tag;
|
|
75
|
+
yep_sview anchor;
|
|
76
|
+
} yep_dnode; /* 48 B: line/col never left the event stream (64-2c) —
|
|
77
|
+
the pull/push/recorder APIs remain the source */
|
|
78
|
+
|
|
79
|
+
/* 11's node-size gate, tightened by 64-2c: <= 48 B. */
|
|
80
|
+
YEPTRIS_CT_ASSERT(sizeof(yep_dnode) <= 48);
|
|
81
|
+
|
|
82
|
+
typedef struct yep_dom {
|
|
83
|
+
const yep_allocator* sys;
|
|
84
|
+
/* Memory guard (the bounded-parse law): when input_len > 0 (set by
|
|
85
|
+
* the parse seams), every growth path is capped by the input size —
|
|
86
|
+
* a parse over N bytes allocates O(N), so a grammar/loop bug fails
|
|
87
|
+
* YEP_ERR_MEMORY instead of ballooning. The mutation API (no input)
|
|
88
|
+
* leaves it 0 and is uncapped. */
|
|
89
|
+
size_t input_len;
|
|
90
|
+
/* mutation side tables (64-2a): attached bitmap + depths, grown
|
|
91
|
+
* lazily on first mutation — parse-built docs never pay */
|
|
92
|
+
uint8_t* mut_att;
|
|
93
|
+
uint16_t* mut_depth;
|
|
94
|
+
uint32_t mut_tbl_cap;
|
|
95
|
+
/* the strict-JSON route's fused walk (TODO.restructure/81): when
|
|
96
|
+
* set, dom_on_flow_build's walker enforces RFC 8259 keys — the
|
|
97
|
+
* engine's flow path leaves it 0 (the lenient YAML flow class) */
|
|
98
|
+
int flow_strict;
|
|
99
|
+
/* fused-flow staging (TODO.restructure/53): scratch nodes live at
|
|
100
|
+
* [stage_base, ncount) until commit; rollback restores the counts */
|
|
101
|
+
int flow_staged;
|
|
102
|
+
uint32_t flow_stage_base, flow_stage_str;
|
|
103
|
+
uint32_t flow_stage_root, flow_stage_anchor;
|
|
104
|
+
const struct yep_resolver* resolver; /* implicit typing for direct
|
|
105
|
+
builders (NULL = core12); parse_impl sets it beside the engine's
|
|
106
|
+
so the two paths resolve identically (the typing SSOT) */
|
|
107
|
+
yep_pool* pool; /* node/docs arrays (strings live in str) */
|
|
108
|
+
/* string arena: contiguous, realloc-grown; node strings are
|
|
109
|
+
* OFFSETS into it, so growth never dangles (dom_str_put) */
|
|
110
|
+
char* str;
|
|
111
|
+
uint32_t str_len, str_cap;
|
|
112
|
+
const char* input_base; /* borrowed parse input (offset base) */
|
|
113
|
+
/* handle arena: thread-safe (atomic bump) — query APIs allocate
|
|
114
|
+
* YeptrisNode wrappers here, so read-only document sharing across
|
|
115
|
+
* threads is safe; parse-path pools stay single-threaded */
|
|
116
|
+
struct yep_hpool* handles;
|
|
117
|
+
/* #377: the lazy indexed-children cache — child ids of the LAST
|
|
118
|
+
* container indexed via seq_at/map_at. Built once per container
|
|
119
|
+
* under the lazy-init mutex (read-only sharing), O(1) after;
|
|
120
|
+
* invalidated by every child-list mutation. NULL when idle. */
|
|
121
|
+
uint32_t* child_cache;
|
|
122
|
+
uint32_t child_cache_id; /* UINT32_MAX = empty */
|
|
123
|
+
uint32_t child_cache_len;
|
|
124
|
+
yep_dnode* nodes;
|
|
125
|
+
uint32_t ncount, ncap;
|
|
126
|
+
uint32_t* docs; /* document root node ids */
|
|
127
|
+
uint32_t dcount, dcap;
|
|
128
|
+
/* anchor ordinal -> binding node id, indexed directly (the engine
|
|
129
|
+
* stamps 1-based ordinals into the events; no name hashing here) */
|
|
130
|
+
uint32_t* anchor_nodes;
|
|
131
|
+
uint32_t anchor_nodes_cap; /* slots allocated */
|
|
132
|
+
uint32_t anchor_max; /* highest ordinal seen (clear prefix) */
|
|
133
|
+
struct yep_midx_state midx; /* lazy per-map lookup index (mapindex.c) */
|
|
134
|
+
/* builder state */
|
|
135
|
+
uint32_t stack[YEP_DOM_MAX_DEPTH];
|
|
136
|
+
int depth;
|
|
137
|
+
int doc_open;
|
|
138
|
+
int map_pending_key[YEP_DOM_MAX_DEPTH]; /* per-frame: key seen, value next */
|
|
139
|
+
uint32_t pending_key_id[YEP_DOM_MAX_DEPTH];
|
|
140
|
+
uint32_t pending_key;
|
|
141
|
+
} yep_dom;
|
|
142
|
+
|
|
143
|
+
/* Decodes to the pointer view callers use (defined after yep_dom).
|
|
144
|
+
* Absent views (len 0) decode to a valid base pointer with length
|
|
145
|
+
* 0 — callers test len. */
|
|
146
|
+
static inline yep_view yep_dom_view(const yep_dom* d, yep_sview sv) {
|
|
147
|
+
yep_view v = {NULL, 0};
|
|
148
|
+
if (sv.len == 0) {
|
|
149
|
+
return v; /* NULL+0 would be UB on a regionless document */
|
|
150
|
+
}
|
|
151
|
+
v.len = sv.len;
|
|
152
|
+
v.p = (sv.off & YEP_SV_INPUT ? d->str : d->input_base) + (sv.off & YEP_SV_OFF);
|
|
153
|
+
return v;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/* Input-region encoding; arena copies go through dom_str_put. */
|
|
157
|
+
static inline yep_sview yep_sv_input(const yep_dom* d, yep_view v) {
|
|
158
|
+
yep_sview sv = {(uint32_t)((const char*)v.p - d->input_base), v.len};
|
|
159
|
+
return sv;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
yep_dom* yep_dom_create(const yep_allocator* sys);
|
|
163
|
+
|
|
164
|
+
/* Pre-sizes the node array and string arena from content-derived
|
|
165
|
+
* hints (TODO.impl/06: one SIMD count pass -> reserves -> at most
|
|
166
|
+
* logarithmic growth remains instead of doubling from empty).
|
|
167
|
+
* Hints are advisory: overshoot wastes memory, undershoot falls
|
|
168
|
+
* back to normal growth. 0 hint skips that reserve. */
|
|
169
|
+
void yep_dom_reserve(yep_dom* d, uint32_t node_hint, uint32_t str_hint);
|
|
170
|
+
|
|
171
|
+
/* One-shot sizing from the input (count passes + reserve above) —
|
|
172
|
+
* the single home of the heuristic; parse_impl and the memory bench
|
|
173
|
+
* both call it so the measure and the product can't drift. */
|
|
174
|
+
void yep_dom_prepare(yep_dom* d, const yep_text_stats* st);
|
|
175
|
+
|
|
176
|
+
/* Length-heuristic pre-sizing (TODO.restructure/66): real corpora
|
|
177
|
+
* run ~0.2-0.35 nodes/byte (the legal worst, deep bracket chains,
|
|
178
|
+
* reaches ~1/byte and regrows once). No input pre-pass needed. */
|
|
179
|
+
void yep_dom_prepare_len(yep_dom* d, size_t len);
|
|
180
|
+
|
|
181
|
+
/* builder helpers shared with mutate.c (dom-internal) */
|
|
182
|
+
int dom_grow_nodes(yep_dom* d, uint32_t need);
|
|
183
|
+
int dom_grow_docs(yep_dom* d, uint32_t need);
|
|
184
|
+
uint32_t dom_new_node(yep_dom* d, const yep_event* ev, uint8_t kind);
|
|
185
|
+
/* Node-init law shared by the event sink, the mutation builder and the
|
|
186
|
+
* direct builders (no yep_event plumbing): creates and initializes a
|
|
187
|
+
* node; UINT32_MAX = OOM. */
|
|
188
|
+
uint32_t dom_open_node(yep_dom* d, uint8_t kind, const yep_view* tag, const yep_view* anchor,
|
|
189
|
+
int anchor_borrowed, uint8_t style, uint8_t implicit, uint8_t flow);
|
|
190
|
+
void dom_link(yep_dom* d, uint32_t parent, uint32_t child);
|
|
191
|
+
|
|
192
|
+
/* Places a built node: at depth 0 it becomes a document root, inside a
|
|
193
|
+
* sequence it links as a child, inside a map the pairing law applies
|
|
194
|
+
* (first placement = key, second = value). Shared by the event sink,
|
|
195
|
+
* the direct builders, and the CBOR decoder. 0 ok, -1 OOM. */
|
|
196
|
+
int dom_place(yep_dom* d, uint32_t id);
|
|
197
|
+
|
|
198
|
+
/* Mutation-only facts (64-2a): the attached flag and node depth read
|
|
199
|
+
* through lazily-grown side tables; parse-built nodes are unattached
|
|
200
|
+
* with depth 0 until a mutation touches them. */
|
|
201
|
+
int dom_mut_att(const yep_dom* d, uint32_t id);
|
|
202
|
+
void dom_mut_set_att(yep_dom* d, uint32_t id, int v);
|
|
203
|
+
uint16_t dom_mut_depth(const yep_dom* d, uint32_t id);
|
|
204
|
+
void dom_mut_set_depth(yep_dom* d, uint32_t id, uint16_t depth);
|
|
205
|
+
|
|
206
|
+
/* thread-safe handle arena (see hpool.c) */
|
|
207
|
+
struct yep_hpool* yep_hpool_create(const yep_allocator* sys);
|
|
208
|
+
/* Lazy handle-pool acquisition (#157): NULL dom or OOM stays NULL. */
|
|
209
|
+
struct yep_hpool* yep_dom_handles(yep_dom* d);
|
|
210
|
+
/* #377: the lazy indexed-children cache (seq_at/map_at's O(1) leg) */
|
|
211
|
+
void dom_invalidate_child_cache(yep_dom* d);
|
|
212
|
+
uint32_t dom_indexed_child(yep_dom* d, uint32_t cid, size_t index, uint32_t* count_out);
|
|
213
|
+
void yep_hpool_destroy(struct yep_hpool* p);
|
|
214
|
+
void* yep_hpool_alloc(struct yep_hpool* p, size_t size, size_t align);
|
|
215
|
+
|
|
216
|
+
/* mutate.c — the from-scratch builder (TODO.impl/11 phase 3).
|
|
217
|
+
*
|
|
218
|
+
* Values passed at runtime have no input buffer to borrow from, so
|
|
219
|
+
* they are copied into the DOM pool. Plain scalars are typed by the
|
|
220
|
+
* core12 resolver (the typing SSOT — mutation never invents types);
|
|
221
|
+
* quoted/block styles are strings. Synthesized documents resolve with
|
|
222
|
+
* the default schema; a compat-mode constructor arrives with 15.
|
|
223
|
+
*
|
|
224
|
+
* Returns: node ids (UINT32_MAX = OOM); statuses 0 ok, -1 invalid
|
|
225
|
+
* argument / OOM, -2 duplicate key (add), -3 would exceed
|
|
226
|
+
* YEP_DOM_MAX_DEPTH, -4 node already attached (would alias a parent).
|
|
227
|
+
*/
|
|
228
|
+
uint32_t yep_mut_scalar(yep_dom* d, const char* value, size_t len, uint8_t style);
|
|
229
|
+
uint32_t yep_mut_seq(yep_dom* d, uint8_t flow);
|
|
230
|
+
uint32_t yep_mut_map(yep_dom* d, uint8_t flow);
|
|
231
|
+
int yep_mut_seq_add(yep_dom* d, uint32_t seq, uint32_t child);
|
|
232
|
+
int yep_mut_map_add(yep_dom* d, uint32_t map, const char* key, size_t klen, uint32_t value);
|
|
233
|
+
/* Replace-in-place (json-c semantics: position kept); 1 = replaced. */
|
|
234
|
+
int yep_mut_map_set(yep_dom* d, uint32_t map, const char* key, size_t klen, uint32_t value);
|
|
235
|
+
int yep_mut_seq_del(yep_dom* d, uint32_t seq, uint32_t index);
|
|
236
|
+
|
|
237
|
+
/* Node props on synthesized trees (15's YAMLTree): values are copied
|
|
238
|
+
* into the arena. set_alias_target links an alias node at the target
|
|
239
|
+
* (the emitter resolves and re-emits the name). */
|
|
240
|
+
int yep_mut_set_anchor(yep_dom* d, uint32_t node, const char* name, size_t len);
|
|
241
|
+
int yep_mut_set_tag(yep_dom* d, uint32_t node, const char* tag, size_t len);
|
|
242
|
+
uint32_t yep_mut_new_alias(yep_dom* d, uint32_t target, const char* name, size_t len);
|
|
243
|
+
/* Replace the entry at index (json-c array_put_idx): unlinks the old
|
|
244
|
+
* subtree and splices the new node in at the SAME position. */
|
|
245
|
+
int yep_mut_seq_set(yep_dom* d, uint32_t seq, uint32_t index, uint32_t value);
|
|
246
|
+
int yep_mut_map_del(yep_dom* d, uint32_t map, const char* key, size_t klen);
|
|
247
|
+
|
|
248
|
+
/* Appends a pre-built (key,value) pair (the generator path: keys are
|
|
249
|
+
* constructed nodes, not caller strings). Duplicate keys are
|
|
250
|
+
* REJECTED like map_add. */
|
|
251
|
+
int yep_mut_map_add_node(yep_dom* d, uint32_t map, uint32_t key, uint32_t value);
|
|
252
|
+
int yep_mut_map_append(yep_dom* d, uint32_t map, uint32_t key, uint32_t value);
|
|
253
|
+
int yep_mut_add_root(yep_dom* d, uint32_t node);
|
|
254
|
+
void yep_mut_set_depths(yep_dom* d, uint32_t id, uint16_t depth);
|
|
255
|
+
|
|
256
|
+
/* The sink's flow fast path (TODO.restructure/50): builds the
|
|
257
|
+
* strictly-validated span [open, close] directly through the DOM's own
|
|
258
|
+
* placement/link/anchor laws — node-for-node identical to the event
|
|
259
|
+
* path (the flow-direct-diff ctest pins it). 1 = built, <0 = abort. */
|
|
260
|
+
/* dom_from_tape — the lazy-DOM seam (#342 slice 1): builds the node
|
|
261
|
+
* tree from the tape's records, mirroring dom_on_flow_build's arms
|
|
262
|
+
* (borrowed spans for clean strings, an arena unescape for escaped
|
|
263
|
+
* ones, typed literals by kind). The records are pre-validated, so
|
|
264
|
+
* the walk is placement only. Returns 0, or -1 (allocation/depth/an
|
|
265
|
+
* unexpected record). STRICT tapes only — YEP_T_NUM (the lenient
|
|
266
|
+
* route's deferred numbers) is rejected. */
|
|
267
|
+
int dom_from_tape(yep_dom* d, const yeptris_json_tape* t);
|
|
268
|
+
|
|
269
|
+
int dom_on_flow_build(void* ctx, const char* p, size_t open, size_t len, uint32_t line,
|
|
270
|
+
size_t line_start, yep_view anchor, yep_view tag, uint32_t anchor_id,
|
|
271
|
+
int max_depth, size_t* close);
|
|
272
|
+
int dom_on_flow_commit(void* ctx);
|
|
273
|
+
void dom_on_flow_rollback(void* ctx);
|
|
274
|
+
struct yep_block_value;
|
|
275
|
+
|
|
276
|
+
/* The direct scalar sink path (TODO.restructure/79). */
|
|
277
|
+
int dom_on_scalar(void* ctx, const yep_view* value, const yep_view* tag, const yep_view* anchor,
|
|
278
|
+
uint32_t anchor_id, uint8_t tag_id, uint8_t style, uint8_t implicit, uint8_t flow,
|
|
279
|
+
int borrowed);
|
|
280
|
+
|
|
281
|
+
int dom_on_block_pair(void* ctx, const yep_view* key, const struct yep_block_value* v,
|
|
282
|
+
uint32_t line, uint16_t key_col, uint16_t val_col);
|
|
283
|
+
int dom_on_block_open(void* ctx, const yep_view* key, uint32_t line, uint16_t key_col);
|
|
284
|
+
int dom_on_block_item(void* ctx, const yep_block_value* v);
|
|
285
|
+
|
|
286
|
+
/* Direct DOM construction from a strict-validated JSON buffer
|
|
287
|
+
* (TODO.impl/27): no engine, no event pipeline. The caller validated
|
|
288
|
+
* with yep_json_document; 0 on success, -1 OOM, -2 grammar surprise
|
|
289
|
+
* (defensive). */
|
|
290
|
+
int yep_dom_build_json(yep_dom* d, const char* buf, size_t len);
|
|
291
|
+
|
|
292
|
+
/* Appends len bytes to the string arena; returns the ARENA-offset
|
|
293
|
+
* encoding (input_base-relative encodings use yep_sv_input). */
|
|
294
|
+
yep_sview yep_dom_str_put(yep_dom* d, const char* p, uint32_t len);
|
|
295
|
+
|
|
296
|
+
/* Reserve/commit for in-place decoding (the JSON builder's escape
|
|
297
|
+
* path): tail ensures capacity and returns the write position at
|
|
298
|
+
* str_len; commit advances by the written length and returns the
|
|
299
|
+
* arena-encoded view. */
|
|
300
|
+
char* yep_dom_str_tail(yep_dom* d, uint32_t cap);
|
|
301
|
+
yep_sview yep_dom_str_commit(yep_dom* d, uint32_t written);
|
|
302
|
+
void yep_dom_destroy(yep_dom* d);
|
|
303
|
+
int yep_dom_on_event(void* ctx, const yep_event* ev);
|
|
304
|
+
|
|
305
|
+
/* Node id accessor for the public API layer. */
|
|
306
|
+
const yep_dnode* yep_dom_node(const yep_dom* d, uint32_t id);
|
|
307
|
+
|
|
308
|
+
#ifdef __cplusplus
|
|
309
|
+
}
|
|
310
|
+
#endif
|
|
311
|
+
|
|
312
|
+
#endif /* YEP_DOM_H */
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/* hpool.c — the thread-safe handle arena (TODO.impl/19).
|
|
2
|
+
*
|
|
3
|
+
* Query APIs allocate one YeptrisNode wrapper per call with document
|
|
4
|
+
* lifetime; read-only document sharing across threads makes those
|
|
5
|
+
* allocations concurrent. A mutex-guarded bump arena (uncontended lock
|
|
6
|
+
* per small allocation; blocks freed at document destruction) keeps
|
|
7
|
+
* the parse-path pools entirely lock-free.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
#include <stdint.h>
|
|
11
|
+
#include <stdlib.h>
|
|
12
|
+
|
|
13
|
+
#include "dom/dom.h"
|
|
14
|
+
#include "memory/allocator.h"
|
|
15
|
+
|
|
16
|
+
#include "common/mutex.h"
|
|
17
|
+
|
|
18
|
+
#define HPOOL_BLOCK (16u * 1024u)
|
|
19
|
+
|
|
20
|
+
typedef struct hblock {
|
|
21
|
+
struct hblock* next;
|
|
22
|
+
size_t size;
|
|
23
|
+
size_t used;
|
|
24
|
+
} hblock;
|
|
25
|
+
|
|
26
|
+
struct yep_hpool {
|
|
27
|
+
const yep_allocator* sys;
|
|
28
|
+
hblock* head;
|
|
29
|
+
yep_mutex_raw mu;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
static hblock* hb_new(const yep_allocator* sys, size_t payload) {
|
|
33
|
+
hblock* b = yep_alloc(sys, sizeof(hblock) + payload);
|
|
34
|
+
if (b == NULL) {
|
|
35
|
+
return NULL;
|
|
36
|
+
}
|
|
37
|
+
b->next = NULL;
|
|
38
|
+
b->size = payload;
|
|
39
|
+
b->used = 0;
|
|
40
|
+
return b;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
struct yep_hpool* yep_hpool_create(const yep_allocator* sys) {
|
|
44
|
+
if (sys == NULL) {
|
|
45
|
+
return NULL;
|
|
46
|
+
}
|
|
47
|
+
struct yep_hpool* p = yep_alloc(sys, sizeof(*p));
|
|
48
|
+
if (p == NULL) {
|
|
49
|
+
return NULL;
|
|
50
|
+
}
|
|
51
|
+
p->sys = sys;
|
|
52
|
+
p->head = NULL;
|
|
53
|
+
if (yep_mutex_init(&p->mu) != 0) {
|
|
54
|
+
yep_free(sys, p);
|
|
55
|
+
return NULL;
|
|
56
|
+
}
|
|
57
|
+
p->head = hb_new(sys, HPOOL_BLOCK);
|
|
58
|
+
if (p->head == NULL) {
|
|
59
|
+
yep_mutex_destroy(&p->mu);
|
|
60
|
+
yep_free(sys, p);
|
|
61
|
+
return NULL;
|
|
62
|
+
}
|
|
63
|
+
return p;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
void yep_hpool_destroy(struct yep_hpool* p) {
|
|
67
|
+
if (p == NULL) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
yep_mutex_destroy(&p->mu);
|
|
71
|
+
hblock* b = p->head;
|
|
72
|
+
while (b != NULL) {
|
|
73
|
+
hblock* next = b->next;
|
|
74
|
+
yep_free(p->sys, b);
|
|
75
|
+
b = next;
|
|
76
|
+
}
|
|
77
|
+
yep_free(p->sys, p);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
void* yep_hpool_alloc(struct yep_hpool* p, size_t size, size_t align) {
|
|
81
|
+
if (p == NULL || size == 0 || align == 0 || (align & (align - 1)) != 0) {
|
|
82
|
+
return NULL;
|
|
83
|
+
}
|
|
84
|
+
yep_mutex_lock(&p->mu);
|
|
85
|
+
hblock* b = p->head;
|
|
86
|
+
uintptr_t base = (uintptr_t)b + sizeof(hblock);
|
|
87
|
+
uintptr_t start = (base + b->used + align - 1) & ~(uintptr_t)(align - 1);
|
|
88
|
+
if (start + size > base + b->size) {
|
|
89
|
+
size_t payload = HPOOL_BLOCK;
|
|
90
|
+
if (payload < size + align + sizeof(hblock)) {
|
|
91
|
+
payload = size + align + sizeof(hblock);
|
|
92
|
+
}
|
|
93
|
+
hblock* nb = hb_new(p->sys, payload);
|
|
94
|
+
if (nb == NULL) {
|
|
95
|
+
yep_mutex_unlock(&p->mu);
|
|
96
|
+
return NULL;
|
|
97
|
+
}
|
|
98
|
+
nb->next = b;
|
|
99
|
+
p->head = nb;
|
|
100
|
+
base = (uintptr_t)nb + sizeof(hblock);
|
|
101
|
+
start = (base + align - 1) & ~(uintptr_t)(align - 1);
|
|
102
|
+
b = nb;
|
|
103
|
+
}
|
|
104
|
+
b->used = start + size - base;
|
|
105
|
+
yep_mutex_unlock(&p->mu);
|
|
106
|
+
return (void*)start;
|
|
107
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/* mapindex.c — lazy per-mapping key index (TODO.impl/11). */
|
|
2
|
+
|
|
3
|
+
#include "dom/mapindex.h"
|
|
4
|
+
|
|
5
|
+
#include <stdlib.h>
|
|
6
|
+
#include <string.h>
|
|
7
|
+
|
|
8
|
+
#include "dom/dom.h"
|
|
9
|
+
|
|
10
|
+
typedef struct yep_midx_slot {
|
|
11
|
+
uint32_t hash; /* yep_view_hash of the key view */
|
|
12
|
+
uint32_t key_child; /* key node id; UINT32_MAX = empty */
|
|
13
|
+
} yep_midx_slot;
|
|
14
|
+
|
|
15
|
+
#if defined(_MSC_VER)
|
|
16
|
+
#pragma warning(push)
|
|
17
|
+
#pragma warning(disable : 4200) /* C99 flexible array member */
|
|
18
|
+
#endif
|
|
19
|
+
typedef struct yep_midx_tab {
|
|
20
|
+
uint32_t cap; /* slot count, power of two */
|
|
21
|
+
yep_midx_slot slots[];
|
|
22
|
+
} yep_midx_tab;
|
|
23
|
+
#if defined(_MSC_VER)
|
|
24
|
+
#pragma warning(pop)
|
|
25
|
+
#endif
|
|
26
|
+
|
|
27
|
+
/* Table capacity: power of two, >= 2x pairs (load factor <= 50%). */
|
|
28
|
+
static uint32_t tab_cap_for(uint32_t pairs) {
|
|
29
|
+
uint32_t cap = 8;
|
|
30
|
+
while (cap < pairs * 2) {
|
|
31
|
+
cap *= 2;
|
|
32
|
+
}
|
|
33
|
+
return cap;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
static yep_midx_tab* tab_build(const struct yep_dom* d, uint32_t map) {
|
|
37
|
+
const yep_dnode* m = yep_dom_node(d, map);
|
|
38
|
+
if (m == NULL || m->kind != YEP_DOM_MAPPING) {
|
|
39
|
+
return NULL;
|
|
40
|
+
}
|
|
41
|
+
uint32_t pairs = m->count / 2;
|
|
42
|
+
uint32_t cap = tab_cap_for(pairs);
|
|
43
|
+
yep_midx_tab* t = yep_alloc(d->sys, sizeof(*t) + cap * sizeof(*t->slots));
|
|
44
|
+
if (t == NULL) {
|
|
45
|
+
return NULL;
|
|
46
|
+
}
|
|
47
|
+
t->cap = cap;
|
|
48
|
+
for (uint32_t i = 0; i < cap; i++) {
|
|
49
|
+
t->slots[i].key_child = UINT32_MAX;
|
|
50
|
+
}
|
|
51
|
+
uint32_t mask = cap - 1;
|
|
52
|
+
uint32_t id = m->first_child;
|
|
53
|
+
int want_key = 1;
|
|
54
|
+
while (id != UINT32_MAX) {
|
|
55
|
+
const yep_dnode* cur = yep_dom_node(d, id);
|
|
56
|
+
if (cur == NULL) {
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
if (want_key && cur->kind == YEP_DOM_SCALAR) {
|
|
60
|
+
/* |1: the empty marker is key_child, not hash — this
|
|
61
|
+
* just avoids the all-zero-hash clustering of 1-char keys */
|
|
62
|
+
uint32_t h = yep_view_hash(yep_dom_view(d, cur->value)) | 1u;
|
|
63
|
+
uint32_t i = h & mask;
|
|
64
|
+
while (t->slots[i].key_child != UINT32_MAX) {
|
|
65
|
+
i = (i + 1) & mask; /* first key wins: occupied slots keep their entry */
|
|
66
|
+
}
|
|
67
|
+
t->slots[i].hash = h;
|
|
68
|
+
t->slots[i].key_child = id;
|
|
69
|
+
}
|
|
70
|
+
want_key = !want_key;
|
|
71
|
+
id = cur->next_sibling;
|
|
72
|
+
}
|
|
73
|
+
return t;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
static int tabs_grow(struct yep_dom* d, uint32_t need) {
|
|
77
|
+
struct yep_midx_state* x = &d->midx;
|
|
78
|
+
if (need <= x->tabs_cap) {
|
|
79
|
+
return 0;
|
|
80
|
+
}
|
|
81
|
+
uint32_t cap = x->tabs_cap ? x->tabs_cap : 64;
|
|
82
|
+
while (cap < need) {
|
|
83
|
+
cap *= 2;
|
|
84
|
+
}
|
|
85
|
+
yep_midx_tab** grown = yep_alloc(d->sys, cap * sizeof(*grown));
|
|
86
|
+
if (grown == NULL) {
|
|
87
|
+
return -1;
|
|
88
|
+
}
|
|
89
|
+
if (x->tabs_cap > 0) {
|
|
90
|
+
memcpy(grown, x->tabs, x->tabs_cap * sizeof(*grown));
|
|
91
|
+
memset(grown + x->tabs_cap, 0, (cap - x->tabs_cap) * sizeof(*grown));
|
|
92
|
+
yep_free(d->sys, x->tabs);
|
|
93
|
+
} else {
|
|
94
|
+
memset(grown, 0, cap * sizeof(*grown));
|
|
95
|
+
}
|
|
96
|
+
x->tabs = grown;
|
|
97
|
+
x->tabs_cap = cap;
|
|
98
|
+
return 0;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
uint32_t yep_midx_lookup(struct yep_dom* d, uint32_t map, yep_view key) {
|
|
102
|
+
if (d == NULL || map >= d->ncount) {
|
|
103
|
+
return UINT32_MAX;
|
|
104
|
+
}
|
|
105
|
+
struct yep_midx_state* x = &d->midx;
|
|
106
|
+
if (x->mu_ready == 0) {
|
|
107
|
+
return UINT32_MAX; /* document without a live index (paranoia) */
|
|
108
|
+
}
|
|
109
|
+
yep_mutex_lock(&x->mu);
|
|
110
|
+
if (tabs_grow(d, d->ncount) != 0) {
|
|
111
|
+
yep_mutex_unlock(&x->mu);
|
|
112
|
+
return UINT32_MAX;
|
|
113
|
+
}
|
|
114
|
+
if (x->tabs[map] == NULL) {
|
|
115
|
+
x->tabs[map] = tab_build(d, map);
|
|
116
|
+
if (x->tabs[map] == NULL) {
|
|
117
|
+
yep_mutex_unlock(&x->mu);
|
|
118
|
+
return UINT32_MAX;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
yep_midx_tab* t = x->tabs[map];
|
|
122
|
+
uint32_t mask = t->cap - 1;
|
|
123
|
+
uint32_t h = yep_view_hash(key) | 1u;
|
|
124
|
+
uint32_t i = h & mask;
|
|
125
|
+
uint32_t found = UINT32_MAX;
|
|
126
|
+
for (;;) {
|
|
127
|
+
uint32_t child = t->slots[i].key_child;
|
|
128
|
+
if (child == UINT32_MAX) {
|
|
129
|
+
break; /* empty slot: absent */
|
|
130
|
+
}
|
|
131
|
+
if (t->slots[i].hash == h) {
|
|
132
|
+
const yep_dnode* kn = yep_dom_node(d, child);
|
|
133
|
+
if (kn != NULL && yep_view_eq(yep_dom_view(d, kn->value), key)) {
|
|
134
|
+
found = child;
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
i = (i + 1) & mask;
|
|
139
|
+
}
|
|
140
|
+
yep_mutex_unlock(&x->mu);
|
|
141
|
+
return found;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
void yep_midx_invalidate(struct yep_dom* d, uint32_t map) {
|
|
145
|
+
if (d == NULL || !d->midx.mu_ready || d->midx.tabs == NULL || map >= d->midx.tabs_cap) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
yep_mutex_lock(&d->midx.mu);
|
|
149
|
+
yep_midx_tab* t = d->midx.tabs[map];
|
|
150
|
+
if (t != NULL) {
|
|
151
|
+
d->midx.tabs[map] = NULL;
|
|
152
|
+
yep_free(d->sys, t);
|
|
153
|
+
}
|
|
154
|
+
yep_mutex_unlock(&d->midx.mu);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
void yep_midx_destroy(struct yep_dom* d) {
|
|
158
|
+
if (d == NULL) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (d->midx.tabs != NULL) {
|
|
162
|
+
for (uint32_t i = 0; i < d->midx.tabs_cap; i++) {
|
|
163
|
+
yep_free(d->sys, d->midx.tabs[i]);
|
|
164
|
+
}
|
|
165
|
+
yep_free(d->sys, d->midx.tabs);
|
|
166
|
+
d->midx.tabs = NULL;
|
|
167
|
+
d->midx.tabs_cap = 0;
|
|
168
|
+
}
|
|
169
|
+
if (d->midx.mu_ready) {
|
|
170
|
+
yep_mutex_destroy(&d->midx.mu);
|
|
171
|
+
d->midx.mu_ready = 0;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/* mapindex.h — lazy per-mapping key index (TODO.impl/11).
|
|
2
|
+
*
|
|
3
|
+
* O(1) map lookup over the sibling-linked pair list: on a mapping's
|
|
4
|
+
* first lookup an open-addressing table (view hash -> key child id)
|
|
5
|
+
* is built from its pairs; probes compare the full view bytes on
|
|
6
|
+
* hash matches. First key wins on duplicates (the linear scan's
|
|
7
|
+
* contract). Only SCALAR keys are indexed — collection keys never
|
|
8
|
+
* match a string lookup, exactly like the scan.
|
|
9
|
+
*
|
|
10
|
+
* Tables and the per-node slot array live on the system allocator
|
|
11
|
+
* (NOT the DOM pool): mutation invalidates a table by freeing it,
|
|
12
|
+
* and pool memory cannot be individually released. Everything is
|
|
13
|
+
* freed at document destruction.
|
|
14
|
+
*
|
|
15
|
+
* Threads: table builds and mutations serialize on the document's
|
|
16
|
+
* index mutex; built tables are immutable, so concurrent probes are
|
|
17
|
+
* safe — the read-only sharing contract holds.
|
|
18
|
+
*/
|
|
19
|
+
#ifndef YEP_MAPINDEX_H
|
|
20
|
+
#define YEP_MAPINDEX_H
|
|
21
|
+
|
|
22
|
+
#include <stdint.h>
|
|
23
|
+
|
|
24
|
+
#include "common/mutex.h"
|
|
25
|
+
|
|
26
|
+
#include "common/nametab.h"
|
|
27
|
+
#include "memory/allocator.h"
|
|
28
|
+
|
|
29
|
+
#ifdef __cplusplus
|
|
30
|
+
extern "C" {
|
|
31
|
+
#endif
|
|
32
|
+
|
|
33
|
+
/* Per-mapping table: hash -> key node id (opaque here; mapindex.c). */
|
|
34
|
+
typedef struct yep_midx_tab yep_midx_tab;
|
|
35
|
+
|
|
36
|
+
struct yep_midx_state {
|
|
37
|
+
yep_midx_tab** tabs; /* per node id: table or NULL (lazy) */
|
|
38
|
+
uint32_t tabs_cap; /* slots allocated (grown with the node set) */
|
|
39
|
+
yep_mutex_raw mu;
|
|
40
|
+
int mu_ready;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/* The key node id for `key` in `map`, or UINT32_MAX when absent.
|
|
44
|
+
* Builds the mapping's table on first use. UINT32_MAX also on
|
|
45
|
+
* allocation failure (the caller falls back to a linear scan if it
|
|
46
|
+
* needs to distinguish — callers treat both as "not found"). */
|
|
47
|
+
struct yep_dom;
|
|
48
|
+
uint32_t yep_midx_lookup(struct yep_dom* d, uint32_t map, yep_view key);
|
|
49
|
+
|
|
50
|
+
/* Drops `map`'s table (mutation changed the pairs). Cheap no-op when
|
|
51
|
+
* no table was built. */
|
|
52
|
+
void yep_midx_invalidate(struct yep_dom* d, uint32_t map);
|
|
53
|
+
|
|
54
|
+
/* Frees every table and the slot array (document destruction). */
|
|
55
|
+
void yep_midx_destroy(struct yep_dom* d);
|
|
56
|
+
|
|
57
|
+
#ifdef __cplusplus
|
|
58
|
+
}
|
|
59
|
+
#endif
|
|
60
|
+
|
|
61
|
+
#endif /* YEP_MAPINDEX_H */
|