Skip to content

Commit 67d1c61

Browse files
authored
[ChunkCodecCore] BREAKING change to the resizing behavior in try_resize_decode! (#45)
* change resize logic * update changelog * Add unit tests for `grow_dst!`
1 parent a348174 commit 67d1c61

File tree

22 files changed

+81
-119
lines changed

22 files changed

+81
-119
lines changed

ChunkCodecCore/CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
66

77
## Unreleased
88

9+
### BREAKING the resizing behavior in `try_resize_decode!` changed [#45](https://github.com/JuliaIO/ChunkCodecs.jl/pull/45)
10+
11+
`dst` may now be longer than the returned number of bytes, even if `dst` was grown with `resize!`.
12+
13+
`try_resize_decode!` will now only grow `dst`, never shrink it.
14+
15+
If `max_size` is less than `length(dst)`, instead of throwing an error, `try_resize_decode!` will now act as if `max_size == length(dst)`.
16+
17+
- Added the `grow_dst!` helper function. [#45](https://github.com/JuliaIO/ChunkCodecs.jl/pull/45)
18+
919
## [v0.4.2](https://github.com/JuliaIO/ChunkCodecs.jl/tree/ChunkCodecCore-v0.4.2) - 2025-04-07
1020

1121
- Added the `decode!` function. [#41](https://github.com/JuliaIO/ChunkCodecs.jl/pull/41)

ChunkCodecCore/Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "ChunkCodecCore"
22
uuid = "0b6fb165-00bc-4d37-ab8b-79f91016dbe1"
33
authors = ["nhz2 <nhz2@cornell.edu>"]
4-
version = "0.4.2"
4+
version = "0.5.0-dev"
55

66
[compat]
77
julia = "1.10"

ChunkCodecCore/src/ChunkCodecCore.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ if VERSION >= v"1.11.0-DEV.469"
2424
2525
check_in_range,
2626
check_contiguous,
27+
grow_dst!,
2728
2829
can_concatenate,
2930
is_thread_safe,

ChunkCodecCore/src/interface.jl

Lines changed: 30 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,8 @@ function decode(
6060
throw(DecodedSizeError(_clamp_max_size, try_find_decoded_size(d, src)))
6161
end
6262
@assert real_dst_size 0:_clamp_max_size
63-
if real_dst_size < _clamp_size_hint
64-
resize!(dst, real_dst_size)
65-
end
66-
@assert real_dst_size == length(dst)
63+
@assert real_dst_size length(dst)
64+
resize!(dst, real_dst_size)
6765
dst
6866
end
6967

@@ -206,55 +204,32 @@ Try to decode the input `src` into `dst` using decoder `d`.
206204
207205
Return the size of the decoded output in `dst` if successful.
208206
209-
If `dst` is too small, resize `dst` and try again.
210-
If the `max_size` limit will be passed, return `nothing`.
211-
212-
`dst` can be resized using the `resize!` function to any size between the original length of `dst` and `max_size`.
207+
`dst` can be grown using the `resize!` function to any size between one more than the original length of `dst` and `max_size`.
213208
214-
Throw an `ArgumentError` if `length(dst)` is not in `0:max_size`.
209+
Return `nothing` if the size of `dst` is too small to contain the decoded output and cannot be grown due to the `max_size` restriction.
215210
216211
Precondition: `dst` and `src` do not overlap in memory.
217212
218213
All of `dst` can be written to or used as scratch space by the decoder.
219214
Only the initial returned number of bytes are valid output.
220-
221-
If the size of `dst` is increased, its length will be equal to the returned number of bytes.
222215
"""
223216
function try_resize_decode!(d, dst::AbstractVector{UInt8}, src::AbstractVector{UInt8}, max_size::Int64; kwargs...)::Union{Nothing, Int64}
224-
check_in_range(Int64(0):max_size; dst_size=length(dst))
225-
olb::Int64 = length(dst)
226217
decoded_size = try_find_decoded_size(d, src)::Union{Nothing, Int64}
227218
if isnothing(decoded_size)
228219
while true
229220
ds = try_decode!(d, dst, src)::Union{Nothing, Int64}
230221
if isnothing(ds)
231-
# grow dst
232-
local cur_size::Int64 = length(dst)
233-
if cur_size == max_size
234-
return
235-
end
236-
@assert cur_size < max_size
237-
# This inequality prevents overflow
238-
local next_size = if max_size - cur_size cur_size
239-
max_size
240-
else
241-
max(2*cur_size, Int64(1))
242-
end
243-
resize!(dst, next_size)
222+
@something grow_dst!(dst, max_size) return nothing
244223
else
245224
@assert ds 0:length(dst)
246-
if length(dst) > olb && length(dst) != ds
247-
@assert ds > olb
248-
resize!(dst, ds) # shrink to just contain output if it was resized.
249-
end
250225
return ds
251226
end
252227
end
253228
else
254-
if decoded_size 0:max_size
255-
return
256-
end
257-
if decoded_size > olb
229+
if decoded_size > length(dst)
230+
if decoded_size > max_size
231+
return nothing
232+
end
258233
resize!(dst, decoded_size)
259234
end
260235
real_dst_size = something(try_decode!(d, dst, src))
@@ -300,3 +275,24 @@ function check_in_range(range; kwargs...)
300275
end
301276
end
302277
end
278+
279+
"""
280+
grow_dst!(dst::AbstractVector{UInt8}, max_size::Int64)::Union{Nothing, Int64}
281+
282+
Grow the destination vector `dst` to a size between its current size and `max_size`.
283+
Return the new size of `dst` if it was grown, or `nothing` if it could not be grown due to the `max_size` restriction.
284+
"""
285+
function grow_dst!(dst::AbstractVector{UInt8}, max_size::Int64)::Union{Nothing, Int64}
286+
cur_size::Int64 = length(dst)
287+
if cur_size max_size
288+
return
289+
end
290+
# This inequality prevents overflow
291+
next_size::Int64 = if max_size - cur_size cur_size
292+
max_size
293+
else
294+
max(2*cur_size, Int64(1))
295+
end
296+
resize!(dst, next_size)
297+
return next_size
298+
end

ChunkCodecCore/test/runtests.jl

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,21 @@ end
5353
@test_throws ArgumentError ChunkCodecCore.check_in_range(1:6; x=7)
5454
@test isnothing(ChunkCodecCore.check_in_range(1:6; x=6))
5555
@test isnothing(ChunkCodecCore.check_in_range(1:6; x=1))
56+
57+
x = zeros(UInt8, 0)
58+
for m in [typemin(Int64), Int64(-1), Int64(0)]
59+
@test isnothing(ChunkCodecCore.grow_dst!(x, m))
60+
@test length(x) == 0
61+
end
62+
@test ChunkCodecCore.grow_dst!(x, Int64(1)) === Int64(1)
63+
@test length(x) == 1
64+
@test ChunkCodecCore.grow_dst!(x, typemax(Int64)) == length(x)
65+
n1 = length(x)
66+
@test n1 > 1
67+
@test isnothing(ChunkCodecCore.grow_dst!(x, Int64(n1)))
68+
@test length(x) == n1
69+
@test ChunkCodecCore.grow_dst!(x, Int64(n1 + 1)) == n1 + 1
70+
@test length(x) == n1 + 1
5671
end
5772

5873
# version of NoopDecodeOptions that returns unknown try_find_decoded_size

ChunkCodecTests/Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ ChunkCodecCore = "0b6fb165-00bc-4d37-ab8b-79f91016dbe1"
88
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
99

1010
[compat]
11-
ChunkCodecCore = "0.4"
11+
ChunkCodecCore = "0.5"
1212
Test = "1"
1313
julia = "1.10"

ChunkCodecTests/src/ChunkCodecTests.jl

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,8 @@ function test_encoder_decoder(e, d; trials=100)
110110

111111
if s > 0
112112
dst = zeros(UInt8, s - 1)
113-
@test_throws(
114-
ArgumentError("dst_size ∈ $(0:-1) must hold. Got\ndst_size => $(s-1)"),
115-
try_resize_decode!(d, dst, encoded, Int64(-1))
116-
)
113+
@test isnothing(try_resize_decode!(d, dst, encoded, Int64(-1)))
114+
@test length(dst) == s - 1
117115
dst = zeros(UInt8, s - 1)
118116
@test try_resize_decode!(d, dst, encoded, s) == s
119117
@test length(dst) == s
@@ -130,10 +128,8 @@ function test_encoder_decoder(e, d; trials=100)
130128
end
131129
dst_buffer = zeros(UInt8, s + 2)
132130
dst = view(dst_buffer, 1:s+1)
133-
@test_throws(
134-
ArgumentError("dst_size ∈ $(0:s) must hold. Got\ndst_size => $(s+1)"),
135-
try_resize_decode!(d, dst, encoded, s),
136-
)
131+
@test try_resize_decode!(d, dst, encoded, s-1) === s
132+
@test try_resize_decode!(d, dst, encoded, s) === s
137133
@test try_resize_decode!(d, dst, encoded, s+2) === s
138134
@test length(dst) == s + 1
139135
@test dst[1:s] == data

LibBlosc/Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ ChunkCodecCore = "0b6fb165-00bc-4d37-ab8b-79f91016dbe1"
99

1010
[compat]
1111
Blosc_jll = "1"
12-
ChunkCodecCore = "0.4"
12+
ChunkCodecCore = "0.5"
1313
julia = "1.10"
1414

1515
[workspace]

LibBrotli/Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ ChunkCodecCore = "0b6fb165-00bc-4d37-ab8b-79f91016dbe1"
88
brotli_jll = "4611771a-a7d2-5e23-8d00-b1becdba1aae"
99

1010
[compat]
11-
ChunkCodecCore = "0.4"
11+
ChunkCodecCore = "0.5"
1212
brotli_jll = "1"
1313
julia = "1.10"
1414

LibBrotli/src/ChunkCodecLibBrotli.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ using ChunkCodecCore:
88
DecodeOptions,
99
check_contiguous,
1010
check_in_range,
11+
grow_dst!,
1112
DecodingError
1213
import ChunkCodecCore:
1314
decode_options,

0 commit comments

Comments
 (0)