Skip to content

Commit

Permalink
Merge pull request #55 from JuliaString/spj/useprintf
Browse files Browse the repository at this point in the history
Use new Printf.format call directly, don't use macro
  • Loading branch information
ScottPJones authored Oct 16, 2020
2 parents dffbbd7 + 93aabf5 commit ecf5bd6
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 9 deletions.
69 changes: 60 additions & 9 deletions src/cformat.jl
Original file line number Diff line number Diff line change
@@ -1,17 +1,67 @@
@static if VERSION > v"1.6.0-DEV.854"

const NoCommas = 0
const CheckCommas = 1
const CheckRat = 2
const AddCommas = 3

const formatters = Dict{ ASCIIStr, Tuple{Printf.Format, Int} }()

function _checkfmt(fmt)
test = Printf.Format(fmt)
len = length(test.formats)
len === 0 && error("Invalid format string $fmt")
len === 1 || error("Only one undecorated format string is allowed")
test
end

function _get_formatter(fmt)
global formatters

chkfmt = get(formatters, fmt, nothing)
chkfmt === nothing || return chkfmt
# Check for thousands separator
if occursin("'", fmt)
conversion = fmt[end]
conversion in "sduifFgG" ||
error( string("thousand separator not defined for ", conversion, " conversion") )
typ = conversion in "dui" ? CheckCommas : conversion === 's' ? CheckRat : AddCommas
formatters[fmt] = (_checkfmt( replace( fmt, "'" => ""; count=1 ) ), typ)
else
formatters[fmt] = (_checkfmt(fmt), NoCommas)
end
end

function cfmt(fmt::ASCIIStr, x::T) where {T}
formatter, typ = _get_formatter(fmt)
s = Printf.format(formatter, x)
typ === NoCommas ? s :
typ === CheckCommas ? checkcommas(s) :
(typ === CheckRat && T <: Rational) ? addcommasrat(s) : addcommasreal(s)
end

function _checkrat(formatter, x::T) where {T}
s = Printf.format(formatter, x)
T <: Rational ? addcommasrat(s) : addcommasreal(s)
end

function generate_formatter( fmt::ASCIIStr )
formatter, typ = _get_formatter(fmt)
typ === NoCommas ? x -> Printf.format(formatter, x) :
typ === CheckCommas ? x -> checkcomma(Printf.format(formatter, x)) :
typ === CheckRat ? x -> _checkrat(formatter, x) :
x -> addcommasreal(Printf.format(formatter, x))
end

else
formatters = Dict{ ASCIIStr, Function }()

cfmt( fmt::ASCIIStr, x ) = m_eval(Expr(:call, generate_formatter( fmt ), x))

function checkfmt(fmt)
@static if VERSION > v"1.6.0-DEV.854"
test = Printf.Format(fmt)
length(test.formats) == 1 ||
error( "Only one AND undecorated format string is allowed")
else
test = @static VERSION >= v"1.4.0-DEV.180" ? Printf.parse(fmt) : Base.Printf.parse( fmt )
(length( test ) == 1 && typeof( test[1] ) <: Tuple) ||
error( "Only one AND undecorated format string is allowed")
end
test = @static VERSION >= v"1.4.0-DEV.180" ? Printf.parse(fmt) : Base.Printf.parse( fmt )
(length( test ) == 1 && typeof( test[1] ) <: Tuple) ||
error( "Only one AND undecorated format string is allowed")
end

function generate_formatter( fmt::ASCIIStr )
Expand Down Expand Up @@ -43,6 +93,7 @@ function generate_formatter( fmt::ASCIIStr )
end
return (formatters[ fmt ] = x->Base.invokelatest(formatter, x))
end
end

function addcommasreal(s)
len = length(s)
Expand Down
8 changes: 8 additions & 0 deletions src/fmtcore.jl
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,14 @@ function _pfmt_e(out::IO, fs::FormatSpec, x::AbstractFloat)
rax = round(ax; sigdigits = fs.prec + 1)
e = floor(Integer, log10(rax)) # exponent
u = rax * exp10(-e) # significand
i = 0
v10 = 1
while isinf(u)
i += 1
i > 18 && (u = 0.0; e = 0; break)
v10 *= 10
u = v10 * rax * exp(-e - i)
end
end

# calculate length
Expand Down

0 comments on commit ecf5bd6

Please sign in to comment.