@@ -783,6 +783,80 @@ function take!(io::IOBuffer)
783783 return data
784784end
785785
786+ " Internal method. This method can be faster than takestring!, because it does not
787+ reset the buffer to a usable state, and it does not check for io.reinit.
788+ Using the buffer after calling unsafe_takestring! may cause undefined behaviour.
789+ This function is meant to be used when the buffer is only used as a temporary
790+ string builder, which is discarded after the string is built."
791+ function unsafe_takestring! (io:: IOBuffer )
792+ used_span = get_used_span (io)
793+ nbytes = length (used_span)
794+ from = first (used_span)
795+ isempty (used_span) && return " "
796+ # The C function can only copy from the start of the memory.
797+ # Fortunately, in most cases, the offset will be zero.
798+ return if isone (from)
799+ ccall (:jl_genericmemory_to_string , Ref{String}, (Any, Int), io. data, nbytes)
800+ else
801+ mem = StringMemory (nbytes % UInt)
802+ unsafe_copyto! (mem, 1 , io. data, from, nbytes)
803+ unsafe_takestring (mem)
804+ end
805+ end
806+
807+ """
808+ takestring!(io::IOBuffer) -> String
809+
810+ Return the content of `io` as a `String`, resetting the buffer to its initial
811+ state.
812+ This is preferred over calling `String(take!(io))` to create a string from
813+ an `IOBuffer`.
814+
815+ # Examples
816+ ```jldoctest
817+ julia> io = IOBuffer();
818+
819+ julia> write(io, [0x61, 0x62, 0x63]);
820+
821+ julia> s = takestring!(io)
822+ "abc"
823+
824+ julia> isempty(take!(io)) # io is now empty
825+ true
826+ ```
827+
828+ !!! compat "Julia 1.13"
829+ This function requires at least Julia 1.13.
830+ """
831+ function takestring! (io:: IOBuffer )
832+ # If the buffer has been used up and needs to be replaced, there are no bytes, and
833+ # we can return an empty string without interacting with the buffer at all.
834+ io. reinit && return " "
835+
836+ # If the iobuffer is writable, taking will remove the buffer from `io`.
837+ # So, we reset the iobuffer, and directly unsafe takestring.
838+ return if io. writable
839+ s = unsafe_takestring! (io)
840+ io. reinit = true
841+ io. mark = - 1
842+ io. ptr = 1
843+ io. size = 0
844+ io. offset_or_compacted = 0
845+ s
846+ else
847+ # If the buffer is not writable, taking will NOT remove the buffer,
848+ # so if we just converted the buffer to a string, garbage collecting
849+ # the string would free the memory underneath the iobuffer
850+ used_span = get_used_span (io)
851+ mem = StringMemory (length (used_span))
852+ unsafe_copyto! (mem, 1 , io. data, first (used_span), length (used_span))
853+ unsafe_takestring (mem)
854+ end
855+ end
856+
857+ # Fallback methods
858+ takestring! (io:: GenericIOBuffer ) = String (take! (io))
859+
786860"""
787861 _unsafe_take!(io::IOBuffer)
788862
0 commit comments