From 52a25df86dc313a62825e92c2c4876440aad2ae2 Mon Sep 17 00:00:00 2001 From: ScottPJones Date: Sat, 29 Jul 2023 13:09:40 -0400 Subject: [PATCH] Fix issue 110 from Formatting.jl --- .drone.yml | 8 ++--- .github/workflows/ci.yml | 2 +- Project.toml | 2 +- src/fmtcore.jl | 77 +++++++++++++++++++++++++++++----------- test/formatexpr.jl | 8 +++++ 5 files changed, 71 insertions(+), 26 deletions(-) diff --git a/.drone.yml b/.drone.yml index d5da3da..70154d4 100644 --- a/.drone.yml +++ b/.drone.yml @@ -1,6 +1,6 @@ --- kind: pipeline -name: linux - arm64 - Julia 1.5 +name: linux - arm64 - Julia 1.9 platform: os: linux @@ -8,13 +8,13 @@ platform: steps: - name: build - image: julia:1.5 + image: julia:1.9 commands: - "julia --project=. --check-bounds=yes --color=yes -e 'using InteractiveUtils; versioninfo(verbose=true); using Pkg; Pkg.build(); Pkg.test(coverage=true)'" --- kind: pipeline -name: linux - arm64 - Julia 1.6 +name: linux - arm64 - Julia 1.9 platform: os: linux @@ -22,6 +22,6 @@ platform: steps: - name: build - image: julia:1.6 + image: julia:1.9 commands: - "julia --project=. --check-bounds=yes --color=yes -e 'using InteractiveUtils; versioninfo(verbose=true); using Pkg; Pkg.build(); Pkg.test(coverage=true)'" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 36c5c31..70b34ad 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,8 +10,8 @@ jobs: fail-fast: false matrix: version: - - '1.5' - '1.6' + - '1.9' - 'nightly' os: - ubuntu-latest diff --git a/Project.toml b/Project.toml index 9119c67..5903583 100644 --- a/Project.toml +++ b/Project.toml @@ -23,7 +23,7 @@ keywords = ["Strings", "Formatting"] license = "MIT" name = "Format" uuid = "1fa38f19-a742-5d3f-a2b9-30dd87b9d5f8" -version = "1.3.2" +version = "1.3.3" [deps] diff --git a/src/fmtcore.jl b/src/fmtcore.jl index 338cb6f..9eb89cd 100644 --- a/src/fmtcore.jl +++ b/src/fmtcore.jl @@ -19,15 +19,12 @@ function _pfmt_s(out::IO, fs::FormatSpec, s::Union{AbstractString,AbstractChar}) slen = length(s) if wid <= slen print(out, s) + elseif fs.align == '<' + print(out, s) + _repprint(out, fs.fill, wid-slen) else - a = fs.align - if a == '<' - print(out, s) - _repprint(out, fs.fill, wid-slen) - else - _repprint(out, fs.fill, wid-slen) - print(out, s) - end + _repprint(out, fs.fill, wid-slen) + print(out, s) end end @@ -44,6 +41,11 @@ _div(x::Integer, ::_Bin) = x >> 1 _div(x::Integer, ::_Oct) = x >> 3 _div(x::Integer, ::Union{_Hex, _HEX}) = x >> 4 +_str(x::Integer, ::_Dec) = string(x, base=10) +_str(x::Integer, ::_Bin) = string(x, base=2) +_str(x::Integer, ::_Oct) = string(x, base=8) +_str(x::Integer, ::Union{_Hex, _HEX}) = string(x, base=16) + function _ndigits(x::Integer, op) # suppose x is non-negative m = 1 q = _div(x, op) @@ -96,15 +98,53 @@ function _pfmt_intdigits(out::IO, ax::T, op::Op) where {Op, T<:Integer} end end +function _pfmt_intmin(out::IO, ip::ASCIIStr, zs::Integer, s::String) + # print sign + print(out, '-') + # print prefix + isempty(ip) || print(out, ip) + # print padding zeros + zs > 0 && _repprint(out, '0', zs) + # print actual digits + print(out, SubString(s, 2)) + nothing +end + +# Special case were abs would give error +function _pfmt_imin(out::IO, fs::FormatSpec, x::Integer, op::Op) where {Op} + s = _str(x, op) + xlen = length(s) + # prefix (e.g. 0x, 0b, 0o) + ip = "" + if fs.ipre + ip = _ipre(op) + xlen += length(ip) + end + + # printing + wid = fs.width + if wid <= xlen + _pfmt_intmin(out, ip, 0, s) + elseif fs.zpad + _pfmt_intmin(out, ip, wid-xlen, s) + elseif fs.align == '<' + _pfmt_intmin(out, ip, 0, s) + _repprint(out, fs.fill, wid-xlen) + else + _repprint(out, fs.fill, wid-xlen) + _pfmt_intmin(out, ip, 0, s) + end +end + function _pfmt_i(out::IO, fs::FormatSpec, x::Integer, op::Op) where {Op} + # Specially handle edge case of typemin + x === typemin(typeof(x)) && x isa Signed && return _pfmt_imin(out, fs, x, op) # calculate actual length ax = abs(x) - xlen = _ndigits(abs(x), op) + xlen = _ndigits(ax, op) # sign char sch = _signchar(x, fs.sign) - if sch != '\0' - xlen += 1 - end + xlen += (sch != '\0') # prefix (e.g. 0x, 0b, 0o) ip = "" if fs.ipre @@ -118,15 +158,12 @@ function _pfmt_i(out::IO, fs::FormatSpec, x::Integer, op::Op) where {Op} _pfmt_int(out, sch, ip, 0, ax, op) elseif fs.zpad _pfmt_int(out, sch, ip, wid-xlen, ax, op) + elseif fs.align == '<' + _pfmt_int(out, sch, ip, 0, ax, op) + _repprint(out, fs.fill, wid-xlen) else - a = fs.align - if a == '<' - _pfmt_int(out, sch, ip, 0, ax, op) - _repprint(out, fs.fill, wid-xlen) - else - _repprint(out, fs.fill, wid-xlen) - _pfmt_int(out, sch, ip, 0, ax, op) - end + _repprint(out, fs.fill, wid-xlen) + _pfmt_int(out, sch, ip, 0, ax, op) end end diff --git a/test/formatexpr.jl b/test/formatexpr.jl index 34fe9ac..79cc6aa 100644 --- a/test/formatexpr.jl +++ b/test/formatexpr.jl @@ -53,3 +53,11 @@ end @testset "format with filter" begin @test format("{1|>abs2} + {2|>abs2:.2f}", 2, 3) == "4 + 9.00" end + +@testset "test typemin/typemax edge cases" begin + f = FormatExpr("{1:+d}") + for T in (Int8,Int16,Int32,Int64) + @test format(f, typemin(T)) == string(typemin(T)) + @test format(f, typemax(T)) == "+"*string(typemax(T)) + end +end