Thanks to visit codestin.com
Credit goes to github.com

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)