leptris 1.9.193.2 → 1.9.193.4

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: a1403106ca3fcdf3f417fccf03e36a651e99282294f8689c793483cb8e1ae86d
4
- data.tar.gz: 0103b3de1a79e13aebf6c8f1710050857c8430696c9a4d5c5d63d186f049573c
3
+ metadata.gz: e8dfa1d679021485dc59bc3def9d0f0ce75b9e4c303f32ce24a0a52c4578533d
4
+ data.tar.gz: c3ca5ffb266236d2e414fb71ac16c107077a4a16746423ec9337d81969b96d27
5
5
  SHA512:
6
- metadata.gz: 50033a452f4d59d8ae42c89b58f9fbea1a4aa8567aa75bafe04f9d4fbb5761a6a98a374799bf3c189f2f5f224d5a5ca3053d35d4cf7625f4473b459c8d3e385d
7
- data.tar.gz: 2329a71cc2a7a7c7f390ea9021b9cd18dcb1d232845f5ce03b1ebe3b0ec2afa9d0e09b3df320c7d54d9a0380428c2ceeddb336baf0884f7ba8c0c36f78cd4bbc
6
+ metadata.gz: d9d7a367bca5e65895201664b92270577bd46621ce305f632ea78a1f9c4ffc7df31032cbabf18be20569b3cffb9455365117205e6396c3304098af0364734f2d
7
+ data.tar.gz: d240ca100f2706689e8d7396036bdad599b186a25c7973fe4eb65cb1bd3edbf68167720e105dc006949c7e9e05203438aed002a08bef10e67b5bbcad98ea8430
@@ -5,6 +5,7 @@
5
5
  * bulk — one cache round-trip, zero Ruby frames, zero FFI
6
6
  * marshaling per node. */
7
7
  #include <ruby.h>
8
+ #include <ruby/encoding.h>
8
9
  #include <stdint.h>
9
10
  #include <string.h>
10
11
 
@@ -266,7 +267,13 @@ static VALUE nn_name(VALUE self)
266
267
  const char *s;
267
268
  TypedData_Get_Struct(self, struct native_node, &nn_type, n);
268
269
  s = f_elem_name(n->ptr);
269
- return s ? rb_utf8_str_new_cstr(s) : Qnil;
270
+ /* Interned (shared, frozen) fstring: element names repeat
271
+ * massively across a document — one RString per distinct name
272
+ * per process instead of one per read (lutaml/moxml#249:
273
+ * ~18% of consumer materialize allocations were fresh name
274
+ * strings). Names are identifiers; nothing downstream mutates
275
+ * them in place (renames mint new strings). */
276
+ return s ? rb_enc_interned_str(s, strlen(s), rb_utf8_encoding()) : Qnil;
270
277
  }
271
278
 
272
279
  static VALUE nn_content(VALUE self)
@@ -1873,6 +1880,67 @@ static VALUE nf_snapshot_subtree(VALUE self, VALUE document, VALUE addr)
1873
1880
  return out;
1874
1881
  }
1875
1882
 
1883
+ /* ---- Lean plan rows (lutaml/moxml#249 plan layer) ----------------
1884
+ * Elements only, one 4-tuple per element: [name, attrs_flat, text,
1885
+ * depth] — no Hash per row, no text/comment rows, attr and element
1886
+ * NAMES interned (shared frozen fstrings: names repeat across the
1887
+ * document, so repeat reads allocate zero). Pre-order, depth 0 at
1888
+ * the addressed node. */
1889
+ static void walk_rows_impl(void *node, int depth, VALUE out)
1890
+ {
1891
+ if (f_node_type(node) == WS_NODE_ELEMENT) {
1892
+ VALUE row = rb_ary_new_capa(4);
1893
+ VALUE attrs;
1894
+ const char *name = f_elem_name(node);
1895
+ const char *an;
1896
+ const char *av;
1897
+ void *a;
1898
+ void *c;
1899
+
1900
+ rb_ary_store(row, 0, name ? rb_enc_interned_str(name, strlen(name),
1901
+ rb_utf8_encoding())
1902
+ : Qnil);
1903
+ attrs = rb_ary_new();
1904
+ for (a = f_attr_first(node); a; a = f_attr_next(a)) {
1905
+ an = f_attr_name(a);
1906
+ av = f_attr_value(node, a);
1907
+ rb_ary_push(attrs, an ? rb_enc_interned_str(an, strlen(an),
1908
+ rb_utf8_encoding())
1909
+ : Qnil);
1910
+ rb_ary_push(attrs, av ? rb_utf8_str_new_cstr(av) : Qnil);
1911
+ }
1912
+ rb_ary_store(row, 1, attrs);
1913
+ for (c = f_first_child(node); c; c = f_next_sibling(c)) {
1914
+ if (f_node_type(c) == WS_NODE_TEXT) {
1915
+ const char *t = f_text_content(c);
1916
+ rb_ary_store(row, 2, t ? rb_utf8_str_new_cstr(t) : Qnil);
1917
+ break;
1918
+ }
1919
+ }
1920
+ rb_ary_store(row, 3, INT2NUM(depth));
1921
+ rb_ary_push(out, row);
1922
+
1923
+ for (c = f_first_child(node); c; c = f_next_sibling(c)) {
1924
+ walk_rows_impl(c, depth + 1, out);
1925
+ }
1926
+ } else if (f_node_type(node) == WS_NODE_DOCTYPE || f_node_type(node) == 9) {
1927
+ void *dc = f_first_child(node);
1928
+ while (dc) {
1929
+ walk_rows_impl(dc, depth, out);
1930
+ dc = f_next_sibling(dc);
1931
+ }
1932
+ }
1933
+ }
1934
+
1935
+ static VALUE nf_snapshot_rows(VALUE self, VALUE document, VALUE addr)
1936
+ {
1937
+ (void)self;
1938
+ (void)document;
1939
+ VALUE out = rb_ary_new();
1940
+ walk_rows_impl((void *)(uintptr_t)NUM2ULL(addr), 0, out);
1941
+ return out;
1942
+ }
1943
+
1876
1944
  /* ---- inner_html in one C pass (TODO.perf/18) --------------------
1877
1945
  * Serializes the receiver's children into one growable buffer:
1878
1946
  * elements via leptris_element_serialize_into (the same opts the
@@ -2415,6 +2483,8 @@ void Init_native(void)
2415
2483
  nf_fast_inner_xml, 1);
2416
2484
  rb_define_module_function(m_native, "snapshot_subtree",
2417
2485
  nf_snapshot_subtree, 2);
2486
+ rb_define_module_function(m_native, "snapshot_rows",
2487
+ nf_snapshot_rows, 2);
2418
2488
  rb_define_module_function(m_native, "doc_handle_attach",
2419
2489
  nf_doc_handle_attach, 1);
2420
2490
  rb_define_module_function(m_native, "doc_handle_release",
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Leptris
4
- VERSION = "1.9.193.2"
4
+ VERSION = "1.9.193.4"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: leptris
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.193.2
4
+ version: 1.9.193.4
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-17 00:00:00.000000000 Z
11
+ date: 2026-09-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi