Skip to content

Commit

Permalink
implement the immobilized buffer (#33)
Browse files Browse the repository at this point in the history
  • Loading branch information
bicycle1885 authored Feb 7, 2017
1 parent d0eed65 commit fd271a2
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 21 deletions.
56 changes: 36 additions & 20 deletions src/bufferedinputstream.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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})
Expand All @@ -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), "(<closed>)")
end
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/emptystream.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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})
Expand Down
18 changes: 18 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit fd271a2

Please sign in to comment.