From 856031880e7a223b6bf5c0875d843b88c0359495 Mon Sep 17 00:00:00 2001 From: Nick Robinson Date: Tue, 28 Jan 2025 14:30:58 +0000 Subject: [PATCH] Loosen type restriction on `Ryu.writeshortest` (#57172) `Ryu.writeshortest` is documented to have a method that "allows passing in a byte buffer", just like `Ryu.writefixed` and `Ryu.writeexp`, but unlike those functions `writeshortest` is type constrained to `::Vector{UInt8}`. This PR loosens that to `::AbstractVector{UInt8}`, to allow the "byte buffer" to e.g. be a `Memory` rather than a `Vector`. I've added tests and updated the docstrings for all three functions to ensure that they're not just restricted to `Vector{UInt8}`. This change was prompted by our private codebase hitting `MethodError: no method matching writeshortest(::Memory{UInt8}, ::Int64, ::Float64, ...)` when trying it out with Julia v1.12.0-DEV. (cc @quinnj -- i think you added this method originally, but i couldn't see any reason why e.g. Memory shouldn't be allowed now we have it) --- base/ryu/Ryu.jl | 6 +++--- base/ryu/shortest.jl | 2 +- test/ryu.jl | 51 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 4 deletions(-) diff --git a/base/ryu/Ryu.jl b/base/ryu/Ryu.jl index e44e240baafda..86b9a64c002d5 100644 --- a/base/ryu/Ryu.jl +++ b/base/ryu/Ryu.jl @@ -19,7 +19,7 @@ neededdigits(::Type{Float16}) = 9 + 5 + 9 """ Ryu.writeshortest(x, plus=false, space=false, hash=true, precision=-1, expchar=UInt8('e'), padexp=false, decchar=UInt8('.'), typed=false, compact=false) - Ryu.writeshortest(buf::Vector{UInt8}, pos::Int, x, args...) + Ryu.writeshortest(buf::AbstractVector{UInt8}, pos::Int, x, args...) Convert a float value `x` into its "shortest" decimal string, which can be parsed back to the same value. This function allows achieving the `%g` printf format. @@ -53,7 +53,7 @@ end """ Ryu.writefixed(x, precision, plus=false, space=false, hash=false, decchar=UInt8('.'), trimtrailingzeros=false) - Ryu.writefixed(buf::Vector{UInt8}, pos::Int, x, args...) + Ryu.writefixed(buf::AbstractVector{UInt8}, pos::Int, x, args...) Convert a float value `x` into a "fixed" size decimal string of the provided precision. This function allows achieving the `%f` printf format. @@ -81,7 +81,7 @@ end """ Ryu.writeexp(x, precision, plus=false, space=false, hash=false, expchar=UInt8('e'), decchar=UInt8('.'), trimtrailingzeros=false) - Ryu.writeexp(buf::Vector{UInt8}, pos::Int, x, args...) + Ryu.writeexp(buf::AbstractVector{UInt8}, pos::Int, x, args...) Convert a float value `x` into a scientific notation decimal string. This function allows achieving the `%e` printf format. diff --git a/base/ryu/shortest.jl b/base/ryu/shortest.jl index 32aa993467e7a..c1ec648bfacdd 100644 --- a/base/ryu/shortest.jl +++ b/base/ryu/shortest.jl @@ -224,7 +224,7 @@ integer. If a `maxsignif` argument is provided, then `b < maxsignif`. return b, e10 end -function writeshortest(buf::Vector{UInt8}, pos, x::T, +function writeshortest(buf::AbstractVector{UInt8}, pos, x::T, plus=false, space=false, hash=true, precision=-1, expchar=UInt8('e'), padexp=false, decchar=UInt8('.'), typed=false, compact=false) where {T} diff --git a/test/ryu.jl b/test/ryu.jl index 4acd2fd08df50..05eedef9a0da2 100644 --- a/test/ryu.jl +++ b/test/ryu.jl @@ -370,6 +370,23 @@ end end # Float16 +@testset "writeshortest(::AbstractVector, pos, ...)" begin + @testset for Vec in (Vector{UInt8}, Memory{UInt8}) + buf = Vec(undef, 4) + @test Ryu.writeshortest(buf, 1, -0.0) == 5 + @test String(buf) == "-0.0" + + buf = Vec(undef, 100) + xx = 4.7223665f21 + expected = "4.7223665e21" + start_pos = 42 + nwritten = length(expected) + end_pos = start_pos + nwritten + @test Ryu.writeshortest(buf, start_pos, xx) == end_pos + @test String(buf[start_pos:end_pos-1]) == expected + end +end + @testset "Ryu.writefixed" begin @testset "Basic" begin @test Ryu.writefixed(todouble(false, 1234, 99999), 0) == @@ -563,6 +580,23 @@ end # Float16 @test Ryu.writefixed(-100.0+eps(-100.0), 0, false, false, true, UInt8('.'), false) == "-100." @test Ryu.writefixed(100.0-eps(100.0), 1, false, false, true, UInt8('.'), false) == "100.0" @test Ryu.writefixed(-100.0+eps(-100.0), 1, false, false, true, UInt8('.'), false) == "-100.0" + + @testset "writefixed(::AbstractVector, pos, ...)" begin + @testset for Vec in (Vector{UInt8}, Memory{UInt8}) + buf = Vec(undef, 6) + @test Ryu.writefixed(buf, 1, 0.0, 4) == 7 + @test String(buf) == "0.0000" + + buf = Vec(undef, 100) + xx = 1729.142857142857 + prec = 8 + start_pos = 42 + nwritten = 4 + 1 + prec + end_pos = start_pos + nwritten + @test Ryu.writefixed(buf, start_pos, xx, prec) == end_pos + @test String(buf[start_pos:end_pos-1]) == "1729.14285714" + end + end end # fixed @testset "Ryu.writeexp" begin @@ -761,6 +795,23 @@ end @test Ryu.writeexp(2.0, 1, false, false, false, UInt8('e'), UInt8('.'), true) == "2e+00" end +@testset "writeexp(::AbstractVector, pos, ...)" begin + @testset for Vec in (Vector{UInt8}, Memory{UInt8}) + buf = Vec(undef, 10) + @test Ryu.writeexp(buf, 1, 0.0, 4) == 11 + @test String(buf) == "0.0000e+00" + + buf = Vec(undef, 100) + xx = 1729.142857142857 + prec = 8 + start_pos = 42 + nwritten = 1 + 1 + prec + 4 + end_pos = start_pos + nwritten + @test Ryu.writeexp(buf, start_pos, xx, prec) == end_pos + @test String(buf[start_pos:end_pos-1]) == "1.72914286e+03" + end +end + end # exp @testset "compact" begin