77# . are bytes which can neither be read nor written - but the IOBuffer has control
88# of the full array.
99
10- # uuuuuuuuuuuuuXXXXXXXXXXXXX------.......
11- # | | | | | |
12- # | | ptr size | |
13- # 1 mark (zero-indexed) | lastindex(data)
14- # maxsize
10+ # uuuuuuuuuuuuuXXXXXXXXXXXXX------------
11+ # | | | | | |
12+ # | | ptr size | maxsize (≥ lastindex)
13+ # 1 mark (zero-indexed) lastindex(data)
1514
1615# AFTER COMPACTION
1716# Mark, ptr and size decreases by `mark`
1817
19- # uuuuuXXXXXXXXXXXXX--------------.......
20- # | | | | |
21- # | ptr size | lastindex(data )
22- # mark (zero-indexed) maxsize
18+ # uuuuuXXXXXXXXXXXXX---------------------
19+ # || | | | |
20+ # |1 ptr size | maxsize (≥ lastindex)
21+ # mark (zero-indexed) lastindex(data)
2322
2423# * The underlying array is always 1-indexed
2524# * The IOBuffer has full control of the underlying array.
@@ -44,11 +43,12 @@ mutable struct GenericIOBuffer{T<:AbstractVector{UInt8}} <: IO
4443
4544 # Last index of `data` that has been written to. Data in size+1:end has not yet been used,
4645 # and may contain arbitrary values.
47- # This value is always in 0 : min(maxsize, lastindex(data) )
46+ # This value is always in 0 : lastindex(data)
4847 size:: Int
4948
5049 # This is the maximum length that the buffer size can grow to.
51- # This value is always in 0:typemax(Int)
50+ # This value is always in 0:typemax(Int).
51+ # We always have length(data) <= maxsize
5252 maxsize:: Int
5353
5454 # Data is read/written from/to ptr, except in situations where append is true, in which case
@@ -62,6 +62,8 @@ mutable struct GenericIOBuffer{T<:AbstractVector{UInt8}} <: IO
6262 # This value is always == -1, or in 0:size-1
6363 mark:: Int
6464
65+ # TODO : The invariants of the values should be enforced in all constructors,
66+ # except explicitly unsafe ones.
6567 function GenericIOBuffer {T} (data:: T , readable:: Bool , writable:: Bool , seekable:: Bool , append:: Bool ,
6668 maxsize:: Integer ) where T<: AbstractVector{UInt8}
6769 require_one_based_indexing (data)
@@ -163,6 +165,7 @@ function IOBuffer(
163165 truncate:: Union{Bool,Nothing} = nothing ,
164166 maxsize:: Integer = typemax (Int),
165167 sizehint:: Union{Integer,Nothing} = nothing )
168+ # TODO : Add a check that length(data) <= maxsize and error if not.
166169 if maxsize < 0
167170 throw (ArgumentError (" negative maxsize" ))
168171 end
684687@inline function write (to:: GenericIOBuffer , a:: UInt8 )
685688 ensureroom (to, UInt (1 ))
686689 ptr = (to. append ? to. size+ 1 : to. ptr)
690+ # We have just ensured there is room for 1 byte, EXCEPT if we were to exceed
691+ # maxsize. So, we just need to check that here.
687692 if ptr > to. maxsize
688693 return 0
689694 else
@@ -731,21 +736,45 @@ function copyuntil(out::IO, io::GenericIOBuffer, delim::UInt8; keep::Bool=false)
731736end
732737
733738function copyline (out:: GenericIOBuffer , s:: IO ; keep:: Bool = false )
734- copyuntil (out, s, 0x0a , keep= true )
735- line = out. data
736- i = out. size # XXX : this is only correct for appended data. if the data was inserted, only ptr should change
737- if keep || iszero (i) || line[i] != 0x0a
739+ # If the data is copied into the middle of the buffer of `out` instead of appended to the end,
740+ # and !keep, and the line copied ends with \r\n, then the copyuntil (even if keep=false)
741+ # will overwrite one too many bytes with the new \r byte.
742+ # Work around this by making a new temporary buffer.
743+ # Could perhaps be done better
744+ if ! out. append && out. ptr < out. size + 1
745+ newbuf = IOBuffer ()
746+ copyuntil (newbuf, s, 0x0a , keep= true )
747+ v = take! (newbuf)
748+ # Remove \r\n or \n if present
749+ if ! keep
750+ if length (v) > 1 && last (v) == UInt8 (' \n ' )
751+ pop! (v)
752+ end
753+ if length (v) > 1 && last (v) == UInt8 (' \r ' )
754+ pop! (v)
755+ end
756+ end
757+ write (out, v)
738758 return out
739- elseif i < 2 || line[i- 1 ] != 0x0d
740- i -= 1
741759 else
742- i -= 2
743- end
744- out. size = i
745- if ! out. append
746- out. ptr = i+ 1
760+ # Else, we can just copy the data directly into the buffer, and then
761+ # subtract the last one or two bytes depending on `keep`.
762+ copyuntil (out, s, 0x0a , keep= true )
763+ line = out. data
764+ i = out. size
765+ if keep || iszero (i) || line[i] != 0x0a
766+ return out
767+ elseif i < 2 || line[i- 1 ] != 0x0d
768+ i -= 1
769+ else
770+ i -= 2
771+ end
772+ out. size = i
773+ if ! out. append
774+ out. ptr = i+ 1
775+ end
776+ return out
747777 end
748- return out
749778end
750779
751780function _copyline (out:: IO , io:: GenericIOBuffer ; keep:: Bool = false )
0 commit comments