mirror of
https://github.com/open-source-parsers/jsoncpp.git
synced 2025-02-24 15:26:51 +01:00
Add setting precision for json writers and also add decimal places precision type. (#752)
* Added setting precision for writers. * Added special case for precise precision and global precision. * Added good setting of type of precision and also added this type to BuiltStreamWriter and for its settings. * Added some tests.
This commit is contained in:
parent
af2598cdd3
commit
a07fc53287
@ -109,6 +109,13 @@ enum CommentPlacement {
|
|||||||
numberOfCommentPlacement
|
numberOfCommentPlacement
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** \brief Type of precision for formatting of real values.
|
||||||
|
*/
|
||||||
|
enum PrecisionType {
|
||||||
|
significantDigits = 0, ///< we set max number of significant digits in string
|
||||||
|
decimalPlaces ///< we set max number of digits after "." in string
|
||||||
|
};
|
||||||
|
|
||||||
//# ifdef JSON_USE_CPPTL
|
//# ifdef JSON_USE_CPPTL
|
||||||
// typedef CppTL::AnyEnumerator<const char *> EnumMemberNames;
|
// typedef CppTL::AnyEnumerator<const char *> EnumMemberNames;
|
||||||
// typedef CppTL::AnyEnumerator<const Value &> EnumValues;
|
// typedef CppTL::AnyEnumerator<const Value &> EnumValues;
|
||||||
@ -220,6 +227,9 @@ public:
|
|||||||
static const UInt64 maxUInt64;
|
static const UInt64 maxUInt64;
|
||||||
#endif // defined(JSON_HAS_INT64)
|
#endif // defined(JSON_HAS_INT64)
|
||||||
|
|
||||||
|
/// Default precision for real value for string representation.
|
||||||
|
static const UInt defaultRealPrecision;
|
||||||
|
|
||||||
// Workaround for bug in the NVIDIAs CUDA 9.1 nvcc compiler
|
// Workaround for bug in the NVIDIAs CUDA 9.1 nvcc compiler
|
||||||
// when using gcc and clang backend compilers. CZString
|
// when using gcc and clang backend compilers. CZString
|
||||||
// cannot be defined as private. See issue #486
|
// cannot be defined as private. See issue #486
|
||||||
|
@ -106,6 +106,10 @@ public:
|
|||||||
- If true, outputs non-finite floating point values in the following way:
|
- If true, outputs non-finite floating point values in the following way:
|
||||||
NaN values as "NaN", positive infinity as "Infinity", and negative infinity
|
NaN values as "NaN", positive infinity as "Infinity", and negative infinity
|
||||||
as "-Infinity".
|
as "-Infinity".
|
||||||
|
- "precision": int
|
||||||
|
- Number of precision digits for formatting of real values.
|
||||||
|
- "precisionType": "significant"(default) or "decimal"
|
||||||
|
- Type of precision for formatting of real values.
|
||||||
|
|
||||||
You can examine 'settings_` yourself
|
You can examine 'settings_` yourself
|
||||||
to see the defaults. You can also write and read them just like any
|
to see the defaults. You can also write and read them just like any
|
||||||
@ -339,7 +343,8 @@ JSONCPP_STRING JSON_API valueToString(UInt value);
|
|||||||
#endif // if defined(JSON_HAS_INT64)
|
#endif // if defined(JSON_HAS_INT64)
|
||||||
JSONCPP_STRING JSON_API valueToString(LargestInt value);
|
JSONCPP_STRING JSON_API valueToString(LargestInt value);
|
||||||
JSONCPP_STRING JSON_API valueToString(LargestUInt value);
|
JSONCPP_STRING JSON_API valueToString(LargestUInt value);
|
||||||
JSONCPP_STRING JSON_API valueToString(double value);
|
JSONCPP_STRING JSON_API valueToString(double value, unsigned int precision = Value::defaultRealPrecision,
|
||||||
|
PrecisionType precisionType = PrecisionType::significantDigits);
|
||||||
JSONCPP_STRING JSON_API valueToString(bool value);
|
JSONCPP_STRING JSON_API valueToString(bool value);
|
||||||
JSONCPP_STRING JSON_API valueToQuotedString(const char* value);
|
JSONCPP_STRING JSON_API valueToQuotedString(const char* value);
|
||||||
|
|
||||||
|
@ -109,6 +109,20 @@ static inline void fixNumericLocaleInput(char* begin, char* end) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete zeros in the end of string, if it isn't last zero before '.' character.
|
||||||
|
*/
|
||||||
|
static inline void fixZerosInTheEnd(char* begin, char* end) {
|
||||||
|
end--;
|
||||||
|
while ((begin < end) && (*end == '0')) {
|
||||||
|
// don't delete last zero before point.
|
||||||
|
if (*(end - 1) != '.') {
|
||||||
|
*end = '\0';
|
||||||
|
}
|
||||||
|
end--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Json {
|
} // namespace Json {
|
||||||
|
|
||||||
#endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED
|
#endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED
|
||||||
|
@ -64,6 +64,8 @@ const LargestInt Value::minLargestInt = LargestInt(~(LargestUInt(-1) / 2));
|
|||||||
const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2);
|
const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2);
|
||||||
const LargestUInt Value::maxLargestUInt = LargestUInt(-1);
|
const LargestUInt Value::maxLargestUInt = LargestUInt(-1);
|
||||||
|
|
||||||
|
const UInt Value::defaultRealPrecision = 17;
|
||||||
|
|
||||||
#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
|
#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
static inline bool InRange(double d, T min, U max) {
|
static inline bool InRange(double d, T min, U max) {
|
||||||
|
@ -118,14 +118,18 @@ JSONCPP_STRING valueToString(UInt value) {
|
|||||||
#endif // # if defined(JSON_HAS_INT64)
|
#endif // # if defined(JSON_HAS_INT64)
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
JSONCPP_STRING valueToString(double value, bool useSpecialFloats, unsigned int precision) {
|
JSONCPP_STRING valueToString(double value, bool useSpecialFloats, unsigned int precision, PrecisionType precisionType) {
|
||||||
// Allocate a buffer that is more than large enough to store the 16 digits of
|
// Allocate a buffer that is more than large enough to store the 16 digits of
|
||||||
// precision requested below.
|
// precision requested below.
|
||||||
char buffer[36];
|
char buffer[36];
|
||||||
int len = -1;
|
int len = -1;
|
||||||
|
|
||||||
char formatString[15];
|
char formatString[15];
|
||||||
snprintf(formatString, sizeof(formatString), "%%.%ug", precision);
|
if (precisionType == PrecisionType::significantDigits) {
|
||||||
|
snprintf(formatString, sizeof(formatString), "%%.%ug", precision);
|
||||||
|
} else {
|
||||||
|
snprintf(formatString, sizeof(formatString), "%%.%uf", precision);
|
||||||
|
}
|
||||||
|
|
||||||
// Print into the buffer. We need not request the alternative representation
|
// Print into the buffer. We need not request the alternative representation
|
||||||
// that always has a decimal point because JSON doesn't distinguish the
|
// that always has a decimal point because JSON doesn't distinguish the
|
||||||
@ -133,6 +137,10 @@ JSONCPP_STRING valueToString(double value, bool useSpecialFloats, unsigned int p
|
|||||||
if (isfinite(value)) {
|
if (isfinite(value)) {
|
||||||
len = snprintf(buffer, sizeof(buffer), formatString, value);
|
len = snprintf(buffer, sizeof(buffer), formatString, value);
|
||||||
fixNumericLocale(buffer, buffer + len);
|
fixNumericLocale(buffer, buffer + len);
|
||||||
|
// to delete use-less too much zeros in the end of string
|
||||||
|
if (precisionType == PrecisionType::decimalPlaces) {
|
||||||
|
fixZerosInTheEnd(buffer, buffer + len);
|
||||||
|
}
|
||||||
|
|
||||||
// try to ensure we preserve the fact that this was given to us as a double on input
|
// try to ensure we preserve the fact that this was given to us as a double on input
|
||||||
if (!strchr(buffer, '.') && !strchr(buffer, 'e')) {
|
if (!strchr(buffer, '.') && !strchr(buffer, 'e')) {
|
||||||
@ -154,7 +162,9 @@ JSONCPP_STRING valueToString(double value, bool useSpecialFloats, unsigned int p
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONCPP_STRING valueToString(double value) { return valueToString(value, false, 17); }
|
JSONCPP_STRING valueToString(double value, unsigned int precision, PrecisionType precisionType) {
|
||||||
|
return valueToString(value, false, precision, precisionType);
|
||||||
|
}
|
||||||
|
|
||||||
JSONCPP_STRING valueToString(bool value) { return value ? "true" : "false"; }
|
JSONCPP_STRING valueToString(bool value) { return value ? "true" : "false"; }
|
||||||
|
|
||||||
@ -856,7 +866,8 @@ struct BuiltStyledStreamWriter : public StreamWriter
|
|||||||
JSONCPP_STRING const& nullSymbol,
|
JSONCPP_STRING const& nullSymbol,
|
||||||
JSONCPP_STRING const& endingLineFeedSymbol,
|
JSONCPP_STRING const& endingLineFeedSymbol,
|
||||||
bool useSpecialFloats,
|
bool useSpecialFloats,
|
||||||
unsigned int precision);
|
unsigned int precision,
|
||||||
|
PrecisionType precisionType);
|
||||||
int write(Value const& root, JSONCPP_OSTREAM* sout) JSONCPP_OVERRIDE;
|
int write(Value const& root, JSONCPP_OSTREAM* sout) JSONCPP_OVERRIDE;
|
||||||
private:
|
private:
|
||||||
void writeValue(Value const& value);
|
void writeValue(Value const& value);
|
||||||
@ -885,6 +896,7 @@ private:
|
|||||||
bool indented_ : 1;
|
bool indented_ : 1;
|
||||||
bool useSpecialFloats_ : 1;
|
bool useSpecialFloats_ : 1;
|
||||||
unsigned int precision_;
|
unsigned int precision_;
|
||||||
|
PrecisionType precisionType_;
|
||||||
};
|
};
|
||||||
BuiltStyledStreamWriter::BuiltStyledStreamWriter(
|
BuiltStyledStreamWriter::BuiltStyledStreamWriter(
|
||||||
JSONCPP_STRING const& indentation,
|
JSONCPP_STRING const& indentation,
|
||||||
@ -893,7 +905,8 @@ BuiltStyledStreamWriter::BuiltStyledStreamWriter(
|
|||||||
JSONCPP_STRING const& nullSymbol,
|
JSONCPP_STRING const& nullSymbol,
|
||||||
JSONCPP_STRING const& endingLineFeedSymbol,
|
JSONCPP_STRING const& endingLineFeedSymbol,
|
||||||
bool useSpecialFloats,
|
bool useSpecialFloats,
|
||||||
unsigned int precision)
|
unsigned int precision,
|
||||||
|
PrecisionType precisionType)
|
||||||
: rightMargin_(74)
|
: rightMargin_(74)
|
||||||
, indentation_(indentation)
|
, indentation_(indentation)
|
||||||
, cs_(cs)
|
, cs_(cs)
|
||||||
@ -904,6 +917,7 @@ BuiltStyledStreamWriter::BuiltStyledStreamWriter(
|
|||||||
, indented_(false)
|
, indented_(false)
|
||||||
, useSpecialFloats_(useSpecialFloats)
|
, useSpecialFloats_(useSpecialFloats)
|
||||||
, precision_(precision)
|
, precision_(precision)
|
||||||
|
, precisionType_(precisionType)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
int BuiltStyledStreamWriter::write(Value const& root, JSONCPP_OSTREAM* sout)
|
int BuiltStyledStreamWriter::write(Value const& root, JSONCPP_OSTREAM* sout)
|
||||||
@ -933,7 +947,7 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) {
|
|||||||
pushValue(valueToString(value.asLargestUInt()));
|
pushValue(valueToString(value.asLargestUInt()));
|
||||||
break;
|
break;
|
||||||
case realValue:
|
case realValue:
|
||||||
pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_));
|
pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_, precisionType_));
|
||||||
break;
|
break;
|
||||||
case stringValue:
|
case stringValue:
|
||||||
{
|
{
|
||||||
@ -1145,6 +1159,7 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const
|
|||||||
{
|
{
|
||||||
JSONCPP_STRING indentation = settings_["indentation"].asString();
|
JSONCPP_STRING indentation = settings_["indentation"].asString();
|
||||||
JSONCPP_STRING cs_str = settings_["commentStyle"].asString();
|
JSONCPP_STRING cs_str = settings_["commentStyle"].asString();
|
||||||
|
JSONCPP_STRING pt_str = settings_["precisionType"].asString();
|
||||||
bool eyc = settings_["enableYAMLCompatibility"].asBool();
|
bool eyc = settings_["enableYAMLCompatibility"].asBool();
|
||||||
bool dnp = settings_["dropNullPlaceholders"].asBool();
|
bool dnp = settings_["dropNullPlaceholders"].asBool();
|
||||||
bool usf = settings_["useSpecialFloats"].asBool();
|
bool usf = settings_["useSpecialFloats"].asBool();
|
||||||
@ -1157,6 +1172,14 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const
|
|||||||
} else {
|
} else {
|
||||||
throwRuntimeError("commentStyle must be 'All' or 'None'");
|
throwRuntimeError("commentStyle must be 'All' or 'None'");
|
||||||
}
|
}
|
||||||
|
PrecisionType precisionType(significantDigits);
|
||||||
|
if (pt_str == "significant") {
|
||||||
|
precisionType = PrecisionType::significantDigits;
|
||||||
|
} else if (pt_str == "decimal") {
|
||||||
|
precisionType = PrecisionType::decimalPlaces;
|
||||||
|
} else {
|
||||||
|
throwRuntimeError("precisionType must be 'significant' or 'decimal'");
|
||||||
|
}
|
||||||
JSONCPP_STRING colonSymbol = " : ";
|
JSONCPP_STRING colonSymbol = " : ";
|
||||||
if (eyc) {
|
if (eyc) {
|
||||||
colonSymbol = ": ";
|
colonSymbol = ": ";
|
||||||
@ -1171,7 +1194,7 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const
|
|||||||
JSONCPP_STRING endingLineFeedSymbol;
|
JSONCPP_STRING endingLineFeedSymbol;
|
||||||
return new BuiltStyledStreamWriter(
|
return new BuiltStyledStreamWriter(
|
||||||
indentation, cs,
|
indentation, cs,
|
||||||
colonSymbol, nullSymbol, endingLineFeedSymbol, usf, pre);
|
colonSymbol, nullSymbol, endingLineFeedSymbol, usf, pre, precisionType);
|
||||||
}
|
}
|
||||||
static void getValidWriterKeys(std::set<JSONCPP_STRING>* valid_keys)
|
static void getValidWriterKeys(std::set<JSONCPP_STRING>* valid_keys)
|
||||||
{
|
{
|
||||||
@ -1182,6 +1205,7 @@ static void getValidWriterKeys(std::set<JSONCPP_STRING>* valid_keys)
|
|||||||
valid_keys->insert("dropNullPlaceholders");
|
valid_keys->insert("dropNullPlaceholders");
|
||||||
valid_keys->insert("useSpecialFloats");
|
valid_keys->insert("useSpecialFloats");
|
||||||
valid_keys->insert("precision");
|
valid_keys->insert("precision");
|
||||||
|
valid_keys->insert("precisionType");
|
||||||
}
|
}
|
||||||
bool StreamWriterBuilder::validate(Json::Value* invalid) const
|
bool StreamWriterBuilder::validate(Json::Value* invalid) const
|
||||||
{
|
{
|
||||||
@ -1214,6 +1238,7 @@ void StreamWriterBuilder::setDefaults(Json::Value* settings)
|
|||||||
(*settings)["dropNullPlaceholders"] = false;
|
(*settings)["dropNullPlaceholders"] = false;
|
||||||
(*settings)["useSpecialFloats"] = false;
|
(*settings)["useSpecialFloats"] = false;
|
||||||
(*settings)["precision"] = 17;
|
(*settings)["precision"] = 17;
|
||||||
|
(*settings)["precisionType"] = "significant";
|
||||||
//! [StreamWriterBuilderDefaults]
|
//! [StreamWriterBuilderDefaults]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1757,6 +1757,27 @@ JSONTEST_FIXTURE(ValueTest, precision) {
|
|||||||
expected = "0.25634569487374054";
|
expected = "0.25634569487374054";
|
||||||
result = Json::writeString(b, v);
|
result = Json::writeString(b, v);
|
||||||
JSONTEST_ASSERT_STRING_EQUAL(expected, result);
|
JSONTEST_ASSERT_STRING_EQUAL(expected, result);
|
||||||
|
|
||||||
|
b.settings_["precision"] = 5;
|
||||||
|
b.settings_["precisionType"] = "decimal";
|
||||||
|
v = 0.256345694873740545068;
|
||||||
|
expected = "0.25635";
|
||||||
|
result = Json::writeString(b, v);
|
||||||
|
JSONTEST_ASSERT_STRING_EQUAL(expected, result);
|
||||||
|
|
||||||
|
b.settings_["precision"] = 1;
|
||||||
|
b.settings_["precisionType"] = "decimal";
|
||||||
|
v = 0.256345694873740545068;
|
||||||
|
expected = "0.3";
|
||||||
|
result = Json::writeString(b, v);
|
||||||
|
JSONTEST_ASSERT_STRING_EQUAL(expected, result);
|
||||||
|
|
||||||
|
b.settings_["precision"] = 10;
|
||||||
|
b.settings_["precisionType"] = "decimal";
|
||||||
|
v = 0.23300000;
|
||||||
|
expected = "0.233";
|
||||||
|
result = Json::writeString(b, v);
|
||||||
|
JSONTEST_ASSERT_STRING_EQUAL(expected, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct WriterTest : JsonTest::TestCase {};
|
struct WriterTest : JsonTest::TestCase {};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user