make sure precision is reset on output streams during serialization

This commit is contained in:
Niels 2016-07-20 20:07:45 +02:00
parent cb145cfe71
commit 1286d35767
3 changed files with 66 additions and 18 deletions

View file

@ -2120,6 +2120,12 @@ class basic_json
// fix locale problems // fix locale problems
ss.imbue(std::locale(std::locale(), new DecimalSeparator)); ss.imbue(std::locale(std::locale(), new DecimalSeparator));
// 6, 15 or 16 digits of precision allows round-trip IEEE 754
// string->float->string, string->double->string or string->long
// double->string; to be safe, we read this value from
// std::numeric_limits<number_float_t>::digits10
ss.precision(std::numeric_limits<double>::digits10);
if (indent >= 0) if (indent >= 0)
{ {
dump(ss, true, static_cast<unsigned int>(indent)); dump(ss, true, static_cast<unsigned int>(indent));
@ -5693,6 +5699,10 @@ class basic_json
`std::setw(4)` on @a o sets the indentation level to `4` and the `std::setw(4)` on @a o sets the indentation level to `4` and the
serialization result is the same as calling `dump(4)`. serialization result is the same as calling `dump(4)`.
@note During serializaion, the locale and the precision of the output
stream @a o are changed. The original values are restored when the
function returns.
@param[in,out] o stream to serialize to @param[in,out] o stream to serialize to
@param[in] j JSON value to serialize @param[in] j JSON value to serialize
@ -5713,14 +5723,23 @@ class basic_json
// reset width to 0 for subsequent calls to this stream // reset width to 0 for subsequent calls to this stream
o.width(0); o.width(0);
// fix locale problems // fix locale problems
auto old_locale = o.imbue(std::locale(std::locale(), new DecimalSeparator)); const auto old_locale = o.imbue(std::locale(std::locale(), new DecimalSeparator));
// set precision
// 6, 15 or 16 digits of precision allows round-trip IEEE 754
// string->float->string, string->double->string or string->long
// double->string; to be safe, we read this value from
// std::numeric_limits<number_float_t>::digits10
const auto old_preicison = o.precision(std::numeric_limits<double>::digits10);
// do the actual serialization // do the actual serialization
j.dump(o, pretty_print, static_cast<unsigned int>(indentation)); j.dump(o, pretty_print, static_cast<unsigned int>(indentation));
// reset locale // reset locale and precision
o.imbue(old_locale); o.imbue(old_locale);
o.precision(old_preicison);
return o; return o;
} }
@ -6184,13 +6203,7 @@ class basic_json
} }
else else
{ {
// Otherwise 6, 15 or 16 digits of precision allows o << m_value.number_float;
// round-trip IEEE 754 string->float->string,
// string->double->string or string->long
// double->string; to be safe, we read this value from
// std::numeric_limits<number_float_t>::digits10
o << std::setprecision(std::numeric_limits<double>::digits10)
<< m_value.number_float;
} }
return; return;
} }

View file

@ -2120,6 +2120,12 @@ class basic_json
// fix locale problems // fix locale problems
ss.imbue(std::locale(std::locale(), new DecimalSeparator)); ss.imbue(std::locale(std::locale(), new DecimalSeparator));
// 6, 15 or 16 digits of precision allows round-trip IEEE 754
// string->float->string, string->double->string or string->long
// double->string; to be safe, we read this value from
// std::numeric_limits<number_float_t>::digits10
ss.precision(std::numeric_limits<double>::digits10);
if (indent >= 0) if (indent >= 0)
{ {
dump(ss, true, static_cast<unsigned int>(indent)); dump(ss, true, static_cast<unsigned int>(indent));
@ -5693,6 +5699,10 @@ class basic_json
`std::setw(4)` on @a o sets the indentation level to `4` and the `std::setw(4)` on @a o sets the indentation level to `4` and the
serialization result is the same as calling `dump(4)`. serialization result is the same as calling `dump(4)`.
@note During serializaion, the locale and the precision of the output
stream @a o are changed. The original values are restored when the
function returns.
@param[in,out] o stream to serialize to @param[in,out] o stream to serialize to
@param[in] j JSON value to serialize @param[in] j JSON value to serialize
@ -5713,14 +5723,23 @@ class basic_json
// reset width to 0 for subsequent calls to this stream // reset width to 0 for subsequent calls to this stream
o.width(0); o.width(0);
// fix locale problems // fix locale problems
auto old_locale = o.imbue(std::locale(std::locale(), new DecimalSeparator)); const auto old_locale = o.imbue(std::locale(std::locale(), new DecimalSeparator));
// set precision
// 6, 15 or 16 digits of precision allows round-trip IEEE 754
// string->float->string, string->double->string or string->long
// double->string; to be safe, we read this value from
// std::numeric_limits<number_float_t>::digits10
const auto old_preicison = o.precision(std::numeric_limits<double>::digits10);
// do the actual serialization // do the actual serialization
j.dump(o, pretty_print, static_cast<unsigned int>(indentation)); j.dump(o, pretty_print, static_cast<unsigned int>(indentation));
// reset locale // reset locale and precision
o.imbue(old_locale); o.imbue(old_locale);
o.precision(old_preicison);
return o; return o;
} }
@ -6184,13 +6203,7 @@ class basic_json
} }
else else
{ {
// Otherwise 6, 15 or 16 digits of precision allows o << m_value.number_float;
// round-trip IEEE 754 string->float->string,
// string->double->string or string->long
// double->string; to be safe, we read this value from
// std::numeric_limits<number_float_t>::digits10
o << std::setprecision(std::numeric_limits<double>::digits10)
<< m_value.number_float;
} }
return; return;
} }

View file

@ -1685,6 +1685,28 @@ TEST_CASE("object inspection")
json j_discarded(json::value_t::discarded); json j_discarded(json::value_t::discarded);
CHECK(j_discarded.dump() == "<discarded>"); CHECK(j_discarded.dump() == "<discarded>");
} }
SECTION("check that precision is reset after serialization")
{
// create stringstream and set precision
std::stringstream ss;
ss.precision(3);
ss << 3.141592653589793 << std::fixed;
CHECK(ss.str() == "3.14");
// reset stringstream
ss.str(std::string());
// use stringstream for JSON serialization
json j_number = 3.141592653589793;
ss << j_number;
// check that precision has been overridden during serialization
CHECK(ss.str() == "3.141592653589793");
// check that precision has been restored
CHECK(ss.precision() == 3);
}
} }
SECTION("return the type of the object (explicit)") SECTION("return the type of the object (explicit)")