Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update cfmt code based on latest changes to Printf.jl #82

Merged
merged 1 commit into from
Mar 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .drone.yml
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
---
kind: pipeline
name: linux - arm64 - Julia 1.9
name: linux - arm64 - Julia 1.10

platform:
os: linux
arch: arm64

steps:
- name: build
image: julia:1.9
image: julia:1.10
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.9
name: linux - arm64 - Julia 1.10

platform:
os: linux
arch: arm64

steps:
- name: build
image: julia:1.9
image: julia:1.10
commands:
- "julia --project=. --check-bounds=yes --color=yes -e 'using InteractiveUtils; versioninfo(verbose=true); using Pkg; Pkg.build(); Pkg.test(coverage=true)'"
3 changes: 0 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@ jobs:
- os: ubuntu-latest
arch: x86
version: '1'
- os: ubuntu-latest
arch: x64
version: '1.6'
- os: ubuntu-latest
arch: x64
version: 'nightly'
Expand Down
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ keywords = ["Strings", "Formatting"]
license = "MIT"
name = "Format"
uuid = "1fa38f19-a742-5d3f-a2b9-30dd87b9d5f8"
version = "1.3.6"
version = "1.3.7"

[deps]

Expand Down
83 changes: 58 additions & 25 deletions src/printf.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# C-style formatting functions, originally based on Printf.jl

using Base.Ryu

abstract type FmtType end
Expand Down Expand Up @@ -117,7 +119,7 @@ function FmtSpec(f::AbstractString)
end
end
# parse prec
prec = -1
prec = 0
parsedprecdigits = false
if b == UInt8('.')
pos > len && throw(ArgumentError("incomplete format string: '$f'"))
Expand All @@ -141,6 +143,8 @@ function FmtSpec(f::AbstractString)
# parse length modifier (ignored)
if b == UInt8('h') || b == UInt8('l')
prev = b
pos > len &&
throw(ArgumentError("format string - length modifier is missing type specifier: '$f'"))
b = bytes[pos]
pos += 1
if b == prev
Expand All @@ -149,6 +153,8 @@ function FmtSpec(f::AbstractString)
pos += 1
end
elseif b in b"Ljqtz"
pos > len &&
throw(ArgumentError("format string - length modifier is missing type specifier: '$f'"))
b = bytes[pos]
pos += 1
end
Expand Down Expand Up @@ -206,7 +212,7 @@ end

function _fmt(buf, pos, spec::FmtSpec{FmtChr}, arg)
ch = arg isa String ? arg[1] : Char(arg)
width = spec.width - 1
width = spec.width - textwidth(ch)
width <= 0 && return writechar(buf, pos, ch)
if spec.leftalign
padn(buf, writechar(buf, pos, ch), width)
Expand Down Expand Up @@ -277,21 +283,24 @@ _fmt(buf, pos, spec::FmtSpec{<:FmtInts}, arg::BaseUns) =
_fmt(buf, pos, spec::FmtSpec{<:FmtInts}, arg::BaseInt) =
_fmt(buf, pos, spec, arg < 0, unsigned(abs(arg)))

hex_len(x) = x == 0 ? 1 : (sizeof(x)<<1) - (leading_zeros(x)>>2)
oct_len(x) = x == 0 ? 1 : div((sizeof(x)<<3) - leading_zeros(x)+2, 3)

function _fmt(buf, pos, spec::FmtSpec{F}, neg, x::T) where {F<:FmtInts,T<:Union{String,BaseUns}}
n = T === String ? sizeof(x) :
F === FmtDec ? dec_len(x) :
F === FmtHex ? (sizeof(x)<<1) - (leading_zeros(x)>>2) :
div((sizeof(x)<<3) - leading_zeros(x)+2, 3)
F === FmtDec ? dec_len(x) : F === FmtHex ? hex_len(x) : oct_len(x)
i = n
arglen = n + (neg || (spec.plus | spec.space)) +
((spec.altf && (F !== FmtDec)) ? ifelse(F === FmtOct, 1, 2) : 0)
width, prec = spec.width, spec.prec
arglen2 = arglen < width && prec > 0 ? arglen + min(max(0, prec - n), width - arglen) : arglen
precpad = max(0, prec - n)
# Calculate width including padding due to width or precision
arglen2 = arglen < width && prec > 0 ? arglen + min(precpad, width - arglen) : arglen

# Make sure that remaining output buffer is large enough
# This means that it isn't necessary to preallocate for cases that usually will never happen
buflen = sizeof(buf) - pos
buflen < arglen2 && resize!(buf, arglen2 + pos)
buflen = pos + max(width, arglen + precpad)
buflen > sizeof(buf) && resize!(buf, buflen)

!spec.leftalign && !spec.zero && arglen2 < width &&
(pos = padn(buf, pos, width - arglen2))
Expand All @@ -312,7 +321,7 @@ function _fmt(buf, pos, spec::FmtSpec{F}, neg, x::T) where {F<:FmtInts,T<:Union{
if spec.zero && arglen2 < width
pos = padzero(buf, pos, width - arglen2)
elseif n < prec
pos = padzero(buf, pos, prec - n)
pos = padzero(buf, pos, precpad)
elseif arglen < arglen2
pos = padzero(buf, pos, arglen2 - arglen)
end
Expand Down Expand Up @@ -380,7 +389,7 @@ function output_fmt_a(buf, pos, spec, neg, x)
pos = outch(buf, pos, '0', upchar(spec, 'X'))
if x == 0
pos = outch(buf, pos, '0')
prec > 0 && (pos = padzero(buf, pos, prec))
prec > 0 && (pos = outch(buf, pos, '.'); pos = padzero(buf, pos, prec))
return outch(buf, pos, upchar(spec, 'P'), '+', '0')
end
s, p = frexp(x)
Expand Down Expand Up @@ -471,26 +480,48 @@ end

function _fmt(buf, pos, spec::FmtSpec{T}, arg) where {T <: FmtFlts}
# Make sure there is enough room
width = spec.width
width, prec, plus, space, hash = spec.width, spec.prec, spec.plus, spec.space, spec.altf
buflen = sizeof(buf) - pos
needed = max(width, 309 + 17 + 5)
buflen < needed && resize!(buf, pos + needed)

x = tofloat(arg)
if T === FmtFltE
newpos = Ryu.writeexp(buf, pos, x, spec.prec, spec.plus, spec.space,
spec.altf, upchar(spec, 'E'), UInt8('.'))
newpos = Ryu.writeexp(buf, pos, x, prec, plus, space, hash, upchar(spec, 'E'), UInt8('.'))
elseif T === FmtFltF
newpos = Ryu.writefixed(buf, pos, x, spec.prec, spec.plus, spec.space, spec.altf,
UInt8('.'))
newpos = Ryu.writefixed(buf, pos, x, prec, plus, space, hash, UInt8('.'))
elseif T === FmtFltG
prec = spec.prec
prec = prec == 0 ? 1 : prec
x = round(x, sigdigits=prec)
newpos = Ryu.writeshortest(buf, pos, x, spec.plus, spec.space, spec.altf, prec,
upchar(spec, 'E'), true, UInt8('.'))
if isinf(x) || isnan(x)
newpos = Ryu.writeshortest(buf, pos, x, plus, space)
else
# C11-compliant general format
prec = prec == 0 ? 1 : prec
# format the value in scientific notation and parse the exponent part
exp = let p = Ryu.writeexp(buf, pos, x, prec)
b1, b2, b3, b4 = buf[p-4], buf[p-3], buf[p-2], buf[p-1]
Z = UInt8('0')
if b1 == UInt8('e')
# two-digit exponent
sign = b2 == UInt8('+') ? 1 : -1
exp = 10 * (b3 - Z) + (b4 - Z)
else
# three-digit exponent
sign = b1 == UInt8('+') ? 1 : -1
exp = 100 * (b2 - Z) + 10 * (b3 - Z) + (b4 - Z)
end
flipsign(exp, sign)
end
if -4 ≤ exp < prec
newpos = Ryu.writefixed(buf, pos, x, prec - (exp + 1), plus, space, hash,
UInt8('.'), !hash)
else
newpos = Ryu.writeexp(buf, pos, x, prec - 1, plus, space, hash,
upchar(spec, 'E'), UInt8('.'), !hash)
end
end
elseif T === FmtFltA
newpos = output_fmt_a(buf, pos, spec, x < 0, abs(x))
x, neg = x < 0 || x === -Base.zero(x) ? (-x, true) : (x, false)
newpos = output_fmt_a(buf, pos, spec, neg, x)
end
if newpos - pos < width
# need to pad
Expand All @@ -500,8 +531,8 @@ function _fmt(buf, pos, spec::FmtSpec{T}, arg) where {T <: FmtFlts}
else
# right aligned
n = width - (newpos - pos)
if spec.zero
ex = (arg < 0 || (spec.plus | spec.space)) + ifelse(T === FmtFltA, 2, 0)
if spec.zero && isfinite(x)
ex = (arg < 0 || (plus | space)) + ifelse(T === FmtFltA, 2, 0)
so = pos + ex
len = (newpos - pos) - ex
copyto!(buf, so + n, buf, so, len)
Expand All @@ -523,12 +554,14 @@ end

# pointers
_fmt(buf, pos, spec::FmtSpec{FmtPtr}, arg) =
_fmt(buf, pos, ptrfmt(spec, arg), UInt(arg))
_fmt(buf, pos, ptrfmt(spec, arg), UInt64(arg))

@inline _dec_len1(v) = ifelse(v < 100, ifelse(v < 10, 1, 2), 3)
@inline _dec_len2(v) = v < 1_000 ? _dec_len1(v) : ifelse(v < 10_000, 4, 5)
@inline _dec_len4(v) = v < 100_000 ? _dec_len2(v) :
(v < 10_000_000 ? ifelse(v < 1_000_000, 6, 7) : ifelse(v < 100_000_000, 8, 9))
(v < 10_000_000
? ifelse(v < 1_000_000, 6, 7)
: ifelse(v < 100_000_000, 8, ifelse(v < 1_000_000_000, 9, 10)))
@inline function _dec_len8(v)
if v < 1_000_000_000 # 1 - 9 digits
_dec_len4(v)
Expand Down
Loading
Loading