yeptris 0.6.20.2-aarch64-linux → 0.6.21.1-aarch64-linux
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/lib/yeptris/3.3/native.so +0 -0
- data/lib/yeptris.rb +1 -1
- data/libyeptris.so +0 -0
- data/vendor/libyeptris/CMakeLists.txt +1 -1
- data/vendor/libyeptris/src/yeptris/build.c +1 -0
- data/vendor/libyeptris/src/yeptris/cbor/decode.c +2 -0
- data/vendor/libyeptris/src/yeptris/doc.h +19 -13
- data/vendor/libyeptris/src/yeptris/dom/dom.c +12 -14
- data/vendor/libyeptris/src/yeptris/dom/ytape.c +2 -0
- data/vendor/libyeptris/src/yeptris/marshal.c +7 -2
- data/vendor/libyeptris/src/yeptris/parse.c +88 -106
- data/vendor/libyeptris/src/yeptris/tape.c +126 -11
- data/vendor/libyeptris/src/yeptris/tape_in.h +6 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5d1fa4e8d3637757def7e98646b997efcf9f34e5b2335e6204200233bac8513a
|
|
4
|
+
data.tar.gz: 72a73f4d7545cdb8bbf4c276833675805ca331e7d7327954418207c24c32eaf8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b4ac43d4cf4e3bc79c97cc0e617760d5ce0f7a14bd6eae195b9cd13fe801c7a146175ef3786f5523de51499827bc52b7daf60b08920e21a8ed4b18ca08e5fded
|
|
7
|
+
data.tar.gz: e24ea1b81fc184268f6ee5a88464c2d91d9f4ad17ac36c84aa193de972fc0f9dd5359ff6081f43ebfd6dc1145fa5f3dc50ba794161cb4c8436c09d61cb770dce
|
data/lib/yeptris/3.3/native.so
CHANGED
|
Binary file
|
data/lib/yeptris.rb
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
module Yeptris
|
|
4
4
|
# The gem's version lives in the parent namespace's file — the last
|
|
5
5
|
# internal require (yeptris/version) retired with it.
|
|
6
|
-
VERSION = "0.6.
|
|
6
|
+
VERSION = "0.6.21.1".freeze
|
|
7
7
|
|
|
8
8
|
# Informational notices are OPT-IN (yeptris-ruby#217): consumers
|
|
9
9
|
# embed yeptris inside CLIs that assert clean stderr, and a
|
data/libyeptris.so
CHANGED
|
Binary file
|
|
@@ -860,6 +860,7 @@ static YeptrisDocument cbor_wrap(yep_dom* dom, const void* buf, const yep_alloca
|
|
|
860
860
|
yep_dom_destroy(dom);
|
|
861
861
|
return NULL;
|
|
862
862
|
}
|
|
863
|
+
yep_mutex_init(&d->lazy_mu);
|
|
863
864
|
d->dom = dom;
|
|
864
865
|
d->sys = sys;
|
|
865
866
|
d->schema = YEPTRIS_SCHEMA_12_CORE;
|
|
@@ -967,6 +968,7 @@ YEPTRIS_API YeptrisDocument yeptris_cbor_decode(const void* buf, size_t len, uin
|
|
|
967
968
|
}
|
|
968
969
|
return NULL;
|
|
969
970
|
}
|
|
971
|
+
yep_mutex_init(&doc->lazy_mu);
|
|
970
972
|
doc->dom = dom;
|
|
971
973
|
doc->sys = sys;
|
|
972
974
|
doc->schema = YEPTRIS_SCHEMA_12_CORE; /* CBOR's model is the core schema */
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
#include <stddef.h>
|
|
9
9
|
|
|
10
|
+
#include "common/mutex.h"
|
|
10
11
|
#include "dom/dom.h"
|
|
11
12
|
#include "memory/allocator.h"
|
|
12
13
|
|
|
@@ -18,19 +19,24 @@ typedef struct yeptris_document {
|
|
|
18
19
|
* conditioned on it (TODO.restructure/32) */
|
|
19
20
|
unsigned char* transcoded; /* owned when non-NULL */
|
|
20
21
|
size_t transcoded_len;
|
|
21
|
-
const char* input;
|
|
22
|
-
void* finish_pool;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
void* lazy_tape;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
int lazy_kind;
|
|
32
|
-
|
|
33
|
-
|
|
22
|
+
const char* input; /* borrowed input (lifetime documentation) */
|
|
23
|
+
void* finish_pool; /* engine finish pool: resolved tags, folded and
|
|
24
|
+
escaped scalars outlive the engine through the
|
|
25
|
+
document */
|
|
26
|
+
void* lazy_tape; /* #342 slice 2: the parsed tape when the tree is
|
|
27
|
+
* deferred (gate-clean strict JSON; #378: the YAML
|
|
28
|
+
* record tape). dom==NULL until the first tree
|
|
29
|
+
* access materializes; freed with the document.
|
|
30
|
+
* void* to avoid a header cycle — parse.c casts
|
|
31
|
+
* per lazy_kind */
|
|
32
|
+
int lazy_kind; /* 0 = none/json (yeptris_json_tape), 1 = yaml
|
|
33
|
+
* (yep_ytape) — every constructor must set it
|
|
34
|
+
* (the field-by-field ctor trap) */
|
|
35
|
+
yep_mutex_raw lazy_mu; /* materialization lock: the first tree
|
|
36
|
+
* access builds; concurrent first accesses
|
|
37
|
+
* wait (read-only sharing stays lock-free
|
|
38
|
+
* once dom is set — every constructor must
|
|
39
|
+
* yep_mutex_init it, the ctor trap) */
|
|
34
40
|
} yeptris_document;
|
|
35
41
|
|
|
36
42
|
/* Node handle: a (document, node-id) pair so nodes stay usable even if
|
|
@@ -542,18 +542,18 @@ uint32_t dom_indexed_child(yep_dom* d, uint32_t cid, size_t index, uint32_t* cou
|
|
|
542
542
|
*count_out = 0;
|
|
543
543
|
return UINT32_MAX;
|
|
544
544
|
}
|
|
545
|
+
/* the midx discipline (TSAN, Threads.ReadOnlySharing): READS of
|
|
546
|
+
* the cache ride the mutex too — a concurrent builder publishes
|
|
547
|
+
* under it, so the old unlocked hit path raced the build's
|
|
548
|
+
* stores. Uncontended in the single-threaded hot path. */
|
|
549
|
+
yep_mutex_lock(&d->midx.mu);
|
|
550
|
+
uint32_t out;
|
|
545
551
|
*count_out = n->count;
|
|
546
552
|
if (d->child_cache_id == cid) {
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
}
|
|
552
|
-
/* miss: build once under the lazy-init mutex (Threads.
|
|
553
|
-
* ReadOnlySharing — concurrent first calls race here exactly like
|
|
554
|
-
* the handle pool's) */
|
|
555
|
-
yep_mutex_lock(&d->midx.mu);
|
|
556
|
-
if (d->child_cache_id != cid) {
|
|
553
|
+
out = index < d->child_cache_len ? d->child_cache[index] : UINT32_MAX;
|
|
554
|
+
} else {
|
|
555
|
+
/* miss: build once under the lazy-init mutex (concurrent
|
|
556
|
+
* first calls race here exactly like the handle pool's) */
|
|
557
557
|
yep_free(d->sys, d->child_cache);
|
|
558
558
|
d->child_cache = NULL;
|
|
559
559
|
d->child_cache_len = 0;
|
|
@@ -574,12 +574,10 @@ uint32_t dom_indexed_child(yep_dom* d, uint32_t cid, size_t index, uint32_t* cou
|
|
|
574
574
|
}
|
|
575
575
|
}
|
|
576
576
|
d->child_cache_id = cid;
|
|
577
|
+
out = index < d->child_cache_len ? d->child_cache[index] : UINT32_MAX;
|
|
577
578
|
}
|
|
578
579
|
yep_mutex_unlock(&d->midx.mu);
|
|
579
|
-
|
|
580
|
-
return d->child_cache[index];
|
|
581
|
-
}
|
|
582
|
-
return UINT32_MAX;
|
|
580
|
+
return out;
|
|
583
581
|
}
|
|
584
582
|
|
|
585
583
|
void yep_dom_destroy(yep_dom* d) {
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* (test/unit/test_ytape.cpp) pins tree identity across the corpora.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
+
#include <stdio.h>
|
|
17
18
|
#include <string.h>
|
|
18
19
|
|
|
19
20
|
#include "dom/dom.h"
|
|
@@ -327,6 +328,7 @@ static int yt_on_flow_build(void* ctx, const char* p, size_t open, size_t len, u
|
|
|
327
328
|
* the same reject/long-key verdicts, then ONE record for the
|
|
328
329
|
* whole staged span (replay runs the full build through
|
|
329
330
|
* dom_on_flow_build). */
|
|
331
|
+
t->max_depth = max_depth; /* replay re-walks at the engine's limit */
|
|
330
332
|
yep_json_walk w;
|
|
331
333
|
yep_json_tok tok;
|
|
332
334
|
yep_json_walk_init(&w, p, len, open, max_depth);
|
|
@@ -756,14 +756,19 @@ YEPTRIS_API YeptrisStatus yeptris_marshal_node(YeptrisNode node, char** out, siz
|
|
|
756
756
|
*out = NULL;
|
|
757
757
|
*out_len = 0;
|
|
758
758
|
yeptris_node* h = (yeptris_node*)node;
|
|
759
|
-
|
|
759
|
+
yep_dom* dom = yep_doc_dom(h->doc); /* #378: a lazy parse carries the
|
|
760
|
+
* tape — the tree materializes here */
|
|
761
|
+
if (dom == NULL) {
|
|
762
|
+
return YEPTRIS_ERROR_MEMORY; /* the lazy route's retry contract */
|
|
763
|
+
}
|
|
764
|
+
if (dom_subtree_tagged(dom, h->id) != 0) {
|
|
760
765
|
yep_error_set(yep_error_tls(), YEP_ERR_UNEXPECTED, 0, 0, 0,
|
|
761
766
|
"marshal: explicitly tagged node not expressible; "
|
|
762
767
|
"fall back to the value walk");
|
|
763
768
|
return YEPTRIS_ERROR_UNSUPPORTED;
|
|
764
769
|
}
|
|
765
770
|
yep_value_ctx* c = NULL;
|
|
766
|
-
if (yep_values_from_dom(
|
|
771
|
+
if (yep_values_from_dom(dom, h->id, 0, &c) != 0) {
|
|
767
772
|
return YEPTRIS_ERROR_MEMORY;
|
|
768
773
|
}
|
|
769
774
|
YeptrisStatus st = marshal_records(c, h->doc->schema == YEPTRIS_SCHEMA_11_COMPAT,
|
|
@@ -48,89 +48,57 @@ yep_dom* yep_doc_dom(yeptris_document* doc) {
|
|
|
48
48
|
if (doc == NULL) {
|
|
49
49
|
return NULL;
|
|
50
50
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
if (dom != NULL) {
|
|
58
|
-
dom->resolver = (doc->schema == YEPTRIS_SCHEMA_11_COMPAT) ? yep_resolver_compat11()
|
|
59
|
-
: yep_resolver_core12();
|
|
60
|
-
}
|
|
61
|
-
if (dom != NULL && dom_from_ytape(dom, t) == 0) {
|
|
62
|
-
doc->dom = dom;
|
|
63
|
-
ytap_free(t);
|
|
64
|
-
yep_free(doc->sys, t);
|
|
65
|
-
doc->lazy_tape = NULL;
|
|
66
|
-
yep_pool_destroy((yep_pool*)doc->finish_pool);
|
|
67
|
-
doc->finish_pool = NULL;
|
|
68
|
-
} else {
|
|
69
|
-
yep_dom_destroy(dom);
|
|
70
|
-
dom = NULL; /* the tape stays: a later access retries, or
|
|
71
|
-
* free drops it (replay fails only on
|
|
72
|
-
* allocation/depth, as the builders do) */
|
|
73
|
-
}
|
|
74
|
-
return dom;
|
|
75
|
-
}
|
|
51
|
+
/* the midx discipline (the #157 TSAN lesson): EVERY dom read and
|
|
52
|
+
* write rides the mutex — the unlock publishes the built tree
|
|
53
|
+
* (readers get their happens-before through the lock), so the
|
|
54
|
+
* plain field needs no atomics. Entry-level only: node walks ride
|
|
55
|
+
* handles created after this returns. */
|
|
56
|
+
yep_mutex_lock(&doc->lazy_mu);
|
|
76
57
|
if (doc->dom == NULL && doc->lazy_tape != NULL) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
free drops it (the materializer only fails on
|
|
88
|
-
malformed NUM spans, which the strict gate
|
|
89
|
-
already rejected at parse) */
|
|
90
|
-
}
|
|
91
|
-
return dom;
|
|
92
|
-
}
|
|
93
|
-
return doc->dom;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/* The strict-JSON document wrapper (both routes share it). */
|
|
97
|
-
/* The lazy route's acceptance debt: the fused lenient walk records
|
|
98
|
-
* number runs UNVALIDATED (its simdjson-style deferred contract).
|
|
99
|
-
* parse_json's contract is RFC 8259 at parse time, so the deferred
|
|
100
|
-
* spans settle HERE — full-span shape check per NUM record, decoding
|
|
101
|
-
* the packed records directly (no columns build at parse; the walk
|
|
102
|
-
* guarantees recs are primary on this route). */
|
|
103
|
-
static int lazy_nums_settled(const yeptris_json_tape* t) {
|
|
104
|
-
const char* p = (const char*)t->_src;
|
|
105
|
-
for (uint32_t i = 0; i < t->count; i++) {
|
|
106
|
-
uint64_t r = t->recs[i];
|
|
107
|
-
if ((uint8_t)(r & 0xFFu) != YEP_T_NUM) {
|
|
108
|
-
continue;
|
|
109
|
-
}
|
|
110
|
-
uint32_t len = (uint32_t)((r >> 8) & 0x7FFFFFu);
|
|
111
|
-
uint32_t off = (uint32_t)(r >> 32);
|
|
112
|
-
{ /* the pure-integer fast path: all digits (optional '-'), no
|
|
113
|
-
* leading zero unless a lone digit — number_shape would
|
|
114
|
-
* consume the whole span and answer float-less; skip it */
|
|
115
|
-
const char* q = p + off;
|
|
116
|
-
size_t d = (*q == '-') ? 1 : 0;
|
|
117
|
-
size_t w = d;
|
|
118
|
-
for (; w < len; w++) {
|
|
119
|
-
if ((unsigned)(unsigned char)q[w] - '0' > 9u) {
|
|
120
|
-
break;
|
|
121
|
-
}
|
|
58
|
+
if (doc->lazy_kind == 1) {
|
|
59
|
+
/* #378: the YAML record tape — replay through the eager
|
|
60
|
+
* builders; the finish pool (whose spans the records
|
|
61
|
+
* carry) dies once the builders copied what must outlive
|
|
62
|
+
* it */
|
|
63
|
+
yep_ytape* t = (yep_ytape*)doc->lazy_tape;
|
|
64
|
+
yep_dom* dom = yep_dom_create(doc->sys);
|
|
65
|
+
if (dom != NULL) {
|
|
66
|
+
dom->resolver = (doc->schema == YEPTRIS_SCHEMA_11_COMPAT) ? yep_resolver_compat11()
|
|
67
|
+
: yep_resolver_core12();
|
|
122
68
|
}
|
|
123
|
-
if (
|
|
124
|
-
|
|
69
|
+
if (dom != NULL && dom_from_ytape(dom, t) == 0) {
|
|
70
|
+
doc->dom = dom;
|
|
71
|
+
ytap_free(t);
|
|
72
|
+
yep_free(doc->sys, t);
|
|
73
|
+
doc->lazy_tape = NULL;
|
|
74
|
+
yep_pool_destroy((yep_pool*)doc->finish_pool);
|
|
75
|
+
doc->finish_pool = NULL;
|
|
76
|
+
} else {
|
|
77
|
+
yep_dom_destroy(dom);
|
|
78
|
+
/* the tape stays: a later access retries, or free
|
|
79
|
+
* drops it (replay fails only on allocation/depth, as
|
|
80
|
+
* the builders do) */
|
|
81
|
+
}
|
|
82
|
+
} else {
|
|
83
|
+
yeptris_json_tape* t = (yeptris_json_tape*)doc->lazy_tape;
|
|
84
|
+
yep_dom* dom = yep_dom_create(doc->sys);
|
|
85
|
+
if (dom != NULL && dom_from_tape(dom, t) == 0) {
|
|
86
|
+
doc->dom = dom;
|
|
87
|
+
yeptris_tape_free(t);
|
|
88
|
+
yep_free(doc->sys, t);
|
|
89
|
+
doc->lazy_tape = NULL;
|
|
90
|
+
} else {
|
|
91
|
+
yep_dom_destroy(dom);
|
|
92
|
+
/* the tape stays: a later access retries, or free
|
|
93
|
+
* drops it (the materializer only fails on malformed
|
|
94
|
+
* NUM spans, which the strict gate already rejected at
|
|
95
|
+
* parse) */
|
|
125
96
|
}
|
|
126
|
-
}
|
|
127
|
-
size_t adv = 0;
|
|
128
|
-
int flt = 0;
|
|
129
|
-
if (yep_json_number_shape(p + off, len, &adv, &flt) == 0 || adv != (size_t)len) {
|
|
130
|
-
return -1;
|
|
131
97
|
}
|
|
132
98
|
}
|
|
133
|
-
|
|
99
|
+
yep_dom* dom = doc->dom;
|
|
100
|
+
yep_mutex_unlock(&doc->lazy_mu);
|
|
101
|
+
return dom;
|
|
134
102
|
}
|
|
135
103
|
|
|
136
104
|
/* The strict-JSON document wrapper (both routes share it). */
|
|
@@ -145,6 +113,7 @@ static YeptrisDocument yep_json_doc_wrap(yep_dom* dom, const char* buf, size_t l
|
|
|
145
113
|
}
|
|
146
114
|
return NULL;
|
|
147
115
|
}
|
|
116
|
+
yep_mutex_init(&doc->lazy_mu);
|
|
148
117
|
doc->dom = dom;
|
|
149
118
|
doc->sys = sys;
|
|
150
119
|
doc->lazy_tape = NULL;
|
|
@@ -166,40 +135,31 @@ YEPTRIS_API YeptrisDocument yeptris_parse_json(const char* buf, size_t len, Yept
|
|
|
166
135
|
st = YEPTRIS_ERROR_ARG;
|
|
167
136
|
goto jfail;
|
|
168
137
|
}
|
|
169
|
-
/* Clean-
|
|
170
|
-
*
|
|
171
|
-
*
|
|
172
|
-
*
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
|
|
176
|
-
|
|
138
|
+
/* Clean-walk fast route (TODO.restructure/81 stage 2, #342): the
|
|
139
|
+
* fused walk runs clean_only — tabs and non-ASCII bytes REJECT —
|
|
140
|
+
* and ANY reject falls to the original sequence below, whose error
|
|
141
|
+
* precedence is byte-for-byte the pinned behavior
|
|
142
|
+
* (json-suite-strict gates this). The entry's full-input gate_scan
|
|
143
|
+
* + tab-memchr pre-passes are GONE: the walk's own byte guarantees
|
|
144
|
+
* route identically by construction, and the strict path re-gates
|
|
145
|
+
* only when actually taken (the profile's 5% + 2% lanes). */
|
|
146
|
+
{
|
|
177
147
|
size_t off = 0;
|
|
178
148
|
while (off < len &&
|
|
179
149
|
(buf[off] == ' ' || buf[off] == '\t' || buf[off] == '\n' || buf[off] == '\r')) {
|
|
180
150
|
off++;
|
|
181
151
|
}
|
|
182
|
-
|
|
183
|
-
* takes them); the strict routes reject them (ErrorParity's
|
|
184
|
-
* pinned agreement). A tab-carrying buffer must NOT take the
|
|
185
|
-
* lazy walk — the validating sequence below reports exactly
|
|
186
|
-
* the pinned reject. */
|
|
187
|
-
if (off < len && (buf[off] == '[' || buf[off] == '{') && memchr(buf, '\t', len) == NULL) {
|
|
188
|
-
/* #342 slice 2: the fused LENIENT walk (one pass, records
|
|
189
|
-
* only — no node building) settles the deferred number
|
|
190
|
-
* grammar inline, then the tape rides the document and
|
|
191
|
-
* dom_from_tape builds nodes on the first tree access.
|
|
192
|
-
* A reject or malformed span falls to the original
|
|
193
|
-
* sequence below, whose error precedence is byte-for-byte
|
|
194
|
-
* the pinned behavior. */
|
|
152
|
+
if (off < len && (buf[off] == '[' || buf[off] == '{')) {
|
|
195
153
|
const yep_allocator* sys = yep_system_allocator();
|
|
196
154
|
yeptris_json_tape* t = yep_alloc(sys, sizeof(*t));
|
|
197
155
|
if (t == NULL) {
|
|
198
156
|
st = YEPTRIS_ERROR_MEMORY;
|
|
199
157
|
goto jfail;
|
|
200
158
|
}
|
|
201
|
-
if (yep_tape_walk_lenient_fused(buf, len, off, t) == YEPTRIS_OK
|
|
202
|
-
|
|
159
|
+
if (yep_tape_walk_lenient_fused(buf, len, off, t, 1, 1) == YEPTRIS_OK) {
|
|
160
|
+
/* strict_nums=1: the arms validated the numbers at
|
|
161
|
+
* record time — the settle pass is gone (the profile's
|
|
162
|
+
* 10% lane; the spans were cache-warm in the walk) */
|
|
203
163
|
YeptrisDocument h = yep_json_doc_wrap(NULL, buf, len, sys, status);
|
|
204
164
|
if (h != NULL) {
|
|
205
165
|
((yeptris_document*)h)->lazy_tape = t;
|
|
@@ -208,7 +168,8 @@ YEPTRIS_API YeptrisDocument yeptris_parse_json(const char* buf, size_t len, Yept
|
|
|
208
168
|
}
|
|
209
169
|
yeptris_tape_free(t); /* wrap failed (memory): below */
|
|
210
170
|
} else {
|
|
211
|
-
yeptris_tape_free(t); /* reject
|
|
171
|
+
yeptris_tape_free(t); /* reject (incl. clean-route tabs
|
|
172
|
+
and non-ASCII): below */
|
|
212
173
|
}
|
|
213
174
|
yep_free(sys, t);
|
|
214
175
|
}
|
|
@@ -220,6 +181,9 @@ YEPTRIS_API YeptrisDocument yeptris_parse_json(const char* buf, size_t len, Yept
|
|
|
220
181
|
st = YEPTRIS_ERROR_PARSE;
|
|
221
182
|
goto jfail;
|
|
222
183
|
}
|
|
184
|
+
/* the fallback re-gates: a buffer here was walk-rejected, so its
|
|
185
|
+
* printability decides whether UTF-8 validation is owed */
|
|
186
|
+
int gated = len > 0 && yep_text_active()->gate_scan(buf, len);
|
|
223
187
|
size_t uerr = 0;
|
|
224
188
|
if (gated && !yep_utf8_validate((const unsigned char*)buf, len, &uerr)) {
|
|
225
189
|
yep_error_set(yep_error_tls(), YEP_ERR_ENCODING, 0, 0, uerr, "ill-formed UTF-8 at byte %zu",
|
|
@@ -370,9 +334,11 @@ engine_enter:
|
|
|
370
334
|
dom->input_base = transcoded ? (const char*)transcoded : buf;
|
|
371
335
|
yep_dom_prepare_len(dom, data_len);
|
|
372
336
|
}
|
|
373
|
-
{
|
|
337
|
+
if (!json_mode) {
|
|
374
338
|
/* the nametab reserve survives: a memchr chain for '&' is
|
|
375
|
-
* far cheaper than the class sweep it replaced
|
|
339
|
+
* far cheaper than the class sweep it replaced. JSON skips it
|
|
340
|
+
* entirely — no anchors exist (the profile's 4.4% memchr
|
|
341
|
+
* lane on the json corpora). */
|
|
376
342
|
yep_text_stats amp_only = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
|
377
343
|
const char* q = data;
|
|
378
344
|
const char* end = data + data_len;
|
|
@@ -465,6 +431,7 @@ engine_enter:
|
|
|
465
431
|
st = YEPTRIS_ERROR_MEMORY;
|
|
466
432
|
goto fail;
|
|
467
433
|
}
|
|
434
|
+
yep_mutex_init(&doc->lazy_mu);
|
|
468
435
|
doc->sys = sys;
|
|
469
436
|
doc->schema = (opts != NULL && opts->schema == YEPTRIS_SCHEMA_11_COMPAT)
|
|
470
437
|
? YEPTRIS_SCHEMA_11_COMPAT
|
|
@@ -504,7 +471,11 @@ fail:
|
|
|
504
471
|
YEPTRIS_API YeptrisDocument yeptris_parse_ex(const char* buf, size_t len,
|
|
505
472
|
const YeptrisParseOptions* opts,
|
|
506
473
|
YeptrisStatus* status) {
|
|
507
|
-
|
|
474
|
+
/* #378 slice 2: the default YAML route carries the packed record
|
|
475
|
+
* tape — the tree materializes on first access (yep_doc_dom).
|
|
476
|
+
* Same grammar, same errors; parse-only workloads never build
|
|
477
|
+
* nodes. The eager form stays on yeptris_parse_eager_ex. */
|
|
478
|
+
return parse_impl(buf, len, opts, 0, 1, status);
|
|
508
479
|
}
|
|
509
480
|
|
|
510
481
|
/* #378 slice 1 (internal seam): the YAML parse rides the packed record
|
|
@@ -515,6 +486,13 @@ YeptrisDocument yeptris_parse_ytape_ex(const char* buf, size_t len, const Yeptri
|
|
|
515
486
|
return parse_impl(buf, len, opts, 0, 1, status);
|
|
516
487
|
}
|
|
517
488
|
|
|
489
|
+
/* The eager form, kept for the parse-only A/B (bench_matrix's #378
|
|
490
|
+
* table) and as the reference lane the differential gates ride. */
|
|
491
|
+
YeptrisDocument yeptris_parse_eager_ex(const char* buf, size_t len, const YeptrisParseOptions* opts,
|
|
492
|
+
YeptrisStatus* status) {
|
|
493
|
+
return parse_impl(buf, len, opts, 0, 0, status);
|
|
494
|
+
}
|
|
495
|
+
|
|
518
496
|
YEPTRIS_API void yeptris_document_free(YeptrisDocument handle) {
|
|
519
497
|
yeptris_document* doc = (yeptris_document*)handle;
|
|
520
498
|
if (doc == NULL) {
|
|
@@ -528,6 +506,7 @@ YEPTRIS_API void yeptris_document_free(YeptrisDocument handle) {
|
|
|
528
506
|
}
|
|
529
507
|
yep_free(doc->sys, doc->lazy_tape);
|
|
530
508
|
}
|
|
509
|
+
yep_mutex_destroy(&doc->lazy_mu);
|
|
531
510
|
yep_dom_destroy(doc->dom);
|
|
532
511
|
yep_pool_destroy((yep_pool*)doc->finish_pool);
|
|
533
512
|
yep_free(doc->sys, doc->transcoded);
|
|
@@ -536,7 +515,10 @@ YEPTRIS_API void yeptris_document_free(YeptrisDocument handle) {
|
|
|
536
515
|
|
|
537
516
|
YEPTRIS_API size_t yeptris_document_count(YeptrisDocument handle) {
|
|
538
517
|
yeptris_document* doc = (yeptris_document*)handle;
|
|
539
|
-
|
|
518
|
+
yep_dom* dom = doc ? yep_doc_dom(doc) : NULL; /* NULL: the lazy
|
|
519
|
+
* route's failed/retrying materialization — an
|
|
520
|
+
* unusable tree counts as zero documents */
|
|
521
|
+
return dom ? dom->dcount : 0;
|
|
540
522
|
}
|
|
541
523
|
|
|
542
524
|
yeptris_node* yep_handle_new(yeptris_document* doc, uint32_t id) {
|
|
@@ -601,8 +601,54 @@ reject:
|
|
|
601
601
|
* (the classify scan carries no accept/reject structure) and
|
|
602
602
|
* yeptris_tape_convert owns validation. Everything else matches
|
|
603
603
|
* tape_walk state for state. */
|
|
604
|
+
/* The strict RFC 8259 number check over one number-ish run — the
|
|
605
|
+
* in-walk float/exp validator (the out-of-line number_shape call +
|
|
606
|
+
* rescan was 13% of json-doc; the digits-only case never gets here).
|
|
607
|
+
* One pass, no state machine words: sign, digits (leading-zero rule),
|
|
608
|
+
* optional .digits, optional e[+-]digits, consume exactly len. */
|
|
609
|
+
static int tape_num_ok(const char* p, size_t len) {
|
|
610
|
+
size_t k = 0;
|
|
611
|
+
if (k < len && p[k] == '-') {
|
|
612
|
+
k++;
|
|
613
|
+
}
|
|
614
|
+
size_t int_start = k;
|
|
615
|
+
while (k < len && (unsigned)(unsigned char)p[k] - '0' <= 9u) {
|
|
616
|
+
k++;
|
|
617
|
+
}
|
|
618
|
+
if (k == int_start) {
|
|
619
|
+
return 0; /* no integer part */
|
|
620
|
+
}
|
|
621
|
+
if (k - int_start > 1 && p[int_start] == '0') {
|
|
622
|
+
return 0; /* leading zero */
|
|
623
|
+
}
|
|
624
|
+
if (k < len && p[k] == '.') {
|
|
625
|
+
k++;
|
|
626
|
+
size_t frac = k;
|
|
627
|
+
while (k < len && (unsigned)(unsigned char)p[k] - '0' <= 9u) {
|
|
628
|
+
k++;
|
|
629
|
+
}
|
|
630
|
+
if (k == frac) {
|
|
631
|
+
return 0;
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
if (k < len && (p[k] == 'e' || p[k] == 'E')) {
|
|
635
|
+
k++;
|
|
636
|
+
if (k < len && (p[k] == '+' || p[k] == '-')) {
|
|
637
|
+
k++;
|
|
638
|
+
}
|
|
639
|
+
size_t exp = k;
|
|
640
|
+
while (k < len && (unsigned)(unsigned char)p[k] - '0' <= 9u) {
|
|
641
|
+
k++;
|
|
642
|
+
}
|
|
643
|
+
if (k == exp) {
|
|
644
|
+
return 0;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
return k == len;
|
|
648
|
+
}
|
|
649
|
+
|
|
604
650
|
YeptrisStatus yep_tape_walk_lenient_fused(const char* p, size_t len, size_t open,
|
|
605
|
-
yeptris_json_tape* t) {
|
|
651
|
+
yeptris_json_tape* t, int strict_nums, int clean_only) {
|
|
606
652
|
if (tape_carve(t, len) != YEPTRIS_OK) {
|
|
607
653
|
return YEPTRIS_ERROR_MEMORY;
|
|
608
654
|
}
|
|
@@ -624,11 +670,24 @@ YeptrisStatus yep_tape_walk_lenient_fused(const char* p, size_t len, size_t open
|
|
|
624
670
|
kind[0] = top_kind;
|
|
625
671
|
|
|
626
672
|
size_t i = open + 1;
|
|
673
|
+
/* clean_only (parse_json's route): tabs and non-ASCII bytes REJECT
|
|
674
|
+
* — the caller falls to the strict sequence, which owns the pinned
|
|
675
|
+
* error precedences those inputs carry (the tab reject, the UTF-8
|
|
676
|
+
* gate). This replaces the entry's full-input gate_scan +
|
|
677
|
+
* tab-memchr pre-passes: same routing by construction, zero scans
|
|
678
|
+
* before the walk. */
|
|
679
|
+
int cl = clean_only;
|
|
627
680
|
if (top_kind) {
|
|
628
681
|
goto lmap1;
|
|
629
682
|
}
|
|
630
683
|
goto lseq1;
|
|
631
684
|
|
|
685
|
+
/* strict_nums: the parse_json route's contract is RFC 8259 AT
|
|
686
|
+
* parse time, so its number arms validate the run in-place (the
|
|
687
|
+
* settle pass disappears — the span is cache-warm here); the
|
|
688
|
+
* standalone lenient entry keeps its deferred contract (0: the
|
|
689
|
+
* run records unvalidated, yeptris_tape_convert owns it). */
|
|
690
|
+
|
|
632
691
|
/* The specialized member loops (the #342 dispatch-chain cut): once
|
|
633
692
|
* inside a container the grammar is a 2-state cycle — member or
|
|
634
693
|
* separator — so the general chain's expect/key_slot machine and
|
|
@@ -643,7 +702,8 @@ YeptrisStatus yep_tape_walk_lenient_fused(const char* p, size_t len, size_t open
|
|
|
643
702
|
|
|
644
703
|
#define LWS() \
|
|
645
704
|
do { \
|
|
646
|
-
while (i < len &&
|
|
705
|
+
while (i < len && \
|
|
706
|
+
(p[i] == ' ' || p[i] == '\n' || p[i] == '\r' || (p[i] == '\t' && !cl))) { \
|
|
647
707
|
i++; \
|
|
648
708
|
} \
|
|
649
709
|
if (i >= len) { \
|
|
@@ -701,7 +761,8 @@ YeptrisStatus yep_tape_walk_lenient_fused(const char* p, size_t len, size_t open
|
|
|
701
761
|
qm_ = (qm_ - 0x0101010101010101ull) & ~qm_ & 0x8080808080808080ull; \
|
|
702
762
|
bm_ = (bm_ - 0x0101010101010101ull) & ~bm_ & 0x8080808080808080ull; \
|
|
703
763
|
uint64_t c0_ = (w_ - 0x2020202020202020ull) & ~w_ & 0x8080808080808080ull; \
|
|
704
|
-
|
|
764
|
+
uint64_t hi_ = cl ? (w_ & 0x8080808080808080ull) : 0; \
|
|
765
|
+
if (qm_ != 0 && ((bm_ | c0_ | hi_) & (qm_ - 1)) == 0) { \
|
|
705
766
|
size_t cl_ = j_ + (size_t)yep_ctz64(qm_) / 8; \
|
|
706
767
|
recs[count] = ((uint64_t)((uint32_t)j_) << 32) | \
|
|
707
768
|
((uint64_t)((uint32_t)(cl_ - j_)) << 8) | (uint64_t)(YEP_T_STR); \
|
|
@@ -720,12 +781,17 @@ YeptrisStatus yep_tape_walk_lenient_fused(const char* p, size_t len, size_t open
|
|
|
720
781
|
if (room_ >= 8) { \
|
|
721
782
|
uint64_t v_; \
|
|
722
783
|
memcpy(&v_, p + b_, 8); \
|
|
723
|
-
|
|
784
|
+
uint64_t bad_ = \
|
|
785
|
+
(v_ - 0x2020202020202020ull) & ~v_ & 0x8080808080808080ull; \
|
|
786
|
+
if (cl) { \
|
|
787
|
+
bad_ |= v_ & 0x8080808080808080ull; \
|
|
788
|
+
} \
|
|
789
|
+
if (bad_) { \
|
|
724
790
|
goto lreject; \
|
|
725
791
|
} \
|
|
726
792
|
b_ += 8; \
|
|
727
793
|
} else { \
|
|
728
|
-
if ((unsigned char)p[b_] < 0x20) {
|
|
794
|
+
if ((unsigned char)p[b_] < 0x20 || (cl && (unsigned char)p[b_] >= 0x80)) { \
|
|
729
795
|
goto lreject; \
|
|
730
796
|
} \
|
|
731
797
|
b_++; \
|
|
@@ -744,6 +810,16 @@ YeptrisStatus yep_tape_walk_lenient_fused(const char* p, size_t len, size_t open
|
|
|
744
810
|
if (!yep_json_string(p, len, &i, &cl_, &esc_)) { \
|
|
745
811
|
goto lreject; \
|
|
746
812
|
} \
|
|
813
|
+
if (cl) { /* escaped strings skip the sweeps above: the \
|
|
814
|
+
* clean route still owes the strict sequence's \
|
|
815
|
+
* byte guarantees over the content */ \
|
|
816
|
+
for (size_t b_ = at_ + 1; b_ < cl_; b_++) { \
|
|
817
|
+
unsigned char uc_ = (unsigned char)p[b_]; \
|
|
818
|
+
if (uc_ < 0x20 || uc_ >= 0x80) { \
|
|
819
|
+
goto lreject; \
|
|
820
|
+
} \
|
|
821
|
+
} \
|
|
822
|
+
} \
|
|
747
823
|
recs[count] = ((uint64_t)((uint32_t)(at_ + 1)) << 32) | \
|
|
748
824
|
((uint64_t)((uint32_t)(cl_ - at_ - 1)) << 8) | (uint64_t)(YEP_T_STR); \
|
|
749
825
|
count++; \
|
|
@@ -788,15 +864,36 @@ lmapcolon:
|
|
|
788
864
|
}
|
|
789
865
|
if ((unsigned)(c - '0') <= 9u || c == '-') {
|
|
790
866
|
size_t k = i + 1;
|
|
867
|
+
/* the digits-only tracking makes the pure-integer case a
|
|
868
|
+
* 3-cycle leading-zero check — number_shape (a call + a
|
|
869
|
+
* rescan, 13% of json-doc) runs only for dot/exp spans */
|
|
870
|
+
int digits_only = 1, saw_digit = (c != '-');
|
|
791
871
|
while (k < len) {
|
|
792
872
|
char d = p[k];
|
|
793
|
-
if ((d
|
|
794
|
-
|
|
873
|
+
if ((unsigned)(d - '0') <= 9u) {
|
|
874
|
+
k++;
|
|
875
|
+
saw_digit = 1;
|
|
876
|
+
continue;
|
|
877
|
+
}
|
|
878
|
+
digits_only = 0;
|
|
879
|
+
if (d == '-' || d == '+' || d == '.' || d == 'e' || d == 'E') {
|
|
795
880
|
k++;
|
|
796
881
|
continue;
|
|
797
882
|
}
|
|
798
883
|
break;
|
|
799
884
|
}
|
|
885
|
+
if (strict_nums) {
|
|
886
|
+
int ok;
|
|
887
|
+
if (digits_only && saw_digit) {
|
|
888
|
+
size_t d0 = (c == '-') ? i + 1 : i;
|
|
889
|
+
ok = (k - d0 == 1) || p[d0] != '0';
|
|
890
|
+
} else {
|
|
891
|
+
ok = tape_num_ok(p + i, (size_t)(k - i));
|
|
892
|
+
}
|
|
893
|
+
if (!ok) {
|
|
894
|
+
goto lreject;
|
|
895
|
+
}
|
|
896
|
+
}
|
|
800
897
|
recs[count] = ((uint64_t)((uint32_t)i) << 32) | ((uint64_t)((uint32_t)(k - i)) << 8) |
|
|
801
898
|
(uint64_t)(YEP_T_NUM);
|
|
802
899
|
count++;
|
|
@@ -868,15 +965,33 @@ lseqval: {
|
|
|
868
965
|
}
|
|
869
966
|
if ((unsigned)(c - '0') <= 9u || c == '-') {
|
|
870
967
|
size_t k = i + 1;
|
|
968
|
+
int digits_only = 1, saw_digit = (c != '-');
|
|
871
969
|
while (k < len) {
|
|
872
970
|
char d = p[k];
|
|
873
|
-
if ((d
|
|
874
|
-
|
|
971
|
+
if ((unsigned)(d - '0') <= 9u) {
|
|
972
|
+
k++;
|
|
973
|
+
saw_digit = 1;
|
|
974
|
+
continue;
|
|
975
|
+
}
|
|
976
|
+
digits_only = 0;
|
|
977
|
+
if (d == '-' || d == '+' || d == '.' || d == 'e' || d == 'E') {
|
|
875
978
|
k++;
|
|
876
979
|
continue;
|
|
877
980
|
}
|
|
878
981
|
break;
|
|
879
982
|
}
|
|
983
|
+
if (strict_nums) {
|
|
984
|
+
int ok;
|
|
985
|
+
if (digits_only && saw_digit) {
|
|
986
|
+
size_t d0 = (c == '-') ? i + 1 : i;
|
|
987
|
+
ok = (k - d0 == 1) || p[d0] != '0';
|
|
988
|
+
} else {
|
|
989
|
+
ok = tape_num_ok(p + i, (size_t)(k - i));
|
|
990
|
+
}
|
|
991
|
+
if (!ok) {
|
|
992
|
+
goto lreject;
|
|
993
|
+
}
|
|
994
|
+
}
|
|
880
995
|
recs[count] = ((uint64_t)((uint32_t)i) << 32) | ((uint64_t)((uint32_t)(k - i)) << 8) |
|
|
881
996
|
(uint64_t)(YEP_T_NUM);
|
|
882
997
|
count++;
|
|
@@ -940,7 +1055,7 @@ ldone:
|
|
|
940
1055
|
{
|
|
941
1056
|
size_t tail = i;
|
|
942
1057
|
while (tail < len &&
|
|
943
|
-
(p[tail] == ' ' || p[tail] == '\
|
|
1058
|
+
(p[tail] == ' ' || p[tail] == '\n' || p[tail] == '\r' || (p[tail] == '\t' && !cl))) {
|
|
944
1059
|
tail++;
|
|
945
1060
|
}
|
|
946
1061
|
if (tail != len) {
|
|
@@ -1465,7 +1580,7 @@ YEPTRIS_API YeptrisStatus yeptris_parse_json_tape_lenient(const char* source, si
|
|
|
1465
1580
|
return st;
|
|
1466
1581
|
}
|
|
1467
1582
|
free(blocks);
|
|
1468
|
-
return yep_tape_walk_lenient_fused(source, len, at, tape);
|
|
1583
|
+
return yep_tape_walk_lenient_fused(source, len, at, tape, 0, 0);
|
|
1469
1584
|
}
|
|
1470
1585
|
|
|
1471
1586
|
/* scalar root: one record, same deferred split for numbers */
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
/* tape.c (was tape_walk_lnt_fused) */
|
|
17
17
|
YeptrisStatus yep_tape_walk_lenient_fused(const char* p, size_t len, size_t open,
|
|
18
|
-
yeptris_json_tape* t);
|
|
18
|
+
yeptris_json_tape* t, int strict_nums, int clean_only);
|
|
19
19
|
|
|
20
20
|
/* parse.c (#378 slice 1): the YAML parse carrying the packed record
|
|
21
21
|
* tape — the tree materializes on first access (yep_doc_dom). */
|
|
@@ -24,6 +24,11 @@ extern "C" {
|
|
|
24
24
|
#endif
|
|
25
25
|
YeptrisDocument yeptris_parse_ytape_ex(const char* buf, size_t len, const YeptrisParseOptions* opts,
|
|
26
26
|
YeptrisStatus* status);
|
|
27
|
+
|
|
28
|
+
/* the eager form (the A/B reference lane): the engine builds nodes at
|
|
29
|
+
* parse, no tape */
|
|
30
|
+
YeptrisDocument yeptris_parse_eager_ex(const char* buf, size_t len, const YeptrisParseOptions* opts,
|
|
31
|
+
YeptrisStatus* status);
|
|
27
32
|
#ifdef __cplusplus
|
|
28
33
|
}
|
|
29
34
|
#endif
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: yeptris
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.6.
|
|
4
|
+
version: 0.6.21.1
|
|
5
5
|
platform: aarch64-linux
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-09-
|
|
11
|
+
date: 2026-09-25 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: ffi
|