leptris 1.9.242.0-x86_64-linux → 1.9.248.0-x86_64-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: c7bc7c05a3c162f72ff2838f09f9d3de1bb030627a4cb4833f83ccaae3dd1153
4
- data.tar.gz: 7615bc6ed608d0205d5aebddbe2a63fe91b4155374c40d79cf55a121071f282d
3
+ metadata.gz: 187aa679fe75e6ffc44cfcb49d357898cbdd03e3e64cafb6d9838cd86f4b28e2
4
+ data.tar.gz: f76579f64dfbf608de551e2c143b3bb3a4f0980392edac8597d106511506c1d7
5
5
  SHA512:
6
- metadata.gz: 23bd215cd06ffe1165460d596bce0eb4890da1f816fd54986fc1e2050f88f4d03ea9267053253620818ec152cb3b95c1fc2bcef0364c6abe27d39c3eee927d9b
7
- data.tar.gz: a0699a34a4edbaeb646eeec5df48c6b90f4408134ac3100c5153f74fbef4fa20a264a1ffcccde797ade81b071e1cc98e5bb0ac3c1e5a4e5b569cd3fbd1068bd0
6
+ metadata.gz: 9b66f961ac0b8ac7218b5879e085d65732fad5592393ad0152b7cfbbf9d899c3bbe77ddaec12c7d3f73cbf861cc7b7e4e70a71f35b1ef6198461ed1b7dbbc432
7
+ data.tar.gz: 2820785702685e33dbf16f0c14d93170bcc300ee5fac914fbae3fa65f864d5453309d9530ba9addae23f6602bb771eee7dc71acc7ee207be90465dc9323b4bbe
data/CHANGELOG.md CHANGED
@@ -5,6 +5,22 @@ 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.248.0] - 2026-09-26
9
+
10
+ ### Fixed
11
+
12
+ - Vendored libleptris 1.9.248 (riding 1.9.247 + 1.9.248):
13
+ - xpath: filtering a non-nodeset base treats the atom as a
14
+ one-item sequence — `(1)[1]` keeps the atom and `(1)[1] + 1`
15
+ is 2 (was an unconditional empty nodeset).
16
+ - html: the document arena span is sized from the input once
17
+ (#1218) — borrowed pointers stay in the int32 compact range,
18
+ removing ~776k overflow-table inserts on a 2.6 MB parse;
19
+ measured 31.4 -> 50.9 MB/s (+62%) on the table-rows corpus.
20
+ - Restores the naming lockstep: the previous release vendored
21
+ engine 1.9.246 under the version 1.9.242.0; version.rb now
22
+ matches the vendored engine semver again.
23
+
8
24
  ## [1.9.241.0] - 2026-09-25
9
25
 
10
26
  ### 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.246"
11
+ LIBLEPTRIS_VERSION = "1.9.248"
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Leptris
4
- VERSION = "1.9.242.0"
4
+ VERSION = "1.9.248.0"
5
5
  end
data/lib/libleptris.so CHANGED
Binary file
data/vendor-src/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  Sources vendored in this gem (recompile rights; the ruby
2
2
  variant builds them at install via extconf.rb):
3
3
 
4
- - libleptris v1.9.246
4
+ - libleptris v1.9.248
5
5
  - utf8proc v2.11.0
6
6
 
7
7
  Rebuild by hand:
@@ -1,5 +1,21 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.9.248] - 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.247] - 2026-09-26
14
+
15
+ ### Fixed
16
+
17
+ - filter on a non-nodeset base treats the atom as a one-item sequence (xpath)
18
+
3
19
  ## [1.9.246] - 2026-09-25
4
20
 
5
21
  ### Added
@@ -3,7 +3,7 @@
3
3
  cmake_minimum_required(VERSION 3.20)
4
4
 
5
5
  project(leptris
6
- VERSION 1.9.246
6
+ VERSION 1.9.248
7
7
  DESCRIPTION "Fast XML parser and XPath evaluator in pure C"
8
8
  LANGUAGES C CXX
9
9
  )
@@ -5453,8 +5453,17 @@ static LeptrisDocument html_parse_shared(
5453
5453
  if (status) *status = LEPTRIS_ERROR_NULL_ARG;
5454
5454
  return NULL;
5455
5455
  }
5456
+ /* #1218: size the arena span from the input up front — the
5457
+ * HTML tree expands ~8x (nodes + attributes + the owned input
5458
+ * copy), and an undersized span spills later allocations into
5459
+ * extension blocks in a different malloc region, pushing every
5460
+ * borrowed pointer out of the int32 compact range (measured
5461
+ * 776k overflow-table inserts on the 2.6 MB table shape). */
5462
+ extern struct leptris_document* leptris_document_create_with_arena_size(
5463
+ size_t arena_size);
5456
5464
  struct leptris_document* doc =
5457
- (struct leptris_document*)leptris_document_create();
5465
+ (struct leptris_document*)leptris_document_create_with_arena_size(
5466
+ len * 10 + (1u << 18));
5458
5467
  if (!doc) {
5459
5468
  if (status) *status = LEPTRIS_ERROR_MEMORY;
5460
5469
  return NULL;
@@ -173,7 +173,17 @@ void leptris_parse_options_init(leptris_parse_options* opts) {
173
173
  * pool-allocated (TODO 154) zeroed struct, strict mode inherited
174
174
  * from the thread-local setting, standalone unset (-1).
175
175
  */
176
- LEPTRIS_API LeptrisDocument leptris_document_create(void) {
176
+ /* #1218: parse entry points that know their input size reserve the
177
+ * arena span ONCE at content-derived scale — an undersized span
178
+ * overflows into tracked extension blocks, which malloc places in a
179
+ * different region (measured 105 TB away on macOS, ~5.5 GB from the
180
+ * span). Every borrowed pointer (text runs, element names, attribute
181
+ * strings) then exceeds the int32 compact range and pays an
182
+ * overflow-table insert per field plus a hash lookup per decode for
183
+ * the REST of the parse. Sized spans keep the whole parse in one
184
+ * contiguous region. */
185
+ struct leptris_document* leptris_document_create_with_arena_size(
186
+ size_t arena_size) {
177
187
  extern LeptrisMemoryPool* leptris_pool_create_arena_backed(
178
188
  LeptrisArena*, int);
179
189
  extern void* leptris_pool_alloc(LeptrisMemoryPool* pool, size_t size);
@@ -185,7 +195,7 @@ LEPTRIS_API LeptrisDocument leptris_document_create(void) {
185
195
  * documents take the same arena-backed pool the parser uses
186
196
  * (overflow extends via tracked blocks; the pool's page
187
197
  * machinery no longer runs for documents). */
188
- LeptrisArena* arena = leptris_arena_create(64 * 1024);
198
+ LeptrisArena* arena = leptris_arena_create(arena_size);
189
199
  if (!arena) return NULL;
190
200
  LeptrisMemoryPool* pool = leptris_pool_create_arena_backed(arena, 1);
191
201
  if (!pool) {
@@ -210,6 +220,10 @@ LEPTRIS_API LeptrisDocument leptris_document_create(void) {
210
220
  return doc;
211
221
  }
212
222
 
223
+ LEPTRIS_API LeptrisDocument leptris_document_create(void) {
224
+ return leptris_document_create_with_arena_size(64 * 1024);
225
+ }
226
+
213
227
  LEPTRIS_API LeptrisDocument leptris_document_create_html(void) {
214
228
  struct leptris_document* doc = leptris_document_create();
215
229
  if (doc) doc->html_mode = 1;
@@ -985,8 +985,48 @@ struct leptris_xpath_result* evaluate_expr(XPathContext* ctx, XPathASTNode* ast)
985
985
  if (!base) return NULL;
986
986
  if (base->type != XPATH_RESULT_NODESET ||
987
987
  !base->value.nodeset_value) {
988
+ /* Non-nodeset base: the atom is a one-item sequence
989
+ * — (1)[1] keeps it, (1)[true()] keeps it, (1)[2]
990
+ * empties (the old code returned empty
991
+ * unconditionally). The predicate sees position 1
992
+ * of 1; the context node stays the outer one. */
993
+ int keep = 1;
994
+ for (size_t p = 1; p < ast->child_count && keep; p++) {
995
+ XPathASTNode* pred = ast->children[p];
996
+ if (pred->type == XPATH_AST_NUMBER) {
997
+ keep = pred->number_value == 1.0;
998
+ continue;
999
+ }
1000
+ LeptrisElement old_node = ctx->context_node;
1001
+ size_t old_pos = ctx->context_position;
1002
+ size_t old_size = ctx->context_size;
1003
+ void* old_pred = ctx->current_predicate_node;
1004
+ ctx->context_position = 1;
1005
+ ctx->context_size = 1;
1006
+ struct leptris_xpath_result* pr =
1007
+ evaluate_expr(ctx, pred);
1008
+ ctx->context_node = old_node;
1009
+ ctx->context_position = old_pos;
1010
+ ctx->context_size = old_size;
1011
+ ctx->current_predicate_node = old_pred;
1012
+ if (!pr) {
1013
+ keep = 0;
1014
+ continue;
1015
+ }
1016
+ if (pr->type == XPATH_RESULT_NUMBER)
1017
+ keep =
1018
+ (size_t)pr->value.number_value == 1;
1019
+ else
1020
+ keep = xpath_to_boolean(pr) ? 1 : 0;
1021
+ xpath_result_free(pr);
1022
+ }
1023
+ if (keep) return base;
988
1024
  xpath_result_free(base);
989
- return xpath_result_new(XPATH_RESULT_NODESET);
1025
+ struct leptris_xpath_result* empty =
1026
+ xpath_result_new(XPATH_RESULT_NODESET);
1027
+ if (empty && empty->value.nodeset_value)
1028
+ empty->value.nodeset_value->is_sequence = 1;
1029
+ return empty;
990
1030
  }
991
1031
  if (ast->child_count > 1) {
992
1032
  apply_predicates(ctx, base->value.nodeset_value,
@@ -941,7 +941,7 @@ TEST(Qt3Subset, FnReverse) {
941
941
  }
942
942
 
943
943
  TEST(Qt3Subset, FnSubsequence) {
944
- run_test_set("fn/subsequence.xml", {}, 67, {},
944
+ run_test_set("fn/subsequence.xml", {}, 68, {},
945
945
  {
946
946
  "cbcl-subsequence-011",
947
947
  "cbcl-subsequence-012",
@@ -949,7 +949,6 @@ TEST(Qt3Subset, FnSubsequence) {
949
949
  "cbcl-subsequence-014",
950
950
  "cbcl-subsequence-025",
951
951
  "cbcl-subsequence-019", /* document{} + `!` map chain */
952
- "K-SeqSubsequenceFunc-34", /* mixed-type seq item eq */
953
952
  "fn-subsequence-mix-args-025", /* `!` + @id pair */
954
953
 
955
954
  });
@@ -893,6 +893,51 @@ TEST(XQueryCtors, SequenceItemEbv) {
893
893
  /* unordered{E} / ordered{E} order-mode constructors: order is
894
894
  * irrelevant to this engine's sequence model, so the splice strips
895
895
  * them to (E) (QT3 K2-SeqReverseFunc-2 nests three deep). */
896
+ /* Filter on a non-nodeset base: the atom is a one-item sequence —
897
+ * (1)[1] keeps it, (1)[2] empties, boolean predicates see position
898
+ * 1 of 1 (QT3 K-SeqSubsequenceFunc-34 chains (1)[deep-equal(...)]).
899
+ * The old code returned an empty nodeset unconditionally. */
900
+ TEST(XPathFilter, ScalarBase) {
901
+ LeptrisStatus st = LEPTRIS_OK;
902
+ LeptrisDocument doc = leptris_parse_string("<e/>", 4, &st);
903
+ ASSERT_NE(doc, nullptr);
904
+ struct {
905
+ const char* q;
906
+ const char* want;
907
+ } cases[] = {
908
+ {"(1)[1]", "1"},
909
+ {"(1)[true()]", "1"},
910
+ {"(2)[1]", "2"},
911
+ {"(1)[2]", ""},
912
+ {"(1)[false()]", ""},
913
+ {"(1)[deep-equal(1, 1)] eq 1", "true"},
914
+ {"(1)[1] + 1", "2"},
915
+ };
916
+ for (auto& c : cases) {
917
+ LeptrisXQuery xq = leptris_xquery_parse(c.q, strlen(c.q));
918
+ ASSERT_NE(xq, nullptr) << c.q;
919
+ LeptrisXPathResult r = leptris_xquery_eval(xq, doc, NULL);
920
+ ASSERT_NE(r, nullptr) << c.q;
921
+ std::string got;
922
+ if (leptris_xpath_result_type(r) == LEPTRIS_XPATH_NODESET) {
923
+ size_t n = leptris_xpath_result_count(r);
924
+ for (size_t i = 0; i < n; i++) {
925
+ const char* v = leptris_xpath_result_node_value(r, i);
926
+ if (i) got += ' ';
927
+ got += v ? v : "";
928
+ }
929
+ } else {
930
+ char* s2 = leptris_xpath_result_string(r);
931
+ got = s2 ? s2 : "";
932
+ leptris_free_string(s2);
933
+ }
934
+ EXPECT_EQ(got, c.want) << c.q;
935
+ leptris_xpath_result_free(r);
936
+ leptris_xquery_free(xq);
937
+ }
938
+ leptris_document_free(doc);
939
+ }
940
+
896
941
  TEST(XQueryCtors, OrderModeStrip) {
897
942
  LeptrisStatus st = LEPTRIS_OK;
898
943
  LeptrisDocument doc = leptris_parse_string("<e/>", 4, &st);
@@ -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.246",
4
+ "version": "1.9.248",
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.242.0
4
+ version: 1.9.248.0
5
5
  platform: x86_64-linux
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-09-25 00:00:00.000000000 Z
11
+ date: 2026-09-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi