yeptris 0.6.20.2 → 0.6.22.1

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: 1d91dc30d6dd414d0b22ce84b0e573850efa6a86e7d6fcef4425e2d4afc2fca2
4
- data.tar.gz: 9efe2971ff5b4159b077fba5330a12c0c2ac91bb6849c36c86a83ddeba243a86
3
+ metadata.gz: b02278afda0c454592a7e6b4d95fb4649960c08a4b7e3ad7e5260467333edc57
4
+ data.tar.gz: c554fd944064c8b691003b83d9e3a6adc8500a04865dcf6c4fa28db1ba320db5
5
5
  SHA512:
6
- metadata.gz: b40b768c6103cc5715059d7f93350c8c2f9298f86297e2133cf339ec269529237a964bcab0ef5a6ea998a609b5370ac640ba6d195b741bd9382037e2a3114a83
7
- data.tar.gz: ecfe46a3b63e70b38c11541f6926b7e59a622e8450401b0ff271a362d854317f4bc40647b9ffa2bda3233db3b1e3f09470385f8768f27b794b9655a387123ed4
6
+ metadata.gz: 7a1ed5aae840b006a5e2bb6ed27d8a1292969cb14b7963be92bd625f8ac0957ae974de91f73f11f8f642375eda5f773b747c21ee51479473742f7ff323f3b72a
7
+ data.tar.gz: c21b92bec887dce27696762deb7818d30243647775e6113d6ccd4a2d07c759153be042f66f764c962afab3092bb30faacf265c51a1ccb5812ff07c89c8f918a4
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.20.2".freeze
6
+ VERSION = "0.6.22.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
@@ -3,7 +3,7 @@
3
3
  cmake_minimum_required(VERSION 3.20)
4
4
 
5
5
  project(yeptris
6
- VERSION 0.6.20
6
+ VERSION 0.6.22
7
7
  DESCRIPTION "Ultra-fast YAML 1.2 parser, emitter and streamer in C"
8
8
  LANGUAGES C CXX
9
9
  )
@@ -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
- if (index < d->child_cache_len) {
548
- return d->child_cache[index];
549
- }
550
- return UINT32_MAX;
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
- if (index < d->child_cache_len) {
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) {
@@ -605,8 +605,15 @@ reject:
605
605
  * in-walk float/exp validator (the out-of-line number_shape call +
606
606
  * rescan was 13% of json-doc; the digits-only case never gets here).
607
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) {
608
+ * optional .digits, optional e[+-]digits, consume exactly len.
609
+ * always_inline: the spans are 3-8 bytes and the out-of-line call was
610
+ * the cost (the rescan itself is nothing). */
611
+ #if defined(__GNUC__)
612
+ #define TAPE_NUM_OK_INLINE __attribute__((always_inline)) inline
613
+ #else
614
+ #define TAPE_NUM_OK_INLINE
615
+ #endif
616
+ static TAPE_NUM_OK_INLINE int tape_num_ok(const char* p, size_t len) {
610
617
  size_t k = 0;
611
618
  if (k < len && p[k] == '-') {
612
619
  k++;
@@ -770,6 +777,38 @@ YeptrisStatus yep_tape_walk_lenient_fused(const char* p, size_t len, size_t open
770
777
  i = cl_ + 1; \
771
778
  goto after; \
772
779
  } \
780
+ /* rounds 2-4 (up to 32 bytes inline): the email-class strings \
781
+ * close here without the quote_scan call and its redundant \
782
+ * content re-sweep; reached only when round 1 had no close, \
783
+ * so the short-string case pays nothing */ \
784
+ if ((qm_ | bm_ | c0_ | hi_) == 0) { \
785
+ size_t nr_ = (len - j_) >> 3; \
786
+ if (nr_ > 4) { \
787
+ nr_ = 4; \
788
+ } \
789
+ for (size_t r_ = 1; r_ < nr_; r_++) { \
790
+ size_t b2_ = j_ + (r_ << 3); \
791
+ memcpy(&w_, p + b2_, 8); \
792
+ qm_ = (w_ ^ 0x2222222222222222ull); \
793
+ bm_ = (w_ ^ 0x5C5C5C5C5C5C5C5Cull); \
794
+ qm_ = (qm_ - 0x0101010101010101ull) & ~qm_ & 0x8080808080808080ull; \
795
+ bm_ = (bm_ - 0x0101010101010101ull) & ~bm_ & 0x8080808080808080ull; \
796
+ c0_ = (w_ - 0x2020202020202020ull) & ~w_ & 0x8080808080808080ull; \
797
+ hi_ = cl ? (w_ & 0x8080808080808080ull) : 0; \
798
+ if (qm_ != 0 && ((bm_ | c0_ | hi_) & (qm_ - 1)) == 0) { \
799
+ size_t cl_ = b2_ + (size_t)yep_ctz64(qm_) / 8; \
800
+ recs[count] = ((uint64_t)((uint32_t)j_) << 32) | \
801
+ ((uint64_t)((uint32_t)(cl_ - j_)) << 8) | \
802
+ (uint64_t)(YEP_T_STR); \
803
+ count++; \
804
+ i = cl_ + 1; \
805
+ goto after; \
806
+ } \
807
+ if ((qm_ | bm_ | c0_ | hi_) != 0) { \
808
+ break; /* escape, c0 or hi: kernel authority */ \
809
+ } \
810
+ } \
811
+ } \
773
812
  } \
774
813
  { \
775
814
  const yep_text_kernels* kk_ = yep_text_active(); \
@@ -875,8 +914,12 @@ lmapcolon:
875
914
  saw_digit = 1;
876
915
  continue;
877
916
  }
878
- digits_only = 0;
917
+ /* the flag clears only on a CONSUMED byte: the run's
918
+ * terminator (',', '}', ']', whitespace) must leave
919
+ * digits_only intact, or every plain integer followed
920
+ * by a delimiter falls into the full validator */
879
921
  if (d == '-' || d == '+' || d == '.' || d == 'e' || d == 'E') {
922
+ digits_only = 0;
880
923
  k++;
881
924
  continue;
882
925
  }
@@ -973,8 +1016,9 @@ lseqval: {
973
1016
  saw_digit = 1;
974
1017
  continue;
975
1018
  }
976
- digits_only = 0;
1019
+ /* consumed-only clearing: see the map arm's comment */
977
1020
  if (d == '-' || d == '+' || d == '.' || d == 'e' || d == 'E') {
1021
+ digits_only = 0;
978
1022
  k++;
979
1023
  continue;
980
1024
  }
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.20.2
4
+ version: 0.6.22.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-09-24 00:00:00.000000000 Z
11
+ date: 2026-09-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi