Skip to content

Commit dca13d8

Browse files
authored
fix transcode's performance problem (#87)
1 parent d45d238 commit dca13d8

File tree

2 files changed

+58
-11
lines changed

2 files changed

+58
-11
lines changed

src/stream.jl

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -636,12 +636,13 @@ function callprocess(stream::TranscodingStream, inbuf::Buffer, outbuf::Buffer)
636636
makemargin!(outbuf, minoutsize(stream.codec, input))
637637
Δin, Δout, state.code = process(stream.codec, input, marginmem(outbuf), state.error)
638638
@debug(
639-
"called process()",
639+
"called process()",
640+
code = state.code,
640641
input_size = buffersize(inbuf),
641642
output_size = marginsize(outbuf),
642643
input_delta = Δin,
643644
output_delta = Δout,
644-
)
645+
)
645646
consumed!(inbuf, Δin, transcode = true)
646647
supplied!(outbuf, Δout, transcode = true)
647648
if state.code == :error
@@ -709,8 +710,7 @@ function changemode!(stream::TranscodingStream, newmode::Symbol)
709710
return
710711
elseif newmode == :panic
711712
if !haserror(state.error)
712-
# set a default error
713-
state.error[] = ErrorException("unknown error happened while processing data")
713+
set_default_error!(state.error)
714714
end
715715
state.mode = newmode
716716
finalize_codec(stream.codec, state.error)
@@ -767,6 +767,11 @@ function throw_panic_error()
767767
throw(ArgumentError("stream is in unrecoverable error; only isopen and close are callable"))
768768
end
769769

770+
# Set a defualt error.
771+
function set_default_error!(error::Error)
772+
error[] = ErrorException("unknown error happened while processing data")
773+
end
774+
770775
# Call the finalize method of the codec.
771776
function finalize_codec(codec::Codec, error::Error)
772777
try

src/transcode.jl

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,53 @@ julia> String(decompressed)
7777
```
7878
"""
7979
function Base.transcode(codec::Codec, data::ByteData)
80-
# Add `minoutsize` because `transcode` will be called at least two times.
81-
buffer2 = Buffer(
82-
expectedsize(codec, Memory(data)) + minoutsize(codec, Memory(C_NULL, 0)))
83-
mark!(buffer2)
84-
stream = TranscodingStream(codec, devnull, State(Buffer(data), buffer2); initialized=true)
85-
write(stream, TOKEN_END)
86-
return takemarked!(buffer2)
80+
input = Buffer(data)
81+
output = Buffer(initial_output_size(codec, buffermem(input)))
82+
error = Error()
83+
code = startproc(codec, :write, error)
84+
if code === :error
85+
@goto error
86+
end
87+
n = minoutsize(codec, buffermem(input))
88+
while code !== :end || buffersize(input) > 0
89+
makemargin!(output, n)
90+
Δin, Δout, code = process(codec, buffermem(input), marginmem(output), error)
91+
@debug(
92+
"called process()",
93+
code = code,
94+
input_size = buffersize(input),
95+
output_size = marginsize(output),
96+
input_delta = Δin,
97+
output_delta = Δout,
98+
)
99+
consumed!(input, Δin)
100+
supplied!(output, Δout)
101+
if code === :error
102+
@goto error
103+
elseif code === :end && buffersize(input) > 0
104+
if startproc(codec, :write, error) === :error
105+
@goto error
106+
end
107+
end
108+
n = max(Δout, minoutsize(codec, buffermem(input)))
109+
end
110+
if marginsize(output) == 0
111+
return output.data
112+
else
113+
return output.data[1:output.marginpos-1]
114+
end
115+
@label error
116+
if !haserror(error)
117+
set_default_error!(error)
118+
end
119+
throw(error[])
120+
end
121+
122+
# Return the initial output buffer size.
123+
function initial_output_size(codec::Codec, input::Memory)
124+
return max(
125+
minoutsize(codec, input),
126+
expectedsize(codec, input),
127+
8, # just in case where both minoutsize and expectedsize are foolish
128+
)
87129
end

0 commit comments

Comments
 (0)