-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Add setting precision for json writers and also add decimal places precision type. #752
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
43a2fc5
3d229ef
c86c4d0
caf639d
ec714b2
747e11a
857da44
4129da4
141ee3a
ab7337d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -118,21 +118,29 @@ 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 | ||
// concepts of reals and integers. | ||
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 @@ struct BuiltStyledStreamWriter : public StreamWriter | |
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") { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These names seem long and ambiguous. Maybe There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I used |
||
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] | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. okay, but we broke compability for guys who alreafy using "precision" option for their programs, but I don't think there are much of such people. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, you're right. I forgot about that. Yes, we need to keep the word "precision". I guess "precisionType" is fine. |
||
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 {}; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be
e
instead ofg
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking about saving old behaviour with
g
when used the shortest variant for float, because maybe some guys expect old behaviour from code. Maybe it is better to add third type fore
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right. Preserving the old way by default is a good idea.
I don't have an opinion on a third type.
Let's drop this latest commit. Then we can merge.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, i've dropped last commit. U can merge when test will be don.