diff --git a/doc/jsoncpp.dox b/doc/jsoncpp.dox index 2c19664..fe06d50 100644 --- a/doc/jsoncpp.dox +++ b/doc/jsoncpp.dox @@ -81,8 +81,8 @@ root["indent"]["use_space"] = getCurrentIndentUseSpace(); // To write into a steam with minimal memory overhead, // create a Builder for a StreamWriter. -Json::StreamWriter::Builder builder; -builder.withIndentation(" "); // or whatever you like +Json::StreamWriterBuilder builder; +builder.indentation_ = " "; // or whatever you like // Then build a StreamWriter. std::shared_ptr writer( @@ -94,6 +94,9 @@ writer->write( root ); // If you like the defaults, you can insert directly into a stream. std::cout << root; +// If desired, remember to add a linefeed and flush. +std::cout << std::endl; + // Of course, you can write to `std::ostringstream` if you prefer. Or // use `writeString()` for convenience. std::string document = Json::writeString( root, builder ); diff --git a/include/json/writer.h b/include/json/writer.h index 5407906..be8ea38 100644 --- a/include/json/writer.h +++ b/include/json/writer.h @@ -11,6 +11,7 @@ #endif // if !defined(JSON_IS_AMALGAMATION) #include #include +#include // Disable warning C4251: : needs to have dll-interface to // be used by... @@ -22,20 +23,18 @@ namespace Json { class Value; -class StreamWriterBuilder; /** Usage: \code using namespace Json; - Value value; - StreamWriter::Builder builder; - builder.withCommentStyle(StreamWriter::CommentStyle::None); - std::shared_ptr writer( - builder.newStreamWriter(&std::cout)); - writer->write(value); - std::cout.flush(); + void writeToStdout(StreamWriter::Builder const& builder, Value const& value) { + std::unique_ptr const writer( + builder.newStreamWriter(&std::cout)); + writer->write(value); + std::cout << std::endl; // add lf and flush + } \endcode */ class JSON_API StreamWriter { @@ -57,53 +56,103 @@ public: /// \throw std::exception possibly, depending on configuration virtual int write(Value const& root) = 0; - /// Because this Builder is non-virtual, we can safely add - /// methods without a major version bump. - /// \see http://stackoverflow.com/questions/14875052/pure-virtual-functions-and-binary-compatibility - class Builder { - StreamWriterBuilder* own_; - Builder(Builder const&); // noncopyable - void operator=(Builder const&); // noncopyable + /** \brief A simple abstract factory. + */ + class JSON_API Factory { public: - Builder(); - ~Builder(); // delete underlying StreamWriterBuilder - - Builder& withCommentStyle(CommentStyle cs); /// default: All - /** \brief Write in human-friendly style. - - If "", then skip all indentation, newlines, and comments, - which implies CommentStyle::None. - Default: "\t" - */ - Builder& withIndentation(std::string indentation); - /** \brief Drop the "null" string from the writer's output for nullValues. - * Strictly speaking, this is not valid JSON. But when the output is being - * fed to a browser's Javascript, it makes for smaller output and the - * browser can handle the output just fine. - */ - Builder& withDropNullPlaceholders(bool v); - /** \brief Do not add \n at end of document. - * Normally, we add an extra newline, just because. - */ - Builder& withOmitEndingLineFeed(bool v); - /** \brief Add a space after ':'. - * If indentation is non-empty, we surround colon with whitespace, - * e.g. " : " - * This will add back the trailing space when there is no indentation. - * This seems dubious when the entire document is on a single line, - * but we leave this here to repduce the behavior of the old `FastWriter`. - */ - Builder& withEnableYAMLCompatibility(bool v); - + virtual ~Factory(); /// Do not take ownership of sout, but maintain a reference. - StreamWriter* newStreamWriter(std::ostream* sout) const; - }; -}; + virtual StreamWriter* newStreamWriter(std::ostream* sout) const = 0; + }; // Factory +}; // StreamWriter /// \brief Write into stringstream, then return string, for convenience. -std::string writeString(Value const& root, StreamWriter::Builder const& builder); +std::string writeString(Value const& root, StreamWriter::Factory const& factory); +/** \brief Build a StreamWriter implementation. + +Usage: +\code + using namespace Json; + Value value = ...; + StreamWriter::Builder builder; + builder.cs_ = StreamWriter::CommentStyle::None; + std::shared_ptr writer( + builder.newStreamWriter(&std::cout)); + writer->write(value); + std::cout << std::endl; // add lf and flush +\endcode +*/ +class JSON_API StreamWriterBuilder : public StreamWriter::Factory { +public: + // Note: We cannot add data-members to this class without a major version bump. + // So these might as well be completely exposed. + + /** \brief How to write comments. + * Default: All + */ + StreamWriter::CommentStyle cs_; + /** \brief Write in human-friendly style. + + If "", then skip all indentation and newlines. + In that case, you probably want CommentStyle::None also. + Default: "\t" + */ + std::string indentation_; + + StreamWriterBuilder(); + + /// Do not take ownership of sout, but maintain a reference. + StreamWriter* newStreamWriter(std::ostream* sout) const; +}; + +/** \brief Build a StreamWriter implementation. + * Comments are not written, and most whitespace is omitted. + * In addition, there are some special settings to allow compatibility + * with the old FastWriter. + * Usage: + * \code + * OldCompressingStreamWriterBuilder b; + * b.dropNullPlaceHolders_ = true; // etc. + * StreamWriter* w = b.newStreamWriter(&std::cout); + * w.write(value); + * delete w; + * \endcode + */ +class JSON_API OldCompressingStreamWriterBuilder : public StreamWriter::Factory +{ +public: + // Note: We cannot add data-members to this class without a major version bump. + // So these might as well be completely exposed. + + /** \brief Drop the "null" string from the writer's output for nullValues. + * Strictly speaking, this is not valid JSON. But when the output is being + * fed to a browser's Javascript, it makes for smaller output and the + * browser can handle the output just fine. + */ + bool dropNullPlaceholders_; + /** \brief Do not add \n at end of document. + * Normally, we add an extra newline, just because. + */ + bool omitEndingLineFeed_; + /** \brief Add a space after ':'. + * If indentation is non-empty, we surround colon with whitespace, + * e.g. " : " + * This will add back the trailing space when there is no indentation. + * This seems dubious when the entire document is on a single line, + * but we leave this here to repduce the behavior of the old `FastWriter`. + */ + bool enableYAMLCompatibility_; + + OldCompressingStreamWriterBuilder() + : dropNullPlaceholders_(false) + , omitEndingLineFeed_(false) + , enableYAMLCompatibility_(false) + {} + virtual StreamWriter* newStreamWriter(std::ostream*) const; +}; + /** \brief Abstract class for writers. * \deprecated Use StreamWriter::Builder. */ diff --git a/src/jsontestrunner/main.cpp b/src/jsontestrunner/main.cpp index 3a2229c..dba943b 100644 --- a/src/jsontestrunner/main.cpp +++ b/src/jsontestrunner/main.cpp @@ -184,8 +184,7 @@ static std::string useStyledStreamWriter( static std::string useBuiltStyledStreamWriter( Json::Value const& root) { - Json::StreamWriter::Builder builder; - builder.withCommentStyle(Json::StreamWriter::CommentStyle::All); + Json::StreamWriterBuilder builder; return writeString(root, builder); } static int rewriteValueTree( diff --git a/src/lib_json/json_writer.cpp b/src/lib_json/json_writer.cpp index 7f542aa..6e0a429 100644 --- a/src/lib_json/json_writer.cpp +++ b/src/lib_json/json_writer.cpp @@ -959,78 +959,25 @@ int MyStreamWriter::write(Value const& root) sout_ << root; return 0; } -class StreamWriterBuilder { - typedef StreamWriter::CommentStyle CommentStyle; - CommentStyle cs_; - std::string indentation_; - bool dropNullPlaceholders_; - bool omitEndingLineFeed_; - bool enableYAMLCompatibility_; -public: - StreamWriterBuilder(); - virtual ~StreamWriterBuilder(); - virtual void setCommentStyle(CommentStyle cs); - virtual void setIndentation(std::string indentation); - virtual void setDropNullPlaceholders(bool v); - virtual void setOmitEndingLineFeed(bool v); - virtual void setEnableYAMLCompatibility(bool v); - virtual StreamWriter* newStreamWriter(std::ostream* sout) const; -}; +StreamWriter::Factory::~Factory() +{} StreamWriterBuilder::StreamWriterBuilder() - : cs_(CommentStyle::All) + : cs_(StreamWriter::CommentStyle::All) , indentation_("\t") - , dropNullPlaceholders_(false) - , omitEndingLineFeed_(false) - , enableYAMLCompatibility_(false) -{ -} -StreamWriterBuilder::~StreamWriterBuilder() -{ -} -void StreamWriterBuilder::setCommentStyle(CommentStyle v) -{ - cs_ = v; -} -void StreamWriterBuilder::setIndentation(std::string v) -{ - indentation_ = v; - if (indentation_.empty()) cs_ = CommentStyle::None; -} -void StreamWriterBuilder::setDropNullPlaceholders(bool v) -{ - dropNullPlaceholders_ = v; -} -void StreamWriterBuilder::setOmitEndingLineFeed(bool v) -{ - omitEndingLineFeed_ = v; -} -void StreamWriterBuilder::setEnableYAMLCompatibility(bool v) -{ - enableYAMLCompatibility_ = v; -} +{} StreamWriter* StreamWriterBuilder::newStreamWriter(std::ostream* stream) const { std::string colonSymbol = " : "; if (indentation_.empty()) { - if (enableYAMLCompatibility_) { - colonSymbol = ": "; - } else { - colonSymbol = ":"; - } + colonSymbol = ":"; } std::string nullSymbol = "null"; - if (dropNullPlaceholders_) { - nullSymbol = ""; - } - std::string endingLineFeedSymbol = "\n"; - if (omitEndingLineFeed_) { - endingLineFeedSymbol = ""; - } + std::string endingLineFeedSymbol = ""; return new BuiltStyledStreamWriter(stream, indentation_, cs_, colonSymbol, nullSymbol, endingLineFeedSymbol); } - +/* // This might become public someday. class StreamWriterBuilderFactory { public: @@ -1044,51 +991,31 @@ StreamWriterBuilder* StreamWriterBuilderFactory::newStreamWriterBuilder() const { return new StreamWriterBuilder; } +*/ -StreamWriter::Builder::Builder() - : own_(StreamWriterBuilderFactory().newStreamWriterBuilder()) +StreamWriter* OldCompressingStreamWriterBuilder::newStreamWriter( + std::ostream* stream) const { -} -StreamWriter::Builder::~Builder() -{ - delete own_; -} -StreamWriter::Builder::Builder(Builder const&) - : own_(nullptr) -{abort();} -void StreamWriter::Builder::operator=(Builder const&) -{abort();} -StreamWriter::Builder& StreamWriter::Builder::withCommentStyle(CommentStyle v) -{ - own_->setCommentStyle(v); - return *this; -} -StreamWriter::Builder& StreamWriter::Builder::withIndentation(std::string v) -{ - own_->setIndentation(v); - return *this; -} -StreamWriter::Builder& StreamWriter::Builder::withDropNullPlaceholders(bool v) -{ - own_->setDropNullPlaceholders(v); - return *this; -} -StreamWriter::Builder& StreamWriter::Builder::withOmitEndingLineFeed(bool v) -{ - own_->setOmitEndingLineFeed(v); - return *this; -} -StreamWriter::Builder& StreamWriter::Builder::withEnableYAMLCompatibility(bool v) -{ - own_->setEnableYAMLCompatibility(v); - return *this; -} -StreamWriter* StreamWriter::Builder::newStreamWriter(std::ostream* sout) const -{ - return own_->newStreamWriter(sout); + std::string colonSymbol = " : "; + if (enableYAMLCompatibility_) { + colonSymbol = ": "; + } else { + colonSymbol = ":"; + } + std::string nullSymbol = "null"; + if (dropNullPlaceholders_) { + nullSymbol = ""; + } + std::string endingLineFeedSymbol = "\n"; + if (omitEndingLineFeed_) { + endingLineFeedSymbol = ""; + } + return new BuiltStyledStreamWriter(stream, + "", StreamWriter::CommentStyle::None, + colonSymbol, nullSymbol, endingLineFeedSymbol); } -std::string writeString(Value const& root, StreamWriter::Builder const& builder) { +std::string writeString(Value const& root, StreamWriter::Factory const& builder) { std::ostringstream sout; std::unique_ptr const sw(builder.newStreamWriter(&sout)); sw->write(root); @@ -1096,9 +1023,7 @@ std::string writeString(Value const& root, StreamWriter::Builder const& builder) } std::ostream& operator<<(std::ostream& sout, Value const& root) { - StreamWriter::Builder builder; - builder.withCommentStyle(StreamWriter::CommentStyle::All); - builder.withIndentation("\t"); + StreamWriterBuilder builder; std::shared_ptr writer(builder.newStreamWriter(&sout)); writer->write(root); return sout;