leptris 1.9.249.0 → 1.9.255.0
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 +19 -0
- data/Rakefile +1 -1
- 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 +58 -0
- data/vendor-src/libleptris/CMakeLists.txt +1 -1
- data/vendor-src/libleptris/benchmarks/CMakeLists.txt +15 -0
- data/vendor-src/libleptris/benchmarks/modification/bench_append_attr_pugixml.cpp +79 -0
- data/vendor-src/libleptris/src/leptris/flat/direct_parse.c +59 -10
- data/vendor-src/libleptris/src/leptris/html/html_parse.c +292 -316
- data/vendor-src/libleptris/src/leptris/xpath/evaluator_internal.h +14 -0
- data/vendor-src/libleptris/src/leptris/xpath/evaluator_operators.c +388 -10
- data/vendor-src/libleptris/src/leptris/xpath/functions_ext31.c +13 -40
- data/vendor-src/libleptris/src/leptris/xpath/parser.c +202 -2
- data/vendor-src/libleptris/src/leptris/xquery/xquery.c +15 -1
- data/vendor-src/libleptris/test/html/test_html.cpp +16 -0
- data/vendor-src/libleptris/test/xquery/test_qt3.cpp +36 -13
- data/vendor-src/libleptris/test/xquery/test_xquery.cpp +171 -10
- data/vendor-src/libleptris/vcpkg.json +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5d1418101d40d96692273fa9327b6ad4c666a0705beeaa3c1500cdea623d3b83
|
|
4
|
+
data.tar.gz: f8605c3bd4a6f64e8a2361d4bdb375808665a57ec26f21deaf2d619a7695fa55
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 83c628648a66102c5a29da7f443761cf35c9b238328b22f9a46a4a43146e8a4b83a993aff7e53f1ca8b325abbe98c9f8c28a255ffb2a040ae050c91b01383a52
|
|
7
|
+
data.tar.gz: f831136e4a5fe977c2cd6ecc91ffd5e010f278fe0201f644d384ae6e1fa29aa4c887508a660c83fb5d87d38d8104f71e2656eab13876757a48c546e077065804
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,25 @@ 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.255.0] - 2026-09-26
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- Vendored libleptris 1.9.255 (riding 1.9.249-1.9.255, seven
|
|
13
|
+
engine syncs). Highlights:
|
|
14
|
+
- xquery: numeric-variable predicates are positional, not EBV —
|
|
15
|
+
(1)[1] keeps the atom, (1)[1] + 1 = 2 (#1392).
|
|
16
|
+
- xquery: document{...} materializes a real node (path steps
|
|
17
|
+
resolve over constructor results), the ! simple map is
|
|
18
|
+
item-preserving, multi-binding for/quantifier clauses parse,
|
|
19
|
+
and keyword constructors run the path continuation.
|
|
20
|
+
- xquery: F&O 3.0 numeric type promotion in value comparisons
|
|
21
|
+
and dedup (QT3 typed-atom lane) + timezone-normalized
|
|
22
|
+
xs:time comparison.
|
|
23
|
+
- html: implied-end pair checks run on tag ids with the tag
|
|
24
|
+
table gaps fixed (rb/rp/rt/rtc, option/optgroup) — round 2 of
|
|
25
|
+
the #1218 parse profile.
|
|
26
|
+
|
|
8
27
|
## [1.9.248.0] - 2026-09-26
|
|
9
28
|
|
|
10
29
|
### Fixed
|
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.255"
|
|
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
|
|
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
|
@@ -1,5 +1,63 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [1.9.255] - 2026-09-26
|
|
4
|
+
|
|
5
|
+
<!-- Edit this section with the actual release notes. -->
|
|
6
|
+
<!-- See https://keepachangelog.com for format guidance. -->
|
|
7
|
+
|
|
8
|
+
### Changed
|
|
9
|
+
|
|
10
|
+
- (describe changes here)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
## [1.9.254] - 2026-09-26
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- timezone-normalized xs:time comparison and ordering (xquery)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
## [1.9.253] - 2026-09-26
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- F&O numeric promotion in value comparison and distinct-values (xquery)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
## [1.9.252] - 2026-09-26
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
|
|
33
|
+
- multi-binding for/quantifier clauses (xquery)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
## [1.9.251] - 2026-09-26
|
|
38
|
+
|
|
39
|
+
### Added
|
|
40
|
+
|
|
41
|
+
- document{} materializes a node; simple map preserves items (xquery)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
## [1.9.250] - 2026-09-26
|
|
46
|
+
|
|
47
|
+
### Fixed
|
|
48
|
+
|
|
49
|
+
- keyword ctors run the path continuation (document{...}/M) (xquery)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
## [1.9.249] - 2026-09-26
|
|
54
|
+
|
|
55
|
+
### Performance
|
|
56
|
+
|
|
57
|
+
- classify implied-end pairs on tag ids (#1218) (html)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
3
61
|
## [1.9.248] - 2026-09-26
|
|
4
62
|
|
|
5
63
|
<!-- Edit this section with the actual release notes. -->
|
|
@@ -211,6 +211,21 @@ endif()
|
|
|
211
211
|
leptris_add_benchmark(bench_serialize serialization/bench_leptris_serialize.c)
|
|
212
212
|
leptris_add_benchmark(bench_modify_leptris modification/bench_leptris_modify.c)
|
|
213
213
|
|
|
214
|
+
# Lane 18 (#1179): append + attr-parse vs pugixml (the lane bar is
|
|
215
|
+
# <=1x on both shapes). Needs C++ (pugixml.hpp) and the pugixml
|
|
216
|
+
# target; skipped when the dependency is absent.
|
|
217
|
+
if(PUGIXML_AVAILABLE)
|
|
218
|
+
add_executable(bench_append_attr_pugixml
|
|
219
|
+
modification/bench_append_attr_pugixml.cpp)
|
|
220
|
+
target_link_libraries(bench_append_attr_pugixml PRIVATE leptris::leptris)
|
|
221
|
+
if(PUGIXML_TARGET)
|
|
222
|
+
target_link_libraries(bench_append_attr_pugixml PRIVATE ${PUGIXML_TARGET})
|
|
223
|
+
else()
|
|
224
|
+
target_include_directories(bench_append_attr_pugixml PRIVATE ${PUGIXML_INCLUDE_DIR})
|
|
225
|
+
target_link_libraries(bench_append_attr_pugixml PRIVATE ${PUGIXML_LIBRARY})
|
|
226
|
+
endif()
|
|
227
|
+
endif()
|
|
228
|
+
|
|
214
229
|
# XSLT release scorecard (TODO.xslt-full/13, #682): the transform
|
|
215
230
|
# fixtures the perf lane gates on — best-of protocol, never mean.
|
|
216
231
|
leptris_add_benchmark(bench_xslt_dispatch xslt/bench_dispatch.c utils.c)
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// bench_append_attr_pugixml — Lane 18 (#1179): DOM append and
|
|
2
|
+
// attr-parse throughput vs pugixml. The lane bar is append <=1x and
|
|
3
|
+
// attr-parse <=1x against pugixml on these shapes.
|
|
4
|
+
#include "leptris.h"
|
|
5
|
+
#include "pugixml.hpp"
|
|
6
|
+
#include <chrono>
|
|
7
|
+
#include <cstdio>
|
|
8
|
+
#include <cstring>
|
|
9
|
+
#include <string>
|
|
10
|
+
|
|
11
|
+
static double now_ns() {
|
|
12
|
+
return (double)std::chrono::duration_cast<std::chrono::nanoseconds>(
|
|
13
|
+
std::chrono::steady_clock::now().time_since_epoch())
|
|
14
|
+
.count();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
int main(void) {
|
|
18
|
+
const int N_APPEND = 200000;
|
|
19
|
+
const int N_PARSE = 20000;
|
|
20
|
+
|
|
21
|
+
/* ---- append: 200k element children on one root ---- */
|
|
22
|
+
{
|
|
23
|
+
double t0 = now_ns();
|
|
24
|
+
LeptrisDocument d = leptris_document_create();
|
|
25
|
+
LeptrisElement root = leptris_element_create(d, "root");
|
|
26
|
+
leptris_document_set_root(d, root);
|
|
27
|
+
for (int i = 0; i < N_APPEND; i++) {
|
|
28
|
+
LeptrisElement c = leptris_element_create(d, "c");
|
|
29
|
+
leptris_element_append_child(root, c);
|
|
30
|
+
}
|
|
31
|
+
double t1 = now_ns();
|
|
32
|
+
printf("append leptris : %8.1f ns/child\n",
|
|
33
|
+
(t1 - t0) / N_APPEND);
|
|
34
|
+
leptris_document_free(d);
|
|
35
|
+
}
|
|
36
|
+
{
|
|
37
|
+
double t0 = now_ns();
|
|
38
|
+
pugi::xml_document d;
|
|
39
|
+
pugi::xml_node root = d.append_child("root");
|
|
40
|
+
for (int i = 0; i < N_APPEND; i++)
|
|
41
|
+
root.append_child("c");
|
|
42
|
+
double t1 = now_ns();
|
|
43
|
+
printf("append pugixml : %8.1f ns/child\n",
|
|
44
|
+
(t1 - t0) / N_APPEND);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/* ---- attr-parse: parse 20k docs, 4 elems x 16 attrs ---- */
|
|
48
|
+
std::string xml = "<r>";
|
|
49
|
+
for (int e = 0; e < 4; e++) {
|
|
50
|
+
xml += "<e";
|
|
51
|
+
for (int a = 0; a < 16; a++)
|
|
52
|
+
xml += " a" + std::to_string(a) + "='value-" +
|
|
53
|
+
std::to_string(a) + "-xyz'";
|
|
54
|
+
xml += "/>";
|
|
55
|
+
}
|
|
56
|
+
xml += "</r>";
|
|
57
|
+
{
|
|
58
|
+
double t0 = now_ns();
|
|
59
|
+
for (int i = 0; i < N_PARSE; i++) {
|
|
60
|
+
LeptrisDocument d =
|
|
61
|
+
leptris_parse_string(xml.data(), xml.size(), NULL);
|
|
62
|
+
leptris_document_free(d);
|
|
63
|
+
}
|
|
64
|
+
double t1 = now_ns();
|
|
65
|
+
printf("attrparse leptris: %7.1f ns/doc (%zu bytes)\n",
|
|
66
|
+
(t1 - t0) / N_PARSE, xml.size());
|
|
67
|
+
}
|
|
68
|
+
{
|
|
69
|
+
double t0 = now_ns();
|
|
70
|
+
for (int i = 0; i < N_PARSE; i++) {
|
|
71
|
+
pugi::xml_document d;
|
|
72
|
+
d.load_buffer((void*)xml.data(), xml.size());
|
|
73
|
+
}
|
|
74
|
+
double t1 = now_ns();
|
|
75
|
+
printf("attrparse pugixml: %7.1f ns/doc\n",
|
|
76
|
+
(t1 - t0) / N_PARSE);
|
|
77
|
+
}
|
|
78
|
+
return 0;
|
|
79
|
+
}
|
|
@@ -108,6 +108,13 @@ typedef struct {
|
|
|
108
108
|
* (the element cache line only needs touching twice per tag). */
|
|
109
109
|
struct leptris_attribute* attr_cursor;
|
|
110
110
|
struct leptris_attribute* attr_end;
|
|
111
|
+
/* #1200 round 2: per-element attr-name hash prefilter — the
|
|
112
|
+
* dup scan compares uint32 hashes (uint32 loop, no pointer
|
|
113
|
+
* chasing) and only walks the attr chain with memcmp on a hash
|
|
114
|
+
* hit. Pool-backed growth; reset per element. */
|
|
115
|
+
uint32_t* attr_dup_hashes;
|
|
116
|
+
size_t attr_dup_count;
|
|
117
|
+
size_t attr_dup_cap;
|
|
111
118
|
/* Bulk text-node block (round 8): leptris_text_create_borrowed
|
|
112
119
|
* is an out-of-line call per text node — pool_alloc alone costs
|
|
113
120
|
* more than the field stores. Same carve pattern as the elem and
|
|
@@ -454,20 +461,56 @@ static inline int dp_add_attr_inline(DParser* p, LeptrisElement elem,
|
|
|
454
461
|
* (libxml2 recover semantics, and the digest's first-wins
|
|
455
462
|
* becomes official); the duplicate never enters the chain, it
|
|
456
463
|
* costs its already-carved slot. */
|
|
457
|
-
|
|
464
|
+
{
|
|
465
|
+
uint32_t dh = 2166136261u;
|
|
466
|
+
for (size_t i = 0; i < name_len; i++) {
|
|
467
|
+
dh ^= (unsigned char)name[i];
|
|
468
|
+
dh *= 16777619u;
|
|
469
|
+
}
|
|
458
470
|
int dup = 0;
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
if (a->name_view.length == attr->name_view.length &&
|
|
464
|
-
a->name_view.data[0] == attr->name_view.data[0] &&
|
|
465
|
-
memcmp(a->name_view.data, attr->name_view.data,
|
|
466
|
-
attr->name_view.length) == 0) {
|
|
467
|
-
dup = 1;
|
|
471
|
+
int cand = 0;
|
|
472
|
+
for (size_t i = 0; i < p->attr_dup_count; i++) {
|
|
473
|
+
if (p->attr_dup_hashes[i] == dh) {
|
|
474
|
+
cand = 1;
|
|
468
475
|
break;
|
|
469
476
|
}
|
|
470
477
|
}
|
|
478
|
+
if (cand && elem->first_attribute_off != 0) {
|
|
479
|
+
/* hash hit: confirm against the real chain (collision
|
|
480
|
+
* or genuine duplicate) */
|
|
481
|
+
for (struct leptris_attribute* a =
|
|
482
|
+
(struct leptris_attribute*)(
|
|
483
|
+
(char*)elem + elem->first_attribute_off);
|
|
484
|
+
a; a = leptris_attr_next(a)) {
|
|
485
|
+
if (a->name_view.length ==
|
|
486
|
+
attr->name_view.length &&
|
|
487
|
+
a->name_view.data[0] ==
|
|
488
|
+
attr->name_view.data[0] &&
|
|
489
|
+
memcmp(a->name_view.data, attr->name_view.data,
|
|
490
|
+
attr->name_view.length) == 0) {
|
|
491
|
+
dup = 1;
|
|
492
|
+
break;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
if (!dup) {
|
|
497
|
+
if (p->attr_dup_count == p->attr_dup_cap) {
|
|
498
|
+
size_t nc = p->attr_dup_cap ? p->attr_dup_cap * 2
|
|
499
|
+
: 16;
|
|
500
|
+
uint32_t* nh = (uint32_t*)leptris_pool_alloc(
|
|
501
|
+
p->pool, nc * sizeof(uint32_t));
|
|
502
|
+
if (nh) {
|
|
503
|
+
if (p->attr_dup_count)
|
|
504
|
+
memcpy(nh, p->attr_dup_hashes,
|
|
505
|
+
p->attr_dup_count *
|
|
506
|
+
sizeof(uint32_t));
|
|
507
|
+
p->attr_dup_hashes = nh;
|
|
508
|
+
p->attr_dup_cap = nc;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
if (p->attr_dup_count < p->attr_dup_cap)
|
|
512
|
+
p->attr_dup_hashes[p->attr_dup_count++] = dh;
|
|
513
|
+
}
|
|
471
514
|
if (dup) {
|
|
472
515
|
if (p->doc) {
|
|
473
516
|
extern struct LeptrisDiag* leptris_diag_emit(
|
|
@@ -489,6 +532,7 @@ static inline int dp_add_attr_inline(DParser* p, LeptrisElement elem,
|
|
|
489
532
|
* the raw-attr registration so BOTH surfaces agree. */
|
|
490
533
|
return 1;
|
|
491
534
|
}
|
|
535
|
+
if (elem->first_attribute_off != 0) {
|
|
492
536
|
/* Cache should always be valid mid-parse. Fall back to walk
|
|
493
537
|
* only if cache is NULL (defensive — shouldn't happen). */
|
|
494
538
|
struct leptris_attribute* tail = p->current_elem_last_attr;
|
|
@@ -506,6 +550,7 @@ static inline int dp_add_attr_inline(DParser* p, LeptrisElement elem,
|
|
|
506
550
|
* offset is ever needed. */
|
|
507
551
|
elem->first_attribute_off =
|
|
508
552
|
(int32_t)((char*)attr - (char*)elem);
|
|
553
|
+
}
|
|
509
554
|
}
|
|
510
555
|
p->current_elem_last_attr = attr;
|
|
511
556
|
p->cur_attr_count++;
|
|
@@ -723,6 +768,7 @@ static int dp_parse_attrs(DParser* p, LeptrisElement elem) {
|
|
|
723
768
|
p->current_elem_last_ns = NULL;
|
|
724
769
|
p->raw_last = NULL;
|
|
725
770
|
p->cur_attr_count = 0;
|
|
771
|
+
p->attr_dup_count = 0; /* hash array + cap persist across elements */
|
|
726
772
|
/* Sentinel-terminated (parse endgame, third application): buf[len]
|
|
727
773
|
* is NUL and NUL fails every classification below — not '>', not
|
|
728
774
|
* '/', not '=' , not a quote, not IS_NAME_START. Each former
|
|
@@ -1333,6 +1379,9 @@ static struct leptris_document* direct_parse_internal(char* buf, size_t len,
|
|
|
1333
1379
|
p.attr_capacity = attr_capacity;
|
|
1334
1380
|
p.attr_cursor = attr_block;
|
|
1335
1381
|
p.attr_end = attr_block + attr_capacity;
|
|
1382
|
+
p.attr_dup_hashes = NULL;
|
|
1383
|
+
p.attr_dup_count = 0;
|
|
1384
|
+
p.attr_dup_cap = 0;
|
|
1336
1385
|
p.text_cursor = text_block;
|
|
1337
1386
|
p.text_end = text_block + lt_count;
|
|
1338
1387
|
p.cpi_cursor = cpi_block;
|