leptris 1.9.222.1-arm-linux → 1.9.222.3-arm-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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c5b4eab095e1cec2d20a2966c7d07ef6088a7d2f412f0e7e1910a54099d76416
4
- data.tar.gz: 339ad816465350ca84ca28fdc4955bb047c488758fd87c43eb3f3d4c13d0b266
3
+ metadata.gz: 7532c10f6daec3e59677e99c9f0159e0aa724c2755a6e86f66093c86f5895ccb
4
+ data.tar.gz: 668e020302bd7472c9f997bf511f9492d0631265e53727b580ff45ed3a1c39a0
5
5
  SHA512:
6
- metadata.gz: 5ab816b1b94f5571c59c49522192ef92dfd2cc5c7ef2bb219171edd1b726fe313cdac3a85f6199df82a2ef07c8bd35ca80977fd0df9dda0d189de385cf37dc8a
7
- data.tar.gz: ae6eb3c963cddea9341e80e1b8316566f08cfa9d431b43f8feb45b51ccd84c90e1066dc9c9abb7cf7fb914221eb7dea084d596fa3e44d3274b983040c8d7c1de
6
+ metadata.gz: e4d37b6a7f25c6704ff4e4fce1184e69f8daace1f36e99c330985e6f4f61b1fc4fc2b1927dffd923c7d9bf95fb8009fdcebbd8c085efcd034ad93d8ee91014b0
7
+ data.tar.gz: 8548e4b4ea99a0ff40417f30f23ace3dcd819d2176c98f47e5ec8e7e3b973a0695b9995d87235e3b085c2853dbc005cbb4f281f9901a76567cb9278c48926939
@@ -135,6 +135,9 @@ static VALUE c_iteration_scope;
135
135
  static VALUE c_leptris_error;
136
136
  static VALUE c_b_document, c_b_freed, c_ffi_pointer;
137
137
  static ID id_ptr_new, id_freed_new, id_alive;
138
+ static ID id_iv_c_address, id_iv_document, id_iv_parent;
139
+ static ID id_iv_structure_memoizable, id_iv_native_fast;
140
+ static ID id_iv_pub_document, id_iv_addr_reads_fast, id_iv_node_type;
138
141
  static void check_status_c(int st);
139
142
 
140
143
  #define NT_ELEMENT 0
@@ -839,8 +842,38 @@ struct trav_state {
839
842
  VALUE err;
840
843
  void *self_ptr;
841
844
  int for_visit;
845
+ /* Hoisted per-walk state (was re-resolved per node): the
846
+ * document's wrapper cache and the iteration-scope class
847
+ * check. #312 item 1. */
848
+ VALUE cache;
849
+ VALUE klass_memo_flag;
842
850
  };
843
851
 
852
+ /* Construct-or-fetch the binding wrapper for node_ptr against the
853
+ * per-walk hoisted cache (#312 item 1): static-ID ivar writes (no
854
+ * per-call string interning), the scope class check precomputed. */
855
+ static VALUE trav_wrapper_for(struct trav_state *st, void *node_ptr,
856
+ int kind)
857
+ {
858
+ VALUE key = ULL2NUM((uint64_t)(uintptr_t)node_ptr);
859
+ VALUE node = rb_hash_aref(st->cache, key);
860
+ if (!NIL_P(node)) return node;
861
+
862
+ node = rb_obj_alloc(binding_klass_for(kind));
863
+ rb_ivar_set(node, id_iv_c_address, key);
864
+ rb_ivar_set(node, id_iv_document, st->document);
865
+ rb_ivar_set(node, id_iv_parent, Qnil);
866
+ VALUE fast = st->klass_memo_flag;
867
+ rb_ivar_set(node, id_iv_structure_memoizable, fast);
868
+ rb_ivar_set(node, id_iv_native_fast, fast);
869
+ rb_ivar_set(node, id_iv_pub_document,
870
+ fast == Qtrue ? st->document : Qnil);
871
+ rb_ivar_set(node, id_iv_addr_reads_fast, Qtrue);
872
+ rb_ivar_set(node, id_iv_node_type, INT2FIX(kind));
873
+ rb_hash_aset(st->cache, key, node);
874
+ return node;
875
+ }
876
+
844
877
  static VALUE trav_yield_one(VALUE arg)
845
878
  {
846
879
  return rb_yield(arg);
@@ -849,33 +882,13 @@ static VALUE trav_yield_one(VALUE arg)
849
882
  static int trav_cb(void *node_ptr, void *user)
850
883
  {
851
884
  struct trav_state *st = user;
852
- VALUE cache, key, node;
885
+ VALUE node;
853
886
  int kind, state;
854
887
 
855
888
  if (st->err != Qnil)
856
889
  return 1;
857
890
  kind = f_node_type(node_ptr);
858
- cache = binding_cache_of(st->document);
859
- key = ULL2NUM((uint64_t)(uintptr_t)node_ptr);
860
- node = rb_hash_aref(cache, key);
861
- if (NIL_P(node)) {
862
- node = rb_obj_alloc(binding_klass_for(kind));
863
- rb_iv_set(node, "@c_address", key);
864
- rb_iv_set(node, "@document", st->document);
865
- rb_iv_set(node, "@parent", Qnil);
866
- if (rb_obj_class(st->document) == c_iteration_scope) {
867
- rb_iv_set(node, "@structure_memoizable", Qfalse);
868
- rb_iv_set(node, "@native_fast", Qfalse);
869
- rb_iv_set(node, "@pub_document", Qnil);
870
- } else {
871
- rb_iv_set(node, "@structure_memoizable", Qtrue);
872
- rb_iv_set(node, "@native_fast", Qtrue);
873
- rb_iv_set(node, "@pub_document", st->document);
874
- }
875
- rb_iv_set(node, "@addr_reads_fast", Qtrue);
876
- rb_iv_set(node, "@node_type", INT2FIX(kind));
877
- rb_hash_aset(cache, key, node);
878
- }
891
+ node = trav_wrapper_for(st, node_ptr, kind);
879
892
  rb_protect(trav_yield_one, node, &state);
880
893
  if (state) {
881
894
  st->err = rb_errinfo();
@@ -894,6 +907,9 @@ static VALUE nf_traverse_binding(VALUE self, VALUE document,
894
907
  st.document = document;
895
908
  st.err = Qnil;
896
909
  st.self_ptr = (void *)(uintptr_t)NUM2ULL(addr);
910
+ st.cache = binding_cache_of(document);
911
+ st.klass_memo_flag =
912
+ rb_obj_class(document) == c_iteration_scope ? Qfalse : Qtrue;
897
913
  st.for_visit = 0;
898
914
  f_node_traverse(st.self_ptr, 1 /* TRAVERSE_POST_ORDER */,
899
915
  trav_cb, &st);
@@ -922,33 +938,13 @@ static void visit_cb(void *user, void *node_ptr, int entering,
922
938
  * happens after the walk, same observable outcome. */
923
939
  struct trav_state *st = user;
924
940
  struct visit_yield_args va;
925
- VALUE cache, key, node;
941
+ VALUE node;
926
942
  int kind, state;
927
943
 
928
944
  if (st->err != Qnil)
929
945
  return;
930
946
  kind = f_node_type(node_ptr);
931
- cache = binding_cache_of(st->document);
932
- key = ULL2NUM((uint64_t)(uintptr_t)node_ptr);
933
- node = rb_hash_aref(cache, key);
934
- if (NIL_P(node)) {
935
- node = rb_obj_alloc(binding_klass_for(kind));
936
- rb_iv_set(node, "@c_address", key);
937
- rb_iv_set(node, "@document", st->document);
938
- rb_iv_set(node, "@parent", Qnil);
939
- if (rb_obj_class(st->document) == c_iteration_scope) {
940
- rb_iv_set(node, "@structure_memoizable", Qfalse);
941
- rb_iv_set(node, "@native_fast", Qfalse);
942
- rb_iv_set(node, "@pub_document", Qnil);
943
- } else {
944
- rb_iv_set(node, "@structure_memoizable", Qtrue);
945
- rb_iv_set(node, "@native_fast", Qtrue);
946
- rb_iv_set(node, "@pub_document", st->document);
947
- }
948
- rb_iv_set(node, "@addr_reads_fast", Qtrue);
949
- rb_iv_set(node, "@node_type", INT2FIX(kind));
950
- rb_hash_aset(cache, key, node);
951
- }
947
+ node = trav_wrapper_for(st, node_ptr, kind);
952
948
  va.node = node;
953
949
  va.entering = entering ? Qtrue : Qfalse;
954
950
  va.depth = INT2NUM(depth);
@@ -966,6 +962,9 @@ static VALUE nf_visit_binding(VALUE self, VALUE document, VALUE addr)
966
962
  st.document = document;
967
963
  st.err = Qnil;
968
964
  st.self_ptr = (void *)(uintptr_t)NUM2ULL(addr);
965
+ st.cache = binding_cache_of(document);
966
+ st.klass_memo_flag =
967
+ rb_obj_class(document) == c_iteration_scope ? Qfalse : Qtrue;
969
968
  st.for_visit = 1;
970
969
  f_node_visit(st.self_ptr, visit_cb, &st);
971
970
  if (st.err != Qnil)
@@ -2150,6 +2149,34 @@ static VALUE nf_plan_structs_typed_p(VALUE self)
2150
2149
  return Qtrue;
2151
2150
  }
2152
2151
 
2152
+ /* ---- Bulk attribute rows (leptris-ruby#278) ----------------------
2153
+ * One C crossing per element: walks the attribute chain and
2154
+ * returns a flat [name, value, address, ...] array. Names
2155
+ * interned (they repeat), values fresh UTF-8 strings, addresses
2156
+ * as Integers for Attr c_handle reconstruction. Identical data
2157
+ * to the per-attribute FFI chain (first/next/get_name/get_value,
2158
+ * 4 crossings each) — the win amplifies with attribute density
2159
+ * (40-attr elements: ~7x on the listing). */
2160
+ static VALUE nf_attribute_rows(VALUE self, VALUE document, VALUE addr)
2161
+ {
2162
+ (void)self;
2163
+ (void)document;
2164
+ void *node = (void *)(uintptr_t)NUM2ULL(addr);
2165
+ VALUE out = rb_ary_new();
2166
+ if (f_node_type(node) != WS_NODE_ELEMENT) return out;
2167
+
2168
+ for (void *a = f_attr_first(node); a; a = f_attr_next(a)) {
2169
+ const char *an = f_attr_name(a);
2170
+ const char *av = f_attr_value(node, a);
2171
+ rb_ary_push(out, an ? rb_enc_interned_str(an, strlen(an),
2172
+ rb_utf8_encoding())
2173
+ : Qnil);
2174
+ rb_ary_push(out, av ? rb_utf8_str_new_cstr(av) : Qnil);
2175
+ rb_ary_push(out, ULL2NUM((uintptr_t)a));
2176
+ }
2177
+ return out;
2178
+ }
2179
+
2153
2180
  static VALUE nf_plan_structs(VALUE self, VALUE document, VALUE addr,
2154
2181
  VALUE spec)
2155
2182
  {
@@ -2620,6 +2647,14 @@ LEPTRIS_INIT_EXPORT void Init_native(void)
2620
2647
  id_iv_c_address = rb_intern("@c_address");
2621
2648
  id_iv_native_cache = rb_intern("@native_cache");
2622
2649
  id_iv_binding_cache = rb_intern("@wrapper_cache");
2650
+ id_iv_c_address = rb_intern("@c_address");
2651
+ id_iv_document = rb_intern("@document");
2652
+ id_iv_parent = rb_intern("@parent");
2653
+ id_iv_structure_memoizable = rb_intern("@structure_memoizable");
2654
+ id_iv_native_fast = rb_intern("@native_fast");
2655
+ id_iv_pub_document = rb_intern("@pub_document");
2656
+ id_iv_addr_reads_fast = rb_intern("@addr_reads_fast");
2657
+ id_iv_node_type = rb_intern("@node_type");
2623
2658
  id_iv_version = rb_intern("@version");
2624
2659
  id_iv_readonly = rb_intern("@readonly");
2625
2660
  id_address = rb_intern("address");
@@ -2732,6 +2767,8 @@ LEPTRIS_INIT_EXPORT void Init_native(void)
2732
2767
  nf_attribute_pairs, 2);
2733
2768
  rb_define_module_function(m_native, "plan_structs",
2734
2769
  nf_plan_structs, 3);
2770
+ rb_define_module_function(m_native, "attribute_rows",
2771
+ nf_attribute_rows, 2);
2735
2772
  rb_define_module_function(m_native, "plan_structs_typed?",
2736
2773
  nf_plan_structs_typed_p, 0);
2737
2774
  rb_define_module_function(m_native, "doc_handle_attach",
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Leptris
4
- VERSION = "1.9.222.1"
4
+ VERSION = "1.9.222.3"
5
5
  end
@@ -311,7 +311,11 @@ class Leptris::XML::Element < Leptris::XML::Node
311
311
 
312
312
  def attribute_nodes
313
313
  return @attribute_nodes if memo_hit?(@attribute_nodes_version)
314
- result = each_attribute.to_a
314
+ result = if NATIVE_ATTR_ROWS && @c_address && @document
315
+ attribute_rows_native
316
+ else
317
+ each_attribute.to_a
318
+ end
315
319
  if @document
316
320
  @attribute_nodes = result
317
321
  @attribute_nodes_version = @document.version
@@ -319,6 +323,26 @@ class Leptris::XML::Element < Leptris::XML::Node
319
323
  result
320
324
  end
321
325
 
326
+ # One C crossing per element (leptris-ruby#278): the native face
327
+ # walks the attribute chain and returns flat [name, value,
328
+ # address] triples; the Attr value objects are minted from them
329
+ # with zero further engine crossings — identical objects to
330
+ # each_attribute. The win amplifies with attribute density
331
+ # (40-attr elements list ~7x faster than the chain).
332
+ def attribute_rows_native
333
+ ::Leptris::XML::Native.attribute_rows(@document, @c_address)
334
+ .each_slice(3)
335
+ .map do |name, value, handle|
336
+ ::Leptris::XML::Attr.new(name, value, self,
337
+ c_handle: ::FFI::Pointer.new(handle))
338
+ end
339
+ end
340
+
341
+ NATIVE_ATTR_ROWS =
342
+ defined?(::Leptris::XML::Native) &&
343
+ ::Leptris::XML::Native.respond_to?(:attribute_rows)
344
+ private_constant :NATIVE_ATTR_ROWS
345
+
322
346
  # The element's own namespace prefix (e.g. "foo" for <foo:child/>),
323
347
  # or nil when the element has none.
324
348
  def prefix
Binary file
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.222.1
4
+ version: 1.9.222.3
5
5
  platform: arm-linux
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-09-22 00:00:00.000000000 Z
11
+ date: 2026-09-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi