yeptris 0.6.8.2 → 0.6.9.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e3cd35014222c85dc46a7d9cc3622ae85729d055a218ab89899aaee638d774bb
4
- data.tar.gz: abab0a3805fad843a6c1ac6e6f09e28e5cd0c3874f6e58e1cc3bf86dbdbaec9b
3
+ metadata.gz: 128c08457353396f6f709f8719256a3b3ce1463518456b34987f252314a0dda4
4
+ data.tar.gz: 9c20441656c1fdb05003d3e0fa0ee4af6d7d758d5505d387fb09dfb86d37e493
5
5
  SHA512:
6
- metadata.gz: 2af308efb9fc6d825adc204d950ed2c2496fcaad50194015711c6d89dec0c4c32a7630e5644c0edc1df880fa684311d1aa7ddabfb7572e05a9d28d7ae81df1fb
7
- data.tar.gz: 3ce1d7a886d39e9afafacd94f0869152b0d21cacb548ce49b76b929c7a705163ce8dc996e636a40541d7e334d4a3aa49a0ee3a79488dac55477ebdb570f76303
6
+ metadata.gz: a3db668d48f7febd05d6ab518c5696704a6673fe5b9e7dd2fab2ea3ea3fcb41e021cb41b3136ddc96f6d5540a8ee9e8cc6c37997ff4a56de719ec1e783fa7fa0
7
+ data.tar.gz: 4cb9c60fd78802cb49a97fffb1ce9fd27e047cd5204edf5c1e2621110613122babbac634d2a273a360029ea6c5df15bbdb7298fcb100c3fa53a66abb838bbf56
@@ -0,0 +1,134 @@
1
+ /* cbor_ruby.c — CBOR decode → Ruby VALUE in one C pass (#157).
2
+ *
3
+ * The FFI ladder's CBOR.load pays decode + a Marshal emit/load round
4
+ * trip; this walks the decoded DOM directly, building the same VALUEs
5
+ * the materializer builds (tag-driven scalar semantics, insertion-
6
+ * order mappings), with no intermediate representation.
7
+ */
8
+ #include <ruby.h>
9
+ /* rb_hash_new_capa is Ruby 3.2+; older Rubies grow dynamically (the
10
+ * json_ruby.c guard, verbatim). */
11
+ #if RUBY_API_VERSION_MAJOR > 3 || (RUBY_API_VERSION_MAJOR == 3 && RUBY_API_VERSION_MINOR >= 2)
12
+ #define HASH_NEW_CAPA(n) rb_hash_new_capa(n)
13
+ #else
14
+ #define HASH_NEW_CAPA(n) rb_hash_new()
15
+ #endif
16
+ #include <ruby/encoding.h>
17
+ #include <stdlib.h>
18
+ #include <string.h>
19
+
20
+ #include "dom/dom.h"
21
+ #include "doc.h" /* the public YeptrisDocument wrapper: ->dom */
22
+ #include <yeptris/cbor.h>
23
+ #include <yeptris/dom.h>
24
+ #include <yeptris/resolve.h>
25
+
26
+ static const char* cr_view(const yep_dom* d, yep_sview sv, uint32_t* len) {
27
+ *len = sv.len;
28
+ if (sv.len == 0) {
29
+ return "";
30
+ }
31
+ return (sv.off & YEP_SV_INPUT) ? (d->str + (sv.off & YEP_SV_OFF)) : (d->input_base + sv.off);
32
+ }
33
+
34
+ static VALUE cr_scalar(const yep_dom* d, const yep_dnode* n) {
35
+ uint32_t len = 0;
36
+ const char* p = cr_view(d, n->value, &len);
37
+ switch (n->tag_id) {
38
+ case YEPTRIS_TAG_NULL:
39
+ return Qnil;
40
+ case YEPTRIS_TAG_BOOL:
41
+ if (len == 1) { /* Psych: "y"/"n" stay Strings */
42
+ return rb_utf8_str_new(p, len);
43
+ }
44
+ return (len == 4 && memcmp(p, "true", 4) == 0) ? Qtrue : Qfalse;
45
+ case YEPTRIS_TAG_INT: {
46
+ char buf[32];
47
+ size_t cp = len < sizeof(buf) - 1 ? len : sizeof(buf) - 1;
48
+ memcpy(buf, p, cp);
49
+ buf[cp] = '\0';
50
+ char* end = NULL;
51
+ long long v = strtoll(buf, &end, 10);
52
+ if (end != buf && *end == '\0' && end == buf + len && v > INT64_MIN) {
53
+ return LL2NUM(v);
54
+ }
55
+ return rb_utf8_str_new(p, len); /* int_or_string's fallback */
56
+ }
57
+ case YEPTRIS_TAG_FLOAT: {
58
+ char buf[64];
59
+ size_t cp = len < sizeof(buf) - 1 ? len : sizeof(buf) - 1;
60
+ memcpy(buf, p, cp);
61
+ buf[cp] = '\0';
62
+ char* end = NULL;
63
+ double v = strtod(buf, &end);
64
+ if (end != buf && end != buf + len) {
65
+ return rb_utf8_str_new(p, len); /* float_or_string's fallback */
66
+ }
67
+ return DBL2NUM(v);
68
+ }
69
+ default:
70
+ return rb_utf8_str_new(p, len);
71
+ }
72
+ }
73
+
74
+ static VALUE cr_walk(const yep_dom* d, uint32_t id) {
75
+ const yep_dnode* n = &d->nodes[id];
76
+ switch (n->kind) {
77
+ case YEP_DOM_SCALAR:
78
+ return cr_scalar(d, n);
79
+ case YEP_DOM_SEQUENCE: {
80
+ long cnt = (long)n->count;
81
+ VALUE a = rb_ary_new_capa(cnt);
82
+ uint32_t c = n->first_child;
83
+ for (long i = 0; i < cnt && c != UINT32_MAX; i++) {
84
+ rb_ary_push(a, cr_walk(d, c));
85
+ c = d->nodes[c].next_sibling;
86
+ }
87
+ return a;
88
+ }
89
+ case YEP_DOM_MAPPING: {
90
+ long pairs = (long)(n->count / 2);
91
+ VALUE h = HASH_NEW_CAPA(pairs);
92
+ uint32_t c = n->first_child;
93
+ for (long i = 0; i < pairs && c != UINT32_MAX; i++) {
94
+ VALUE k = cr_walk(d, c);
95
+ c = d->nodes[c].next_sibling;
96
+ VALUE v = (c != UINT32_MAX) ? cr_walk(d, c) : Qnil;
97
+ if (c != UINT32_MAX) {
98
+ c = d->nodes[c].next_sibling;
99
+ }
100
+ rb_hash_aset(h, k, v);
101
+ }
102
+ return h;
103
+ }
104
+ default: /* ALIAS: CBOR decode never produces one */
105
+ return Qnil;
106
+ }
107
+ }
108
+
109
+ VALUE yep_rb_cbor_load(const char* p, size_t len, int strict) {
110
+ YeptrisStatus st = YEPTRIS_OK;
111
+ /* the DOM borrows the input buffer zero-copy; the walk ALLOCATES,
112
+ * and a GC compaction mid-walk moves the caller's String — the
113
+ * borrowed base dangles (the #160 CI bus error on 3.2/linux).
114
+ * Same discipline as the JSON walk: GC off across decode+walk */
115
+ VALUE gc_on = rb_gc_disable();
116
+ /* YeptrisDocument is a WRAPPER (doc.h) — ->dom is the tree; a raw
117
+ * yep_dom* cast read the wrapper's fields as the dom (the CI
118
+ * segfaults: docs at the wrong offset) */
119
+ yeptris_document* doc = (yeptris_document*)yeptris_cbor_decode(
120
+ p, len, strict ? YEPTRIS_CBOR_STRICT : 0, &st);
121
+ yep_dom* d = (doc != NULL) ? doc->dom : NULL;
122
+ if (d == NULL) {
123
+ if (RTEST(gc_on)) {
124
+ rb_gc_enable();
125
+ }
126
+ return Qundef;
127
+ }
128
+ VALUE v = (d->dcount > 0 && d->docs[0] != UINT32_MAX) ? cr_walk(d, d->docs[0]) : Qnil;
129
+ yeptris_document_free((YeptrisDocument)doc);
130
+ if (RTEST(gc_on)) {
131
+ rb_gc_enable();
132
+ }
133
+ return v;
134
+ }
@@ -230,6 +230,7 @@ static const YeptrisVisitVTable k_vt = {
230
230
 
231
231
  /* fused JSON→Ruby (json_ruby.c) — no vtable, beats JSON.parse */
232
232
  VALUE yep_rb_parse_json(const char* p, size_t len, int strict_dup);
233
+ VALUE yep_rb_cbor_load(const char* p, size_t len, int strict);
233
234
 
234
235
  static VALUE ctx_result(rb_ctx* c, YeptrisStatus st) {
235
236
  if (st != YEPTRIS_OK || c->failed) {
@@ -244,6 +245,18 @@ static VALUE ctx_result(rb_ctx* c, YeptrisStatus st) {
244
245
  return c->root;
245
246
  }
246
247
 
248
+ static VALUE native_cbor_load(int argc, VALUE* argv, VALUE self) {
249
+ (void)self;
250
+ VALUE input, strict;
251
+ rb_scan_args(argc, argv, "11", &input, &strict);
252
+ StringValue(input);
253
+ VALUE v = yep_rb_cbor_load(RSTRING_PTR(input), (size_t)RSTRING_LEN(input), RTEST(strict));
254
+ if (v == Qundef) {
255
+ rb_raise(rb_path2class("Yeptris::ParseError"), "native cbor decode failed");
256
+ }
257
+ return v;
258
+ }
259
+
247
260
  static VALUE native_load_json(int argc, VALUE* argv, VALUE self) {
248
261
  (void)self;
249
262
  VALUE input, strict;
@@ -415,6 +428,7 @@ RUBY_FUNC_EXPORTED void Init_native(void) {
415
428
  VALUE mYep = rb_define_module("Yeptris");
416
429
  VALUE mNat = rb_define_module_under(mYep, "Native");
417
430
  rb_define_singleton_method(mNat, "load_json", native_load_json, -1);
431
+ rb_define_singleton_method(mNat, "cbor_load", native_cbor_load, -1);
418
432
  rb_define_singleton_method(mNat, "load", native_load, 2);
419
433
  rb_define_singleton_method(mNat, "load_stream", native_load_stream, 2);
420
434
  rb_define_singleton_method(mNat, "gc_mode", native_gc_mode, 0);
data/lib/yeptris/cbor.rb CHANGED
@@ -26,6 +26,13 @@ module Yeptris
26
26
  def load(data, strict: false)
27
27
  raise Error, "libyeptris has no CBOR support" unless available?
28
28
 
29
+ # #157: the native materializer (decode + direct VALUE
30
+ # construction in one C pass) when the extension is loaded;
31
+ # the FFI ladder otherwise
32
+ if defined?(::Yeptris::Native) && ::Yeptris::Native.respond_to?(:cbor_load)
33
+ return ::Yeptris::Native.cbor_load(data, strict)
34
+ end
35
+
29
36
  doc_ptr = ::Yeptris::FFI.yeptris_cbor_decode(data, data.bytesize, strict ? STRICT : 0, nil)
30
37
  raise ParseError, ::Yeptris::FFI.last_error_message if doc_ptr.null?
31
38
 
data/lib/yeptris/ffi.rb CHANGED
@@ -66,10 +66,16 @@ module Yeptris
66
66
  # the caller's string (no arena copy, no second validating parse).
67
67
  # v2 records: numbers are spans at parse; yeptris_tape_convert
68
68
  # materializes them in one bulk call.
69
+ # v3 (libyeptris 0.6.9): the interleaved records (recs) are the
70
+ # primary storage on the lenient route; the strict route keeps the
71
+ # columns eager. The layout MUST mirror yeptris_json_tape — a stale
72
+ # layout makes C write past the FFI buffer (a silent heap overflow
73
+ # that only some allocators catch; the 0.6.9.1 windows crash).
69
74
  class JsonTape < ::FFI::Struct
70
75
  layout :count, :size_t, :kinds, :pointer, :offs, :pointer,
71
- :lens, :pointer, :int_min, :int64, :_src, :pointer, :_srclen, :size_t,
72
- :_block, :pointer
76
+ :lens, :pointer, :recs, :pointer, :_cols_ready, :int,
77
+ :_rec_primary, :int, :int_min, :int64, :_src, :pointer,
78
+ :_srclen, :size_t, :_block, :pointer
73
79
  end
74
80
 
75
81
  attach_function :yeptris_parse_json_tape, %i[pointer size_t pointer], :int
data/lib/yeptris/json.rb CHANGED
@@ -24,6 +24,7 @@ module Yeptris
24
24
  # behavior — strictness follows it (issue #37, found by canon's
25
25
  # CI where json 3.0.0 resolved while the dev box had 2.x).
26
26
  require "json"
27
+ require "date" # place_obj's `when Date` — psych loads it elsewhere, JSON.dump must not depend on that
27
28
  STRICT_DUPLICATE_KEYS = Gem::Version.new(::JSON::VERSION) >= Gem::Version.new("3")
28
29
 
29
30
  module_function
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.8.2".freeze
6
+ VERSION = "0.6.9.2".freeze
7
7
  # The error hierarchy lives in THIS file (the parent namespace's
8
8
  # own file): nested constants do not trigger a parent-constant
9
9
  # autoload, and the law forbids internal requires — defining the
@@ -3,7 +3,7 @@
3
3
  cmake_minimum_required(VERSION 3.20)
4
4
 
5
5
  project(yeptris
6
- VERSION 0.6.8
6
+ VERSION 0.6.9
7
7
  DESCRIPTION "Ultra-fast YAML 1.2 parser, emitter and streamer in C"
8
8
  LANGUAGES C CXX
9
9
  )
@@ -46,15 +46,32 @@ enum {
46
46
  spans; simdjson's deferred contract) */
47
47
  };
48
48
 
49
+ /* The interleaved record (TODO.max-perf/07): one 8-byte store per
50
+ * token instead of three column stores. Layout: off:u32 | len:u23 |
51
+ * kind:u8 — a span longer than 0xFEFFFF bytes carries len == 0xFFFFFF
52
+ * with the true length stored as a CONT-terminated extension record
53
+ * (kind YEP_T_CONT; unreachable for <16 MiB tokens). The columns
54
+ * stay the compatibility ABI: yeptris_tape_columns materializes them
55
+ * lazily from the records on first touch. */
56
+ #define YEP_T_CONT 8 /* record-length extension (not a token kind) */
57
+ typedef uint64_t yeptris_tape_rec;
58
+
49
59
  typedef struct yeptris_json_tape {
50
60
  size_t count;
51
- uint8_t* kinds; /* yeptris tape kind per record */
52
- uint32_t* offs; /* span starts (STR/INT/FLOAT); container links */
53
- uint32_t* lens; /* span lengths (STR/INT/FLOAT) */
54
- int64_t int_min; /* set by yeptris_tape_convert when an INT span
55
- exceeds int64 (materialize-time discovery) */
56
- const void* _src; /* the parsed buffer (spans borrow it; it must
57
- outlive the tape — same contract as the spans) */
61
+ uint8_t* kinds; /* compat columns materialized lazily (see
62
+ yeptris_tape_columns) when the interleaved
63
+ records are the primary storage */
64
+ uint32_t* offs; /* span starts (STR/INT/FLOAT); container links */
65
+ uint32_t* lens; /* span lengths (STR/INT/FLOAT) */
66
+ yeptris_tape_rec* recs; /* primary storage (may be NULL on legacy
67
+ column-built tapes: the strict route) */
68
+ int _cols_ready; /* columns materialized from recs already */
69
+ int _rec_primary; /* the lenient route: recs carry the data and
70
+ the columns are lazy */
71
+ int64_t int_min; /* set by yeptris_tape_convert when an INT span
72
+ exceeds int64 (materialize-time discovery) */
73
+ const void* _src; /* the parsed buffer (spans borrow it; it must
74
+ outlive the tape — same contract as the spans) */
58
75
  size_t _srclen;
59
76
  void* _block; /* the carved allocation base */
60
77
  } yeptris_json_tape;
@@ -89,6 +106,13 @@ YEPTRIS_API void yeptris_tape_free(yeptris_json_tape* tape);
89
106
  * number records converted, or SIZE_MAX if a span does not re-scan
90
107
  * as a number (impossible for a tape this library produced).
91
108
  * Sets t->int_min when an INT span exceeds int64. */
109
+ /* Materializes the kinds/offs/lens columns from the interleaved
110
+ * records (no-op when the tape was built column-primary or the
111
+ * columns are already materialized). Consumers reading the column
112
+ * pointers directly (the FFI binding) must call this once first.
113
+ * Returns 0 on success, nonzero on allocation failure. */
114
+ YEPTRIS_API int yeptris_tape_columns(yeptris_json_tape* t);
115
+
92
116
  YEPTRIS_API size_t yeptris_tape_convert(yeptris_json_tape* t, size_t from, size_t to,
93
117
  int64_t* ivals, double* dvals);
94
118
 
@@ -415,6 +415,9 @@ static yeptris_plan_result* plan_result_carve(const yeptris_plan* plan, size_t r
415
415
 
416
416
  YEPTRIS_API yeptris_plan_result*
417
417
  yeptris_tape_plan_walk(const yeptris_json_tape* tape, const yeptris_plan* plan, YeptrisStatus* st) {
418
+ /* item 07: the lenient tape's columns are lazy — materialize (a
419
+ * cache write through a const view; idempotent) */
420
+ yeptris_tape_columns((yeptris_json_tape*)tape);
418
421
  if (st != NULL) {
419
422
  *st = YEPTRIS_OK;
420
423
  }
@@ -59,7 +59,8 @@ static int rec_put(tape_ctx* c, uint8_t kind, uint32_t off, uint32_t len) {
59
59
  static YeptrisStatus tape_carve(yeptris_json_tape* t, size_t len) {
60
60
  size_t cap = len + 2;
61
61
  size_t off_o = (cap + 15) & ~(size_t)15;
62
- char* block = yep_alloc(yep_system_allocator(), off_o + 2 * cap * sizeof(uint32_t));
62
+ char* block = yep_alloc(yep_system_allocator(),
63
+ off_o + 2 * cap * sizeof(uint32_t) + cap * sizeof(yeptris_tape_rec));
63
64
  if (block == NULL) {
64
65
  return YEPTRIS_ERROR_MEMORY;
65
66
  }
@@ -67,11 +68,31 @@ static YeptrisStatus tape_carve(yeptris_json_tape* t, size_t len) {
67
68
  t->kinds = (uint8_t*)block;
68
69
  t->offs = (uint32_t*)(void*)(block + off_o);
69
70
  t->lens = t->offs + cap;
71
+ t->recs = (yeptris_tape_rec*)(void*)(t->lens + cap);
70
72
  t->count = 0;
71
73
  t->int_min = 0;
74
+ t->_rec_primary = 0;
75
+ t->_cols_ready = 0;
72
76
  return YEPTRIS_OK;
73
77
  }
74
78
 
79
+ /* The lazy column materialization (TODO.max-perf/07): records are the
80
+ * primary storage on the lenient route; the column ABI materializes
81
+ * from them on first touch. */
82
+ YEPTRIS_API int yeptris_tape_columns(yeptris_json_tape* t) {
83
+ if (t == NULL || !t->_rec_primary || t->recs == NULL || t->_cols_ready) {
84
+ return 0; /* column-primary (the strict route) or ready */
85
+ }
86
+ for (size_t i = 0; i < t->count; i++) {
87
+ yeptris_tape_rec r = t->recs[i];
88
+ t->lens[i] = (uint32_t)((r >> 8) & 0xFFFFFFu);
89
+ t->offs[i] = (uint32_t)(r >> 32);
90
+ t->kinds[i] = (uint8_t)(r & 0xFFu);
91
+ }
92
+ t->_cols_ready = 1;
93
+ return 0;
94
+ }
95
+
75
96
  /* Scalar roots: the walk needs an opener, so a bare root value
76
97
  * converts through the same kernels. */
77
98
  static int tape_put_root_scalar(tape_ctx* c, const char* p, size_t len, size_t at) {
@@ -585,20 +606,18 @@ static YeptrisStatus tape_walk_lnt_fused(const char* p, size_t len, size_t open,
585
606
  if (tape_carve(t, len) != YEPTRIS_OK) {
586
607
  return YEPTRIS_ERROR_MEMORY;
587
608
  }
588
- uint8_t* kinds = t->kinds;
589
- uint32_t* offs = t->offs;
590
- uint32_t* lens = t->lens;
609
+ /* the interleaved records are the primary storage (item 07); the
610
+ * columns materialize lazily via yeptris_tape_columns */
611
+ t->_rec_primary = 1;
612
+ yeptris_tape_rec* recs = t->recs;
591
613
  uint32_t open_at[YEP_JSON_WALK_DEPTH];
592
614
  uint8_t kind[YEP_JSON_WALK_DEPTH];
593
615
 
594
- kinds[0] = YEP_T_DOC;
595
- offs[0] = 0;
596
- lens[0] = 0;
616
+ recs[0] = ((uint64_t)0 << 32) | ((uint64_t)0 << 8) | YEP_T_DOC;
597
617
 
598
618
  uint8_t top_kind = p[open] == '[' ? 0 : 1;
599
- kinds[1] = top_kind ? YEP_T_MAP_OPEN : YEP_T_SEQ_OPEN;
600
- offs[1] = 0;
601
- lens[1] = 0;
619
+ recs[1] =
620
+ ((uint64_t)0 << 32) | ((uint64_t)0 << 8) | (top_kind ? YEP_T_MAP_OPEN : YEP_T_SEQ_OPEN);
602
621
  uint32_t top_open = 1;
603
622
  size_t count = 2;
604
623
  uint8_t top_expect = top_kind ? JW_KEY_OR_CLOSE : JW_VALUE_OR_CLOSE;
@@ -656,9 +675,8 @@ static YeptrisStatus tape_walk_lnt_fused(const char* p, size_t len, size_t open,
656
675
  uint64_t c0 = (w - 0x2020202020202020ull) & ~w & 0x8080808080808080ull;
657
676
  if (qm != 0 && ((bm | c0) & (qm - 1)) == 0) {
658
677
  close = j + (size_t)yep_ctz64(qm) / 8;
659
- kinds[count] = YEP_T_STR;
660
- offs[count] = (uint32_t)j;
661
- lens[count] = (uint32_t)(close - j);
678
+ recs[count] = ((uint64_t)((uint32_t)j) << 32) |
679
+ ((uint64_t)((uint32_t)(close - j)) << 8) | (uint64_t)(YEP_T_STR);
662
680
  count++;
663
681
  i = close + 1;
664
682
  goto lstr_done;
@@ -668,9 +686,8 @@ static YeptrisStatus tape_walk_lnt_fused(const char* p, size_t len, size_t open,
668
686
  if (!yep_json_string(p, len, &i, &close, &esc)) {
669
687
  goto lreject;
670
688
  }
671
- kinds[count] = YEP_T_STR;
672
- offs[count] = (uint32_t)(at + 1);
673
- lens[count] = (uint32_t)(close - at - 1);
689
+ recs[count] = ((uint64_t)((uint32_t)(at + 1)) << 32) |
690
+ ((uint64_t)((uint32_t)(close - at - 1)) << 8) | (uint64_t)(YEP_T_STR);
674
691
  count++;
675
692
  lstr_done:
676
693
  if (key_slot) {
@@ -698,9 +715,8 @@ static YeptrisStatus tape_walk_lnt_fused(const char* p, size_t len, size_t open,
698
715
  }
699
716
  break;
700
717
  }
701
- kinds[count] = YEP_T_NUM;
702
- offs[count] = (uint32_t)at;
703
- lens[count] = (uint32_t)(i - at);
718
+ recs[count] = ((uint64_t)((uint32_t)at) << 32) | ((uint64_t)((uint32_t)(i - at)) << 8) |
719
+ (uint64_t)(YEP_T_NUM);
704
720
  count++;
705
721
  lcomma:
706
722
  if (i < len && p[i] == ',') {
@@ -719,10 +735,11 @@ static YeptrisStatus tape_walk_lnt_fused(const char* p, size_t len, size_t open,
719
735
  top_expect != JW_COMMA_OR_CLOSE)) {
720
736
  goto lreject;
721
737
  }
722
- kinds[count] = YEP_T_CLOSE;
723
- offs[count] = top_open;
724
- lens[count] = 0;
725
- offs[top_open] = (uint32_t)count;
738
+ recs[count] = ((uint64_t)top_open << 32) | ((uint64_t)0 << 8) | YEP_T_CLOSE;
739
+ /* back-patch the opener's count link: keep the original
740
+ * off/len, set the link into the record's off word */
741
+ recs[top_open] = (recs[top_open] & ~(uint64_t)0xFFFFFFFF00000000u) |
742
+ ((uint64_t)(uint32_t)count << 32);
726
743
  count++;
727
744
  i = at + 1;
728
745
  depth--;
@@ -745,9 +762,8 @@ static YeptrisStatus tape_walk_lnt_fused(const char* p, size_t len, size_t open,
745
762
  kind[depth - 1] = top_kind;
746
763
  open_at[depth - 1] = top_open;
747
764
  top_kind = c == '[' ? 0 : 1;
748
- kinds[count] = c == '[' ? YEP_T_SEQ_OPEN : YEP_T_MAP_OPEN;
749
- offs[count] = 0;
750
- lens[count] = 0;
765
+ recs[count] = ((uint64_t)0 << 32) | ((uint64_t)0 << 8) |
766
+ (uint64_t)(c == '[' ? YEP_T_SEQ_OPEN : YEP_T_MAP_OPEN);
751
767
  top_open = (uint32_t)count;
752
768
  count++;
753
769
  top_expect = top_kind ? JW_KEY_OR_CLOSE : JW_VALUE_OR_CLOSE;
@@ -778,9 +794,8 @@ static YeptrisStatus tape_walk_lnt_fused(const char* p, size_t len, size_t open,
778
794
  goto lreject;
779
795
  }
780
796
  }
781
- kinds[count] = c == 'n' ? YEP_T_NULL : (c == 't' ? YEP_T_TRUE : YEP_T_FALSE);
782
- offs[count] = (uint32_t)at;
783
- lens[count] = (uint32_t)wl;
797
+ recs[count] = ((uint64_t)((uint32_t)at) << 32) | ((uint64_t)((uint32_t)wl) << 8) |
798
+ (uint64_t)(c == 'n' ? YEP_T_NULL : (c == 't' ? YEP_T_TRUE : YEP_T_FALSE));
784
799
  count++;
785
800
  i = at + wl;
786
801
  goto lcomma;
@@ -1244,6 +1259,7 @@ YEPTRIS_API YeptrisStatus yeptris_parse_json_tape(const char* source, size_t len
1244
1259
 
1245
1260
  YEPTRIS_API size_t yeptris_tape_convert(yeptris_json_tape* t, size_t from, size_t to,
1246
1261
  int64_t* ivals, double* dvals) {
1262
+ yeptris_tape_columns(t);
1247
1263
  if (t == NULL || t->_src == NULL || from > to || to > t->count) {
1248
1264
  return SIZE_MAX;
1249
1265
  }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yeptris
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.8.2
4
+ version: 0.6.9.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
@@ -37,6 +37,7 @@ files:
37
37
  - README.adoc
38
38
  - ext/build_windows_native.rb
39
39
  - ext/libyeptris/extconf.rb
40
+ - ext/yeptris_native/cbor_ruby.c
40
41
  - ext/yeptris_native/extconf.rb
41
42
  - ext/yeptris_native/json_ruby.c
42
43
  - ext/yeptris_native/yeptris_native.c