diff --git a/include/rapidjson/prettywriter.h b/include/rapidjson/prettywriter.h index 2a0a505f..07ed92fc 100644 --- a/include/rapidjson/prettywriter.h +++ b/include/rapidjson/prettywriter.h @@ -25,6 +25,9 @@ class PrettyWriter : public 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; } + //! 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) { (void)copy; Prefix(kStringType); @@ -161,18 +203,21 @@ class Writer { } 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. void WriteDouble(double d) { char buffer[100]; -#if _MSC_VER - int ret = sprintf_s(buffer, sizeof(buffer), "%g", d); -#else - int ret = snprintf(buffer, sizeof(buffer), "%g", d); -#endif + int ret = RAPIDJSON_SNPRINTF(buffer, sizeof(buffer), "%.*g", doublePrecision_, d); RAPIDJSON_ASSERT(ret >= 1); for (int i = 0; i < ret; i++) os_.Put(buffer[i]); } +#undef RAPIDJSON_SNPRINTF 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' }; @@ -234,6 +279,9 @@ class Writer { OutputStream& os_; internal::Stack level_stack_; + int doublePrecision_; + + static const int kDefaultDoublePrecision = 6; private: // Prohibit assignment for VC C4512 warning diff --git a/test/unittest/writertest.cpp b/test/unittest/writertest.cpp index 9d81018e..f198b890 100644 --- a/test/unittest/writertest.cpp +++ b/test/unittest/writertest.cpp @@ -1,4 +1,5 @@ #include "unittest.h" +#include "rapidjson/document.h" #include "rapidjson/reader.h" #include "rapidjson/writer.h" #include "rapidjson/stringbuffer.h" @@ -56,6 +57,61 @@ TEST(Writer, String) { TEST_ROUNDTRIP("[\"\\\"\\\\/\\b\\f\\n\\r\\t\"]"); } +TEST(Writer,DoublePrecision) { + const char json[] = "[1.2345,1.2345678,0.123456789012,1234567.8]"; + + StringBuffer buffer; + Writer 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) { // 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\" } ");