Skip to content

Commit 772f634

Browse files
committed
Merge pull request open-source-parsers#381 from bknecht/precision
Resolves open-source-parsers#284
2 parents 9c17e61 + 9fd1ca8 commit 772f634

File tree

2 files changed

+56
-7
lines changed

2 files changed

+56
-7
lines changed

src/lib_json/json_writer.cpp

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -133,17 +133,20 @@ std::string valueToString(UInt value) {
133133

134134
#endif // # if defined(JSON_HAS_INT64)
135135

136-
std::string valueToString(double value, bool useSpecialFloats) {
136+
std::string valueToString(double value, bool useSpecialFloats, unsigned int precision) {
137137
// Allocate a buffer that is more than large enough to store the 16 digits of
138138
// precision requested below.
139139
char buffer[32];
140140
int len = -1;
141141

142+
char formatString[6];
143+
sprintf(formatString, "%%.%dg", precision);
144+
142145
// Print into the buffer. We need not request the alternative representation
143146
// that always has a decimal point because JSON doesn't distingish the
144147
// concepts of reals and integers.
145148
if (isfinite(value)) {
146-
len = snprintf(buffer, sizeof(buffer), "%.17g", value);
149+
len = snprintf(buffer, sizeof(buffer), formatString, value);
147150
} else {
148151
// IEEE standard states that NaN values will not compare to themselves
149152
if (value != value) {
@@ -160,7 +163,7 @@ std::string valueToString(double value, bool useSpecialFloats) {
160163
return buffer;
161164
}
162165

163-
std::string valueToString(double value) { return valueToString(value, false); }
166+
std::string valueToString(double value) { return valueToString(value, false, 17); }
164167

165168
std::string valueToString(bool value) { return value ? "true" : "false"; }
166169

@@ -832,7 +835,8 @@ struct BuiltStyledStreamWriter : public StreamWriter
832835
std::string const& colonSymbol,
833836
std::string const& nullSymbol,
834837
std::string const& endingLineFeedSymbol,
835-
bool useSpecialFloats);
838+
bool useSpecialFloats,
839+
unsigned int precision);
836840
int write(Value const& root, std::ostream* sout) override;
837841
private:
838842
void writeValue(Value const& value);
@@ -860,14 +864,16 @@ struct BuiltStyledStreamWriter : public StreamWriter
860864
bool addChildValues_ : 1;
861865
bool indented_ : 1;
862866
bool useSpecialFloats_ : 1;
867+
unsigned int precision_;
863868
};
864869
BuiltStyledStreamWriter::BuiltStyledStreamWriter(
865870
std::string const& indentation,
866871
CommentStyle::Enum cs,
867872
std::string const& colonSymbol,
868873
std::string const& nullSymbol,
869874
std::string const& endingLineFeedSymbol,
870-
bool useSpecialFloats)
875+
bool useSpecialFloats,
876+
unsigned int precision)
871877
: rightMargin_(74)
872878
, indentation_(indentation)
873879
, cs_(cs)
@@ -877,6 +883,7 @@ BuiltStyledStreamWriter::BuiltStyledStreamWriter(
877883
, addChildValues_(false)
878884
, indented_(false)
879885
, useSpecialFloats_(useSpecialFloats)
886+
, precision_(precision)
880887
{
881888
}
882889
int BuiltStyledStreamWriter::write(Value const& root, std::ostream* sout)
@@ -906,7 +913,7 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) {
906913
pushValue(valueToString(value.asLargestUInt()));
907914
break;
908915
case realValue:
909-
pushValue(valueToString(value.asDouble(), useSpecialFloats_));
916+
pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_));
910917
break;
911918
case stringValue:
912919
{
@@ -1121,6 +1128,7 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const
11211128
bool eyc = settings_["enableYAMLCompatibility"].asBool();
11221129
bool dnp = settings_["dropNullPlaceholders"].asBool();
11231130
bool usf = settings_["useSpecialFloats"].asBool();
1131+
unsigned int pre = settings_["precision"].asUInt();
11241132
CommentStyle::Enum cs = CommentStyle::All;
11251133
if (cs_str == "All") {
11261134
cs = CommentStyle::All;
@@ -1139,10 +1147,11 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const
11391147
if (dnp) {
11401148
nullSymbol = "";
11411149
}
1150+
if (pre > 17) pre = 17;
11421151
std::string endingLineFeedSymbol = "";
11431152
return new BuiltStyledStreamWriter(
11441153
indentation, cs,
1145-
colonSymbol, nullSymbol, endingLineFeedSymbol, usf);
1154+
colonSymbol, nullSymbol, endingLineFeedSymbol, usf, pre);
11461155
}
11471156
static void getValidWriterKeys(std::set<std::string>* valid_keys)
11481157
{
@@ -1152,6 +1161,7 @@ static void getValidWriterKeys(std::set<std::string>* valid_keys)
11521161
valid_keys->insert("enableYAMLCompatibility");
11531162
valid_keys->insert("dropNullPlaceholders");
11541163
valid_keys->insert("useSpecialFloats");
1164+
valid_keys->insert("precision");
11551165
}
11561166
bool StreamWriterBuilder::validate(Json::Value* invalid) const
11571167
{
@@ -1183,6 +1193,7 @@ void StreamWriterBuilder::setDefaults(Json::Value* settings)
11831193
(*settings)["enableYAMLCompatibility"] = false;
11841194
(*settings)["dropNullPlaceholders"] = false;
11851195
(*settings)["useSpecialFloats"] = false;
1196+
(*settings)["precision"] = 17;
11861197
//! [StreamWriterBuilderDefaults]
11871198
}
11881199

src/test_lib_json/main.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1675,6 +1675,43 @@ JSONTEST_FIXTURE(ValueTest, specialFloats) {
16751675
JSONTEST_ASSERT_STRING_EQUAL(expected, result);
16761676
}
16771677

1678+
JSONTEST_FIXTURE(ValueTest, precision) {
1679+
Json::StreamWriterBuilder b;
1680+
b.settings_["precision"] = 5;
1681+
1682+
Json::Value v = 100.0/3;
1683+
std::string expected = "33.333";
1684+
std::string result = Json::writeString(b, v);
1685+
JSONTEST_ASSERT_STRING_EQUAL(expected, result);
1686+
1687+
v = 0.25000000;
1688+
expected = "0.25";
1689+
result = Json::writeString(b, v);
1690+
JSONTEST_ASSERT_STRING_EQUAL(expected, result);
1691+
1692+
v = 0.2563456;
1693+
expected = "0.25635";
1694+
result = Json::writeString(b, v);
1695+
JSONTEST_ASSERT_STRING_EQUAL(expected, result);
1696+
1697+
b.settings_["precision"] = 1;
1698+
expected = "0.3";
1699+
result = Json::writeString(b, v);
1700+
JSONTEST_ASSERT_STRING_EQUAL(expected, result);
1701+
1702+
b.settings_["precision"] = 17;
1703+
v = 1234857476305.256345694873740545068;
1704+
expected = "1234857476305.2563";
1705+
result = Json::writeString(b, v);
1706+
JSONTEST_ASSERT_STRING_EQUAL(expected, result);
1707+
1708+
b.settings_["precision"] = 24;
1709+
v = 0.256345694873740545068;
1710+
expected = "0.25634569487374054";
1711+
result = Json::writeString(b, v);
1712+
JSONTEST_ASSERT_STRING_EQUAL(expected, result);
1713+
}
1714+
16781715
struct WriterTest : JsonTest::TestCase {};
16791716

16801717
JSONTEST_FIXTURE(WriterTest, dropNullPlaceholders) {
@@ -2489,6 +2526,7 @@ int main(int argc, const char* argv[]) {
24892526
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, zeroes);
24902527
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, zeroesInKeys);
24912528
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, specialFloats);
2529+
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, precision);
24922530

24932531
JSONTEST_REGISTER_FIXTURE(runner, WriterTest, dropNullPlaceholders);
24942532
JSONTEST_REGISTER_FIXTURE(runner, StreamWriterTest, dropNullPlaceholders);

0 commit comments

Comments
 (0)