7
7
# . are bytes which can neither be read nor written - but the IOBuffer has control
8
8
# of the full array.
9
9
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)
15
14
16
15
# AFTER COMPACTION
17
16
# Mark, ptr and size decreases by `mark`
18
17
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)
23
22
24
23
# * The underlying array is always 1-indexed
25
24
# * The IOBuffer has full control of the underlying array.
@@ -44,11 +43,12 @@ mutable struct GenericIOBuffer{T<:AbstractVector{UInt8}} <: IO
44
43
45
44
# Last index of `data` that has been written to. Data in size+1:end has not yet been used,
46
45
# 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)
48
47
size:: Int
49
48
50
49
# 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
52
52
maxsize:: Int
53
53
54
54
# 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
62
62
# This value is always == -1, or in 0:size-1
63
63
mark:: Int
64
64
65
+ # TODO : The invariants of the values should be enforced in all constructors,
66
+ # except explicitly unsafe ones.
65
67
function GenericIOBuffer {T} (data:: T , readable:: Bool , writable:: Bool , seekable:: Bool , append:: Bool ,
66
68
maxsize:: Integer ) where T<: AbstractVector{UInt8}
67
69
require_one_based_indexing (data)
@@ -163,6 +165,7 @@ function IOBuffer(
163
165
truncate:: Union{Bool,Nothing} = nothing ,
164
166
maxsize:: Integer = typemax (Int),
165
167
sizehint:: Union{Integer,Nothing} = nothing )
168
+ # TODO : Add a check that length(data) <= maxsize and error if not.
166
169
if maxsize < 0
167
170
throw (ArgumentError (" negative maxsize" ))
168
171
end
684
687
@inline function write (to:: GenericIOBuffer , a:: UInt8 )
685
688
ensureroom (to, UInt (1 ))
686
689
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.
687
692
if ptr > to. maxsize
688
693
return 0
689
694
else
@@ -731,21 +736,45 @@ function copyuntil(out::IO, io::GenericIOBuffer, delim::UInt8; keep::Bool=false)
731
736
end
732
737
733
738
function 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)
738
758
return out
739
- elseif i < 2 || line[i- 1 ] != 0x0d
740
- i -= 1
741
759
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
747
777
end
748
- return out
749
778
end
750
779
751
780
function _copyline (out:: IO , io:: GenericIOBuffer ; keep:: Bool = false )
0 commit comments