From fd271a237d2da76b2d5c0cd32fd8df3c6e7b21ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kenta=20Sato=20=28=E4=BD=90=E8=97=A4=20=E5=BB=BA=E5=A4=AA?= =?UTF-8?q?=29?= Date: Tue, 7 Feb 2017 11:11:31 +0900 Subject: [PATCH] implement the immobilized buffer (#33) --- src/bufferedinputstream.jl | 56 ++++++++++++++++++++++++-------------- src/emptystream.jl | 2 +- test/runtests.jl | 18 ++++++++++++ 3 files changed, 55 insertions(+), 21 deletions(-) diff --git a/src/bufferedinputstream.jl b/src/bufferedinputstream.jl index c34e84d..0622cad 100644 --- a/src/bufferedinputstream.jl +++ b/src/bufferedinputstream.jl @@ -27,13 +27,16 @@ type BufferedInputStream{T} <: IO # If positive, preserve and move buffer[anchor:available] # when refilling the buffer. anchor::Int + + # If `true`, buffered data `buffer[anchor:available]` is not shifted. + immobilized::Bool end function BufferedInputStream{T}(source::T, bufsize::Integer=default_buffer_size) if bufsize ≤ 0 throw(ArgumentError("buffer size must be positive")) end - return BufferedInputStream{T}(source, Vector{UInt8}(bufsize), 1, 0, 0) + return BufferedInputStream{T}(source, Vector{UInt8}(bufsize), 1, 0, 0, false) end function Base.show{T}(io::IO, stream::BufferedInputStream{T}) @@ -43,7 +46,8 @@ function Base.show{T}(io::IO, stream::BufferedInputStream{T}) print(io, summary(stream), "(<", _datasize(bufsize), " buffer, ", - round(Int, filled / bufsize * 100), "% filled>)") + round(Int, filled / bufsize * 100), "% filled", + stream.immobilized ? ", data immobilized" : "", ">)") else print(io, summary(stream), "()") end @@ -57,32 +61,44 @@ function fillbuffer!(stream::BufferedInputStream) return 0 end - if ismarked(stream) - keepfrom = stream.anchor - keeplen = stream.available - keepfrom + 1 - # expand the buffer if we are attempting to keep most of it - if keeplen > div(length(stream.buffer), 2) - resize!(stream.buffer, length(stream.buffer) * 2) - end - stream.anchor = 1 - stream.position -= keepfrom - 1 - else - keepfrom = stream.position - keeplen = stream.available - keepfrom + 1 - stream.position = 1 + shiftdata!(stream) + margin = length(stream.buffer) - stream.available + if margin * 2 < length(stream.buffer) + resize!(stream.buffer, length(stream.buffer) * 2) end - copy!(stream.buffer, 1, stream.buffer, keepfrom, keeplen) nbytes = readbytes!( stream.source, stream.buffer, - keeplen + 1, - endof(stream.buffer)) - stream.available = keeplen + nbytes - + stream.available + 1, + length(stream.buffer)) + stream.available += nbytes return nbytes end +# Shift data to be kept. +function shiftdata!(stream::BufferedInputStream) + if stream.immobilized + return 0 + else + if stream.anchor > 0 && stream.available - stream.anchor + 1 > 0 + shift = stream.anchor - 1 + n = stream.available - shift + copy!(stream.buffer, 1, stream.buffer, stream.anchor, n) + stream.anchor -= shift + elseif stream.available - stream.position + 1 > 0 + shift = stream.position - 1 + n = stream.available - shift + copy!(stream.buffer, 1, stream.buffer, stream.position, n) + else + shift = 0 + end + stream.position -= shift + stream.available -= shift + return shift + end +end + @inline function Base.eof(stream::BufferedInputStream) if stream.position > stream.available return fillbuffer!(stream) == 0 diff --git a/src/emptystream.jl b/src/emptystream.jl index fc0b70a..62dbcf4 100644 --- a/src/emptystream.jl +++ b/src/emptystream.jl @@ -17,7 +17,7 @@ Base.position(stream::BufferedOutputStream{EmptyStream}) = stream.position - 1 # --------------------- function BufferedInputStream(data::Vector{UInt8}, len::Integer=endof(data)) - return BufferedInputStream{EmptyStream}(EmptyStream(), data, 1, len, 0) + return BufferedInputStream{EmptyStream}(EmptyStream(), data, 1, len, 0, false) end function fillbuffer!(stream::BufferedInputStream{EmptyStream}) diff --git a/test/runtests.jl b/test/runtests.jl index 8398bb3..ed7a7b2 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -285,6 +285,24 @@ end end end + @testset "immobilized buffer" begin + stream = BufferedInputStream(IOBuffer("abcdefg"), 2) + stream.immobilized = false + @assert read(stream, UInt8) == UInt8('a') + mark(stream) + @assert read(stream, UInt8) == UInt8('b') + BufferedStreams.fillbuffer!(stream) + @test stream.buffer[1] == UInt8('b') + + stream = BufferedInputStream(IOBuffer("abcdefg"), 2) + stream.immobilized = true + @assert read(stream, UInt8) == UInt8('a') + mark(stream) + @assert read(stream, UInt8) == UInt8('b') + BufferedStreams.fillbuffer!(stream) + @test stream.buffer[2] == UInt8('b') + end + @testset "misc." begin stream = BufferedInputStream(IOBuffer("foobar"), 10) @test !BufferedStreams.ensurebuffered!(stream, 10)