leptris 1.9.220.0 → 1.9.221.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 +4 -4
- data/CHANGELOG.md +8 -0
- data/README.adoc +63 -4
- data/Rakefile +1 -1
- data/ext/build_windows_native.rb +19 -0
- data/ext/leptris/native/native.c +20 -4
- data/lib/leptris/vendor/aarch64-linux/libleptris.so +0 -0
- data/lib/leptris/vendor/aarch64-linux-musl/libleptris.so +0 -0
- data/lib/leptris/vendor/arm-linux/libleptris.so +0 -0
- data/lib/leptris/vendor/arm-linux-musl/libleptris.so +0 -0
- data/lib/leptris/vendor/arm64-darwin/libleptris.dylib +0 -0
- data/lib/leptris/vendor/ppc64le-linux/libleptris.so +0 -0
- data/lib/leptris/vendor/s390x-linux-musl/libleptris.so +0 -0
- data/lib/leptris/vendor/x86_64-darwin/libleptris.dylib +0 -0
- data/lib/leptris/vendor/x86_64-linux/libleptris.so +0 -0
- data/lib/leptris/vendor/x86_64-linux-musl/libleptris.so +0 -0
- data/lib/leptris/version.rb +1 -1
- data/vendor-src/README.md +1 -1
- data/vendor-src/libleptris/CHANGELOG.md +8 -0
- data/vendor-src/libleptris/CMakeLists.txt +1 -1
- data/vendor-src/libleptris/src/leptris/dom/compact.c +40 -17
- data/vendor-src/libleptris/src/leptris/dom/compact.h +3 -0
- data/vendor-src/libleptris/vcpkg.json +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: abec97f5dc76127e52554fe9254f7b9a93676c0583dde964e474a7e662884878
|
|
4
|
+
data.tar.gz: d2d30b60d8ad656c6ed3564e63e9ea7ecc006ebe17cdb026075dfd8407311dd8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fe37f35a8359f66544471ea70405b3895ce07acc64d9e92067fd26d9945b1c6ec2f2b82ca7a4b18628f59ca012c8347adbea24a173a8fc52bf725dacdd761e36
|
|
7
|
+
data.tar.gz: d2531467d1c319ff967ab0eb7b6cafc54beead04048d3d788300e8bc042cd1ce20784caf98d9e1646944d6db346cec66368bece7f1e1ace2adbf05d779039906
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,14 @@ All notable changes to Leptris will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.9.221.0] - 2026-09-22
|
|
9
|
+
|
|
10
|
+
### Performance — engine sync (1.9.221)
|
|
11
|
+
|
|
12
|
+
- Vendored libleptris 1.9.221: per-document overflow teardown in
|
|
13
|
+
the dispatch row (#682). No binding-facing surface changes;
|
|
14
|
+
audit 342/342, suite 770/0.
|
|
15
|
+
|
|
8
16
|
## [1.9.220.0] - 2026-09-22
|
|
9
17
|
|
|
10
18
|
### Performance — engine sync (1.9.217–1.9.220)
|
data/README.adoc
CHANGED
|
@@ -504,10 +504,69 @@ Row kinds: `:scalar`, `:collection`, `:nested` (via `plan:`), `:raw`
|
|
|
504
504
|
offset + `type_tag` echo, matching `Node#byte_offset`). Namespace
|
|
505
505
|
binding lives on plans: `ns:` is `:none` (default), `:any`, or
|
|
506
506
|
`{ exact: "urn:..." }`; `flags:` also accepts `:cdata`, `:ordered`,
|
|
507
|
-
`:ns_lenient` (#754 out-of-namespace adoption)
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
507
|
+
`:ns_lenient` (#754 out-of-namespace adoption), and `:order_spine`
|
|
508
|
+
(#1273 — unmatched sibling text/comment/PI runs emit as positioned
|
|
509
|
+
scalars so ordered hosts rebuild element order without re-parsing).
|
|
510
|
+
Children the plan does not describe are skipped; undescribed document
|
|
511
|
+
order within a row is preserved. `#walk` returns a lazy `PlanValue`
|
|
512
|
+
tree (the result outlives the document); `#to_ruby` materializes it.
|
|
513
|
+
|
|
514
|
+
=== Typed scalars and the fused entry (#230/#298)
|
|
515
|
+
|
|
516
|
+
Plan rows accept `type: :integer | :float | :boolean` — the walk
|
|
517
|
+
parses the values natively (in-pass, libleptris #1269a) and
|
|
518
|
+
`#to_ruby` / the bulk face return `Integer` / `Float` / `true` /
|
|
519
|
+
`false`. Unparseable values fall back to the raw String;
|
|
520
|
+
`PlanValue#string_value` stays the raw escape, and
|
|
521
|
+
`#int_value` / `#float_value` / `#bool_value` expose the parsed
|
|
522
|
+
accessors directly.
|
|
523
|
+
|
|
524
|
+
`Descriptor#materialize(source)` is the fused entry: source bytes →
|
|
525
|
+
typed rows in ONE C call — parse, walk, and free happen natively
|
|
526
|
+
(#1269b); the standalone `PlanValue` tree is all that surfaces.
|
|
527
|
+
|
|
528
|
+
[source,ruby]
|
|
529
|
+
----
|
|
530
|
+
descriptor = Leptris::XML::Descriptor.build(
|
|
531
|
+
name: "iso",
|
|
532
|
+
children: [{ name: "row", kind: :collection, plan: {
|
|
533
|
+
name: "row",
|
|
534
|
+
attributes: [{ name: "id", kind: :scalar, type: :integer }],
|
|
535
|
+
children: [
|
|
536
|
+
{ name: "price", kind: :scalar, type: :float },
|
|
537
|
+
{ name: "active", kind: :scalar, type: :boolean },
|
|
538
|
+
] } },
|
|
539
|
+
])
|
|
540
|
+
|
|
541
|
+
rows = descriptor.materialize(xml_source) # one C call
|
|
542
|
+
rows.as_kwarg_hash[:children]["row"] # typed, hydrator-ready
|
|
543
|
+
----
|
|
544
|
+
|
|
545
|
+
=== Predicate rows (#1272) and order identity (#1273)
|
|
546
|
+
|
|
547
|
+
Same-wire-name rows can partition on attribute values with `when:` —
|
|
548
|
+
AND across pairs, exclusive routing (first matching row wins per
|
|
549
|
+
occurrence):
|
|
550
|
+
|
|
551
|
+
[source,ruby]
|
|
552
|
+
----
|
|
553
|
+
Leptris::XML::Descriptor.build(
|
|
554
|
+
name: "r",
|
|
555
|
+
children: [
|
|
556
|
+
{ name: "item", kind: :collection, when: { "kind" => "a" },
|
|
557
|
+
plan: { name: "item", children: [{ name: "name", kind: :scalar }] } },
|
|
558
|
+
{ name: "item", kind: :collection, when: { "kind" => "b" },
|
|
559
|
+
plan: { name: "item", children: [{ name: "name", kind: :scalar }] } },
|
|
560
|
+
])
|
|
561
|
+
----
|
|
562
|
+
|
|
563
|
+
`PlanValue#node_kind` and `#order_index` carry document-order
|
|
564
|
+
identity for matched rows (and, under `:order_spine`, for the
|
|
565
|
+
interleaved text runs) — ordered/mixed content reconstructs
|
|
566
|
+
without fragment re-parsing. `PlanValue#as_kwarg_hash` is the
|
|
567
|
+
bulk hydrator face: one Ruby call per node returns the typed
|
|
568
|
+
attribute/children hash (the crossings floor on the 5k-row ISO
|
|
569
|
+
fixture is ~4 FFI crossings per row, pinned by spec).
|
|
511
570
|
|
|
512
571
|
== XQuery
|
|
513
572
|
|
data/Rakefile
CHANGED
|
@@ -8,7 +8,7 @@ RSpec::Core::RakeTask.new(:spec)
|
|
|
8
8
|
# Pin for `rake compile` and the platform-gem builds. Keep in lockstep
|
|
9
9
|
# with .github/workflows/build.yml (which calls `rake compile`) and the
|
|
10
10
|
# CHANGELOG when libleptris releases.
|
|
11
|
-
LIBLEPTRIS_VERSION = "1.9.
|
|
11
|
+
LIBLEPTRIS_VERSION = "1.9.221"
|
|
12
12
|
# Vendored alongside libleptris for fn:normalize-unicode (TODO
|
|
13
13
|
# .restructure/20): built per platform with a RELOCATABLE @rpath
|
|
14
14
|
# install name, loaded by ffi.rb before libleptris so the
|
data/ext/build_windows_native.rb
CHANGED
|
@@ -22,8 +22,15 @@ root = File.expand_path("..", __dir__)
|
|
|
22
22
|
ext_dir = File.join(root, "ext", "leptris", "native")
|
|
23
23
|
minor = RUBY_VERSION[/\A\d+\.\d+/]
|
|
24
24
|
minor_us = minor.tr(".", "_")
|
|
25
|
+
INIT_PREFIX = "Init_native_"
|
|
25
26
|
|
|
26
27
|
Dir.chdir(ext_dir) do
|
|
28
|
+
# aarch64-ucrt 1.9.221.0 shipped a DLL exporting only Init_native
|
|
29
|
+
# because make reused a stale native.obj from a failed earlier
|
|
30
|
+
# attempt (the log shows "creating Makefile -> linking" with no
|
|
31
|
+
# compile). Force a clean compile on every invocation.
|
|
32
|
+
FileUtils.rm_f(Dir.glob("#{ext_dir}/native.{o,obj,so,dll}"))
|
|
33
|
+
FileUtils.rm_f("#{ext_dir}/leptris/xml/native.so")
|
|
27
34
|
system(RbConfig.ruby, "extconf.rb") or abort "extconf failed under #{RUBY_VERSION}"
|
|
28
35
|
# mkmf's link binds the CURRENT Ruby's runtime DLL — exactly
|
|
29
36
|
# what the versioned naming is for.
|
|
@@ -31,6 +38,18 @@ Dir.chdir(ext_dir) do
|
|
|
31
38
|
abort "make failed under #{RUBY_VERSION}" unless success
|
|
32
39
|
so = Dir.glob("native.{so,dll}").first
|
|
33
40
|
abort "native bundle not produced under #{RUBY_VERSION}" unless so
|
|
41
|
+
# Functional export gate: dlopen the built DLL and resolve the
|
|
42
|
+
# MINOR-SUFFIXED init symbol. A PE DLL can carry the symbol in its
|
|
43
|
+
# string table while exporting only mkmf's Init_native (the arm64
|
|
44
|
+
# toolchain ignores our .def when its own wins the link) — only a
|
|
45
|
+
# real lookup proves native_<minor>.so will load.
|
|
46
|
+
require "fiddle"
|
|
47
|
+
begin
|
|
48
|
+
Fiddle.dlopen(File.expand_path(so))[INIT_PREFIX + minor_us]
|
|
49
|
+
rescue Fiddle::DLError => e
|
|
50
|
+
abort "#{so} does not export #{INIT_PREFIX + minor_us} — refusing to " \
|
|
51
|
+
"install a DLL that would 127 at require (#{e.message})"
|
|
52
|
+
end
|
|
34
53
|
dest = File.join(root, "lib", "leptris", "xml", "native_#{minor_us}.so")
|
|
35
54
|
# The artifact must reference only this minor's Ruby DLL.
|
|
36
55
|
imported = `strings #{so} 2>/dev/null`[/[a-z0-9-]*ruby\d{3,}\.dll/i]
|
data/ext/leptris/native/native.c
CHANGED
|
@@ -2524,7 +2524,23 @@ static VALUE leptris_native_resolve_rb(VALUE self, VALUE lib_path)
|
|
|
2524
2524
|
return Qnil;
|
|
2525
2525
|
}
|
|
2526
2526
|
|
|
2527
|
-
|
|
2527
|
+
/*
|
|
2528
|
+
* Windows export discipline: a PE DLL exports only what a .def file or
|
|
2529
|
+
* __declspec(dllexport) names. native_layer requires the MINOR-SUFFIXED
|
|
2530
|
+
* symbol (native_3_4.so -> Init_native_3_4), but mkmf generates its own
|
|
2531
|
+
* .def listing just Init_native, and depending on toolchain that def
|
|
2532
|
+
* can win over ours (aarch64-ucrt ld does not auto-export the rest, so
|
|
2533
|
+
* the lookup 127s and the platform silently degrades to the FFI
|
|
2534
|
+
* surface). dllexport pins all four entry points into the export table
|
|
2535
|
+
* on every Windows toolchain; it is a no-op elsewhere.
|
|
2536
|
+
*/
|
|
2537
|
+
#if defined(_WIN32)
|
|
2538
|
+
# define LEPTRIS_INIT_EXPORT __declspec(dllexport)
|
|
2539
|
+
#else
|
|
2540
|
+
# define LEPTRIS_INIT_EXPORT
|
|
2541
|
+
#endif
|
|
2542
|
+
|
|
2543
|
+
LEPTRIS_INIT_EXPORT void Init_native(void)
|
|
2528
2544
|
{
|
|
2529
2545
|
VALUE m_leptris, m_xml, m_native;
|
|
2530
2546
|
|
|
@@ -2683,7 +2699,7 @@ void Init_native(void)
|
|
|
2683
2699
|
* each needs its exact init name exported. All are defined here
|
|
2684
2700
|
* unconditionally: a DLL only ever loads under the Ruby minor it
|
|
2685
2701
|
* was built against (PE binds its build Ruby's runtime DLL). */
|
|
2686
|
-
void Init_native_3_3(void) { Init_native(); }
|
|
2687
|
-
void Init_native_3_4(void) { Init_native(); }
|
|
2688
|
-
void Init_native_4_0(void) { Init_native(); }
|
|
2702
|
+
LEPTRIS_INIT_EXPORT void Init_native_3_3(void) { Init_native(); }
|
|
2703
|
+
LEPTRIS_INIT_EXPORT void Init_native_3_4(void) { Init_native(); }
|
|
2704
|
+
LEPTRIS_INIT_EXPORT void Init_native_4_0(void) { Init_native(); }
|
|
2689
2705
|
#endif
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
data/lib/leptris/version.rb
CHANGED
data/vendor-src/README.md
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
#include "compact.h"
|
|
12
|
+
#include "../leptris_internal.h" /* struct leptris_document (overflow_entries) */
|
|
12
13
|
#include "../common/port.h"
|
|
13
14
|
#include <stdlib.h>
|
|
14
15
|
#include <string.h>
|
|
@@ -158,6 +159,14 @@ int leptris_compact_overflow_set(LeptrisCompactOverflowTable* table,
|
|
|
158
159
|
table->buckets[index] = entry;
|
|
159
160
|
table->entry_count++;
|
|
160
161
|
|
|
162
|
+
/* #682: parallel per-document chain — teardown walks exactly
|
|
163
|
+
* this doc's entries instead of scanning the whole table. */
|
|
164
|
+
if (doc) {
|
|
165
|
+
entry->doc_next =
|
|
166
|
+
(struct leptris_compact_overflow_entry*)doc->overflow_entries;
|
|
167
|
+
doc->overflow_entries = entry;
|
|
168
|
+
}
|
|
169
|
+
|
|
161
170
|
if (table->entry_count >= table->bucket_count) {
|
|
162
171
|
overflow_table_grow(table);
|
|
163
172
|
}
|
|
@@ -208,26 +217,40 @@ void leptris_compact_cleanup(void) {
|
|
|
208
217
|
void leptris_compact_cleanup_document(struct leptris_document* doc) {
|
|
209
218
|
if (!doc || !g_overflow_table) return;
|
|
210
219
|
|
|
211
|
-
|
|
220
|
+
/* #682: walk THIS document's entry chain (linked at set time)
|
|
221
|
+
* instead of scanning every bucket of the global table — the
|
|
222
|
+
* old full-table sweep ran on every document free and dominated
|
|
223
|
+
* apply-heavy XSLT profiles (result docs register thousands of
|
|
224
|
+
* cross-block edge entries; the sampler pinned 35% of the
|
|
225
|
+
* dispatch bench in this loop). */
|
|
226
|
+
LeptrisCompactOverflowEntry* e =
|
|
227
|
+
(LeptrisCompactOverflowEntry*)doc->overflow_entries;
|
|
228
|
+
doc->overflow_entries = NULL;
|
|
212
229
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
LeptrisCompactOverflowEntry*
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
230
|
+
size_t removed_count = 0;
|
|
231
|
+
while (e) {
|
|
232
|
+
LeptrisCompactOverflowEntry* next = e->doc_next;
|
|
233
|
+
if (e->doc == doc) {
|
|
234
|
+
/* Stale chain links (entry re-registered under another
|
|
235
|
+
* doc) are skipped — the ->doc check keeps them alive
|
|
236
|
+
* for their true owner. */
|
|
237
|
+
size_t index = hash_pointer(e->key,
|
|
238
|
+
g_overflow_table->bucket_count);
|
|
239
|
+
LeptrisCompactOverflowEntry** entry_ptr =
|
|
240
|
+
&g_overflow_table->buckets[index];
|
|
241
|
+
while (*entry_ptr) {
|
|
242
|
+
if (*entry_ptr == e) {
|
|
243
|
+
/* Unlink only — entries live in SLABS owned by
|
|
244
|
+
* the table; free()ing them corrupted the heap
|
|
245
|
+
* (#450 sibling-edge follow-up). */
|
|
246
|
+
*entry_ptr = e->next;
|
|
247
|
+
removed_count++;
|
|
248
|
+
break;
|
|
249
|
+
}
|
|
250
|
+
entry_ptr = &(*entry_ptr)->next;
|
|
229
251
|
}
|
|
230
252
|
}
|
|
253
|
+
e = next;
|
|
231
254
|
}
|
|
232
255
|
|
|
233
256
|
g_overflow_table->entry_count -= removed_count;
|
|
@@ -60,6 +60,9 @@ typedef struct leptris_compact_overflow_entry {
|
|
|
60
60
|
void* value; /* Actual pointer value */
|
|
61
61
|
struct leptris_document* doc; /* Document that owns this entry */
|
|
62
62
|
struct leptris_compact_overflow_entry* next;
|
|
63
|
+
/* #682: per-document chain — teardown walks THIS doc's entries
|
|
64
|
+
* instead of scanning every bucket of the global table. */
|
|
65
|
+
struct leptris_compact_overflow_entry* doc_next;
|
|
63
66
|
} LeptrisCompactOverflowEntry;
|
|
64
67
|
|
|
65
68
|
/**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://raw.githubusercontent.com/microsoft/vcpkg/master/scripts/vcpkg.schema.json",
|
|
3
3
|
"name": "leptris",
|
|
4
|
-
"version": "1.9.
|
|
4
|
+
"version": "1.9.221",
|
|
5
5
|
"description": "High-performance XML parser and XPath 1.0 engine in C (libleptris)",
|
|
6
6
|
"homepage": "https://github.com/leptris/leptris",
|
|
7
7
|
"license": "MIT",
|
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.
|
|
4
|
+
version: 1.9.221.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-
|
|
11
|
+
date: 2026-09-22 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: ffi
|