|
31 | 31 | # This can be done only if the buffer is not seekable
|
32 | 32 |
|
33 | 33 | mutable struct GenericIOBuffer{T<:AbstractVector{UInt8}} <: IO
|
34 |
| - # T should support: getindex, setindex!, length, copyto!, similar, and (optionally) resize! |
| 34 | + # T should support: getindex, setindex!, length, copyto!, similar, size and (optionally) resize! |
35 | 35 | data::T
|
36 | 36 |
|
37 | 37 | # The user can take control of `data` out of this struct. When that happens, instead of eagerly allocating
|
@@ -274,7 +274,7 @@ _similar_data(b::IOBuffer, len::Int) = StringMemory(len)
|
274 | 274 | function copy(b::GenericIOBuffer{T}) where T
|
275 | 275 | if b.reinit
|
276 | 276 | # If buffer is used up, allocate a new size-zero buffer
|
277 |
| - # Reinit implies wriable, and that ptr, size, offset and mark are already the default values |
| 277 | + # Reinit implies writable, and that ptr, size, offset and mark are already the default values |
278 | 278 | return typeof(b)(_similar_data(b, 0), b.readable, b.writable, b.seekable, b.append, b.maxsize)
|
279 | 279 | elseif b.writable
|
280 | 280 | # Else, we just copy the reachable bytes. If buffer is seekable, all bytes
|
@@ -443,8 +443,7 @@ filesize(io::GenericIOBuffer) = (io.seekable ? io.size - io.offset : bytesavaila
|
443 | 443 | bytesavailable(io::GenericIOBuffer) = io.size - io.ptr + 1
|
444 | 444 |
|
445 | 445 | # Position is zero-indexed, but ptr is one-indexed, hence the -1
|
446 |
| -# TODO: Document that position for an unseekable stream is invalid, or |
447 |
| -# make it error |
| 446 | +# TODO: Document that position for an unmarked and unseekable stream is invalid (and make it error?) |
448 | 447 | position(io::GenericIOBuffer) = io.ptr - io.offset - 1
|
449 | 448 |
|
450 | 449 | function skip(io::GenericIOBuffer, n::Integer)
|
@@ -484,7 +483,6 @@ function seek(io::GenericIOBuffer, n::Int)
|
484 | 483 | return io
|
485 | 484 | end
|
486 | 485 |
|
487 |
| -# TODO: Should check for seekable and error if not |
488 | 486 | function seekend(io::GenericIOBuffer)
|
489 | 487 | io.ptr = io.size+1
|
490 | 488 | return io
|
@@ -512,7 +510,6 @@ function _resize!(io::GenericIOBuffer, new_size::Int)
|
512 | 510 | return io
|
513 | 511 | end
|
514 | 512 |
|
515 |
| -# TODO: These errors cannot be converted to LazyString, but it's wasteful to interpolate them here. |
516 | 513 | function truncate(io::GenericIOBuffer, n::Integer)
|
517 | 514 | io.writable || throw(ArgumentError("truncate failed, IOBuffer is not writeable"))
|
518 | 515 | # Non-seekable buffers can only be constructed with `PipeBuffer`, which is explicitly
|
@@ -587,21 +584,22 @@ end
|
587 | 584 | size = io.size
|
588 | 585 | data = io.data
|
589 | 586 | to_delete = (mark > -1 ? min(mark, ptr - 1) : ptr - 1)
|
590 |
| - # Only shift data if: |
591 |
| - if ( |
592 |
| - # It will prevent us from having to resize buffer, or |
593 |
| - to_delete >= nshort % Int || |
594 |
| - # We will recover at least 256 bytes, and at least 1/8th |
595 |
| - # of the data buffer's total length |
596 |
| - (to_delete > data_len >>> 3 && to_delete > 255) |
597 |
| - ) |
| 587 | + |
| 588 | + # We don't want to shift data too often to avoid making writing O(n), |
| 589 | + # so we prefer resizing if the shift would free up too little data. |
| 590 | + # Therefore, we prefer to resize if copying gets us less than 32 bytes, |
| 591 | + # or less than 1/8th of the data's size. |
| 592 | + # But we need to shift data if maxsize prevents us from gaining enough |
| 593 | + # space through resizing |
| 594 | + can_allocate_enough = (io.maxsize - (io.append ? io.size : io.ptr - 1)) % UInt ≥ nshort |
| 595 | + if !can_allocate_enough || to_delete ≥ max(32, data_len >>> 3) |
598 | 596 | copyto!(data, 1, data, to_delete + 1, size - to_delete)
|
599 | 597 | io.ptr = ptr - to_delete
|
600 | 598 | io.mark = max(-1, mark - to_delete)
|
601 | 599 | io.size = size - to_delete
|
| 600 | + nshort -= min(nshort, to_delete % UInt) |
| 601 | + iszero(nshort) && return io |
602 | 602 | end
|
603 |
| - nshort -= min(nshort, to_delete % UInt) |
604 |
| - iszero(nshort) && return io |
605 | 603 | end
|
606 | 604 | # Don't exceed maxsize. Otherwise, we overshoot the number of bytes needed,
|
607 | 605 | # such that we don't need to resize too often.
|
|
0 commit comments