omnizip 0.3.23 → 0.3.24

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: 61cf26f9e324600f286b236ab80e02d720059f32bca2fa3c71640ba3abc4355a
4
- data.tar.gz: fa189e081e402ecb4d084490e7874402faacf231a296cd009a15f218fcd9453e
3
+ metadata.gz: a0119d9a2a28f5bc71cc0aa63f142b373196b8ca3f4abc0db93a71e0a9e45051
4
+ data.tar.gz: b3f6b837610a9005322e25dc5fd9d79a34529b9cd29d2c4d634efb3d64ad50fa
5
5
  SHA512:
6
- metadata.gz: 308660d6095a909d72c528bdfb5e828e76d320172b979a53ef7401aa2c1c12a560a0afd57f49991eb5190f87deca1c15cd798e8abae89bd3341ed3bb43c39b3d
7
- data.tar.gz: 29ac9066539f2d8cef3973a2eb9cfe15a549a5efead04a1f5c88f28587fb6a2d23ac28c401c1c4187f5c226bfe4b531e3565523400dcd183adc83c842cd2d5dc
6
+ metadata.gz: dfa90d09bbe46eed96bec5565d1751e2bed9d47ee0e9a52b587c3cbad87aaf650e1083a4e8e9d3a22b7089ff0cf218386a2f55f637691f0de363d7646c114b3a
7
+ data.tar.gz: 5fecb94fb627f48411717bd7dcc4c9243f86b4030b4a24a951d8f0816a123e6ec7288cd4c6920e70a89fa0297e0d082389370341d4792d87985c6198ec7c2bbe
data/CHANGELOG.md CHANGED
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.3.24] - 2026-08-26
11
+
12
+ ### Changed
13
+ - LZMA2 encoder hot paths avoid per-call allocations: the
14
+ range-encoder symbol drain reuses its 10 KB scratch buffer
15
+ (profiles showed String#* at ~half of encoder CPU), and the optimal
16
+ parser compares 8-byte windows and selects best matches without
17
+ intermediate strings/arrays. ~180k fewer object allocations and
18
+ ~94 MB less churn per 138 KB compressed, with byte-identical
19
+ output; covers both the xz and 7-Zip paths.
20
+
10
21
  ## [0.3.23] - 2026-08-26
11
22
 
12
23
  ### Changed
@@ -67,11 +67,12 @@ module Omnizip
67
67
  ].min
68
68
 
69
69
  len = 2
70
- # Compare 8 bytes at a time using 64-bit integers
70
+ # Compare 8 bytes at a time using 64-bit integers read
71
+ # without intermediate strings (byteslice + unpack1
72
+ # allocates two Strings per step and dominated GC time).
71
73
  while len + 8 <= max_match_len
72
- # Read 8 bytes as little-endian 64-bit integers
73
- v1 = buf.byteslice(buf_pos + len, 8).unpack1("Q<")
74
- v2 = buf.byteslice(buf_back_index + len, 8).unpack1("Q<")
74
+ v1 = read8(buf, buf_pos + len)
75
+ v2 = read8(buf, buf_back_index + len)
75
76
  break if v1 != v2
76
77
 
77
78
  len += 8
@@ -104,7 +105,15 @@ module Omnizip
104
105
  # A match may reference anything before `position`: bytes already
105
106
  # committed to the dictionary *and* bytes decoded earlier within
106
107
  # the chunk currently being encoded.
107
- best_normal = matches.max_by { |m| [m.length, m.distance] }
108
+ best_normal = nil
109
+ matches.each do |m|
110
+ next if best_normal &&
111
+ (m.length < best_normal.length ||
112
+ (m.length == best_normal.length &&
113
+ m.distance <= best_normal.distance))
114
+
115
+ best_normal = m
116
+ end
108
117
 
109
118
  if best_normal && best_normal.length >= nice_len &&
110
119
  best_normal.distance <= position
@@ -126,6 +135,18 @@ module Omnizip
126
135
  end
127
136
  end
128
137
 
138
+ # Allocation-free little-endian 8-byte read.
139
+ def read8(buf, pos)
140
+ buf.getbyte(pos) |
141
+ (buf.getbyte(pos + 1) << 8) |
142
+ (buf.getbyte(pos + 2) << 16) |
143
+ (buf.getbyte(pos + 3) << 24) |
144
+ (buf.getbyte(pos + 4) << 32) |
145
+ (buf.getbyte(pos + 5) << 40) |
146
+ (buf.getbyte(pos + 6) << 48) |
147
+ (buf.getbyte(pos + 7) << 56)
148
+ end
149
+
129
150
  # Constants
130
151
  REPS = 4
131
152
  MATCH_LEN_MAX = 273 # From lzma.h
@@ -339,8 +339,11 @@ module Omnizip
339
339
  def encode_queued_symbols(encoder, output)
340
340
  return if encoder.none?
341
341
 
342
- # Create temporary buffer for encoding
343
- temp_buffer = "\0" * 10000
342
+ # Reused scratch buffer: allocating a fresh 10 KB String
343
+ # per drain showed up as half the encoder's runtime via
344
+ # GC (String#* in profiles).
345
+ @symbol_buffer ||= "\0".b * 10_000
346
+ temp_buffer = @symbol_buffer
344
347
  out_pos = Omnizip::Algorithms::LZMA::IntRef.new(0)
345
348
 
346
349
  # Track size before encoding
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Omnizip
4
- VERSION = "0.3.23"
4
+ VERSION = "0.3.24"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omnizip
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.23
4
+ version: 0.3.24
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-08-25 00:00:00.000000000 Z
11
+ date: 2026-08-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: base64