teptris 0.2.46-powerpc64le-linux → 0.2.48-powerpc64le-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/ext/teptris_ext/materialize.c +120 -22
- data/lib/teptris/3.3/teptris_ext.so +0 -0
- data/lib/teptris/3.4/teptris_ext.so +0 -0
- data/lib/teptris/4.0/teptris_ext.so +0 -0
- data/lib/teptris/version.rb +1 -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: 6ab5c640ceac5cbe96addaf083d40607a834e3ffbf93063cf95085c4a7b19fe9
|
|
4
|
+
data.tar.gz: fc71dd53f489b7b47ff550b07a4039e8bd5fe7a79fd192bde0a8690dda37a415
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1545f3eeaaf6d7ec37bb5f8e31c6143cf5193c0f7ae9747284f2dbc9ebe2071113cb44a3bfb84d64fe331bb4a52f361581d4f04ae4b25547b0c8ced922f0a177
|
|
7
|
+
data.tar.gz: 1181e760f9351324f8edf9bae816d8f8b5626735c222e1d81dfa86d2eb9135ee018d8065d5d778acc9b009891c560a0310008575ac3e0ec52122dfa7ce8b95f4
|
|
@@ -21,18 +21,25 @@ static int64_t days_from_civil(int32_t y, uint8_t m, uint8_t d) {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
/* exact (no double) Time materialization: nsec stays nsec. Offset
|
|
24
|
-
* datetimes
|
|
25
|
-
* Time.local with Rational seconds (
|
|
26
|
-
*
|
|
24
|
+
* datetimes carry a fixed utc offset via rb_time_num_new; local
|
|
25
|
+
* datetimes go through Time.local with Rational seconds (both treat
|
|
26
|
+
* the epoch value as wall-clock for locals / instant+offset for
|
|
27
|
+
* fixed zones). No struct timespec crosses the Ruby boundary:
|
|
28
|
+
* armhf glibc rubies build with _TIME_BITS=64 (16-byte timespec)
|
|
29
|
+
* while an ext compiled without it lays out 8 bytes — the struct
|
|
30
|
+
* APIs then read (load) or write (dump) past each side's layout. */
|
|
27
31
|
static VALUE time_from_dt(const teptris_datetime *d, bool has_offset) {
|
|
28
32
|
if (has_offset) {
|
|
29
33
|
int64_t days = days_from_civil(d->year, d->month, d->day);
|
|
30
34
|
int64_t secs =
|
|
31
35
|
days * 86400 + d->hour * 3600 + d->minute * 60 + d->second;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
+
VALUE num = LL2NUM(secs - d->offset_seconds);
|
|
37
|
+
if (d->nanosecond != 0) {
|
|
38
|
+
num = rb_funcall(num, '+', 1,
|
|
39
|
+
rb_Rational(LL2NUM((int64_t)d->nanosecond),
|
|
40
|
+
LL2NUM(1000000000)));
|
|
41
|
+
}
|
|
42
|
+
return rb_time_num_new(num, INT2FIX(d->offset_seconds));
|
|
36
43
|
}
|
|
37
44
|
VALUE args[6] = {INT2FIX(d->year), INT2FIX(d->month), INT2FIX(d->day),
|
|
38
45
|
INT2FIX(d->hour), INT2FIX(d->minute),
|
|
@@ -82,7 +89,87 @@ static VALUE dt_string(const teptris_datetime *d, int kind) {
|
|
|
82
89
|
return rb_enc_str_new(buf, l, rb_utf8_encoding());
|
|
83
90
|
}
|
|
84
91
|
|
|
85
|
-
|
|
92
|
+
/* ---- per-load table-key cache ------------------------------------------------
|
|
93
|
+
* TOML keys repeat within a document and across a batch; a fresh String
|
|
94
|
+
* per occurrence costs an allocation and a full Hash re-hash each time.
|
|
95
|
+
* This cache maps key CONTENT to one frozen String, shared everywhere:
|
|
96
|
+
* repeated keys become a single GC-pinned object with its hash already
|
|
97
|
+
* computed. It is document-local (dies with the load call), capped at
|
|
98
|
+
* KC_CAP entries so unique-key corpora pay only a cheap failed probe
|
|
99
|
+
* after the cap, and never touches the VM's global fstring table (the
|
|
100
|
+
* intern-always attempt regressed there — teptris-ruby#122: unique
|
|
101
|
+
* keys make the intern table pure overhead). Strings are frozen so the
|
|
102
|
+
* sharing cannot alias a mutation. NULL cache = fresh strings (the
|
|
103
|
+
* low-volume schema-RAW path). */
|
|
104
|
+
|
|
105
|
+
#define KC_CAP 4096
|
|
106
|
+
#define KC_SLOTS (KC_CAP * 2) /* stays <=50% full: probes stay ~2 */
|
|
107
|
+
|
|
108
|
+
typedef struct {
|
|
109
|
+
VALUE str; /* Qfalse = empty slot */
|
|
110
|
+
} kc_slot;
|
|
111
|
+
|
|
112
|
+
typedef struct {
|
|
113
|
+
VALUE keep; /* Ruby Array pinning every cached String */
|
|
114
|
+
kc_slot *slots;
|
|
115
|
+
size_t used;
|
|
116
|
+
} keycache;
|
|
117
|
+
|
|
118
|
+
static uint64_t kc_hash(const char *p, size_t len)
|
|
119
|
+
{
|
|
120
|
+
uint64_t h = 1469598103934665603ULL;
|
|
121
|
+
for (size_t i = 0; i < len; i++) {
|
|
122
|
+
h ^= (unsigned char)p[i];
|
|
123
|
+
h *= 1099511628211ULL;
|
|
124
|
+
}
|
|
125
|
+
return h;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
static void kc_init(keycache *kc)
|
|
129
|
+
{
|
|
130
|
+
kc->keep = rb_ary_new_capa(64);
|
|
131
|
+
kc->slots = calloc(KC_SLOTS, sizeof(kc_slot)); /* zero = Qfalse empty */
|
|
132
|
+
if (kc->slots == NULL) {
|
|
133
|
+
/* no cache is a correctness-preserving fallback */
|
|
134
|
+
kc->keep = Qnil;
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
kc->used = 0;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
static void kc_free(keycache *kc)
|
|
141
|
+
{
|
|
142
|
+
free(kc->slots);
|
|
143
|
+
kc->slots = NULL;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
static VALUE kc_key(keycache *kc, const char *p, size_t len)
|
|
147
|
+
{
|
|
148
|
+
if (kc == NULL || kc->slots == NULL) {
|
|
149
|
+
return rb_enc_str_new(p, (long)len, rb_utf8_encoding());
|
|
150
|
+
}
|
|
151
|
+
size_t mask = KC_SLOTS - 1;
|
|
152
|
+
size_t slot = (size_t)kc_hash(p, len) & mask;
|
|
153
|
+
while (kc->slots[slot].str != Qfalse) {
|
|
154
|
+
VALUE s = kc->slots[slot].str;
|
|
155
|
+
if ((size_t)RSTRING_LEN(s) == len &&
|
|
156
|
+
memcmp(RSTRING_PTR(s), p, len) == 0) {
|
|
157
|
+
return s; /* hit: one shared object, hash already cached */
|
|
158
|
+
}
|
|
159
|
+
slot = (slot + 1) & mask;
|
|
160
|
+
}
|
|
161
|
+
VALUE fresh = rb_enc_str_new(p, (long)len, rb_utf8_encoding());
|
|
162
|
+
rb_obj_freeze(fresh);
|
|
163
|
+
rb_ary_push(kc->keep, fresh); /* GC pin before it enters the slots */
|
|
164
|
+
if (kc->used < KC_CAP) {
|
|
165
|
+
kc->slots[slot].str = fresh;
|
|
166
|
+
kc->used++;
|
|
167
|
+
}
|
|
168
|
+
return fresh;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
static VALUE obj_from_node(const teptris_node *n, unsigned flags,
|
|
172
|
+
keycache *kc) {
|
|
86
173
|
switch (teptris_node_kind(n)) {
|
|
87
174
|
case TEPTRIS_TABLE: {
|
|
88
175
|
size_t len = teptris_node_table_length(n);
|
|
@@ -90,9 +177,8 @@ static VALUE obj_from_node(const teptris_node *n, unsigned flags) {
|
|
|
90
177
|
for (size_t i = 0; i < len; i++) {
|
|
91
178
|
teptris_view key;
|
|
92
179
|
const teptris_node *v = teptris_node_table_at(n, i, &key);
|
|
93
|
-
rb_hash_aset(h,
|
|
94
|
-
|
|
95
|
-
obj_from_node(v, flags));
|
|
180
|
+
rb_hash_aset(h, kc_key(kc, key.ptr, (size_t)key.len),
|
|
181
|
+
obj_from_node(v, flags, kc));
|
|
96
182
|
}
|
|
97
183
|
return h;
|
|
98
184
|
}
|
|
@@ -100,7 +186,7 @@ static VALUE obj_from_node(const teptris_node *n, unsigned flags) {
|
|
|
100
186
|
size_t len = teptris_node_array_length(n);
|
|
101
187
|
VALUE a = rb_ary_new_capa((long)len);
|
|
102
188
|
for (size_t i = 0; i < len; i++)
|
|
103
|
-
rb_ary_push(a, obj_from_node(teptris_node_array_at(n, i), flags));
|
|
189
|
+
rb_ary_push(a, obj_from_node(teptris_node_array_at(n, i), flags, kc));
|
|
104
190
|
return a;
|
|
105
191
|
}
|
|
106
192
|
case TEPTRIS_STRING: {
|
|
@@ -169,7 +255,10 @@ static VALUE ext_load(int argc, VALUE *argv, VALUE self) {
|
|
|
169
255
|
if (RTEST(fd)) flags |= FMT_FORBID_DATE;
|
|
170
256
|
}
|
|
171
257
|
teptris_document *doc = parse_or_raise(str);
|
|
172
|
-
|
|
258
|
+
keycache kc;
|
|
259
|
+
kc_init(&kc);
|
|
260
|
+
VALUE out = obj_from_node(teptris_document_root(doc), flags, &kc);
|
|
261
|
+
kc_free(&kc);
|
|
173
262
|
teptris_document_free(doc);
|
|
174
263
|
return out;
|
|
175
264
|
}
|
|
@@ -180,7 +269,7 @@ static VALUE ext_version(VALUE self) {
|
|
|
180
269
|
|
|
181
270
|
/* ------------------------------------------------------------------ dump */
|
|
182
271
|
|
|
183
|
-
static ID id_utc_offset, id_to_s;
|
|
272
|
+
static ID id_utc_offset, id_to_s, id_to_i, id_nsec;
|
|
184
273
|
|
|
185
274
|
static void dump_check(teptris_status st) {
|
|
186
275
|
if (st == TEPTRIS_OK) return;
|
|
@@ -206,12 +295,12 @@ static void civil_from_days(int64_t z, int32_t *y, uint8_t *m, uint8_t *d) {
|
|
|
206
295
|
*d = (uint8_t)dd;
|
|
207
296
|
}
|
|
208
297
|
|
|
209
|
-
/*
|
|
210
|
-
*
|
|
298
|
+
/* the instant and its subsecond part come back as Integers (to_i
|
|
299
|
+
* floors, nsec stays in [0, 1e9) — same split the timespec gave);
|
|
300
|
+
* the civil fields are integer math on epoch + offset */
|
|
211
301
|
static void fill_dt_from_time(VALUE v, teptris_datetime *dt) {
|
|
212
|
-
struct timespec ts = rb_time_timespec(v);
|
|
213
302
|
dt->offset_seconds = NUM2INT(rb_funcall(v, id_utc_offset, 0));
|
|
214
|
-
int64_t secs = (
|
|
303
|
+
int64_t secs = NUM2LL(rb_funcall(v, id_to_i, 0)) + dt->offset_seconds;
|
|
215
304
|
int64_t days = secs / 86400;
|
|
216
305
|
int32_t rem = (int32_t)(secs % 86400);
|
|
217
306
|
if (rem < 0) { /* floor division: keep rem in [0, 86400) */
|
|
@@ -222,7 +311,7 @@ static void fill_dt_from_time(VALUE v, teptris_datetime *dt) {
|
|
|
222
311
|
dt->hour = (uint8_t)(rem / 3600);
|
|
223
312
|
dt->minute = (uint8_t)((rem / 60) % 60);
|
|
224
313
|
dt->second = (uint8_t)(rem % 60);
|
|
225
|
-
dt->nanosecond = (uint32_t)
|
|
314
|
+
dt->nanosecond = (uint32_t)NUM2LL(rb_funcall(v, id_nsec, 0));
|
|
226
315
|
}
|
|
227
316
|
|
|
228
317
|
static void dump_scalar(teptris_builder *b, const char *key, size_t klen,
|
|
@@ -519,7 +608,7 @@ static VALUE asm_rows(const teptris_plan *p, const teptris_plan_result *res,
|
|
|
519
608
|
case TEPTRIS_PLAN_RAW_RESULT: {
|
|
520
609
|
const teptris_node *raw = teptris_plan_result_raw_at(res, i);
|
|
521
610
|
if (raw != NULL) {
|
|
522
|
-
val = obj_from_node(raw, 0);
|
|
611
|
+
val = obj_from_node(raw, 0, NULL);
|
|
523
612
|
}
|
|
524
613
|
break;
|
|
525
614
|
}
|
|
@@ -773,7 +862,11 @@ static VALUE lazy_dig(int argc, VALUE *argv, VALUE self) {
|
|
|
773
862
|
/* full materialization: the eager path, owned */
|
|
774
863
|
static VALUE lazy_to(VALUE self) {
|
|
775
864
|
lazy_value *v = lazy_self(self);
|
|
776
|
-
|
|
865
|
+
keycache kc;
|
|
866
|
+
kc_init(&kc);
|
|
867
|
+
VALUE out = obj_from_node(v->node, 0, &kc);
|
|
868
|
+
kc_free(&kc);
|
|
869
|
+
return out;
|
|
777
870
|
}
|
|
778
871
|
|
|
779
872
|
/* ---------------------------------------------------------------- batch --
|
|
@@ -929,11 +1022,14 @@ static VALUE ext_load_batch(int argc, VALUE *argv, VALUE self) {
|
|
|
929
1022
|
rb_exc_raise(ex);
|
|
930
1023
|
}
|
|
931
1024
|
VALUE out = rb_ary_new_capa(n);
|
|
1025
|
+
keycache kc;
|
|
1026
|
+
kc_init(&kc); /* one cache across the batch: keys repeat across docs */
|
|
932
1027
|
for (long i = 0; i < n; i++) {
|
|
933
1028
|
const teptris_node *root = teptris_document_root(s->docs[i]);
|
|
934
|
-
rb_ary_store(out, i, obj_from_node(root, flags));
|
|
1029
|
+
rb_ary_store(out, i, obj_from_node(root, flags, &kc));
|
|
935
1030
|
teptris_document_free(s->docs[i]);
|
|
936
1031
|
}
|
|
1032
|
+
kc_free(&kc);
|
|
937
1033
|
batch_scratch_free(s);
|
|
938
1034
|
return out;
|
|
939
1035
|
}
|
|
@@ -967,4 +1063,6 @@ void Init_teptris_ext(void) {
|
|
|
967
1063
|
cDate = rb_const_get(rb_cObject, rb_intern("Date"));
|
|
968
1064
|
id_utc_offset = rb_intern("utc_offset");
|
|
969
1065
|
id_to_s = rb_intern("to_s");
|
|
1066
|
+
id_to_i = rb_intern("to_i");
|
|
1067
|
+
id_nsec = rb_intern("nsec");
|
|
970
1068
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
data/lib/teptris/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: teptris
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.48
|
|
5
5
|
platform: powerpc64le-linux
|
|
6
6
|
authors:
|
|
7
7
|
- teptris contributors
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-09-
|
|
11
|
+
date: 2026-09-26 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: A native C extension over libteptris, a C99 TOML 1.1 parser/emitter.
|
|
14
14
|
API shape mirrors the tomlib gem.
|