5
5
# Here, u represents used bytes (already read), X represents bytes still to read,
6
6
# - represents bytes uninitialized data but which can be written to later.
7
7
# . are bytes which can neither be read nor written - but the IOBuffer has control
8
- # of the full array, and may move the offset as it wishes to overwrite any . bytes .
8
+ # of the full array.
9
9
10
- # ... uuuuuuuuuuuuuXXXXXXXXXXXXX------.......
11
- # | | | | | | |
12
- # | offset | ptr size | |
13
- # 1 mark | lastindex(data)
14
- # maxsize
10
+ # uuuuuuuuuuuuuXXXXXXXXXXXXX------.......
11
+ # | | | | | |
12
+ # | | ptr size | |
13
+ # 1 mark | lastindex(data)
14
+ # maxsize
15
15
16
16
# AFTER COMPACTION
17
- # Mark, ptr and size decreases by (mark - offset - 1)
17
+ # Mark, ptr and size decreases by (mark - 1)
18
18
19
- # ...uuuuuXXXXXXXXXXXXX--------------.......
20
- # | || | | | |
21
- # | offset| size | lastindex(data)
22
- # 1 | ptr maxsize
23
- # mark ( == offset + 1)
19
+ # uuuuuXXXXXXXXXXXXX--------------.......
20
+ # | | | | |
21
+ # | ptr size | lastindex(data)
22
+ # mark maxsize
24
23
25
24
# * The underlying array is always 1-indexed
26
- # * The IOBuffer has full control of the underlying array. That means it may move
27
- # the offset, clobbering data in 1:offset and in size:lastindex(data) at will.
25
+ # * The IOBuffer has full control of the underlying array.
28
26
# * Data in maxsize+1:lastindex(data) is also never touched.
29
- # * Data in offset+1 :mark-1, if mark > 0 can be deleted, shifting the whole thing to the left
27
+ # * Data in 1: :mark-1, if mark > 0 can be deleted, shifting the whole thing to the left
30
28
# to make room for more data, without replacing or resizing data
31
29
32
30
mutable struct GenericIOBuffer{T<: AbstractVector{UInt8} } <: IO
@@ -39,15 +37,15 @@ mutable struct GenericIOBuffer{T<:AbstractVector{UInt8}} <: IO
39
37
readable:: Bool
40
38
writable:: Bool
41
39
42
- # If not seekable, implementation is free to destroy (compact) data in offset+ 1:mark-1
40
+ # If not seekable, implementation is free to destroy (compact) data in 1:mark-1
43
41
seekable:: Bool
44
42
45
43
# If true, write new data to the index size+1 instead of the index ptr.
46
44
append:: Bool
47
45
48
46
# Last index of `data` that has been written to. Data in size+1:end has not yet been used,
49
47
# and may contain arbitrary values.
50
- # This value is always in offset : min(maxsize, lastindex(data))
48
+ # This value is always in 0 : min(maxsize, lastindex(data))
51
49
size:: Int
52
50
53
51
# Size can never be larger than this value. This is useful for two use cases:
@@ -59,25 +57,19 @@ mutable struct GenericIOBuffer{T<:AbstractVector{UInt8}} <: IO
59
57
60
58
# Data is read/written from/to ptr, except in situations where append is true, in which case
61
59
# data is still read from ptr, but written to size+1.
62
- # This value is alwaus in offset+ 1 : size+1
60
+ # This value is alwaus in 1 : size+1
63
61
ptr:: Int
64
62
65
- # When constructed from a Vector `v`, `data` is its underlying memory, but the memory may contain
66
- # data before v[1]. In that case, the offset is the number of leading bytes in the memory that
67
- # the IO may never touch.
68
- # This value is always in 0:lastindex(data)
69
- offset:: Int
70
-
71
63
# Data before the marked location for non-seekable buffers can be compacted.
72
64
# If this is -1, the mark is not set.
73
65
# The purpose of the mark is to reset the stream to a given position using reset.
74
- # This value is always == -1, or in offset+ 1:size
66
+ # This value is always == -1, or in 1:size
75
67
mark:: Int
76
68
77
69
function GenericIOBuffer {T} (data:: T , readable:: Bool , writable:: Bool , seekable:: Bool , append:: Bool ,
78
70
maxsize:: Integer ) where T<: AbstractVector{UInt8}
79
71
require_one_based_indexing (data)
80
- return new (data, false , readable, writable, seekable, append, length (data), maxsize, 1 , 0 , - 1 )
72
+ return new (data, false , readable, writable, seekable, append, length (data), maxsize, 1 , - 1 )
81
73
end
82
74
end
83
75
@@ -88,16 +80,19 @@ function GenericIOBuffer(data::T, readable::Bool, writable::Bool, seekable::Bool
88
80
GenericIOBuffer {T} (data, readable, writable, seekable, append, maxsize)
89
81
end
90
82
91
- # For this method, we use the underlying Memory of the vector. Therefore, we need to set the offset ,
83
+ # For this method, we use the underlying Memory of the vector. Therefore, we need to set the,
92
84
# ptr and size accordingly, so the buffer only uses the part of the memory that the vector does.
93
85
function GenericIOBuffer (data:: Vector{UInt8} , readable:: Bool , writable:: Bool , seekable:: Bool , append:: Bool ,
94
86
maxsize:: Integer )
95
87
ref = data. ref
96
- buf = GenericIOBuffer (ref. mem, readable, writable, seekable, append, maxsize)
88
+ mem = ref. mem
89
+ len = length (data)
97
90
offset = memoryrefoffset (ref) - 1
98
- buf. ptr += offset
99
- buf. size = length (data) + offset
100
- buf. offset = offset
91
+ if ! iszero (offset)
92
+ unsafe_copyto! (mem, 1 , mem, offset+ 1 , len)
93
+ end
94
+ buf = GenericIOBuffer (mem, readable, writable, seekable, append, maxsize)
95
+ buf. size = len
101
96
return buf
102
97
end
103
98
@@ -181,7 +176,7 @@ function IOBuffer(
181
176
flags = open_flags (read= read, write= write, append= append, truncate= truncate)
182
177
buf = GenericIOBuffer (data, flags. read, flags. write, true , flags. append, Int (maxsize))
183
178
if flags. truncate
184
- buf. size = buf . offset
179
+ buf. size = 0
185
180
end
186
181
return buf
187
182
end
@@ -245,7 +240,6 @@ function copy(b::GenericIOBuffer)
245
240
ret. size = b. size
246
241
ret. ptr = b. ptr
247
242
ret. mark = b. mark
248
- ret. offset = b. offset
249
243
return ret
250
244
end
251
245
@@ -254,9 +248,9 @@ show(io::IO, b::GenericIOBuffer) = print(io, "IOBuffer(data=UInt8[...], ",
254
248
" writable=" , b. writable, " , " ,
255
249
" seekable=" , b. seekable, " , " ,
256
250
" append=" , b. append, " , " ,
257
- " size=" , b. size - b . offset , " , " ,
251
+ " size=" , b. size, " , " ,
258
252
" maxsize=" , b. maxsize == typemax (Int) ? " Inf" : b. maxsize, " , " ,
259
- " ptr=" , b. ptr - b . offset , " , " ,
253
+ " ptr=" , b. ptr, " , " ,
260
254
" mark=" , b. mark, " )" )
261
255
262
256
@noinline function _throw_not_readable ()
@@ -352,13 +346,13 @@ isreadable(io::GenericIOBuffer) = io.readable
352
346
iswritable (io:: GenericIOBuffer ) = io. writable
353
347
354
348
# Number of bytes that can be read from the buffer, if you seek to the start first.
355
- filesize (io:: GenericIOBuffer ) = (io. seekable ? io. size - io . offset : bytesavailable (io))
349
+ filesize (io:: GenericIOBuffer ) = (io. seekable ? io. size : bytesavailable (io))
356
350
357
351
# Number of bytes that can be read from the buffer.
358
352
bytesavailable (io:: GenericIOBuffer ) = io. size - io. ptr + 1
359
353
360
354
# Position is zero-indexed, but ptr is one-indexed, hence the -1
361
- position (io:: GenericIOBuffer ) = io. ptr - io . offset - 1
355
+ position (io:: GenericIOBuffer ) = io. ptr - 1
362
356
363
357
function skip (io:: GenericIOBuffer , n:: Integer )
364
358
skip (io, clamp (n, Int))
@@ -393,7 +387,7 @@ function seek(io::GenericIOBuffer, n::Int)
393
387
# of an GenericIOBuffer), so that would need to be fixed in order to throw an error here
394
388
# (n < 0 || n > io.size - io.offset) && throw(ArgumentError("Attempted to seek outside IOBuffer boundaries."))
395
389
# io.ptr = n + io.offset + 1
396
- io. ptr = clamp (n, 0 , io. size - io . offset) + io . offset + 1
390
+ io. ptr = clamp (n, 0 , io. size) + 1
397
391
return io
398
392
end
399
393
@@ -407,29 +401,18 @@ end
407
401
# this calls `similar`+copy
408
402
function _resize! (io:: GenericIOBuffer , sz:: Int )
409
403
a = io. data
410
- offset = io. offset
411
404
if applicable (resize!, a, sz)
412
- if offset != 0
413
- size = io. size
414
- size > offset && copyto! (a, 1 , a, offset + 1 , min (sz, size - offset))
415
- io. ptr -= offset
416
- io. size -= offset
417
- io. offset = 0
418
- end
419
405
resize! (a, sz)
420
406
else
421
407
size = io. size
422
408
# Make a new data buffer, only if there is not room in existing buffer
423
409
if size >= sz && sz != 0
424
410
b = a
425
411
else
426
- b = _similar_data (io, sz == 0 ? 0 : max (overallocation (size - io . offset ), sz))
412
+ b = _similar_data (io, sz == 0 ? 0 : max (overallocation (size), sz))
427
413
end
428
- size > offset && copyto! (b, 1 , a, offset + 1 , min (sz, size - offset ))
414
+ size > 0 && copyto! (b, 1 , a, 1 , min (sz, size))
429
415
io. data = b
430
- io. ptr -= offset
431
- io. size -= offset
432
- io. offset = 0
433
416
end
434
417
return io
435
418
end
@@ -443,20 +426,18 @@ function truncate(io::GenericIOBuffer, n::Integer)
443
426
if io. reinit
444
427
io. data = _similar_data (io, n)
445
428
io. reinit = false
446
- elseif n > length (io. data) + io . offset
429
+ elseif n > length (io. data)
447
430
_resize! (io, n)
448
431
end
449
432
ismarked (io) && io. mark > n && unmark (io)
450
- n += io. offset
451
433
io. data[io. size+ 1 : n] .= 0
452
434
io. size = n
453
435
io. ptr = min (io. ptr, n+ 1 )
454
436
return io
455
437
end
456
438
457
439
# Internal method. Delete used data in the buffer, shifting the rest to the left.
458
- # Does not delete data at or after the mark, nor data before the offset, nor data
459
- # after ptr.
440
+ # Does not delete data at or after the mark, nor data after ptr.
460
441
function compact (io:: GenericIOBuffer )
461
442
# For a seekable buffer, the user could always seek back to the used data.
462
443
# Therefore, it is invalid to compact a seekable buffer
@@ -467,7 +448,7 @@ function compact(io::GenericIOBuffer)
467
448
local ptr:: Int , bytes_to_move:: Int
468
449
if ismarked (io) && io. mark < position (io)
469
450
io. mark == 0 && return
470
- ptr = io. mark + io . offset
451
+ ptr = io. mark
471
452
bytes_to_move = bytesavailable (io) + (io. ptr - ptr)
472
453
else
473
454
ptr = io. ptr
@@ -476,7 +457,6 @@ function compact(io::GenericIOBuffer)
476
457
copyto! (io. data, 1 , io. data, ptr, bytes_to_move)
477
458
io. size -= ptr - 1
478
459
io. ptr -= ptr - 1
479
- io. offset = 0
480
460
return
481
461
end
482
462
@@ -487,13 +467,12 @@ end
487
467
io. reinit = false
488
468
end
489
469
if ! io. seekable
490
- if ! ismarked (io) && io. ptr > io . offset + 1 && io. size <= io. ptr - 1
470
+ if ! ismarked (io) && io. ptr > 1 && io. size <= io. ptr - 1
491
471
io. ptr = 1
492
472
io. size = 0
493
- io. offset = 0
494
473
else
495
- datastart = (ismarked (io) ? io. mark : io. ptr - io . offset )
496
- if (io. size- io . offset + nshort > io. maxsize) ||
474
+ datastart = (ismarked (io) ? io. mark : io. ptr)
475
+ if (io. size+ nshort > io. maxsize) ||
497
476
(datastart > 4096 && datastart > io. size - io. ptr) ||
498
477
(datastart > 262144 )
499
478
# apply somewhat arbitrary heuristics to decide when to destroy
@@ -507,11 +486,11 @@ end
507
486
508
487
@inline ensureroom (io:: GenericIOBuffer , nshort:: Int ) = ensureroom (io, UInt (nshort))
509
488
@inline function ensureroom (io:: GenericIOBuffer , nshort:: UInt )
510
- if ! io. writable || (! io. seekable && io. ptr > io . offset + 1 ) || io. reinit
489
+ if ! io. writable || (! io. seekable && io. ptr > 1 ) || io. reinit
511
490
ensureroom_slowpath (io, nshort)
512
491
end
513
- n = min ((nshort % Int) + (io. append ? io. size : io. ptr- 1 ) - io . offset , io. maxsize)
514
- l = length (io. data) + io . offset
492
+ n = min ((nshort % Int) + (io. append ? io. size : io. ptr- 1 ), io. maxsize)
493
+ l = length (io. data)
515
494
if n > l
516
495
_resize! (io, Int (n))
517
496
end
530
509
io. writable = false
531
510
io. seekable = false
532
511
io. size = 0
533
- io. offset = 0
534
512
io. maxsize = 0
535
513
io. ptr = 1
536
514
io. mark = - 1
@@ -563,11 +541,11 @@ function take!(io::GenericIOBuffer)
563
541
if io. seekable
564
542
# If the buffer is seekable, then the previously consumed bytes from ptr+1:size
565
543
# must still be output, as they are not truly gone.
566
- # Hence, we output all bytes from offset+ 1:io.size
567
- nbytes = io. size - io . offset
568
- data = copyto! (StringVector (nbytes), 1 , io. data, io . offset + 1 , nbytes)
544
+ # Hence, we output all bytes from 1:io.size
545
+ nbytes = io. size
546
+ data = copyto! (StringVector (nbytes), 1 , io. data, 1 , nbytes)
569
547
else
570
- # Else, if not seekable, bytes from offset+ 1:ptr-1 are truly gone and should not
548
+ # Else, if not seekable, bytes from 1:ptr-1 are truly gone and should not
571
549
# be output. Hence, we output `bytesavailable`, which is ptr:size
572
550
nbytes = bytesavailable (io)
573
551
data = read! (io, StringVector (nbytes))
@@ -577,7 +555,6 @@ function take!(io::GenericIOBuffer)
577
555
if io. writable
578
556
io. ptr = 1
579
557
io. size = 0
580
- io. offset = 0
581
558
end
582
559
return data
583
560
end
@@ -592,9 +569,9 @@ function take!(io::IOBuffer)
592
569
if nbytes == 0 || io. reinit
593
570
data = StringVector (0 )
594
571
elseif io. writable
595
- data = wrap (Array, memoryref (io. data, io . offset + 1 ), nbytes)
572
+ data = wrap (Array, memoryref (io. data, 1 ), nbytes)
596
573
else
597
- data = copyto! (StringVector (nbytes), 1 , io. data, io . offset + 1 , nbytes)
574
+ data = copyto! (StringVector (nbytes), 1 , io. data, 1 , nbytes)
598
575
end
599
576
else
600
577
nbytes = bytesavailable (io)
@@ -610,7 +587,6 @@ function take!(io::IOBuffer)
610
587
io. reinit = true
611
588
io. ptr = 1
612
589
io. size = 0
613
- io. offset = 0
614
590
end
615
591
return data
616
592
end
@@ -628,10 +604,10 @@ It might save an allocation compared to `take!` (if the compiler elides the
628
604
Array allocation), as well as omits some checks.
629
605
"""
630
606
_unsafe_take! (io:: IOBuffer ) =
631
- wrap (Array, io. size == io . offset ?
607
+ wrap (Array, io. size == 0 ?
632
608
memoryref (Memory {UInt8} ()) :
633
- memoryref (io. data, io . offset + 1 ),
634
- io. size - io . offset )
609
+ memoryref (io. data, 1 ),
610
+ io. size)
635
611
636
612
function write (to:: IO , from:: GenericIOBuffer )
637
613
written:: Int = bytesavailable (from)
@@ -733,9 +709,7 @@ function copyline(out::GenericIOBuffer, s::IO; keep::Bool=false)
733
709
copyuntil (out, s, 0x0a , keep= true )
734
710
line = out. data
735
711
i = out. size # XXX : this is only correct for appended data. if the data was inserted, only ptr should change
736
- # TODO : This computation seems to be invalid. The buffer size may be smaller than out.size
737
- # due to the presence of out.offset.
738
- if keep || i == out. offset || line[i] != 0x0a
712
+ if keep || iszero (i) || line[i] != 0x0a
739
713
return out
740
714
elseif i < 2 || line[i- 1 ] != 0x0d
741
715
i -= 1
0 commit comments