Merge pull request #19 from pah/feature/double-precision
User-defined double output precision
This commit is contained in:
commit
d5add05c9a
@ -26,6 +26,9 @@ public:
|
|||||||
PrettyWriter(OutputStream& os, Allocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
|
PrettyWriter(OutputStream& os, Allocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
|
||||||
Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}
|
Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}
|
||||||
|
|
||||||
|
//! Overridden for fluent API, see \ref Writer::SetDoublePrecision()
|
||||||
|
PrettyWriter& SetDoublePrecision(int p) { Base::SetDoublePrecision(p); return *this; }
|
||||||
|
|
||||||
//! Set custom indentation.
|
//! Set custom indentation.
|
||||||
/*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r').
|
/*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r').
|
||||||
\param indentCharCount Number of indent characters for each indentation level.
|
\param indentCharCount Number of indent characters for each indentation level.
|
||||||
@ -48,6 +51,11 @@ public:
|
|||||||
PrettyWriter& Int64(int64_t i64) { PrettyPrefix(kNumberType); Base::WriteInt64(i64); return *this; }
|
PrettyWriter& Int64(int64_t i64) { PrettyPrefix(kNumberType); Base::WriteInt64(i64); return *this; }
|
||||||
PrettyWriter& Uint64(uint64_t u64) { PrettyPrefix(kNumberType); Base::WriteUint64(u64); return *this; }
|
PrettyWriter& Uint64(uint64_t u64) { PrettyPrefix(kNumberType); Base::WriteUint64(u64); return *this; }
|
||||||
PrettyWriter& Double(double d) { PrettyPrefix(kNumberType); Base::WriteDouble(d); return *this; }
|
PrettyWriter& Double(double d) { PrettyPrefix(kNumberType); Base::WriteDouble(d); return *this; }
|
||||||
|
//! Overridden for fluent API, see \ref Writer::Double()
|
||||||
|
PrettyWriter& Double(double d, int precision) {
|
||||||
|
int oldPrecision = Base::GetDoublePrecision();
|
||||||
|
return SetDoublePrecision(precision).Double(d).SetDoublePrecision(oldPrecision);
|
||||||
|
}
|
||||||
|
|
||||||
PrettyWriter& String(const Ch* str, SizeType length, bool copy = false) {
|
PrettyWriter& String(const Ch* str, SizeType length, bool copy = false) {
|
||||||
(void)copy;
|
(void)copy;
|
||||||
|
@ -35,7 +35,23 @@ public:
|
|||||||
typedef typename SourceEncoding::Ch Ch;
|
typedef typename SourceEncoding::Ch Ch;
|
||||||
|
|
||||||
Writer(OutputStream& os, Allocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
|
Writer(OutputStream& os, Allocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
|
||||||
os_(os), level_stack_(allocator, levelDepth * sizeof(Level)) {}
|
os_(os), level_stack_(allocator, levelDepth * sizeof(Level)),
|
||||||
|
doublePrecision_(kDefaultDoublePrecision) {}
|
||||||
|
|
||||||
|
//! Set the number of significant digits for \c double values
|
||||||
|
/*! When writing a \c double value to the \c OutputStream, the number
|
||||||
|
of significant digits is limited to 6 by default.
|
||||||
|
\param p maximum number of significant digits (default: 6)
|
||||||
|
\return The Writer itself for fluent API.
|
||||||
|
*/
|
||||||
|
Writer& SetDoublePrecision(int p = kDefaultDoublePrecision) {
|
||||||
|
if (p < 0) p = kDefaultDoublePrecision; // negative precision is ignored
|
||||||
|
doublePrecision_ = p;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \see SetDoublePrecision()
|
||||||
|
int GetDoublePrecision() const { return doublePrecision_; }
|
||||||
|
|
||||||
//@name Implementation of Handler
|
//@name Implementation of Handler
|
||||||
//@{
|
//@{
|
||||||
@ -45,8 +61,34 @@ public:
|
|||||||
Writer& Uint(unsigned u) { Prefix(kNumberType); WriteUint(u); return *this; }
|
Writer& Uint(unsigned u) { Prefix(kNumberType); WriteUint(u); return *this; }
|
||||||
Writer& Int64(int64_t i64) { Prefix(kNumberType); WriteInt64(i64); return *this; }
|
Writer& Int64(int64_t i64) { Prefix(kNumberType); WriteInt64(i64); return *this; }
|
||||||
Writer& Uint64(uint64_t u64) { Prefix(kNumberType); WriteUint64(u64); return *this; }
|
Writer& Uint64(uint64_t u64) { Prefix(kNumberType); WriteUint64(u64); return *this; }
|
||||||
|
|
||||||
|
//! Writes the given \c double value to the stream
|
||||||
|
/*!
|
||||||
|
The number of significant digits (the precision) to be written
|
||||||
|
can be set by \ref SetDoublePrecision() for the Writer:
|
||||||
|
\code
|
||||||
|
Writer<...> writer(...);
|
||||||
|
writer.SetDoublePrecision(12).Double(M_PI);
|
||||||
|
\endcode
|
||||||
|
\param d The value to be written.
|
||||||
|
\return The Writer itself for fluent API.
|
||||||
|
*/
|
||||||
Writer& Double(double d) { Prefix(kNumberType); WriteDouble(d); return *this; }
|
Writer& Double(double d) { Prefix(kNumberType); WriteDouble(d); return *this; }
|
||||||
|
|
||||||
|
//! Writes the given \c double value to the stream (explicit precision)
|
||||||
|
/*!
|
||||||
|
The currently set double precision is ignored in favor of the explicitly
|
||||||
|
given precision for this value.
|
||||||
|
\see Double(), SetDoublePrecision(), GetDoublePrecision()
|
||||||
|
\param d The value to be written
|
||||||
|
\param precision The number of significant digits for this value
|
||||||
|
\return The Writer itself for fluent API.
|
||||||
|
*/
|
||||||
|
Writer& Double(double d, int precision) {
|
||||||
|
int oldPrecision = GetDoublePrecision();
|
||||||
|
return SetDoublePrecision(precision).Double(d).SetDoublePrecision(oldPrecision);
|
||||||
|
}
|
||||||
|
|
||||||
Writer& String(const Ch* str, SizeType length, bool copy = false) {
|
Writer& String(const Ch* str, SizeType length, bool copy = false) {
|
||||||
(void)copy;
|
(void)copy;
|
||||||
Prefix(kStringType);
|
Prefix(kStringType);
|
||||||
@ -161,18 +203,21 @@ protected:
|
|||||||
} while (p != buffer);
|
} while (p != buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define RAPIDJSON_SNPRINTF sprintf_s
|
||||||
|
#else
|
||||||
|
#define RAPIDJSON_SNPRINTF snprintf
|
||||||
|
#endif
|
||||||
|
|
||||||
//! \todo Optimization with custom double-to-string converter.
|
//! \todo Optimization with custom double-to-string converter.
|
||||||
void WriteDouble(double d) {
|
void WriteDouble(double d) {
|
||||||
char buffer[100];
|
char buffer[100];
|
||||||
#ifdef _MSC_VER
|
int ret = RAPIDJSON_SNPRINTF(buffer, sizeof(buffer), "%.*g", doublePrecision_, d);
|
||||||
int ret = sprintf_s(buffer, sizeof(buffer), "%g", d);
|
|
||||||
#else
|
|
||||||
int ret = snprintf(buffer, sizeof(buffer), "%g", d);
|
|
||||||
#endif
|
|
||||||
RAPIDJSON_ASSERT(ret >= 1);
|
RAPIDJSON_ASSERT(ret >= 1);
|
||||||
for (int i = 0; i < ret; i++)
|
for (int i = 0; i < ret; i++)
|
||||||
os_.Put(buffer[i]);
|
os_.Put(buffer[i]);
|
||||||
}
|
}
|
||||||
|
#undef RAPIDJSON_SNPRINTF
|
||||||
|
|
||||||
void WriteString(const Ch* str, SizeType length) {
|
void WriteString(const Ch* str, SizeType length) {
|
||||||
static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
|
static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
|
||||||
@ -234,6 +279,9 @@ protected:
|
|||||||
|
|
||||||
OutputStream& os_;
|
OutputStream& os_;
|
||||||
internal::Stack<Allocator> level_stack_;
|
internal::Stack<Allocator> level_stack_;
|
||||||
|
int doublePrecision_;
|
||||||
|
|
||||||
|
static const int kDefaultDoublePrecision = 6;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Prohibit assignment for VC C4512 warning
|
// Prohibit assignment for VC C4512 warning
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "unittest.h"
|
#include "unittest.h"
|
||||||
|
#include "rapidjson/document.h"
|
||||||
#include "rapidjson/reader.h"
|
#include "rapidjson/reader.h"
|
||||||
#include "rapidjson/writer.h"
|
#include "rapidjson/writer.h"
|
||||||
#include "rapidjson/stringbuffer.h"
|
#include "rapidjson/stringbuffer.h"
|
||||||
@ -56,6 +57,61 @@ TEST(Writer, String) {
|
|||||||
TEST_ROUNDTRIP("[\"\\\"\\\\/\\b\\f\\n\\r\\t\"]");
|
TEST_ROUNDTRIP("[\"\\\"\\\\/\\b\\f\\n\\r\\t\"]");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(Writer,DoublePrecision) {
|
||||||
|
const char json[] = "[1.2345,1.2345678,0.123456789012,1234567.8]";
|
||||||
|
|
||||||
|
StringBuffer buffer;
|
||||||
|
Writer<StringBuffer> writer(buffer);
|
||||||
|
|
||||||
|
const int kDefaultDoublePrecision = 6;
|
||||||
|
// handling the double precision
|
||||||
|
EXPECT_EQ(writer.GetDoublePrecision(), kDefaultDoublePrecision);
|
||||||
|
writer.SetDoublePrecision(17);
|
||||||
|
EXPECT_EQ(writer.GetDoublePrecision(), 17);
|
||||||
|
writer.SetDoublePrecision(-1); // negative equivalent to reset
|
||||||
|
EXPECT_EQ(writer.GetDoublePrecision(), kDefaultDoublePrecision);
|
||||||
|
writer.SetDoublePrecision(1);
|
||||||
|
writer.SetDoublePrecision(); // reset again
|
||||||
|
EXPECT_EQ(writer.GetDoublePrecision(), kDefaultDoublePrecision);
|
||||||
|
|
||||||
|
{ // write with explicitly increased precision
|
||||||
|
StringStream s(json);
|
||||||
|
Reader reader;
|
||||||
|
reader.Parse<0>(s, writer.SetDoublePrecision(12));
|
||||||
|
EXPECT_EQ(writer.GetDoublePrecision(), 12);
|
||||||
|
EXPECT_STREQ(json, buffer.GetString());
|
||||||
|
buffer.Clear();
|
||||||
|
}
|
||||||
|
{ // explicit individual double precisions
|
||||||
|
writer.SetDoublePrecision(2)
|
||||||
|
.StartArray()
|
||||||
|
.Double(1.2345,5)
|
||||||
|
.Double(1.2345678,9)
|
||||||
|
.Double(0.123456789012,12)
|
||||||
|
.Double(1234567.8,8)
|
||||||
|
.EndArray();
|
||||||
|
|
||||||
|
EXPECT_EQ(writer.GetDoublePrecision(), 2);
|
||||||
|
EXPECT_STREQ(json, buffer.GetString());
|
||||||
|
buffer.Clear();
|
||||||
|
}
|
||||||
|
{ // write with default precision (output with precision loss)
|
||||||
|
Document d;
|
||||||
|
d.Parse<0>(json);
|
||||||
|
d.Accept(writer.SetDoublePrecision());
|
||||||
|
|
||||||
|
// parsed again to avoid platform-dependent floating point outputs
|
||||||
|
// (e.g. width of exponents)
|
||||||
|
d.Parse<0>(buffer.GetString());
|
||||||
|
EXPECT_EQ(writer.GetDoublePrecision(), kDefaultDoublePrecision);
|
||||||
|
EXPECT_DOUBLE_EQ(d[0u].GetDouble(), 1.2345);
|
||||||
|
EXPECT_DOUBLE_EQ(d[1u].GetDouble(), 1.23457);
|
||||||
|
EXPECT_DOUBLE_EQ(d[2u].GetDouble(), 0.123457);
|
||||||
|
EXPECT_DOUBLE_EQ(d[3u].GetDouble(), 1234570);
|
||||||
|
buffer.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TEST(Writer, Transcode) {
|
TEST(Writer, Transcode) {
|
||||||
// UTF8 -> UTF16 -> UTF8
|
// UTF8 -> UTF16 -> UTF8
|
||||||
StringStream s("{ \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3], \"dollar\":\"\x24\", \"cents\":\"\xC2\xA2\", \"euro\":\"\xE2\x82\xAC\", \"gclef\":\"\xF0\x9D\x84\x9E\" } ");
|
StringStream s("{ \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3], \"dollar\":\"\x24\", \"cents\":\"\xC2\xA2\", \"euro\":\"\xE2\x82\xAC\", \"gclef\":\"\xF0\x9D\x84\x9E\" } ");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user