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(Array const&) { }
void Visit(Object const&) { }
void Visit(Integer const&) { }
void Visit(Double const&) { }
void Visit(Integer) { }
void Visit(Double) { }
void Visit(String const&) { }
void Visit(Boolean const&) { }
void Visit(Boolean) { }
void Visit(Null const&) { is_null = true; }
public:
bool is_null = false;

View file

@ -1,125 +1,100 @@
/**********************************************
License: BSD
Project Webpage: http://cajun-jsonapi.sourceforge.net/
Author: Terry Caton
***********************************************/
// 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/
#include "libaegisub/cajun/writer.h"
#include <cmath>
#include <iomanip>
/*
TODO:
* better documentation
* unicode character encoding
*/
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') << ']';
namespace agi {
void JsonWriter::Visit(json::Array const& array) {
if (array.empty()) {
ostr << "[]";
return;
}
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) {
if (object.empty())
m_ostr << "{}";
else {
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') << '}';
void JsonWriter::Visit(json::Object const& object) {
if (object.empty()) {
ostr << "{}";
return;
}
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) {
m_ostr << std::setprecision(20) << numberElement;
void JsonWriter::Visit(double d) {
ostr << std::setprecision(20) << d;
double unused;
if (!std::modf(numberElement, &unused))
m_ostr << ".0";
if (!std::modf(d, &unused))
ostr << ".0";
}
void Writer::Write(Integer const& numberElement) {
m_ostr << numberElement;
}
void JsonWriter::Visit(std::string const& str) {
ostr << '"';
void Writer::Write(Boolean const& booleanElement) {
m_ostr << (booleanElement ? "true" : "false");
}
void Writer::Write(String const& stringElement) {
m_ostr << '"';
std::string::const_iterator it(stringElement.begin()), itend(stringElement.end());
for (; it != itend; ++it) {
switch (*it) {
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;
for (auto c : str) {
switch (c) {
case '"': ostr << "\\\""; break;
case '\\': ostr << "\\\\"; break;
case '\b': ostr << "\\b"; break;
case '\f': ostr << "\\f"; break;
case '\n': ostr << "\\n"; break;
case '\r': ostr << "\\r"; break;
case '\t': ostr << "\\t"; break;
default: ostr << c; break;
}
}
m_ostr << '"';
ostr << '"';
}
void Writer::Write(Null const&) {
m_ostr << "null";
void JsonWriter::Visit(int64_t i) { ostr << i; }
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);
json::Writer::Write(root, file.Get());
agi::JsonWriter::Write(root, file.Get());
}
void Hotkey::SetHotkeyMap(HotkeyMap const& new_map) {

View file

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

View file

@ -89,11 +89,11 @@ void MRUManager::Flush() {
for (auto const& mru_map : mru) {
json::Array &array = out[mru_map.first];
transform(begin(mru_map.second), end(mru_map.second),
back_inserter(array), [](agi::fs::path const& p) { return p.string(); });
for (auto const& p : mru_map.second)
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 {

View file

@ -106,11 +106,11 @@ class ConfigVisitor final : public json::ConstVisitor {
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));
}
void Visit(const json::Double& number) {
void Visit(double 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));
}
@ -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

View file

@ -30,10 +30,10 @@ struct ConstVisitor {
virtual void Visit(const Array& array) = 0;
virtual void Visit(const Object& object) = 0;
virtual void Visit(const Integer& number) = 0;
virtual void Visit(const Double& number) = 0;
virtual void Visit(int64_t number) = 0;
virtual void Visit(double number) = 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;
};

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 <ostream>
#include <string>
namespace json {
namespace agi {
class Writer final : private ConstVisitor {
Writer(std::ostream& ostr);
void Write(const Object& object);
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);
class JsonWriter final : json::ConstVisitor {
std::ostream &ostr;
std::string indent;
void Visit(const Array& array) override;
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;
JsonWriter(std::ostream &ostr) : ostr(ostr) { }
std::ostream& m_ostr;
int tab_depth = 0;
void Visit(json::Array const& array) override;
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:
template <typename ElementTypeT>
static void Write(const ElementTypeT& element, std::ostream& ostr) {
Writer writer(ostr);
writer.Write(element);
ostr.flush(); // all done
template <typename T>
static void Write(T const& value, std::ostream& ostr) {
JsonWriter(ostr).Visit(value);
ostr.flush();
}
};
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);
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) {
LOG_E("dialog_shift_times/save_history") << "Cannot save shift times history: " << e.GetMessage();
@ -333,9 +333,8 @@ void DialogShiftTimes::LoadHistory() {
history_box->Freeze();
try {
std::unique_ptr<std::istream> file(agi::io::Open(history_filename));
json::UnknownElement root;
json::Reader::Read(root, *file);
json::Reader::Read(root, *agi::io::Open(history_filename));
history = root;
for (auto& history_entry : history)

View file

@ -281,27 +281,27 @@ TEST_F(lagi_cajun, Write) {
obj["String"] = "This \"is\" \\a \t test";
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());
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());
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());
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());
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());
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());
}
@ -355,7 +355,7 @@ std::string roundtrip_test(const char *in) {
json::Reader::Read(ele, iss);
std::stringstream oss;
json::Writer::Write(ele, oss);
agi::JsonWriter::Write(ele, oss);
return oss.str();
}