Skip to content

Commit 9368985

Browse files
authored
Fix incorrect zero padding of inf and NaN (#77)
We now follow the rule: if the type is a non-finite floating point type, *and* the stream fill has been zero padded, then reset it to ' '. This prevents zero-padded numbers which turn out to be nan/inf from being oddly formatted with leading zeros.
1 parent b08ca66 commit 9368985

File tree

2 files changed

+28
-0
lines changed

2 files changed

+28
-0
lines changed

tinyformat.h

+17
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ namespace tfm = tinyformat;
144144
#include <algorithm>
145145
#include <iostream>
146146
#include <sstream>
147+
#include <cmath>
147148

148149
#ifndef TINYFORMAT_ASSERT
149150
# include <cassert>
@@ -297,6 +298,21 @@ TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(const char)
297298
TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(char)
298299
#undef TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR
299300

301+
template<typename T>
302+
void spaceFillIfNotFinite(std::ostream& out, const T& value) { }
303+
// TODO: type_traits would clearly be better here. Should consider moving all
304+
// these workarounds into a big pre-C++11 section.
305+
#define TINYFORMAT_SETFILL_NOT_FINITE_FLOATING(type) \
306+
void spaceFillIfNotFinite(std::ostream& out, type value) \
307+
{ \
308+
if (out.fill() == '0' && !std::isfinite(value)) \
309+
out.fill(' '); \
310+
}
311+
TINYFORMAT_SETFILL_NOT_FINITE_FLOATING(float)
312+
TINYFORMAT_SETFILL_NOT_FINITE_FLOATING(double)
313+
TINYFORMAT_SETFILL_NOT_FINITE_FLOATING(long double)
314+
#undef TINYFORMAT_SETFILL_NOT_FINITE_FLOATING
315+
300316
} // namespace detail
301317

302318

@@ -333,6 +349,7 @@ inline void formatValue(std::ostream& out, const char* /*fmtBegin*/,
333349
// could otherwise lead to a crash when printing a dangling (const char*).
334350
const bool canConvertToChar = detail::is_convertible<T,char>::value;
335351
const bool canConvertToVoidPtr = detail::is_convertible<T, const void*>::value;
352+
detail::spaceFillIfNotFinite(out, value);
336353
if (canConvertToChar && *(fmtEnd-1) == 'c')
337354
detail::formatValueAsType<T, char>::invoke(out, value);
338355
else if (canConvertToVoidPtr && *(fmtEnd-1) == 'p')

tinyformat_test.cpp

+11
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ namespace std { class type_info; }
1111

1212
#include <stdexcept>
1313
#include <climits>
14+
#include <limits>
1415
#include <cfloat>
1516
#include <cstddef>
1617

@@ -212,6 +213,16 @@ int unitTests()
212213
CHECK_EQUAL(tfm::format("%1$10.*2$f", 1234.1234567890, 4), " 1234.1235");
213214
CHECK_EQUAL(tfm::format("%1$*3$.*2$f", 1234.1234567890, 4, 10), " 1234.1235");
214215
CHECK_EQUAL(tfm::format("%1$*2$.*3$f", 1234.1234567890, -10, 4), "1234.1235 ");
216+
// Test padding for infinity and NaN
217+
// (Visual Studio 12.0 and earlier print these in a different way)
218+
# if !defined(_MSC_VER) || _MSC_VER >= 1900
219+
CHECK_EQUAL(tfm::format("%.3d", std::numeric_limits<double>::infinity()), "inf");
220+
CHECK_EQUAL(tfm::format("%.4d", std::numeric_limits<double>::infinity()), " inf");
221+
CHECK_EQUAL(tfm::format("%04.0f", std::numeric_limits<double>::infinity()), " inf");
222+
CHECK_EQUAL(tfm::format("%.3d", std::numeric_limits<double>::quiet_NaN()), "nan");
223+
CHECK_EQUAL(tfm::format("%.4d", std::numeric_limits<double>::quiet_NaN()), " nan");
224+
CHECK_EQUAL(tfm::format("%04.0f", std::numeric_limits<double>::quiet_NaN()), " nan");
225+
# endif
215226

216227
//------------------------------------------------------------
217228
// Test flags

0 commit comments

Comments
 (0)