mirror of
https://github.com/open-source-parsers/jsoncpp.git
synced 2024-12-26 18:51:04 +08: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
|
||||
};
|
||||
|
||||
/** \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
|
||||
// typedef CppTL::AnyEnumerator<const char *> EnumMemberNames;
|
||||
// typedef CppTL::AnyEnumerator<const Value &> EnumValues;
|
||||
@ -220,6 +227,9 @@ public:
|
||||
static const UInt64 maxUInt64;
|
||||
#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
|
||||
// when using gcc and clang backend compilers. CZString
|
||||
// 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:
|
||||
NaN values as "NaN", positive infinity as "Infinity", and negative 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
|
||||
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)
|
||||
JSONCPP_STRING JSON_API valueToString(LargestInt 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 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 {
|
||||
|
||||
#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 LargestUInt Value::maxLargestUInt = LargestUInt(-1);
|
||||
|
||||
const UInt Value::defaultRealPrecision = 17;
|
||||
|
||||
#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
|
||||
template <typename T, typename U>
|
||||
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)
|
||||
|
||||
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
|
||||
// precision requested below.
|
||||
char buffer[36];
|
||||
int len = -1;
|
||||
|
||||
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
|
||||
// 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)) {
|
||||
len = snprintf(buffer, sizeof(buffer), formatString, value);
|
||||
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
|
||||
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"; }
|
||||
|
||||
@ -856,7 +866,8 @@ struct BuiltStyledStreamWriter : public StreamWriter
|
||||
JSONCPP_STRING const& nullSymbol,
|
||||
JSONCPP_STRING const& endingLineFeedSymbol,
|
||||
bool useSpecialFloats,
|
||||
unsigned int precision);
|
||||
unsigned int precision,
|
||||
PrecisionType precisionType);
|
||||
int write(Value const& root, JSONCPP_OSTREAM* sout) JSONCPP_OVERRIDE;
|
||||
private:
|
||||
void writeValue(Value const& value);
|
||||
@ -885,6 +896,7 @@ private:
|
||||
bool indented_ : 1;
|
||||
bool useSpecialFloats_ : 1;
|
||||
unsigned int precision_;
|
||||
PrecisionType precisionType_;
|
||||
};
|
||||
BuiltStyledStreamWriter::BuiltStyledStreamWriter(
|
||||
JSONCPP_STRING const& indentation,
|
||||
@ -893,7 +905,8 @@ BuiltStyledStreamWriter::BuiltStyledStreamWriter(
|
||||
JSONCPP_STRING const& nullSymbol,
|
||||
JSONCPP_STRING const& endingLineFeedSymbol,
|
||||
bool useSpecialFloats,
|
||||
unsigned int precision)
|
||||
unsigned int precision,
|
||||
PrecisionType precisionType)
|
||||
: rightMargin_(74)
|
||||
, indentation_(indentation)
|
||||
, cs_(cs)
|
||||
@ -904,6 +917,7 @@ BuiltStyledStreamWriter::BuiltStyledStreamWriter(
|
||||
, indented_(false)
|
||||
, useSpecialFloats_(useSpecialFloats)
|
||||
, precision_(precision)
|
||||
, precisionType_(precisionType)
|
||||
{
|
||||
}
|
||||
int BuiltStyledStreamWriter::write(Value const& root, JSONCPP_OSTREAM* sout)
|
||||
@ -933,7 +947,7 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) {
|
||||
pushValue(valueToString(value.asLargestUInt()));
|
||||
break;
|
||||
case realValue:
|
||||
pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_));
|
||||
pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_, precisionType_));
|
||||
break;
|
||||
case stringValue:
|
||||
{
|
||||
@ -1145,6 +1159,7 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const
|
||||
{
|
||||
JSONCPP_STRING indentation = settings_["indentation"].asString();
|
||||
JSONCPP_STRING cs_str = settings_["commentStyle"].asString();
|
||||
JSONCPP_STRING pt_str = settings_["precisionType"].asString();
|
||||
bool eyc = settings_["enableYAMLCompatibility"].asBool();
|
||||
bool dnp = settings_["dropNullPlaceholders"].asBool();
|
||||
bool usf = settings_["useSpecialFloats"].asBool();
|
||||
@ -1157,6 +1172,14 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const
|
||||
} else {
|
||||
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 = " : ";
|
||||
if (eyc) {
|
||||
colonSymbol = ": ";
|
||||
@ -1171,7 +1194,7 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const
|
||||
JSONCPP_STRING endingLineFeedSymbol;
|
||||
return new BuiltStyledStreamWriter(
|
||||
indentation, cs,
|
||||
colonSymbol, nullSymbol, endingLineFeedSymbol, usf, pre);
|
||||
colonSymbol, nullSymbol, endingLineFeedSymbol, usf, pre, precisionType);
|
||||
}
|
||||
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("useSpecialFloats");
|
||||
valid_keys->insert("precision");
|
||||
valid_keys->insert("precisionType");
|
||||
}
|
||||
bool StreamWriterBuilder::validate(Json::Value* invalid) const
|
||||
{
|
||||
@ -1214,6 +1238,7 @@ void StreamWriterBuilder::setDefaults(Json::Value* settings)
|
||||
(*settings)["dropNullPlaceholders"] = false;
|
||||
(*settings)["useSpecialFloats"] = false;
|
||||
(*settings)["precision"] = 17;
|
||||
(*settings)["precisionType"] = "significant";
|
||||
//! [StreamWriterBuilderDefaults]
|
||||
}
|
||||
|
||||
|
@ -1757,6 +1757,27 @@ JSONTEST_FIXTURE(ValueTest, precision) {
|
||||
expected = "0.25634569487374054";
|
||||
result = Json::writeString(b, v);
|
||||
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 {};
|
||||
|
Loading…
x
Reference in New Issue
Block a user