yeptris 0.6.34.3-arm-linux-eabihf → 0.6.35.1-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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8189e4ab2261a07bf9d18bb5df19c095cea91b787d5e09a65eeacb7e1352f20b
4
- data.tar.gz: f246d41d0e0c84be06b54aa8d3ba4c2ef63009a017ade6f7fa2f637c723f45fb
3
+ metadata.gz: 9b7db4e1966499241be6cb407b04fd1d00ebebbb4c3e47990d95b592311bab1f
4
+ data.tar.gz: 0771a50cd9613aa73b1e7cf26348fc603b3e8fc008d74cc3d05ced5ed339322f
5
5
  SHA512:
6
- metadata.gz: b0b627fc761ab8bb6d4d33556019f06d6d5451382bc81f55b33d826ab73056c99c03eb4062c1902135a02c0ff0fe1f12495c1bb130e07c10ed7f12b0cf4af151
7
- data.tar.gz: 2c9cb261f7bb8ba85f13915a62dfaa97ac31e4f25c94df139026b13d53478cebee0c678bd51048ee8639aceeba5154c6e4cc1214e752f4c97e48a85d35551e92
6
+ metadata.gz: 57af21b77819242da81fe856358b9e6f334bb4d69fbf1688be872f023c5fa0b5658e857cb01bac592986f84c759504e3780ff2816204b63bff9263f6b8687b09
7
+ data.tar.gz: a5b5b8cdbfeaff4272413a0ce5c14d3b3d488582e9648e559f10026fbb907f77faecfd8632c7e50bc9e7272945a35e66946723956b099f43a4b44be46021d188
Binary file
data/lib/yeptris/cbor.rb CHANGED
@@ -103,8 +103,12 @@ module Yeptris
103
103
  def build_documents(objects)
104
104
  # ONE document per object: a visitor's tree is a single
105
105
  # document and push sets its root — reuse would overwrite
106
+ # compat_11 types the documents' plain scalars through the
107
+ # Psych-compatible resolver — the same law the tree builder's
108
+ # plain-safety check rides, so a host String stays a CBOR text
109
+ # string ("1e0" resolved as a float through core-12: #293).
106
110
  objects.map do |obj|
107
- visitor = ::Yeptris::Psych::Visitors::YAMLTree.new
111
+ visitor = ::Yeptris::Psych::Visitors::YAMLTree.new(schema: :compat_11)
108
112
  visitor.push(obj)
109
113
  visitor.document
110
114
  end
@@ -75,8 +75,16 @@ class Yeptris::Document
75
75
  end
76
76
 
77
77
  # An empty document for from-scratch construction (TODO.impl/11 p3).
78
- def self.create
79
- doc = Yeptris::FFI.yeptris_document_new
78
+ # schema: :compat_11 types its plain scalars through the Psych-
79
+ # compatible resolver — the dump faces build with it so a host String
80
+ # the tree builder kept plain ("1e0") stays a string (#293).
81
+ def self.create(schema: nil)
82
+ doc =
83
+ if schema == :compat_11
84
+ Yeptris::FFI.yeptris_document_new_schema(Yeptris::FFI::SCHEMA_11_COMPAT)
85
+ else
86
+ Yeptris::FFI.yeptris_document_new
87
+ end
80
88
  raise Yeptris::Error, "yeptris_document_new failed" if doc.null?
81
89
 
82
90
  wrap(doc)
data/lib/yeptris/ffi.rb CHANGED
@@ -141,6 +141,7 @@ module Yeptris
141
141
 
142
142
  # construction (TODO.impl/11 phase 3)
143
143
  attach_function :yeptris_document_new, [], :yeptris_document
144
+ attach_function :yeptris_document_new_schema, [:int], :yeptris_document
144
145
  attach_function :yeptris_document_set_root,
145
146
  %i[yeptris_document yeptris_node], :int
146
147
  attach_function :yeptris_node_new_mapping, [:yeptris_document], :yeptris_node
@@ -18,8 +18,8 @@ module Yeptris
18
18
  new
19
19
  end
20
20
 
21
- def initialize
22
- @tree = ::Yeptris::Document.create
21
+ def initialize(schema: nil)
22
+ @tree = ::Yeptris::Document.create(schema: schema)
23
23
  @names = {} # object_id -> anchor name
24
24
  @counter = 0
25
25
  end
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.34.3".freeze
6
+ VERSION = "0.6.35.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
@@ -3,7 +3,7 @@
3
3
  cmake_minimum_required(VERSION 3.20)
4
4
 
5
5
  project(yeptris
6
- VERSION 0.6.34
6
+ VERSION 0.6.35
7
7
  DESCRIPTION "Ultra-fast YAML 1.2 parser, emitter and streamer in C"
8
8
  LANGUAGES C CXX
9
9
  )
@@ -9,6 +9,7 @@
9
9
 
10
10
  #include <yeptris/api.h>
11
11
  #include <yeptris/error.h>
12
+ #include <yeptris/resolve.h> /* YeptrisSchema */
12
13
  #include <yeptris/types.h>
13
14
 
14
15
  #ifdef __cplusplus
@@ -99,6 +100,11 @@ YEPTRIS_API size_t yeptris_node_children(YeptrisNode node, YeptrisNode* out, siz
99
100
  /* An empty document with no input; build nodes and set the root. */
100
101
  YEPTRIS_API YeptrisDocument yeptris_document_new(void);
101
102
 
103
+ /* The same, with the schema resolver plain scalars type through
104
+ * (YEPTRIS_SCHEMA_12_CORE is yeptris_document_new's default). Additive
105
+ * ABI. */
106
+ YEPTRIS_API YeptrisDocument yeptris_document_new_schema(YeptrisSchema schema);
107
+
102
108
  /* Records a detached node as document i's root. */
103
109
  YEPTRIS_API int yeptris_document_set_root(YeptrisDocument doc, YeptrisNode root);
104
110
 
@@ -11,6 +11,7 @@
11
11
  #include "doc.h"
12
12
  #include "dom/dom.h"
13
13
  #include "memory/allocator.h"
14
+ #include "resolve/resolver.h"
14
15
 
15
16
  static yeptris_document* doc_of(YeptrisDocument handle) {
16
17
  return (yeptris_document*)handle;
@@ -38,6 +39,21 @@ YEPTRIS_API YeptrisDocument yeptris_document_new(void) {
38
39
  return (YeptrisDocument)doc;
39
40
  }
40
41
 
42
+ /* An empty document whose plain scalars type through the given
43
+ * schema's resolver (yeptris_document_new rides the core-12 default).
44
+ * The CBOR/dump faces create compat-11 documents so a host String the
45
+ * tree builder kept plain ("1e0" — Psych's dot-required float law)
46
+ * stays a text string instead of resolving as a float (#293's shape). */
47
+ YEPTRIS_API YeptrisDocument yeptris_document_new_schema(YeptrisSchema schema) {
48
+ YeptrisDocument doc = yeptris_document_new();
49
+ if (doc != NULL) {
50
+ yeptris_document* d = (yeptris_document*)doc;
51
+ d->dom->resolver =
52
+ schema == YEPTRIS_SCHEMA_11_COMPAT ? yep_resolver_compat11() : yep_resolver_core12();
53
+ }
54
+ return doc;
55
+ }
56
+
41
57
  YEPTRIS_API int yeptris_document_set_root(YeptrisDocument handle, YeptrisNode root) {
42
58
  yeptris_document* doc = doc_of(handle);
43
59
  yeptris_node* n = node_of(root);
@@ -630,7 +630,7 @@ void yep_dom_destroy(yep_dom* d) {
630
630
  #include "scan/json.h"
631
631
  #include "scan/scan.h"
632
632
 
633
- static const yep_resolver* dom_resolver(const yep_dom* d) {
633
+ const yep_resolver* yep_dom_resolver(const yep_dom* d) {
634
634
  return d->resolver != NULL ? d->resolver : yep_resolver_core12();
635
635
  }
636
636
 
@@ -682,7 +682,7 @@ static int jb_scalar_node(jbuilder* b) {
682
682
  yep_dnode* n = &b->d->nodes[id];
683
683
  size_t start = b->i;
684
684
  size_t i = b->i;
685
- const yep_resolver* r = dom_resolver(b->d);
685
+ const yep_resolver* r = yep_dom_resolver(b->d);
686
686
  if (b->p[i] == 't') {
687
687
  if (!yep_json_literal(b->p, b->len, &i, "true")) {
688
688
  return -2;
@@ -846,7 +846,7 @@ int dom_on_flow_build(void* ctx, const char* p, size_t open, size_t len, uint32_
846
846
  d->map_pending_key[d->depth] = 0;
847
847
  d->stack[d->depth++] = root;
848
848
 
849
- const yep_resolver* r = dom_resolver(d);
849
+ const yep_resolver* r = yep_dom_resolver(d);
850
850
  yep_json_walk w;
851
851
  yep_json_tok t;
852
852
  yep_json_walk_init(&w, p, len, open, max_depth);
@@ -1126,7 +1126,7 @@ int dom_on_block_open(void* ctx, const yep_view* key, uint32_t line, uint16_t ke
1126
1126
  if (d->depth >= YEP_DOM_MAX_DEPTH) {
1127
1127
  return 0;
1128
1128
  }
1129
- const yep_resolver* r = dom_resolver(d);
1129
+ const yep_resolver* r = yep_dom_resolver(d);
1130
1130
  uint32_t mid = dom_open_node(d, YEP_DOM_MAPPING, NULL, NULL, 0, 0, 0, 0);
1131
1131
  if (mid == UINT32_MAX) {
1132
1132
  return -1;
@@ -1151,7 +1151,7 @@ int dom_on_block_open(void* ctx, const yep_view* key, uint32_t line, uint16_t ke
1151
1151
  * opened before offering — node-for-node the event path's item. */
1152
1152
  int dom_on_block_item(void* ctx, const yep_block_value* v) {
1153
1153
  yep_dom* d = (yep_dom*)ctx;
1154
- const yep_resolver* r = dom_resolver(d);
1154
+ const yep_resolver* r = yep_dom_resolver(d);
1155
1155
  uint32_t vid = dom_open_node(d, YEP_DOM_SCALAR, NULL, NULL, 0, YEP_STYLE_PLAIN, 1, 0);
1156
1156
  if (vid == UINT32_MAX) {
1157
1157
  return -1;
@@ -1178,7 +1178,7 @@ int dom_on_block_pair(void* ctx, const yep_view* key, const yep_block_value* v,
1178
1178
  return 0;
1179
1179
  }
1180
1180
  }
1181
- const yep_resolver* r = dom_resolver(d);
1181
+ const yep_resolver* r = yep_dom_resolver(d);
1182
1182
  uint32_t kid = dom_open_node(d, YEP_DOM_SCALAR, NULL, NULL, 0, YEP_STYLE_PLAIN, 1, 0);
1183
1183
  if (kid == UINT32_MAX) {
1184
1184
  return -1;
@@ -300,6 +300,11 @@ yep_sview yep_dom_str_put(yep_dom* d, const char* p, uint32_t len);
300
300
  char* yep_dom_str_tail(yep_dom* d, uint32_t cap);
301
301
  yep_sview yep_dom_str_commit(yep_dom* d, uint32_t written);
302
302
  void yep_dom_destroy(yep_dom* d);
303
+
304
+ /* The document's implicit-typing resolver (its own, or the core-12
305
+ * default) — the SSOT the mutation and build paths must share. */
306
+ struct yep_resolver;
307
+ const struct yep_resolver* yep_dom_resolver(const yep_dom* d);
303
308
  int yep_dom_on_event(void* ctx, const yep_event* ev);
304
309
 
305
310
  /* Node id accessor for the public API layer. */
@@ -54,8 +54,8 @@ uint32_t yep_mut_scalar(yep_dom* d, const char* value, size_t len, uint8_t style
54
54
  }
55
55
  n->value = yep_dom_str_put(d, v.p ? (const char*)v.p : "", v.len);
56
56
  n->style = style;
57
- n->tag_id = style == YEP_STYLE_PLAIN ? yep_resolver_core12()->resolve(NULL, v.p, v.len)
58
- : YEPTRIS_TAG_STR;
57
+ n->tag_id =
58
+ style == YEP_STYLE_PLAIN ? yep_dom_resolver(d)->resolve(NULL, v.p, v.len) : YEPTRIS_TAG_STR;
59
59
  return id;
60
60
  }
61
61
 
@@ -80,6 +80,14 @@ int yep_style_plain_safe(const char* p, uint32_t len) {
80
80
  while (i + 8 <= len) {
81
81
  uint64_t w;
82
82
  memcpy(&w, p + i, 8);
83
+ if (w & HIGH) {
84
+ /* multibyte content: the byte loop owns the rest — a raw
85
+ * LS/PS/NEL rides in a scalar value since the quote-aware
86
+ * normalizer (#638) and is a line break on re-parse, so
87
+ * the value must be quoted, not plain (the nightly's
88
+ * round 18, crash-1e79b2e3) */
89
+ break;
90
+ }
83
91
  uint64_t space = YST_ZDET(w, ' ');
84
92
  uint64_t tab = YST_ZDET(w, '\t');
85
93
  uint64_t blank = space | tab;
@@ -113,6 +121,13 @@ int yep_style_plain_safe(const char* p, uint32_t len) {
113
121
  if (is_break(c) || c == '\t') {
114
122
  return 0;
115
123
  }
124
+ if ((unsigned char)c == 0xE2 && i + 2 < len && (unsigned char)p[i + 1] == 0x80 &&
125
+ ((unsigned char)p[i + 2] & 0xFE) == 0xA8) {
126
+ return 0; /* a raw LS/PS re-parses as a line break */
127
+ }
128
+ if ((unsigned char)c == 0xC2 && i + 1 < len && (unsigned char)p[i + 1] == 0x85) {
129
+ return 0; /* a raw NEL ditto */
130
+ }
116
131
  if (c == ':') {
117
132
  if (i + 1 >= len || is_blank(p[i + 1])) {
118
133
  return 0;
@@ -847,7 +847,13 @@ static int key_written_over_limit(yep_writer* w, const yep_dnode* kn) {
847
847
  * 38200627503") */
848
848
  if (q != NULL) {
849
849
  for (uint32_t i = 0; i < n; i++) {
850
- est += (q[i] < 0x20 || q[i] >= 0x7F || q[i] == '"' || q[i] == '\\') ? 4u : 1u;
850
+ /* a single-quoted render DOUBLES every apostrophe; without
851
+ * it the estimate missed a 892-char key carrying 137
852
+ * quotes (rendered 1031, re-parse rejected the simple
853
+ * key — the nightly's crash-b8a18e43) */
854
+ est += (q[i] < 0x20 || q[i] >= 0x7F || q[i] == '"' || q[i] == '\\' || q[i] == '\'')
855
+ ? 4u
856
+ : 1u;
851
857
  }
852
858
  }
853
859
  if (kn->anchor.len > 0) {
@@ -668,9 +668,13 @@ static YeptrisStatus map_fail(int rc) {
668
668
  * contract.
669
669
  *
670
670
  * Key identity is the record's typed payload: span kinds compare the
671
- * arena bytes, the rest compare (kind, b, payload). One growable
672
- * open-addressing table serves the INNERMOST open map (cleared on
673
- * close) — duplicates are per-map by definition.
671
+ * arena bytes, the rest compare (kind, b, payload). Duplicates are
672
+ * per-map by definition, so the scan keeps ONE open-addressing table
673
+ * per open container on a frame stack: a key registers in the
674
+ * innermost frame and frames pop on CLOSE. A single table cleared on
675
+ * open cannot express this — a parent key equal to a key in an
676
+ * earlier child object was a false duplicate, and a parent duplicate
677
+ * after a nested object went unseen.
674
678
  */
675
679
 
676
680
  typedef struct {
@@ -682,8 +686,13 @@ typedef struct {
682
686
  typedef struct {
683
687
  dup_slot* slots;
684
688
  size_t cap; /* power of two */
689
+ size_t count;
685
690
  } dup_set;
686
691
 
692
+ typedef struct {
693
+ dup_set keys;
694
+ } dup_frame;
695
+
687
696
  static uint64_t dup_hash(const dup_slot* k, const char* arena) {
688
697
  uint64_t h = 1469598103934665603ull;
689
698
  if (k->len != UINT32_MAX && (k->kind == YEP_V_STR || k->kind == YEP_V_TIMESTAMP ||
@@ -717,61 +726,102 @@ static int dup_eq(const dup_slot* a, const dup_slot* b, const char* arena) {
717
726
  return a->len == 0 || memcmp(arena + a->off, arena + b->off, a->len) == 0;
718
727
  }
719
728
 
720
- static int dup_set_grow(dup_set* s) {
729
+ static int dup_set_grow(dup_set* s, const char* arena) {
721
730
  size_t ncap = s->cap ? s->cap * 2 : 16;
722
731
  dup_slot* ns = calloc(ncap, sizeof(*ns));
723
732
  if (ns == NULL) {
724
733
  return -1;
725
734
  }
726
- if (s->slots != NULL) {
727
- free(s->slots);
735
+ for (size_t i = 0; i < s->cap; i++) {
736
+ dup_slot* old = &s->slots[i];
737
+ if (old->p == 0) {
738
+ continue;
739
+ }
740
+ uint64_t h = dup_hash(old, arena);
741
+ while (ns[h & (ncap - 1)].p != 0) {
742
+ h++;
743
+ }
744
+ ns[h & (ncap - 1)] = *old;
728
745
  }
746
+ free(s->slots);
729
747
  s->slots = ns;
730
748
  s->cap = ncap;
731
749
  return 0;
732
750
  }
733
751
 
752
+ /* 1 = duplicate, 0 = inserted, -1 = oom. Load factor stays <= 1/2. */
753
+ static int dup_set_insert(dup_set* s, const dup_slot* k, const char* arena) {
754
+ if ((s->count + 1) * 2 > s->cap && dup_set_grow(s, arena) != 0) {
755
+ return -1;
756
+ }
757
+ uint64_t h = dup_hash(k, arena);
758
+ for (;;) {
759
+ dup_slot* slot = &s->slots[h & (s->cap - 1)];
760
+ if (slot->p == 0) {
761
+ *slot = *k;
762
+ s->count++;
763
+ return 0;
764
+ }
765
+ if (dup_eq(slot, k, arena)) {
766
+ return 1;
767
+ }
768
+ h++;
769
+ }
770
+ }
771
+
734
772
  /* 1 = duplicate found (TLS error set), 0 = clean, -1 = oom */
735
773
  static int strict_dup_scan(const yep_value_ctx* c) {
736
- dup_set s = {NULL, 0};
774
+ dup_frame* frames = NULL;
775
+ size_t depth = 0, cap = 0;
737
776
  int rc = 0;
738
777
  const YeptrisValue* vals = c->vals;
739
778
  for (size_t i = 0; i < c->n && rc == 0; i++) {
740
779
  const YeptrisValue* v = &vals[i];
741
- if (v->kind == YEP_V_MAP_OPEN) {
742
- if (s.slots != NULL) {
743
- memset(s.slots, 0, s.cap * sizeof(*s.slots)); /* innermost map only */
780
+ if (v->kind == YEP_V_MAP_OPEN || v->kind == YEP_V_SEQ_OPEN) {
781
+ if (depth == cap) {
782
+ size_t ncap = cap ? cap * 2 : 16;
783
+ dup_frame* nf = realloc(frames, ncap * sizeof(*nf));
784
+ if (nf == NULL) {
785
+ rc = -1;
786
+ break;
787
+ }
788
+ frames = nf;
789
+ cap = ncap;
744
790
  }
791
+ frames[depth].keys.slots = NULL;
792
+ frames[depth].keys.cap = 0;
793
+ frames[depth].keys.count = 0;
794
+ depth++;
745
795
  continue;
746
796
  }
747
- if (v->kind == YEP_V_CLOSE || v->is_key != 1) {
797
+ if (v->kind == YEP_V_CLOSE) {
798
+ if (depth > 0) {
799
+ depth--;
800
+ free(frames[depth].keys.slots);
801
+ }
802
+ continue;
803
+ }
804
+ if (v->is_key != 1 || depth == 0) {
748
805
  continue;
749
806
  }
750
807
  dup_slot k = {v->p, v->off, v->len, v->kind, v->b};
751
808
  if (k.p == 0) {
752
809
  k.p = 1; /* never aliases the empty-slot sentinel */
753
810
  }
754
- if (s.cap == 0 && dup_set_grow(&s) != 0) {
755
- rc = -1;
756
- break;
757
- }
758
- uint64_t h = dup_hash(&k, c->arena);
759
- for (;;) {
760
- dup_slot* slot = &s.slots[h & (s.cap - 1)];
761
- if (slot->p == 0) {
762
- *slot = k;
763
- break;
764
- }
765
- if (dup_eq(slot, &k, c->arena)) {
766
- yep_error_set(yep_error_tls(), YEP_ERR_UNEXPECTED, 0, 0, 0,
767
- "duplicate key in object");
768
- rc = 1;
769
- break;
811
+ int irc = dup_set_insert(&frames[depth - 1].keys, &k, c->arena);
812
+ if (irc != 1) {
813
+ if (irc < 0) {
814
+ rc = -1;
770
815
  }
771
- h++;
816
+ continue;
772
817
  }
818
+ yep_error_set(yep_error_tls(), YEP_ERR_UNEXPECTED, 0, 0, 0, "duplicate key in object");
819
+ rc = 1;
820
+ }
821
+ for (size_t j = 0; j < depth; j++) {
822
+ free(frames[j].keys.slots);
773
823
  }
774
- free(s.slots);
824
+ free(frames);
775
825
  return rc;
776
826
  }
777
827