Merge 0132248b61 into 8215dbafbd
This commit is contained in:
commit
9da75c17c5
@ -978,10 +978,11 @@ notation. Otherwise it will be printed in exponential notation.
|
||||
JSON_HEDLEY_NON_NULL(1)
|
||||
JSON_HEDLEY_RETURNS_NON_NULL
|
||||
inline char* format_buffer(char* buf, int len, int decimal_exponent,
|
||||
int min_exp, int max_exp)
|
||||
int min_exp, int max_exp, size_t precision)
|
||||
{
|
||||
JSON_ASSERT(min_exp < 0);
|
||||
JSON_ASSERT(max_exp > 0);
|
||||
precision = (std::min)<size_t>(precision, std::numeric_limits<FloatType>::max_digits10);
|
||||
|
||||
const int k = len;
|
||||
const int n = len + decimal_exponent;
|
||||
@ -1009,6 +1010,9 @@ inline char* format_buffer(char* buf, int len, int decimal_exponent,
|
||||
|
||||
JSON_ASSERT(k > n);
|
||||
|
||||
// truncate the digits by the precision
|
||||
k = (std::min)(static_cast<size_t>(n) + precision, static_cast<size_t>(k));
|
||||
|
||||
std::memmove(buf + (static_cast<size_t>(n) + 1), buf + n, static_cast<size_t>(k) - static_cast<size_t>(n));
|
||||
buf[n] = '.';
|
||||
return buf + (static_cast<size_t>(k) + 1U);
|
||||
@ -1023,7 +1027,8 @@ inline char* format_buffer(char* buf, int len, int decimal_exponent,
|
||||
buf[0] = '0';
|
||||
buf[1] = '.';
|
||||
std::memset(buf + 2, '0', static_cast<size_t>(-n));
|
||||
return buf + (2U + static_cast<size_t>(-n) + static_cast<size_t>(k));
|
||||
// truncate the reported buffer end by the precision
|
||||
return buf + (std::min)(precision + 2, (2U + static_cast<size_t>(-n) + static_cast<size_t>(k)));
|
||||
}
|
||||
|
||||
if (k == 1)
|
||||
@ -1040,7 +1045,7 @@ inline char* format_buffer(char* buf, int len, int decimal_exponent,
|
||||
|
||||
std::memmove(buf + 2, buf + 1, static_cast<size_t>(k) - 1);
|
||||
buf[1] = '.';
|
||||
buf += 1 + static_cast<size_t>(k);
|
||||
buf += 1 + (std::min)(precision, static_cast<size_t>(k));
|
||||
}
|
||||
|
||||
*buf++ = 'e';
|
||||
@ -1062,7 +1067,7 @@ format. Returns an iterator pointing past-the-end of the decimal representation.
|
||||
template<typename FloatType>
|
||||
JSON_HEDLEY_NON_NULL(1, 2)
|
||||
JSON_HEDLEY_RETURNS_NON_NULL
|
||||
char* to_chars(char* first, const char* last, FloatType value)
|
||||
char* to_chars(char* first, const char* last, FloatType value, size_t precision = std::numeric_limits<FloatType>::max_digits10)
|
||||
{
|
||||
static_cast<void>(last); // maybe unused - fix warning
|
||||
JSON_ASSERT(std::isfinite(value));
|
||||
@ -1111,7 +1116,7 @@ char* to_chars(char* first, const char* last, FloatType value)
|
||||
JSON_ASSERT(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits<FloatType>::max_digits10);
|
||||
JSON_ASSERT(last - first >= std::numeric_limits<FloatType>::max_digits10 + 6);
|
||||
|
||||
return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp);
|
||||
return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp, precision);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@ -64,13 +64,14 @@ class serializer
|
||||
@param[in] ichar indentation character to use
|
||||
@param[in] error_handler_ how to react on decoding errors
|
||||
*/
|
||||
serializer(output_adapter_t<char> s, const char ichar,
|
||||
serializer(output_adapter_t<char> s, const char ichar, std::size_t prec = 1000,
|
||||
error_handler_t error_handler_ = error_handler_t::strict)
|
||||
: o(std::move(s))
|
||||
, loc(std::localeconv())
|
||||
, thousands_sep(loc->thousands_sep == nullptr ? '\0' : std::char_traits<char>::to_char_type(* (loc->thousands_sep)))
|
||||
, decimal_point(loc->decimal_point == nullptr ? '\0' : std::char_traits<char>::to_char_type(* (loc->decimal_point)))
|
||||
, indent_char(ichar)
|
||||
, precision(prec)
|
||||
, indent_string(512, indent_char)
|
||||
, error_handler(error_handler_)
|
||||
{}
|
||||
@ -820,7 +821,7 @@ class serializer
|
||||
void dump_float(number_float_t x, std::true_type /*is_ieee_single_or_double*/)
|
||||
{
|
||||
auto* begin = number_buffer.data();
|
||||
auto* end = ::nlohmann::detail::to_chars(begin, begin + number_buffer.size(), x);
|
||||
auto* end = ::nlohmann::detail::to_chars(begin, begin + number_buffer.size(), x, precision);
|
||||
|
||||
o->write_characters(begin, static_cast<size_t>(end - begin));
|
||||
}
|
||||
@ -828,10 +829,10 @@ class serializer
|
||||
void dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/)
|
||||
{
|
||||
// get number of digits for a float -> text -> float round-trip
|
||||
static constexpr auto d = std::numeric_limits<number_float_t>::max_digits10;
|
||||
static constexpr int d_max = std::numeric_limits<number_float_t>::max_digits10;
|
||||
int d = static_cast<int>((std::min)(precision, static_cast<std::size_t>(d_max)));
|
||||
|
||||
// the actual conversion
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
|
||||
std::ptrdiff_t len = (std::snprintf)(number_buffer.data(), number_buffer.size(), "%.*g", d, x);
|
||||
|
||||
// negative value indicates an error
|
||||
@ -977,6 +978,8 @@ class serializer
|
||||
|
||||
/// the indentation character
|
||||
const char indent_char;
|
||||
/// precision for floating point output
|
||||
std::size_t precision;
|
||||
/// the indentation string
|
||||
string_t indent_string;
|
||||
|
||||
|
||||
@ -1299,10 +1299,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
string_t dump(const int indent = -1,
|
||||
const char indent_char = ' ',
|
||||
const bool ensure_ascii = false,
|
||||
const error_handler_t error_handler = error_handler_t::strict) const
|
||||
const error_handler_t error_handler = error_handler_t::strict,
|
||||
const size_t precision = std::numeric_limits<size_t>::max()) const
|
||||
{
|
||||
string_t result;
|
||||
serializer s(detail::output_adapter<char, string_t>(result), indent_char, error_handler);
|
||||
serializer s(detail::output_adapter<char, string_t>(result), indent_char, precision, error_handler);
|
||||
|
||||
if (indent >= 0)
|
||||
{
|
||||
@ -4010,8 +4011,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
o.width(0);
|
||||
|
||||
// do the actual serialization
|
||||
serializer s(detail::output_adapter<char>(o), o.fill());
|
||||
serializer s(detail::output_adapter<char>(o), o.fill(), static_cast<size_t>(o.precision())).;
|
||||
s.dump(j, pretty_print, false, static_cast<unsigned int>(indentation));
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
@ -18583,10 +18583,11 @@ notation. Otherwise it will be printed in exponential notation.
|
||||
JSON_HEDLEY_NON_NULL(1)
|
||||
JSON_HEDLEY_RETURNS_NON_NULL
|
||||
inline char* format_buffer(char* buf, int len, int decimal_exponent,
|
||||
int min_exp, int max_exp)
|
||||
int min_exp, int max_exp, size_t precision)
|
||||
{
|
||||
JSON_ASSERT(min_exp < 0);
|
||||
JSON_ASSERT(max_exp > 0);
|
||||
precision = std::min<size_t>(precision, 1000);
|
||||
|
||||
const int k = len;
|
||||
const int n = len + decimal_exponent;
|
||||
@ -18616,7 +18617,7 @@ inline char* format_buffer(char* buf, int len, int decimal_exponent,
|
||||
|
||||
std::memmove(buf + (static_cast<size_t>(n) + 1), buf + n, static_cast<size_t>(k) - static_cast<size_t>(n));
|
||||
buf[n] = '.';
|
||||
return buf + (static_cast<size_t>(k) + 1U);
|
||||
return buf + (std::min(n + precision, static_cast<size_t>(k)) + 1U);
|
||||
}
|
||||
|
||||
if (min_exp < n && n <= 0)
|
||||
@ -18628,7 +18629,7 @@ inline char* format_buffer(char* buf, int len, int decimal_exponent,
|
||||
buf[0] = '0';
|
||||
buf[1] = '.';
|
||||
std::memset(buf + 2, '0', static_cast<size_t>(-n));
|
||||
return buf + (2U + static_cast<size_t>(-n) + static_cast<size_t>(k));
|
||||
return buf + std::min(precision + 2, (2U + static_cast<size_t>(-n) + static_cast<size_t>(k)));
|
||||
}
|
||||
|
||||
if (k == 1)
|
||||
@ -18645,7 +18646,7 @@ inline char* format_buffer(char* buf, int len, int decimal_exponent,
|
||||
|
||||
std::memmove(buf + 2, buf + 1, static_cast<size_t>(k) - 1);
|
||||
buf[1] = '.';
|
||||
buf += 1 + static_cast<size_t>(k);
|
||||
buf += 1 + std::min(precision, static_cast<size_t>(k));
|
||||
}
|
||||
|
||||
*buf++ = 'e';
|
||||
@ -18667,7 +18668,7 @@ format. Returns an iterator pointing past-the-end of the decimal representation.
|
||||
template<typename FloatType>
|
||||
JSON_HEDLEY_NON_NULL(1, 2)
|
||||
JSON_HEDLEY_RETURNS_NON_NULL
|
||||
char* to_chars(char* first, const char* last, FloatType value)
|
||||
char* to_chars(char* first, const char* last, FloatType value, size_t precision = std::numeric_limits<FloatType>::max_digits10)
|
||||
{
|
||||
static_cast<void>(last); // maybe unused - fix warning
|
||||
JSON_ASSERT(std::isfinite(value));
|
||||
@ -18716,7 +18717,7 @@ char* to_chars(char* first, const char* last, FloatType value)
|
||||
JSON_ASSERT(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits<FloatType>::max_digits10);
|
||||
JSON_ASSERT(last - first >= std::numeric_limits<FloatType>::max_digits10 + 6);
|
||||
|
||||
return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp);
|
||||
return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp, precision);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
@ -18770,13 +18771,14 @@ class serializer
|
||||
@param[in] ichar indentation character to use
|
||||
@param[in] error_handler_ how to react on decoding errors
|
||||
*/
|
||||
serializer(output_adapter_t<char> s, const char ichar,
|
||||
serializer(output_adapter_t<char> s, const char ichar, size_t precision = 1000,
|
||||
error_handler_t error_handler_ = error_handler_t::strict)
|
||||
: o(std::move(s))
|
||||
, loc(std::localeconv())
|
||||
, thousands_sep(loc->thousands_sep == nullptr ? '\0' : std::char_traits<char>::to_char_type(* (loc->thousands_sep)))
|
||||
, decimal_point(loc->decimal_point == nullptr ? '\0' : std::char_traits<char>::to_char_type(* (loc->decimal_point)))
|
||||
, indent_char(ichar)
|
||||
, precision(precision)
|
||||
, indent_string(512, indent_char)
|
||||
, error_handler(error_handler_)
|
||||
{}
|
||||
@ -19526,7 +19528,7 @@ class serializer
|
||||
void dump_float(number_float_t x, std::true_type /*is_ieee_single_or_double*/)
|
||||
{
|
||||
auto* begin = number_buffer.data();
|
||||
auto* end = ::nlohmann::detail::to_chars(begin, begin + number_buffer.size(), x);
|
||||
auto* end = ::nlohmann::detail::to_chars(begin, begin + number_buffer.size(), x, precision);
|
||||
|
||||
o->write_characters(begin, static_cast<size_t>(end - begin));
|
||||
}
|
||||
@ -19538,6 +19540,8 @@ class serializer
|
||||
|
||||
// the actual conversion
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
|
||||
char format[100];
|
||||
snprintf(format, 100, "%%.%dg", precision);
|
||||
std::ptrdiff_t len = (std::snprintf)(number_buffer.data(), number_buffer.size(), "%.*g", d, x);
|
||||
|
||||
// negative value indicates an error
|
||||
@ -19683,6 +19687,8 @@ class serializer
|
||||
|
||||
/// the indentation character
|
||||
const char indent_char;
|
||||
/// precision for floating point output
|
||||
size_t precision;
|
||||
/// the indentation string
|
||||
string_t indent_string;
|
||||
|
||||
@ -21298,10 +21304,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
string_t dump(const int indent = -1,
|
||||
const char indent_char = ' ',
|
||||
const bool ensure_ascii = false,
|
||||
const error_handler_t error_handler = error_handler_t::strict) const
|
||||
const error_handler_t error_handler = error_handler_t::strict,
|
||||
const size_t precision = std::numeric_limits<size_t>::max()) const
|
||||
{
|
||||
string_t result;
|
||||
serializer s(detail::output_adapter<char, string_t>(result), indent_char, error_handler);
|
||||
serializer s(detail::output_adapter<char, string_t>(result), indent_char, precision, error_handler);
|
||||
|
||||
if (indent >= 0)
|
||||
{
|
||||
@ -24002,15 +24009,17 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
friend std::ostream& operator<<(std::ostream& o, const basic_json& j)
|
||||
{
|
||||
// read width member and use it as indentation parameter if nonzero
|
||||
const bool pretty_print = o.width() > 0;
|
||||
const auto indentation = pretty_print ? o.width() : 0;
|
||||
const auto width = o.width();
|
||||
const bool pretty_print = width > 0;
|
||||
const auto indentation = pretty_print ? width : 0;
|
||||
|
||||
// reset width to 0 for subsequent calls to this stream
|
||||
o.width(0);
|
||||
|
||||
// do the actual serialization
|
||||
serializer s(detail::output_adapter<char>(o), o.fill());
|
||||
serializer s(detail::output_adapter<char>(o), o.fill(), o.precision());
|
||||
s.dump(j, pretty_print, false, static_cast<unsigned int>(indentation));
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
57
tests/src/unit-precision.cpp
Normal file
57
tests/src/unit-precision.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
__ _____ _____ _____
|
||||
__| | __| | | | JSON for Modern C++ (test suite)
|
||||
| | |__ | | | | | | version 3.10.5
|
||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
SPDX-License-Identifier: MIT
|
||||
Copyright (c) 2013-2022 Niels Lohmann <http://nlohmann.me>.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "doctest_compatibility.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <iomanip>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
using json = nlohmann::json;
|
||||
|
||||
#include <set>
|
||||
|
||||
TEST_CASE("precision<nlohmann::json>")
|
||||
{
|
||||
json j;
|
||||
j = M_PI;
|
||||
auto to_string = [](const nlohmann::json & j, size_t precision)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << std::setprecision(precision) << j;
|
||||
return ss.str();
|
||||
};
|
||||
auto s1 = to_string(j, 1);
|
||||
auto s2 = to_string(j, 2);
|
||||
auto s3 = to_string(j, 3);
|
||||
CHECK(s1 == "3.1");
|
||||
CHECK(s2 == "3.14");
|
||||
CHECK(s3 == "3.141");
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user