Writer: add SetDoublePrecision to control number of significant digits

Writing a double to an OutputStream current prints at most 6 significant
digits (according to the C standard).

The function SetDoublePrecision(), added to the Writer classes
can be used to fluently set the precision, i.e. the number of
significant digits to use for writing the double:

  Writer<...> writer(...);
  d.Accept(writer.SetDoublePrecision(12));
This commit is contained in:
Philipp A. Hartmann 2014-02-28 13:57:13 +01:00
parent 60b8c11909
commit 0ccc51fbae
2 changed files with 43 additions and 6 deletions

View File

@ -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.

View File

@ -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,6 +61,18 @@ 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; }
Writer& String(const Ch* str, SizeType length, bool copy = false) { Writer& String(const Ch* str, SizeType length, bool copy = false) {
@ -161,18 +189,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 +265,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