Skip to content

Commit a07fc53

Browse files
melonaerialcdunn2001
authored andcommitted
Add setting precision for json writers and also add decimal places precision type. (open-source-parsers#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.
1 parent af2598c commit a07fc53

File tree

6 files changed

+85
-8
lines changed

6 files changed

+85
-8
lines changed

include/json/value.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,13 @@ enum CommentPlacement {
109109
numberOfCommentPlacement
110110
};
111111

112+
/** \brief Type of precision for formatting of real values.
113+
*/
114+
enum PrecisionType {
115+
significantDigits = 0, ///< we set max number of significant digits in string
116+
decimalPlaces ///< we set max number of digits after "." in string
117+
};
118+
112119
//# ifdef JSON_USE_CPPTL
113120
// typedef CppTL::AnyEnumerator<const char *> EnumMemberNames;
114121
// typedef CppTL::AnyEnumerator<const Value &> EnumValues;
@@ -220,6 +227,9 @@ class JSON_API Value {
220227
static const UInt64 maxUInt64;
221228
#endif // defined(JSON_HAS_INT64)
222229

230+
/// Default precision for real value for string representation.
231+
static const UInt defaultRealPrecision;
232+
223233
// Workaround for bug in the NVIDIAs CUDA 9.1 nvcc compiler
224234
// when using gcc and clang backend compilers. CZString
225235
// cannot be defined as private. See issue #486

include/json/writer.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,10 @@ class JSON_API StreamWriterBuilder : public StreamWriter::Factory {
106106
- If true, outputs non-finite floating point values in the following way:
107107
NaN values as "NaN", positive infinity as "Infinity", and negative infinity
108108
as "-Infinity".
109+
- "precision": int
110+
- Number of precision digits for formatting of real values.
111+
- "precisionType": "significant"(default) or "decimal"
112+
- Type of precision for formatting of real values.
109113
110114
You can examine 'settings_` yourself
111115
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);
339343
#endif // if defined(JSON_HAS_INT64)
340344
JSONCPP_STRING JSON_API valueToString(LargestInt value);
341345
JSONCPP_STRING JSON_API valueToString(LargestUInt value);
342-
JSONCPP_STRING JSON_API valueToString(double value);
346+
JSONCPP_STRING JSON_API valueToString(double value, unsigned int precision = Value::defaultRealPrecision,
347+
PrecisionType precisionType = PrecisionType::significantDigits);
343348
JSONCPP_STRING JSON_API valueToString(bool value);
344349
JSONCPP_STRING JSON_API valueToQuotedString(const char* value);
345350

src/lib_json/json_tool.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,20 @@ static inline void fixNumericLocaleInput(char* begin, char* end) {
109109
}
110110
}
111111

112+
/**
113+
* Delete zeros in the end of string, if it isn't last zero before '.' character.
114+
*/
115+
static inline void fixZerosInTheEnd(char* begin, char* end) {
116+
end--;
117+
while ((begin < end) && (*end == '0')) {
118+
// don't delete last zero before point.
119+
if (*(end - 1) != '.') {
120+
*end = '\0';
121+
}
122+
end--;
123+
}
124+
}
125+
112126
} // namespace Json {
113127

114128
#endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED

src/lib_json/json_value.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ const LargestInt Value::minLargestInt = LargestInt(~(LargestUInt(-1) / 2));
6464
const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2);
6565
const LargestUInt Value::maxLargestUInt = LargestUInt(-1);
6666

67+
const UInt Value::defaultRealPrecision = 17;
68+
6769
#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
6870
template <typename T, typename U>
6971
static inline bool InRange(double d, T min, U max) {

src/lib_json/json_writer.cpp

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -118,21 +118,29 @@ JSONCPP_STRING valueToString(UInt value) {
118118
#endif // # if defined(JSON_HAS_INT64)
119119

120120
namespace {
121-
JSONCPP_STRING valueToString(double value, bool useSpecialFloats, unsigned int precision) {
121+
JSONCPP_STRING valueToString(double value, bool useSpecialFloats, unsigned int precision, PrecisionType precisionType) {
122122
// Allocate a buffer that is more than large enough to store the 16 digits of
123123
// precision requested below.
124124
char buffer[36];
125125
int len = -1;
126126

127127
char formatString[15];
128-
snprintf(formatString, sizeof(formatString), "%%.%ug", precision);
128+
if (precisionType == PrecisionType::significantDigits) {
129+
snprintf(formatString, sizeof(formatString), "%%.%ug", precision);
130+
} else {
131+
snprintf(formatString, sizeof(formatString), "%%.%uf", precision);
132+
}
129133

130134
// Print into the buffer. We need not request the alternative representation
131135
// that always has a decimal point because JSON doesn't distinguish the
132136
// concepts of reals and integers.
133137
if (isfinite(value)) {
134138
len = snprintf(buffer, sizeof(buffer), formatString, value);
135139
fixNumericLocale(buffer, buffer + len);
140+
// to delete use-less too much zeros in the end of string
141+
if (precisionType == PrecisionType::decimalPlaces) {
142+
fixZerosInTheEnd(buffer, buffer + len);
143+
}
136144

137145
// try to ensure we preserve the fact that this was given to us as a double on input
138146
if (!strchr(buffer, '.') && !strchr(buffer, 'e')) {
@@ -154,7 +162,9 @@ JSONCPP_STRING valueToString(double value, bool useSpecialFloats, unsigned int p
154162
}
155163
}
156164

157-
JSONCPP_STRING valueToString(double value) { return valueToString(value, false, 17); }
165+
JSONCPP_STRING valueToString(double value, unsigned int precision, PrecisionType precisionType) {
166+
return valueToString(value, false, precision, precisionType);
167+
}
158168

159169
JSONCPP_STRING valueToString(bool value) { return value ? "true" : "false"; }
160170

@@ -856,7 +866,8 @@ struct BuiltStyledStreamWriter : public StreamWriter
856866
JSONCPP_STRING const& nullSymbol,
857867
JSONCPP_STRING const& endingLineFeedSymbol,
858868
bool useSpecialFloats,
859-
unsigned int precision);
869+
unsigned int precision,
870+
PrecisionType precisionType);
860871
int write(Value const& root, JSONCPP_OSTREAM* sout) JSONCPP_OVERRIDE;
861872
private:
862873
void writeValue(Value const& value);
@@ -885,6 +896,7 @@ struct BuiltStyledStreamWriter : public StreamWriter
885896
bool indented_ : 1;
886897
bool useSpecialFloats_ : 1;
887898
unsigned int precision_;
899+
PrecisionType precisionType_;
888900
};
889901
BuiltStyledStreamWriter::BuiltStyledStreamWriter(
890902
JSONCPP_STRING const& indentation,
@@ -893,7 +905,8 @@ BuiltStyledStreamWriter::BuiltStyledStreamWriter(
893905
JSONCPP_STRING const& nullSymbol,
894906
JSONCPP_STRING const& endingLineFeedSymbol,
895907
bool useSpecialFloats,
896-
unsigned int precision)
908+
unsigned int precision,
909+
PrecisionType precisionType)
897910
: rightMargin_(74)
898911
, indentation_(indentation)
899912
, cs_(cs)
@@ -904,6 +917,7 @@ BuiltStyledStreamWriter::BuiltStyledStreamWriter(
904917
, indented_(false)
905918
, useSpecialFloats_(useSpecialFloats)
906919
, precision_(precision)
920+
, precisionType_(precisionType)
907921
{
908922
}
909923
int BuiltStyledStreamWriter::write(Value const& root, JSONCPP_OSTREAM* sout)
@@ -933,7 +947,7 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) {
933947
pushValue(valueToString(value.asLargestUInt()));
934948
break;
935949
case realValue:
936-
pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_));
950+
pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_, precisionType_));
937951
break;
938952
case stringValue:
939953
{
@@ -1145,6 +1159,7 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const
11451159
{
11461160
JSONCPP_STRING indentation = settings_["indentation"].asString();
11471161
JSONCPP_STRING cs_str = settings_["commentStyle"].asString();
1162+
JSONCPP_STRING pt_str = settings_["precisionType"].asString();
11481163
bool eyc = settings_["enableYAMLCompatibility"].asBool();
11491164
bool dnp = settings_["dropNullPlaceholders"].asBool();
11501165
bool usf = settings_["useSpecialFloats"].asBool();
@@ -1157,6 +1172,14 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const
11571172
} else {
11581173
throwRuntimeError("commentStyle must be 'All' or 'None'");
11591174
}
1175+
PrecisionType precisionType(significantDigits);
1176+
if (pt_str == "significant") {
1177+
precisionType = PrecisionType::significantDigits;
1178+
} else if (pt_str == "decimal") {
1179+
precisionType = PrecisionType::decimalPlaces;
1180+
} else {
1181+
throwRuntimeError("precisionType must be 'significant' or 'decimal'");
1182+
}
11601183
JSONCPP_STRING colonSymbol = " : ";
11611184
if (eyc) {
11621185
colonSymbol = ": ";
@@ -1171,7 +1194,7 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const
11711194
JSONCPP_STRING endingLineFeedSymbol;
11721195
return new BuiltStyledStreamWriter(
11731196
indentation, cs,
1174-
colonSymbol, nullSymbol, endingLineFeedSymbol, usf, pre);
1197+
colonSymbol, nullSymbol, endingLineFeedSymbol, usf, pre, precisionType);
11751198
}
11761199
static void getValidWriterKeys(std::set<JSONCPP_STRING>* valid_keys)
11771200
{
@@ -1182,6 +1205,7 @@ static void getValidWriterKeys(std::set<JSONCPP_STRING>* valid_keys)
11821205
valid_keys->insert("dropNullPlaceholders");
11831206
valid_keys->insert("useSpecialFloats");
11841207
valid_keys->insert("precision");
1208+
valid_keys->insert("precisionType");
11851209
}
11861210
bool StreamWriterBuilder::validate(Json::Value* invalid) const
11871211
{
@@ -1214,6 +1238,7 @@ void StreamWriterBuilder::setDefaults(Json::Value* settings)
12141238
(*settings)["dropNullPlaceholders"] = false;
12151239
(*settings)["useSpecialFloats"] = false;
12161240
(*settings)["precision"] = 17;
1241+
(*settings)["precisionType"] = "significant";
12171242
//! [StreamWriterBuilderDefaults]
12181243
}
12191244

src/test_lib_json/main.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1757,6 +1757,27 @@ JSONTEST_FIXTURE(ValueTest, precision) {
17571757
expected = "0.25634569487374054";
17581758
result = Json::writeString(b, v);
17591759
JSONTEST_ASSERT_STRING_EQUAL(expected, result);
1760+
1761+
b.settings_["precision"] = 5;
1762+
b.settings_["precisionType"] = "decimal";
1763+
v = 0.256345694873740545068;
1764+
expected = "0.25635";
1765+
result = Json::writeString(b, v);
1766+
JSONTEST_ASSERT_STRING_EQUAL(expected, result);
1767+
1768+
b.settings_["precision"] = 1;
1769+
b.settings_["precisionType"] = "decimal";
1770+
v = 0.256345694873740545068;
1771+
expected = "0.3";
1772+
result = Json::writeString(b, v);
1773+
JSONTEST_ASSERT_STRING_EQUAL(expected, result);
1774+
1775+
b.settings_["precision"] = 10;
1776+
b.settings_["precisionType"] = "decimal";
1777+
v = 0.23300000;
1778+
expected = "0.233";
1779+
result = Json::writeString(b, v);
1780+
JSONTEST_ASSERT_STRING_EQUAL(expected, result);
17601781
}
17611782

17621783
struct WriterTest : JsonTest::TestCase {};

0 commit comments

Comments
 (0)