Rewrite the remaining bits of json::Writer

This commit is contained in:
Thomas Goyne 2014-06-27 19:38:53 -07:00
parent bc410a99f6
commit 4c0e578eda
10 changed files with 134 additions and 167 deletions

View File

@ -24,10 +24,10 @@ namespace {
void Visit(Null&) { is_null = true; } void Visit(Null&) { is_null = true; }
void Visit(Array const&) { } void Visit(Array const&) { }
void Visit(Object const&) { } void Visit(Object const&) { }
void Visit(Integer const&) { } void Visit(Integer) { }
void Visit(Double const&) { } void Visit(Double) { }
void Visit(String const&) { } void Visit(String const&) { }
void Visit(Boolean const&) { } void Visit(Boolean) { }
void Visit(Null const&) { is_null = true; } void Visit(Null const&) { is_null = true; }
public: public:
bool is_null = false; bool is_null = false;

View File

@ -1,125 +1,100 @@
/********************************************** // Copyright (c) 2014, Thomas Goyne <plorkyeran@aegisub.org>
//
License: BSD // Permission to use, copy, modify, and distribute this software for any
Project Webpage: http://cajun-jsonapi.sourceforge.net/ // purpose with or without fee is hereby granted, provided that the above
Author: Terry Caton // 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.
//
// Aegisub Project http://www.aegisub.org/
#include "libaegisub/cajun/writer.h" #include "libaegisub/cajun/writer.h"
#include <cmath> #include <cmath>
#include <iomanip> #include <iomanip>
/* namespace agi {
void JsonWriter::Visit(json::Array const& array) {
TODO: if (array.empty()) {
* better documentation ostr << "[]";
* unicode character encoding return;
*/
namespace json {
Writer::Writer(std::ostream& ostr) : m_ostr(ostr) { }
void Writer::Write(Array const& array) {
if (array.empty())
m_ostr << "[]";
else {
m_ostr << '[' << std::endl;
++tab_depth;
Array::const_iterator it(array.begin()), itend(array.end());
while (it != itend) {
m_ostr << std::string(tab_depth, '\t');
Write(*it);
if (++it != itend)
m_ostr << ',';
m_ostr << std::endl;
}
--tab_depth;
m_ostr << std::string(tab_depth, '\t') << ']';
} }
indent += '\t';
ostr << "[\n";
bool first = true;
for (auto const& entry : array) {
if (!first) ostr << ",\n";
first = false;
ostr << indent;
Visit(entry);
}
indent.pop_back();
ostr << '\n' << indent << ']';
} }
void Writer::Write(Object const& object) { void JsonWriter::Visit(json::Object const& object) {
if (object.empty()) if (object.empty()) {
m_ostr << "{}"; ostr << "{}";
else { return;
m_ostr << '{' << std::endl;
++tab_depth;
Object::const_iterator it(object.begin()), itend(object.end());
while (it != itend) {
m_ostr << std::string(tab_depth, '\t');
Write(it->first);
m_ostr << " : ";
Write(it->second);
if (++it != itend)
m_ostr << ',';
m_ostr << std::endl;
}
--tab_depth;
m_ostr << std::string(tab_depth, '\t') << '}';
} }
indent += '\t';
ostr << "{\n";
bool first = true;
for (auto const& entry : object) {
if (!first) ostr << ",\n";
first = false;
ostr << indent;
Visit(entry.first);
ostr << " : ";
Visit(entry.second);
}
indent.pop_back();
ostr << '\n' << indent << '}';
} }
void Writer::Write(Double const& numberElement) { void JsonWriter::Visit(double d) {
m_ostr << std::setprecision(20) << numberElement; ostr << std::setprecision(20) << d;
double unused; double unused;
if (!std::modf(numberElement, &unused)) if (!std::modf(d, &unused))
m_ostr << ".0"; ostr << ".0";
} }
void Writer::Write(Integer const& numberElement) { void JsonWriter::Visit(std::string const& str) {
m_ostr << numberElement; ostr << '"';
}
void Writer::Write(Boolean const& booleanElement) { for (auto c : str) {
m_ostr << (booleanElement ? "true" : "false"); switch (c) {
} case '"': ostr << "\\\""; break;
case '\\': ostr << "\\\\"; break;
void Writer::Write(String const& stringElement) { case '\b': ostr << "\\b"; break;
m_ostr << '"'; case '\f': ostr << "\\f"; break;
case '\n': ostr << "\\n"; break;
std::string::const_iterator it(stringElement.begin()), itend(stringElement.end()); case '\r': ostr << "\\r"; break;
for (; it != itend; ++it) { case '\t': ostr << "\\t"; break;
switch (*it) { default: ostr << c; break;
case '"': m_ostr << "\\\""; break;
case '\\': m_ostr << "\\\\"; break;
case '\b': m_ostr << "\\b"; break;
case '\f': m_ostr << "\\f"; break;
case '\n': m_ostr << "\\n"; break;
case '\r': m_ostr << "\\r"; break;
case '\t': m_ostr << "\\t"; break;
default: m_ostr << *it; break;
} }
} }
m_ostr << '"'; ostr << '"';
} }
void Writer::Write(Null const&) { void JsonWriter::Visit(int64_t i) { ostr << i; }
m_ostr << "null"; void JsonWriter::Visit(bool b) { ostr << (b ? "true" : "false"); }
void JsonWriter::Visit(json::Null const&) { ostr << "null"; }
void JsonWriter::Visit(json::UnknownElement const& unknown) { unknown.Accept(*this); }
} }
void Writer::Write(UnknownElement const& unknown) {
unknown.Accept(*this);
}
void Writer::Visit(Array const& array) { Write(array); }
void Writer::Visit(Object const& object) { Write(object); }
void Writer::Visit(Integer const& integer) { Write(integer); }
void Writer::Visit(Double const& dbl) { Write(dbl); }
void Writer::Visit(String const& string) { Write(string); }
void Writer::Visit(Boolean const& boolean) { Write(boolean); }
void Writer::Visit(Null const& null) { Write(null); }
} // end namespace

View File

@ -162,7 +162,7 @@ void Hotkey::Flush() {
} }
io::Save file(config_file); io::Save file(config_file);
json::Writer::Write(root, file.Get()); agi::JsonWriter::Write(root, file.Get());
} }
void Hotkey::SetHotkeyMap(HotkeyMap const& new_map) { void Hotkey::SetHotkeyMap(HotkeyMap const& new_map) {

View File

@ -113,7 +113,7 @@ void JsonEmitter::log(SinkMessage const& sm) {
entry["func"] = sm.func; entry["func"] = sm.func;
entry["line"] = sm.line; entry["line"] = sm.line;
entry["message"] = sm.message; entry["message"] = sm.message;
json::Writer::Write(entry, *fp); agi::JsonWriter::Write(entry, *fp);
fp->flush(); fp->flush();
} }

View File

@ -89,11 +89,11 @@ void MRUManager::Flush() {
for (auto const& mru_map : mru) { for (auto const& mru_map : mru) {
json::Array &array = out[mru_map.first]; json::Array &array = out[mru_map.first];
transform(begin(mru_map.second), end(mru_map.second), for (auto const& p : mru_map.second)
back_inserter(array), [](agi::fs::path const& p) { return p.string(); }); array.push_back(p.string());
} }
json::Writer::Write(out, io::Save(config_name).Get()); agi::JsonWriter::Write(out, io::Save(config_name).Get());
} }
void MRUManager::Prune(std::string const& key, MRUListMap& map) const { void MRUManager::Prune(std::string const& key, MRUListMap& map) const {

View File

@ -106,11 +106,11 @@ class ConfigVisitor final : public json::ConstVisitor {
Error("Array type not handled"); Error("Array type not handled");
} }
void Visit(const json::Integer& number) { void Visit(int64_t number) {
values.push_back(agi::make_unique<OptionValueInt>(name, number)); values.push_back(agi::make_unique<OptionValueInt>(name, number));
} }
void Visit(const json::Double& number) { void Visit(double number) {
values.push_back(agi::make_unique<OptionValueDouble>(name, number)); values.push_back(agi::make_unique<OptionValueDouble>(name, number));
} }
@ -127,7 +127,7 @@ class ConfigVisitor final : public json::ConstVisitor {
} }
} }
void Visit(const json::Boolean& boolean) { void Visit(bool boolean) {
values.push_back(agi::make_unique<OptionValueBool>(name, boolean)); values.push_back(agi::make_unique<OptionValueBool>(name, boolean));
} }
@ -316,7 +316,7 @@ void Options::Flush() const {
} }
} }
json::Writer::Write(obj_out, io::Save(config_file).Get()); agi::JsonWriter::Write(obj_out, io::Save(config_file).Get());
} }
} // namespace agi } // namespace agi

View File

@ -30,10 +30,10 @@ struct ConstVisitor {
virtual void Visit(const Array& array) = 0; virtual void Visit(const Array& array) = 0;
virtual void Visit(const Object& object) = 0; virtual void Visit(const Object& object) = 0;
virtual void Visit(const Integer& number) = 0; virtual void Visit(int64_t number) = 0;
virtual void Visit(const Double& number) = 0; virtual void Visit(double number) = 0;
virtual void Visit(const String& string) = 0; virtual void Visit(const String& string) = 0;
virtual void Visit(const Boolean& boolean) = 0; virtual void Visit(bool boolean) = 0;
virtual void Visit(const Null& null) = 0; virtual void Visit(const Null& null) = 0;
}; };

View File

@ -1,54 +1,47 @@
/********************************************** // Copyright (c) 2014, Thomas Goyne <plorkyeran@aegisub.org>
//
// Permission to use, copy, modify, and 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.
//
// Aegisub Project http://www.aegisub.org/
License: BSD
Project Webpage: http://cajun-jsonapi.sourceforge.net/
Author: Terry Caton
***********************************************/
#pragma once
#include "elements.h"
#include "visitor.h" #include "visitor.h"
#include <ostream> #include <ostream>
#include <string>
namespace json { namespace agi {
class Writer final : private ConstVisitor { class JsonWriter final : json::ConstVisitor {
Writer(std::ostream& ostr); std::ostream &ostr;
void Write(const Object& object); std::string indent;
void Write(const Array& array);
void Write(const String& string);
void Write(const Integer& number);
void Write(const Double& number);
void Write(const Boolean& boolean);
void Write(const Null& null);
void Write(const UnknownElement& unknown);
void Visit(const Array& array) override; JsonWriter(std::ostream &ostr) : ostr(ostr) { }
void Visit(const Object& object) override;
void Visit(const Integer& number) override;
void Visit(const Double& number) override;
void Visit(const String& string) override;
void Visit(const Boolean& boolean) override;
void Visit(const Null& null) override;
std::ostream& m_ostr; void Visit(json::Array const& array) override;
int tab_depth = 0; void Visit(bool boolean) override;
void Visit(double number) override;
void Visit(int64_t number) override;
void Visit(json::Null const& null) override;
void Visit(json::Object const& object) override;
void Visit(std::string const& string) override;
void Visit(json::UnknownElement const& unknown);
public: public:
template <typename ElementTypeT> template <typename T>
static void Write(const ElementTypeT& element, std::ostream& ostr) { static void Write(T const& value, std::ostream& ostr) {
Writer writer(ostr); JsonWriter(ostr).Visit(value);
writer.Write(element); ostr.flush();
ostr.flush(); // all done
} }
}; };
inline std::ostream& operator <<(std::ostream& ostr, UnknownElement const& elementRoot) {
Writer::Write(elementRoot, ostr);
return ostr;
} }
} // End namespace

View File

@ -321,7 +321,7 @@ void DialogShiftTimes::SaveHistory(json::Array const& shifted_blocks) {
history.resize(50); history.resize(50);
try { try {
json::Writer::Write(history, agi::io::Save(history_filename).Get()); agi::JsonWriter::Write(history, agi::io::Save(history_filename).Get());
} }
catch (agi::fs::FileSystemError const& e) { catch (agi::fs::FileSystemError const& e) {
LOG_E("dialog_shift_times/save_history") << "Cannot save shift times history: " << e.GetMessage(); LOG_E("dialog_shift_times/save_history") << "Cannot save shift times history: " << e.GetMessage();
@ -333,9 +333,8 @@ void DialogShiftTimes::LoadHistory() {
history_box->Freeze(); history_box->Freeze();
try { try {
std::unique_ptr<std::istream> file(agi::io::Open(history_filename));
json::UnknownElement root; json::UnknownElement root;
json::Reader::Read(root, *file); json::Reader::Read(root, *agi::io::Open(history_filename));
history = root; history = root;
for (auto& history_entry : history) for (auto& history_entry : history)

View File

@ -281,27 +281,27 @@ TEST_F(lagi_cajun, Write) {
obj["String"] = "This \"is\" \\a \t test"; obj["String"] = "This \"is\" \\a \t test";
std::stringstream stream; std::stringstream stream;
EXPECT_NO_THROW(json::Writer::Write(obj, stream)); EXPECT_NO_THROW(agi::JsonWriter::Write(obj, stream));
EXPECT_STREQ("{\n\t\"Boolean\" : true,\n\t\"String\" : \"This \\\"is\\\" \\\\a \\t test\"\n}", stream.str().c_str()); EXPECT_STREQ("{\n\t\"Boolean\" : true,\n\t\"String\" : \"This \\\"is\\\" \\\\a \\t test\"\n}", stream.str().c_str());
stream.str(""); stream.str("");
EXPECT_NO_THROW(json::Writer::Write(json::Array(), stream)); EXPECT_NO_THROW(agi::JsonWriter::Write(json::Array(), stream));
EXPECT_STREQ("[]", stream.str().c_str()); EXPECT_STREQ("[]", stream.str().c_str());
stream.str(""); stream.str("");
EXPECT_NO_THROW(json::Writer::Write(json::Object(), stream)); EXPECT_NO_THROW(agi::JsonWriter::Write(json::Object(), stream));
EXPECT_STREQ("{}", stream.str().c_str()); EXPECT_STREQ("{}", stream.str().c_str());
stream.str(""); stream.str("");
EXPECT_NO_THROW(json::Writer::Write(true, stream)); EXPECT_NO_THROW(agi::JsonWriter::Write(true, stream));
EXPECT_STREQ("true", stream.str().c_str()); EXPECT_STREQ("true", stream.str().c_str());
stream.str(""); stream.str("");
EXPECT_NO_THROW(json::Writer::Write(false, stream)); EXPECT_NO_THROW(agi::JsonWriter::Write(false, stream));
EXPECT_STREQ("false", stream.str().c_str()); EXPECT_STREQ("false", stream.str().c_str());
stream.str(""); stream.str("");
EXPECT_NO_THROW(json::Writer::Write(json::Null(), stream)); EXPECT_NO_THROW(agi::JsonWriter::Write(json::Null(), stream));
EXPECT_STREQ("null", stream.str().c_str()); EXPECT_STREQ("null", stream.str().c_str());
} }
@ -355,7 +355,7 @@ std::string roundtrip_test(const char *in) {
json::Reader::Read(ele, iss); json::Reader::Read(ele, iss);
std::stringstream oss; std::stringstream oss;
json::Writer::Write(ele, oss); agi::JsonWriter::Write(ele, oss);
return oss.str(); return oss.str();
} }