Skip to content

Commit 768e31f

Browse files
authored
Merge pull request open-source-parsers#773 from BillyDonahue/precision
Improvements in writing precision and json_tool.h helpers. resolves open-source-parsers#772
2 parents cf73619 + aa1b383 commit 768e31f

File tree

2 files changed

+55
-52
lines changed

2 files changed

+55
-52
lines changed

src/lib_json/json_tool.h

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -88,41 +88,47 @@ static inline void uintToString(LargestUInt value, char*& current) {
8888
* We had a sophisticated way, but it did not work in WinCE.
8989
* @see https://github.com/open-source-parsers/jsoncpp/pull/9
9090
*/
91-
static inline void fixNumericLocale(char* begin, char* end) {
92-
while (begin < end) {
91+
template <typename Iter>
92+
Iter fixNumericLocale(Iter begin, Iter end) {
93+
for (; begin != end; ++begin) {
9394
if (*begin == ',') {
9495
*begin = '.';
9596
}
96-
++begin;
9797
}
98+
return begin;
9899
}
99100

100-
static inline void fixNumericLocaleInput(char* begin, char* end) {
101+
template <typename Iter>
102+
void fixNumericLocaleInput(Iter begin, Iter end) {
101103
char decimalPoint = getDecimalPoint();
102-
if (decimalPoint != '\0' && decimalPoint != '.') {
103-
while (begin < end) {
104-
if (*begin == '.') {
105-
*begin = decimalPoint;
106-
}
107-
++begin;
104+
if (decimalPoint == '\0' || decimalPoint == '.') {
105+
return;
106+
}
107+
for (; begin != end; ++begin) {
108+
if (*begin == '.') {
109+
*begin = decimalPoint;
108110
}
109111
}
110112
}
111113

112114
/**
113-
* Delete zeros in the end of string, if it isn't last zero before '.' character.
115+
* Return iterator that would be the new end of the range [begin,end), if we
116+
* were to delete zeros in the end of string, but not the last zero before '.'.
114117
*/
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';
118+
template <typename Iter>
119+
Iter fixZerosInTheEnd(Iter begin, Iter end) {
120+
for (; begin != end; --end) {
121+
if (*(end-1) != '0') {
122+
return end;
123+
}
124+
// Don't delete the last zero before the decimal point.
125+
if (begin != (end-1) && *(end-2) == '.') {
126+
return end;
121127
}
122-
end--;
123128
}
129+
return end;
124130
}
125131

126-
} // namespace Json {
132+
} // namespace Json
127133

128134
#endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED

src/lib_json/json_writer.cpp

Lines changed: 30 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -127,48 +127,45 @@ JSONCPP_STRING valueToString(UInt value) {
127127

128128
namespace {
129129
JSONCPP_STRING valueToString(double value, bool useSpecialFloats, unsigned int precision, PrecisionType precisionType) {
130-
// Allocate a buffer that is more than large enough to store the 16 digits of
131-
// precision requested below.
132-
char buffer[36];
133-
int len = -1;
134-
135-
char formatString[15];
136-
if (precisionType == PrecisionType::significantDigits) {
137-
snprintf(formatString, sizeof(formatString), "%%.%ug", precision);
138-
} else {
139-
snprintf(formatString, sizeof(formatString), "%%.%uf", precision);
140-
}
141-
142130
// Print into the buffer. We need not request the alternative representation
143131
// that always has a decimal point because JSON doesn't distinguish the
144132
// concepts of reals and integers.
145-
if (isfinite(value)) {
146-
len = snprintf(buffer, sizeof(buffer), formatString, value);
147-
fixNumericLocale(buffer, buffer + len);
148-
// to delete use-less too much zeros in the end of string
149-
if (precisionType == PrecisionType::decimalPlaces) {
150-
fixZerosInTheEnd(buffer, buffer + len);
151-
}
133+
if (!isfinite(value)) {
134+
static const char* const reps[2][3] = {
135+
{"NaN", "-Infinity", "Infinity"},
136+
{"null", "-1e+9999", "1e+9999"}};
137+
return reps[useSpecialFloats ? 0 : 1][isnan(value) ? 0 : (value < 0) ? 1 : 2];
138+
}
152139

153-
// try to ensure we preserve the fact that this was given to us as a double on input
154-
if (!strchr(buffer, '.') && !strchr(buffer, 'e')) {
155-
strcat(buffer, ".0");
156-
}
140+
JSONCPP_STRING buffer(size_t(36), '\0');
141+
while (true) {
142+
int len = snprintf(&*buffer.begin(), buffer.size(),
143+
(precisionType == PrecisionType::significantDigits) ? "%.*g" : "%.*f",
144+
precision, value);
145+
assert(len >= 0);
146+
size_t wouldPrint = static_cast<size_t>(len);
147+
if (wouldPrint >= buffer.size()) {
148+
buffer.resize(wouldPrint + 1);
149+
continue;
150+
}
151+
buffer.resize(wouldPrint);
152+
break;
153+
}
157154

158-
} else {
155+
buffer.erase(fixNumericLocale(buffer.begin(), buffer.end()), buffer.end());
159156

160-
if (isnan(value)) {
161-
len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "NaN" : "null");
162-
} else if (value < 0) {
163-
len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "-Infinity" : "-1e+9999");
164-
} else {
165-
len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "Infinity" : "1e+9999");
166-
}
157+
// strip the zero padding from the right
158+
if (precisionType == PrecisionType::decimalPlaces) {
159+
buffer.erase(fixZerosInTheEnd(buffer.begin(), buffer.end()), buffer.end());
160+
}
161+
162+
// try to ensure we preserve the fact that this was given to us as a double on input
163+
if (buffer.find('.') == buffer.npos && buffer.find('e') == buffer.npos) {
164+
buffer += ".0";
167165
}
168-
assert(len >= 0);
169166
return buffer;
170167
}
171-
}
168+
} // namespace
172169

173170
JSONCPP_STRING valueToString(double value, unsigned int precision, PrecisionType precisionType) {
174171
return valueToString(value, false, precision, precisionType);

0 commit comments

Comments
 (0)