mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
Move streaming Json objects to ripple/json.
This commit is contained in:
159
src/ripple/json/impl/Object.cpp
Normal file
159
src/ripple/json/impl/Object.cpp
Normal file
@@ -0,0 +1,159 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <BeastConfig.h>
|
||||
#include <ripple/json/Object.h>
|
||||
|
||||
namespace Json {
|
||||
|
||||
Collection::Collection (Collection* parent, Writer* writer)
|
||||
: parent_ (parent), writer_ (writer), enabled_ (true)
|
||||
{
|
||||
checkWritable ("Collection::Collection()");
|
||||
if (parent_)
|
||||
{
|
||||
check (parent_->enabled_, "Parent not enabled in constructor");
|
||||
parent_->enabled_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
Collection::~Collection ()
|
||||
{
|
||||
if (writer_)
|
||||
writer_->finish ();
|
||||
if (parent_)
|
||||
parent_->enabled_ = true;
|
||||
}
|
||||
|
||||
Collection& Collection::operator= (Collection&& that) noexcept
|
||||
{
|
||||
parent_ = that.parent_;
|
||||
writer_ = that.writer_;
|
||||
enabled_ = that.enabled_;
|
||||
|
||||
that.parent_ = nullptr;
|
||||
that.writer_ = nullptr;
|
||||
that.enabled_ = false;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Collection::Collection (Collection&& that) noexcept
|
||||
{
|
||||
*this = std::move (that);
|
||||
}
|
||||
|
||||
void Collection::checkWritable (std::string const& label)
|
||||
{
|
||||
if (!enabled_)
|
||||
throw JsonException (label + ": not enabled");
|
||||
if (!writer_)
|
||||
throw JsonException (label + ": not writable");
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
Object::Root::Root (Writer& w) : Object (nullptr, &w)
|
||||
{
|
||||
writer_->startRoot (Writer::object);
|
||||
}
|
||||
|
||||
Object Object::setObject (std::string const& key)
|
||||
{
|
||||
checkWritable ("Object::setObject");
|
||||
if (writer_)
|
||||
writer_->startSet (Writer::object, key);
|
||||
return Object (this, writer_);
|
||||
}
|
||||
|
||||
Array Object::setArray (std::string const& key) {
|
||||
checkWritable ("Object::setArray");
|
||||
if (writer_)
|
||||
writer_->startSet (Writer::array, key);
|
||||
return Array (this, writer_);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
Object Array::appendObject ()
|
||||
{
|
||||
checkWritable ("Array::appendObject");
|
||||
if (writer_)
|
||||
writer_->startAppend (Writer::object);
|
||||
return Object (this, writer_);
|
||||
}
|
||||
|
||||
Array Array::appendArray ()
|
||||
{
|
||||
checkWritable ("Array::makeArray");
|
||||
if (writer_)
|
||||
writer_->startAppend (Writer::array);
|
||||
return Array (this, writer_);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
Object::Proxy::Proxy (Object& object, std::string const& key)
|
||||
: object_ (object)
|
||||
, key_ (key)
|
||||
{
|
||||
}
|
||||
|
||||
Object::Proxy Object::operator[] (std::string const& key)
|
||||
{
|
||||
return Proxy (*this, key);
|
||||
}
|
||||
|
||||
Object::Proxy Object::operator[] (Json::StaticString const& key)
|
||||
{
|
||||
return Proxy (*this, std::string (key));
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
template <class Object>
|
||||
void doCopyFrom (Object& to, Json::Value const& from)
|
||||
{
|
||||
assert (from.isObject());
|
||||
auto members = from.getMemberNames();
|
||||
for (auto& m: members)
|
||||
to[m] = from[m];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void copyFrom (Json::Value& to, Json::Value const& from)
|
||||
{
|
||||
if (to.empty()) // Short circuit this very common case.
|
||||
to = from;
|
||||
else
|
||||
doCopyFrom (to, from);
|
||||
}
|
||||
|
||||
void copyFrom (Object& to, Json::Value const& from)
|
||||
{
|
||||
doCopyFrom (to, from);
|
||||
}
|
||||
|
||||
WriterObject stringWriterObject (std::string& s)
|
||||
{
|
||||
return WriterObject (stringOutput (s));
|
||||
}
|
||||
|
||||
} // Json
|
||||
111
src/ripple/json/impl/Output.cpp
Normal file
111
src/ripple/json/impl/Output.cpp
Normal file
@@ -0,0 +1,111 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <BeastConfig.h>
|
||||
#include <ripple/json/Output.h>
|
||||
#include <ripple/json/Writer.h>
|
||||
|
||||
namespace Json {
|
||||
|
||||
namespace {
|
||||
|
||||
void outputJson (Json::Value const& value, Writer& writer)
|
||||
{
|
||||
switch (value.type())
|
||||
{
|
||||
case Json::nullValue:
|
||||
{
|
||||
writer.output (nullptr);
|
||||
break;
|
||||
}
|
||||
|
||||
case Json::intValue:
|
||||
{
|
||||
writer.output (value.asInt());
|
||||
break;
|
||||
}
|
||||
|
||||
case Json::uintValue:
|
||||
{
|
||||
writer.output (value.asUInt());
|
||||
break;
|
||||
}
|
||||
|
||||
case Json::realValue:
|
||||
{
|
||||
writer.output (value.asDouble());
|
||||
break;
|
||||
}
|
||||
|
||||
case Json::stringValue:
|
||||
{
|
||||
writer.output (value.asString());
|
||||
break;
|
||||
}
|
||||
|
||||
case Json::booleanValue:
|
||||
{
|
||||
writer.output (value.asBool());
|
||||
break;
|
||||
}
|
||||
|
||||
case Json::arrayValue:
|
||||
{
|
||||
writer.startRoot (Writer::array);
|
||||
for (auto const& i: value)
|
||||
{
|
||||
writer.rawAppend();
|
||||
outputJson (i, writer);
|
||||
}
|
||||
writer.finish();
|
||||
break;
|
||||
}
|
||||
|
||||
case Json::objectValue:
|
||||
{
|
||||
writer.startRoot (Writer::object);
|
||||
auto members = value.getMemberNames ();
|
||||
for (auto const& tag: members)
|
||||
{
|
||||
writer.rawSet (tag);
|
||||
outputJson (value[tag], writer);
|
||||
}
|
||||
writer.finish();
|
||||
break;
|
||||
}
|
||||
} // switch
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void outputJson (Json::Value const& value, Output const& out)
|
||||
{
|
||||
Writer writer (out);
|
||||
outputJson (value, writer);
|
||||
}
|
||||
|
||||
std::string jsonAsString (Json::Value const& value)
|
||||
{
|
||||
std::string s;
|
||||
Writer writer (stringOutput (s));
|
||||
outputJson (value, writer);
|
||||
return s;
|
||||
}
|
||||
|
||||
} // Json
|
||||
317
src/ripple/json/impl/Writer.cpp
Normal file
317
src/ripple/json/impl/Writer.cpp
Normal file
@@ -0,0 +1,317 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <BeastConfig.h>
|
||||
#include <ripple/json/Output.h>
|
||||
#include <ripple/json/Writer.h>
|
||||
#include <beast/unit_test/suite.h>
|
||||
|
||||
namespace Json {
|
||||
|
||||
namespace {
|
||||
|
||||
std::map <char, const char*> jsonSpecialCharacterEscape = {
|
||||
{'"', "\\\""},
|
||||
{'\\', "\\\\"},
|
||||
{'/', "\\/"},
|
||||
{'\b', "\\b"},
|
||||
{'\f', "\\f"},
|
||||
{'\n', "\\n"},
|
||||
{'\r', "\\r"},
|
||||
{'\t', "\\t"}
|
||||
};
|
||||
|
||||
static size_t const jsonEscapeLength = 2;
|
||||
|
||||
// All other JSON punctuation.
|
||||
const char closeBrace = '}';
|
||||
const char closeBracket = ']';
|
||||
const char colon = ':';
|
||||
const char comma = ',';
|
||||
const char openBrace = '{';
|
||||
const char openBracket = '[';
|
||||
const char quote = '"';
|
||||
|
||||
const std::string none;
|
||||
|
||||
static auto const integralFloatsBecomeInts = false;
|
||||
|
||||
size_t lengthWithoutTrailingZeros (std::string const& s)
|
||||
{
|
||||
auto dotPos = s.find ('.');
|
||||
if (dotPos == std::string::npos)
|
||||
return s.size();
|
||||
|
||||
auto lastNonZero = s.find_last_not_of ('0');
|
||||
auto hasDecimals = dotPos != lastNonZero;
|
||||
|
||||
if (hasDecimals)
|
||||
return lastNonZero + 1;
|
||||
|
||||
if (integralFloatsBecomeInts || lastNonZero + 2 > s.size())
|
||||
return lastNonZero;
|
||||
|
||||
return lastNonZero + 2;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class Writer::Impl
|
||||
{
|
||||
public:
|
||||
Impl (Output const& output) : output_(output) {}
|
||||
~Impl() = default;
|
||||
|
||||
Impl(Impl&&) = delete;
|
||||
Impl& operator=(Impl&&) = delete;
|
||||
|
||||
bool empty() const { return stack_.empty (); }
|
||||
|
||||
void start (CollectionType ct)
|
||||
{
|
||||
char ch = (ct == array) ? openBracket : openBrace;
|
||||
output ({&ch, 1});
|
||||
stack_.push (Collection());
|
||||
stack_.top().type = ct;
|
||||
}
|
||||
|
||||
void output (boost::string_ref const& bytes)
|
||||
{
|
||||
markStarted ();
|
||||
output_ (bytes);
|
||||
}
|
||||
|
||||
void stringOutput (boost::string_ref const& bytes)
|
||||
{
|
||||
markStarted ();
|
||||
std::size_t position = 0, writtenUntil = 0;
|
||||
|
||||
output_ ({"e, 1});
|
||||
auto data = bytes.data();
|
||||
for (; position < bytes.size(); ++position)
|
||||
{
|
||||
auto i = jsonSpecialCharacterEscape.find (data[position]);
|
||||
if (i != jsonSpecialCharacterEscape.end ())
|
||||
{
|
||||
if (writtenUntil < position)
|
||||
{
|
||||
output_ ({data + writtenUntil, position - writtenUntil});
|
||||
}
|
||||
output_ ({i->second, jsonEscapeLength});
|
||||
writtenUntil = position + 1;
|
||||
};
|
||||
}
|
||||
if (writtenUntil < position)
|
||||
output_ ({data + writtenUntil, position - writtenUntil});
|
||||
output_ ({"e, 1});
|
||||
}
|
||||
|
||||
void markStarted ()
|
||||
{
|
||||
check (!isFinished(), "isFinished() in output.");
|
||||
isStarted_ = true;
|
||||
}
|
||||
|
||||
void nextCollectionEntry (CollectionType type, std::string const& message)
|
||||
{
|
||||
check (!empty() , "empty () in " + message);
|
||||
|
||||
auto t = stack_.top ().type;
|
||||
if (t != type)
|
||||
{
|
||||
check (false, "Not an " +
|
||||
((type == array ? "array: " : "object: ") + message));
|
||||
}
|
||||
if (stack_.top ().isFirst)
|
||||
stack_.top ().isFirst = false;
|
||||
else
|
||||
output_ ({&comma, 1});
|
||||
}
|
||||
|
||||
void writeObjectTag (std::string const& tag)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
// Make sure we haven't already seen this tag.
|
||||
auto& tags = stack_.top ().tags;
|
||||
check (tags.find (tag) == tags.end (), "Already seen tag " + tag);
|
||||
tags.insert (tag);
|
||||
#endif
|
||||
|
||||
stringOutput (tag);
|
||||
output_ ({&colon, 1});
|
||||
}
|
||||
|
||||
bool isFinished() const
|
||||
{
|
||||
return isStarted_ && empty();
|
||||
}
|
||||
|
||||
void finish ()
|
||||
{
|
||||
check (!empty(), "Empty stack in finish()");
|
||||
|
||||
auto isArray = stack_.top().type == array;
|
||||
auto ch = isArray ? closeBracket : closeBrace;
|
||||
output_ ({&ch, 1});
|
||||
stack_.pop();
|
||||
}
|
||||
|
||||
void finishAll ()
|
||||
{
|
||||
if (isStarted_)
|
||||
{
|
||||
while (!isFinished())
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
Output const& getOutput() const { return output_; }
|
||||
|
||||
private:
|
||||
// JSON collections are either arrrays, or objects.
|
||||
struct Collection
|
||||
{
|
||||
/** What type of collection are we in? */
|
||||
Writer::CollectionType type;
|
||||
|
||||
/** Is this the first entry in a collection?
|
||||
* If false, we have to emit a , before we write the next entry. */
|
||||
bool isFirst = true;
|
||||
|
||||
#ifdef DEBUG
|
||||
/** What tags have we already seen in this collection? */
|
||||
std::set <std::string> tags;
|
||||
#endif
|
||||
};
|
||||
|
||||
using Stack = std::stack <Collection, std::vector<Collection>>;
|
||||
|
||||
Output output_;
|
||||
Stack stack_;
|
||||
|
||||
bool isStarted_ = false;
|
||||
};
|
||||
|
||||
Writer::Writer (Output const &output)
|
||||
: impl_(std::make_unique <Impl> (output))
|
||||
{
|
||||
}
|
||||
|
||||
Writer::~Writer()
|
||||
{
|
||||
if (impl_)
|
||||
impl_->finishAll ();
|
||||
}
|
||||
|
||||
Writer::Writer(Writer&& w) noexcept
|
||||
{
|
||||
impl_ = std::move (w.impl_);
|
||||
}
|
||||
|
||||
Writer& Writer::operator=(Writer&& w) noexcept
|
||||
{
|
||||
impl_ = std::move (w.impl_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Writer::output (char const* s)
|
||||
{
|
||||
impl_->stringOutput (s);
|
||||
}
|
||||
|
||||
void Writer::output (std::string const& s)
|
||||
{
|
||||
impl_->stringOutput (s);
|
||||
}
|
||||
|
||||
void Writer::output (Json::Value const& value)
|
||||
{
|
||||
impl_->markStarted();
|
||||
outputJson (value, impl_->getOutput());
|
||||
}
|
||||
|
||||
template <>
|
||||
void Writer::output (float f)
|
||||
{
|
||||
auto s = ripple::to_string (f);
|
||||
impl_->output ({s.data (), lengthWithoutTrailingZeros (s)});
|
||||
}
|
||||
|
||||
template <>
|
||||
void Writer::output (double f)
|
||||
{
|
||||
auto s = ripple::to_string (f);
|
||||
impl_->output ({s.data (), lengthWithoutTrailingZeros (s)});
|
||||
}
|
||||
|
||||
template <>
|
||||
void Writer::output (std::nullptr_t)
|
||||
{
|
||||
impl_->output ("null");
|
||||
}
|
||||
|
||||
void Writer::implOutput (std::string const& s)
|
||||
{
|
||||
impl_->output (s);
|
||||
}
|
||||
|
||||
void Writer::finishAll ()
|
||||
{
|
||||
if (impl_)
|
||||
impl_->finishAll ();
|
||||
}
|
||||
|
||||
void Writer::rawAppend()
|
||||
{
|
||||
impl_->nextCollectionEntry (array, "append");
|
||||
}
|
||||
|
||||
void Writer::rawSet (std::string const& tag)
|
||||
{
|
||||
check (!tag.empty(), "Tag can't be empty");
|
||||
|
||||
impl_->nextCollectionEntry (object, "set");
|
||||
impl_->writeObjectTag (tag);
|
||||
}
|
||||
|
||||
void Writer::startRoot (CollectionType type)
|
||||
{
|
||||
impl_->start (type);
|
||||
}
|
||||
|
||||
void Writer::startAppend (CollectionType type)
|
||||
{
|
||||
impl_->nextCollectionEntry (array, "startAppend");
|
||||
impl_->start (type);
|
||||
}
|
||||
|
||||
void Writer::startSet (CollectionType type, std::string const& key)
|
||||
{
|
||||
impl_->nextCollectionEntry (object, "startSet");
|
||||
impl_->writeObjectTag (key);
|
||||
impl_->start (type);
|
||||
}
|
||||
|
||||
void Writer::finish ()
|
||||
{
|
||||
if (impl_)
|
||||
impl_->finish ();
|
||||
}
|
||||
|
||||
} // Json
|
||||
@@ -178,13 +178,6 @@ std::string valueToQuotedString ( const char* value )
|
||||
return result;
|
||||
}
|
||||
|
||||
// Class Writer
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
Writer::~Writer ()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// Class FastWriter
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
Reference in New Issue
Block a user