Merge pull request #145 from cdunn2001/simplify-builder

Simplify builder
This commit is contained in:
Christopher Dunn 2015-01-26 11:33:16 -06:00
commit 3b5f2b85ca
4 changed files with 133 additions and 157 deletions

View File

@ -81,8 +81,8 @@ root["indent"]["use_space"] = getCurrentIndentUseSpace();
// To write into a steam with minimal memory overhead, // To write into a steam with minimal memory overhead,
// create a Builder for a StreamWriter. // create a Builder for a StreamWriter.
Json::StreamWriter::Builder builder; Json::StreamWriterBuilder builder;
builder.withIndentation(" "); // or whatever you like builder.indentation_ = " "; // or whatever you like
// Then build a StreamWriter. // Then build a StreamWriter.
std::shared_ptr<Json::StreamWriter> writer( std::shared_ptr<Json::StreamWriter> writer(
@ -94,6 +94,9 @@ writer->write( root );
// If you like the defaults, you can insert directly into a stream. // If you like the defaults, you can insert directly into a stream.
std::cout << root; 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 // Of course, you can write to `std::ostringstream` if you prefer. Or
// use `writeString()` for convenience. // use `writeString()` for convenience.
std::string document = Json::writeString( root, builder ); std::string document = Json::writeString( root, builder );

View File

@ -11,6 +11,7 @@
#endif // if !defined(JSON_IS_AMALGAMATION) #endif // if !defined(JSON_IS_AMALGAMATION)
#include <vector> #include <vector>
#include <string> #include <string>
#include <ostream>
// Disable warning C4251: <data member>: <type> needs to have dll-interface to // Disable warning C4251: <data member>: <type> needs to have dll-interface to
// be used by... // be used by...
@ -22,20 +23,18 @@
namespace Json { namespace Json {
class Value; class Value;
class StreamWriterBuilder;
/** /**
Usage: Usage:
\code \code
using namespace Json; using namespace Json;
Value value; void writeToStdout(StreamWriter::Builder const& builder, Value const& value) {
StreamWriter::Builder builder; std::unique_ptr<StreamWriter> const writer(
builder.withCommentStyle(StreamWriter::CommentStyle::None); builder.newStreamWriter(&std::cout));
std::shared_ptr<StreamWriter> writer( writer->write(value);
builder.newStreamWriter(&std::cout)); std::cout << std::endl; // add lf and flush
writer->write(value); }
std::cout.flush();
\endcode \endcode
*/ */
class JSON_API StreamWriter { class JSON_API StreamWriter {
@ -57,53 +56,103 @@ public:
/// \throw std::exception possibly, depending on configuration /// \throw std::exception possibly, depending on configuration
virtual int write(Value const& root) = 0; virtual int write(Value const& root) = 0;
/// Because this Builder is non-virtual, we can safely add /** \brief A simple abstract factory.
/// methods without a major version bump. */
/// \see http://stackoverflow.com/questions/14875052/pure-virtual-functions-and-binary-compatibility class JSON_API Factory {
class Builder {
StreamWriterBuilder* own_;
Builder(Builder const&); // noncopyable
void operator=(Builder const&); // noncopyable
public: public:
Builder(); virtual ~Factory();
~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);
/// Do not take ownership of sout, but maintain a reference. /// 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. /// \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<StreamWriter> 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. /** \brief Abstract class for writers.
* \deprecated Use StreamWriter::Builder. * \deprecated Use StreamWriter::Builder.
*/ */

View File

@ -184,8 +184,7 @@ static std::string useStyledStreamWriter(
static std::string useBuiltStyledStreamWriter( static std::string useBuiltStyledStreamWriter(
Json::Value const& root) Json::Value const& root)
{ {
Json::StreamWriter::Builder builder; Json::StreamWriterBuilder builder;
builder.withCommentStyle(Json::StreamWriter::CommentStyle::All);
return writeString(root, builder); return writeString(root, builder);
} }
static int rewriteValueTree( static int rewriteValueTree(

View File

@ -959,78 +959,25 @@ int MyStreamWriter::write(Value const& root)
sout_ << root; sout_ << root;
return 0; return 0;
} }
class StreamWriterBuilder { StreamWriter::Factory::~Factory()
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;
};
StreamWriterBuilder::StreamWriterBuilder() StreamWriterBuilder::StreamWriterBuilder()
: cs_(CommentStyle::All) : cs_(StreamWriter::CommentStyle::All)
, indentation_("\t") , 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 StreamWriter* StreamWriterBuilder::newStreamWriter(std::ostream* stream) const
{ {
std::string colonSymbol = " : "; std::string colonSymbol = " : ";
if (indentation_.empty()) { if (indentation_.empty()) {
if (enableYAMLCompatibility_) { colonSymbol = ":";
colonSymbol = ": ";
} else {
colonSymbol = ":";
}
} }
std::string nullSymbol = "null"; std::string nullSymbol = "null";
if (dropNullPlaceholders_) { std::string endingLineFeedSymbol = "";
nullSymbol = "";
}
std::string endingLineFeedSymbol = "\n";
if (omitEndingLineFeed_) {
endingLineFeedSymbol = "";
}
return new BuiltStyledStreamWriter(stream, return new BuiltStyledStreamWriter(stream,
indentation_, cs_, indentation_, cs_,
colonSymbol, nullSymbol, endingLineFeedSymbol); colonSymbol, nullSymbol, endingLineFeedSymbol);
} }
/*
// This might become public someday. // This might become public someday.
class StreamWriterBuilderFactory { class StreamWriterBuilderFactory {
public: public:
@ -1044,51 +991,31 @@ StreamWriterBuilder* StreamWriterBuilderFactory::newStreamWriterBuilder() const
{ {
return new StreamWriterBuilder; return new StreamWriterBuilder;
} }
*/
StreamWriter::Builder::Builder() StreamWriter* OldCompressingStreamWriterBuilder::newStreamWriter(
: own_(StreamWriterBuilderFactory().newStreamWriterBuilder()) std::ostream* stream) const
{ {
} std::string colonSymbol = " : ";
StreamWriter::Builder::~Builder() if (enableYAMLCompatibility_) {
{ colonSymbol = ": ";
delete own_; } else {
} colonSymbol = ":";
StreamWriter::Builder::Builder(Builder const&) }
: own_(nullptr) std::string nullSymbol = "null";
{abort();} if (dropNullPlaceholders_) {
void StreamWriter::Builder::operator=(Builder const&) nullSymbol = "";
{abort();} }
StreamWriter::Builder& StreamWriter::Builder::withCommentStyle(CommentStyle v) std::string endingLineFeedSymbol = "\n";
{ if (omitEndingLineFeed_) {
own_->setCommentStyle(v); endingLineFeedSymbol = "";
return *this; }
} return new BuiltStyledStreamWriter(stream,
StreamWriter::Builder& StreamWriter::Builder::withIndentation(std::string v) "", StreamWriter::CommentStyle::None,
{ colonSymbol, nullSymbol, endingLineFeedSymbol);
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 writeString(Value const& root, StreamWriter::Builder const& builder) { std::string writeString(Value const& root, StreamWriter::Factory const& builder) {
std::ostringstream sout; std::ostringstream sout;
std::unique_ptr<StreamWriter> const sw(builder.newStreamWriter(&sout)); std::unique_ptr<StreamWriter> const sw(builder.newStreamWriter(&sout));
sw->write(root); 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) { std::ostream& operator<<(std::ostream& sout, Value const& root) {
StreamWriter::Builder builder; StreamWriterBuilder builder;
builder.withCommentStyle(StreamWriter::CommentStyle::All);
builder.withIndentation("\t");
std::shared_ptr<StreamWriter> writer(builder.newStreamWriter(&sout)); std::shared_ptr<StreamWriter> writer(builder.newStreamWriter(&sout));
writer->write(root); writer->write(root);
return sout; return sout;