ref: d58df01f3ea2de8d41e10d5387445027e59a6c4e
parent: 3b5584581a79cec899c7f6a5233529a64a22ab5f
author: S. Gilles <sgilles@math.umd.edu>
date: Sat Sep 7 11:41:56 EDT 2019
Allow padding for fltXY formatting
--- a/lib/std/fltfmt.myr
+++ b/lib/std/fltfmt.myr
@@ -3,6 +3,7 @@
use "die"
use "extremum"
use "fltbits"
+use "option"
use "slpush"
use "strbuf"
use "types"
@@ -17,6 +18,8 @@
pkglocal type fltparams = struct
mode : int
prec : int
+ padto : size
+ padfill : char
;;
pkglocal const flt64bfmt : (sb : strbuf#, opts : fltparams, val : flt64 -> void)
@@ -30,23 +33,21 @@
var isneg, exp, mant
if isnan(val)
- sbputs(sb, "NaN")
- -> void
+ -> nanfmt(sb, opts)
;;
(isneg, exp, mant) = flt64explode(val)
if exp > Dblbias
- if isneg
- std.sbputs(sb, "-Inf")
- else
- std.sbputs(sb, "Inf")
- ;;
- -> void
+ -> inffmt(sb, opts, isneg)
;;
+ var valsb = mksb()
+
exp = max(exp, 1 - Dblbias)
- dragon4(sb, isneg, mant, exp - 52, Dblbias, opts.mode, opts.prec)
+ dragon4(valsb, false, mant, exp - 52, Dblbias, opts.mode, opts.prec)
+
+ -> blobfmt(sb, sbfin(valsb), opts, isneg)
}
const flt32bfmt = {sb, opts, val
@@ -53,23 +54,72 @@
var isneg, exp, mant
if isnan(val)
- sbputs(sb, "NaN")
- -> void
+ -> nanfmt(sb, opts)
;;
(isneg, exp, mant) = flt32explode(val)
if (exp : int64) > Fltbias
- if isneg
- std.sbputs(sb, "-Inf")
- else
- std.sbputs(sb, "Inf")
- ;;
- -> void
+ -> inffmt(sb, opts, isneg)
;;
+ var valsb = mksb()
+
exp = (max((exp : int64), 1 - Fltbias) : int32)
- dragon4(sb, isneg, (mant : uint64), (exp - 23 : int64), Fltbias, opts.mode, opts.prec)
+ dragon4(valsb, false, (mant : uint64), (exp - 23 : int64), Fltbias, opts.mode, opts.prec)
+
+ -> blobfmt(sb, sbfin(valsb), opts, isneg)
+}
+
+const nanfmt = {sb, opts
+ var npad = clamp(opts.padto - 3, 0, opts.padto)
+
+ for var j = 0; j < npad; j++
+ sbputc(sb, opts.padfill)
+ ;;
+
+ sbputs(sb, "NaN")
+}
+
+const inffmt = {sb, opts, isneg
+ var s = "Inf"
+ var l = 3
+
+ if isneg
+ s = "-Inf"
+ l = 4
+ ;;
+
+ var npad = clamp(opts.padto - l, 0, opts.padto)
+
+ for var j = 0; j < npad; j++
+ sbputc(sb, opts.padfill)
+ ;;
+
+ sbputs(sb, s)
+}
+
+const blobfmt = {sb, blob, opts, isneg
+ /* No exotic characters, so no need for strcellwidth */
+ var width = blob.len
+
+ if isneg
+ width++
+ ;;
+
+ var npad = clamp(opts.padto - width, 0, opts.padto)
+
+ if opts.padfill == '0' && isneg
+ sbputb(sb, ('-' : byte))
+ ;;
+ for var j = 0; j < npad; j++
+ sbputc(sb, opts.padfill)
+ ;;
+ if opts.padfill != '0' && isneg
+ sbputb(sb, ('-' : byte))
+ ;;
+
+ sbputs(sb, blob)
}
/*
--- a/lib/std/fmt.myr
+++ b/lib/std/fmt.myr
@@ -454,10 +454,14 @@
fp = [
.mode = MNormal,
.prec = 0,
+ .padfill = ' ',
+ .padto = 0,
]
for p : params
match p
+ | ("w", wid): fp.padto = getint(wid, "fmt: width must be integer")
+ | ("p", pad): fp.padfill = decode(pad)
| (opt, arg):
std.write(2, "fmt: ")
std.write(2, opt)
@@ -466,6 +470,7 @@
std.die("\nunreachable\n")
;;
;;
+ iassert(fp.padto >= 0, "pad must be >= 0")
-> fp
}
--- a/lib/std/test/fltfmt.myr
+++ b/lib/std/test/fltfmt.myr
@@ -8,21 +8,24 @@
[.name = "put0", .fn = put0],
[.name = "putNaN", .fn = putNaN],
[.name = "putInf", .fn = putInf],
+ [.name = "putinteger", .fn = putinteger],
+ [.name = "putlowprec", .fn = putlowprec],
+ [.name = "padding", .fn = padding],
][:])
}
const put0 = {c
- var f : flt32 = 0.0
- var g : flt64 = 0.0
+ var f : flt32 = 0.0
+ var g : flt64 = 0.0
testr.check(c, std.eq(std.fmt("f is {}", f), "f is 0.0"), "0.0 should format to \"0.0\"")
testr.check(c, std.eq(std.fmt("g is {}", g), "g is 0.0"), "0.0 should format to \"0.0\"")
}
const putNaN = {c
- var f : flt32 = std.flt32nan()
- var g : flt64 = std.flt64nan()
- var f2 : flt32 = std.flt32frombits(0x7fc00ab0)
- var g2 : flt64 = std.flt64frombits(0x7ff800000000abc0)
+ var f : flt32 = std.flt32nan()
+ var g : flt64 = std.flt64nan()
+ var f2 : flt32 = std.flt32frombits(0x7fc00ab0)
+ var g2 : flt64 = std.flt64frombits(0x7ff800000000abc0)
testr.check(c, std.eq(std.fmt("f is {}", f), "f is NaN"), "NaN should format to \"NaN\"")
testr.check(c, std.eq(std.fmt("g is {}", g), "g is NaN"), "NaN should format to \"NaN\"")
testr.check(c, std.eq(std.fmt("f2 is {}", f2), "f2 is NaN"), "alt NaN should format to \"NaN\"")
@@ -30,9 +33,85 @@
}
const putInf = {c
- var f : flt32 = std.flt32inf()
- var g : flt64 = std.flt64inf()
+ var f : flt32 = std.flt32inf()
+ var g : flt64 = std.flt64inf()
testr.check(c, std.eq(std.fmt("f is {}", f), "f is Inf"), "Inf should format to \"Inf\"")
testr.check(c, std.eq(std.fmt("g is {}", g), "g is Inf"), "Inf should format to \"Inf\"")
+ f *= -1.0
+ g *= -1.0
+ testr.check(c, std.eq(std.fmt("f is {}", f), "f is -Inf"), "-Inf should format to \"-Inf\"")
+ testr.check(c, std.eq(std.fmt("g is {}", g), "g is -Inf"), "-Inf should format to \"-Inf\"")
}
+const putinteger = {c
+ var data : (int, byte[:])[:] = [
+ (1, "1.0"), (2, "2.0"), (184, "184.0"), (-37, "-37.0")
+ ][:]
+
+ for (f, exp) : data
+ var f32 : flt32 = (f : flt32)
+ var f64 : flt64 = (f : flt64)
+ var act32 : byte[:] = std.fmt("{}", f32)
+ var act64 : byte[:] = std.fmt("{}", f64)
+
+ testr.check(c, std.eq(act32, exp), "{} should format [flt32] to \"{}\", was \"{}\"", f, exp, act32)
+ testr.check(c, std.eq(act64, exp), "{} should format [flt64] to \"{}\", was \"{}\"", f, exp, act64)
+ ;;
+}
+
+const putlowprec = {c
+ var data : (flt64, byte[:])[:] = [
+ (1.5, "1.5"), (0.0025, "0.0025"), (4.25, "4.25"), (-229.25, "-229.25")
+ ][:]
+
+ for (f, exp) : data
+ var f32 : flt32 = (f : flt32)
+ var f64 : flt64 = (f : flt64)
+ var act32 : byte[:] = std.fmt("{}", f32)
+ var act64 : byte[:] = std.fmt("{}", f64)
+
+ testr.check(c, std.eq(act32, exp), "{} should format [flt32] to \"{}\", was \"{}\"", f, exp, act32)
+ testr.check(c, std.eq(act64, exp), "{} should format [flt64] to \"{}\", was \"{}\"", f, exp, act64)
+ ;;
+}
+
+const padding = {c
+ var exp, act
+ var f32 : flt32
+ var f64 : flt64
+
+ f32 = 1.0
+ exp = "XXXX1.0"
+ act = std.fmt("{w=7,p=X}", f32)
+ testr.check(c, std.eq(exp, act), "{} should format [flt32] to \"{}\", was \"{}\"", f32, exp, act)
+
+ f64 = 1.0
+ exp = "XXXX1.0"
+ act = std.fmt("{w=7,p=X}", f64)
+ testr.check(c, std.eq(exp, act), "{} should format [flt32] to \"{}\", was \"{}\"", f64, exp, act)
+
+ f32 = -2.5
+ exp = "YYYYYY-2.5"
+ act = std.fmt("{w=10,p=Y}", f32)
+ testr.check(c, std.eq(exp, act), "{} should format [flt32] to \"{}\", was \"{}\"", f32, exp, act)
+
+ f64 = -100000.5
+ exp = "-100000.5"
+ act = std.fmt("{w=9,p=Y}", f64)
+ testr.check(c, std.eq(exp, act), "{} should format [flt32] to \"{}\", was \"{}\"", f64, exp, act)
+
+ f32 = -13.25
+ exp = "-013.25"
+ act = std.fmt("{w=7,p=0}", f32)
+ testr.check(c, std.eq(exp, act), "{} should format [flt32] to \"{}\", was \"{}\"", f32, exp, act)
+
+ f32 = -1.0 * std.flt32inf()
+ exp = "0000000-Inf"
+ act = std.fmt("{w=11,p=0}", f32)
+ testr.check(c, std.eq(exp, act), "{} should format [flt32] to \"{}\", was \"{}\"", f32, exp, act)
+
+ f64 = std.flt64nan()
+ exp = " NaN"
+ act = std.fmt("{w=18,p= }", f64)
+ testr.check(c, std.eq(exp, act), "{} should format [flt32] to \"{}\", was \"{}\"", f64, exp, act)
+}