Skip to content

Instantly share code, notes, and snippets.

@azaika
Last active December 23, 2019 16:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save azaika/c2d884b9c54b7de725841b1259c01e7e to your computer and use it in GitHub Desktop.
Save azaika/c2d884b9c54b7de725841b1259c01e7e to your computer and use it in GitHub Desktop.
# pragma once
# include <memory>
# include <variant>
# include "Fwd.hpp"
# include "TextReader.hpp"
# include "TextWriter.hpp"
# include "Array.hpp"
namespace s3d
{
// Fwd.hpp に書く
//////////////////////////////////////////////////////
//
// JSONData.hpp
//
struct JSONItem;
class JSONDataIterator;
class JSONDataConstIterator;
class JSONData;
namespace detail
{
struct JSONDataIteratorDetail;
struct JSONDataConstIteratorDetail;
struct JSONDataDetail;
}
class JSONDataIterator
{
private:
std::shared_ptr<detail::JSONDataIteratorDetail> m_detail;
public:
JSONDataIterator() = default;
JSONDataIterator(const JSONDataIterator&);
explicit JSONDataIterator(const detail::JSONDataIteratorDetail&);
JSONDataIterator& operator = (const JSONDataIterator& rhs)
{
JSONDataIterator tmp = rhs;
m_detail = std::move(tmp.m_detail);
return *this;
}
JSONDataIterator& operator++();
JSONDataIterator operator++(int);
[[nodiscard]] JSONDataIterator operator +(size_t index) const;
[[nodiscard]] JSONItem operator *() const;
[[nodiscard]] String key() const;
[[nodiscard]] JSONData value() const;
[[nodiscard]] bool operator ==(const JSONDataIterator& other) const noexcept;
[[nodiscard]] bool operator !=(const JSONDataIterator& other) const noexcept
{
return !(*this == other);
}
};
class JSONDataConstIterator
{
private:
std::shared_ptr<detail::JSONDataConstIteratorDetail> m_detail;
public:
JSONDataConstIterator() = default;
JSONDataConstIterator(const JSONDataConstIterator&);
explicit JSONDataConstIterator(const detail::JSONDataConstIteratorDetail&);
JSONDataConstIterator& operator = (const JSONDataConstIterator& rhs)
{
JSONDataConstIterator tmp = rhs;
m_detail = std::move(tmp.m_detail);
return *this;
}
JSONDataConstIterator& operator++();
JSONDataConstIterator operator++(int);
[[nodiscard]] JSONDataConstIterator operator +(size_t index) const;
[[nodiscard]] const JSONItem operator *() const;
[[nodiscard]] String key() const;
[[nodiscard]] const JSONData value() const;
[[nodiscard]] bool operator ==(const JSONDataConstIterator& other) const noexcept;
[[nodiscard]] bool operator !=(const JSONDataConstIterator& other) const noexcept
{
return !(*this == other);
}
};
class JSONData
{
private:
std::shared_ptr<detail::JSONDataDetail> m_data;
Optional<int64> getOptInt64() const;
Optional<double> getOptDouble() const;
Optional<String> getOptString() const;
Optional<bool> getOptBool() const;
public:
using reference = JSONData;
using const_reference = const JSONData;
using iterator = JSONDataIterator;
using const_iterator = JSONDataConstIterator;
JSONData() : JSONData(nullptr) {};
JSONData(JSONData&&) = default;
JSONData(const JSONData& data);
explicit JSONData(const detail::JSONDataDetail&);
JSONData(std::nullptr_t);
JSONData(int64 value);
JSONData(uint64 value);
JSONData(double value);
JSONData(bool value);
template <class Type, std::enable_if_t<std::is_integral_v<Type>> * = nullptr>
JSONData(Type value) : JSONData(static_cast<int64>(value)) {}
JSONData(StringView value);
template <class Type, std::enable_if_t<std::is_constructible_v<StringView, Type>> * = nullptr>
JSONData(Type&& value) : JSONData(StringView(std::forward<Type>(value))) {}
JSONData(const Array<JSONData>& array);
template <class Type, std::enable_if_t<!std::is_same_v<std::decay_t<Type>, JSONData> && std::is_constructible_v<JSONData, Type>> * = nullptr>
JSONData(const Array<Type>& arr) : JSONData(arr.map([](auto&& v) { return JSONData(v); })) {}
template <class Type, std::enable_if_t<std::is_constructible_v<JSONData, Type>> * = nullptr>
JSONData(const std::initializer_list<Type>& list) : JSONData(Array(list)) {}
JSONData(const std::initializer_list<std::pair<String, JSONData>>& list);
[[nodiscard]] bool isEmpty() const { return !m_data; }
[[nodiscard]] explicit operator bool() const { return !isEmpty(); }
[[nodiscard]] bool isNull() const;
[[nodiscard]] bool isBool() const;
[[nodiscard]] bool isNumber() const;
[[nodiscard]] bool isInteger() const;
[[nodiscard]] bool isUnsigned() const;
[[nodiscard]] bool isFloat() const;
[[nodiscard]] bool isString() const;
[[nodiscard]] bool isArray() const;
[[nodiscard]] bool isObject() const;
[[nodiscard]] JSONValueType getType() const;
[[nodiscard]] bool hasMember(StringView name) const;
[[nodiscard]] String getString() const;
template <class Type>
[[nodiscard]] Type get() const
{
return getOpt<Type>().value_or(Type());
}
template <class Type, class U>
[[nodiscard]] Type getOr(U&& defaultValue) const
{
return getOpt<Type>().value_or(std::forward<U>(defaultValue));
}
template <class Type>
[[nodiscard]] Optional<Type> getOpt() const
{
return getOpt_<Type>();
}
template <>
[[nodiscard]] Optional<String> getOpt<String>() const
{
return getOptString();
}
template <>
[[nodiscard]] Optional<int64> getOpt<int64>() const
{
return getOptInt64();
}
template <>
[[nodiscard]] Optional<double> getOpt<double>() const
{
return getOptDouble();
}
template <>
[[nodiscard]] Optional<bool> getOpt<bool>() const
{
return getOptBool();
}
reference operator [](StringView name);
[[nodiscard]] const_reference operator [](StringView name) const;
reference operator [](size_t idx);
[[nodiscard]] const_reference operator [](size_t idx) const;
// get reference to the child by JSON pointer
reference access(StringView jsonPointer);
[[nodiscard]] const_reference access(StringView jsonPointer) const;
[[nodiscard]] iterator begin();
[[nodiscard]] const_iterator begin() const;
[[nodiscard]] iterator end();
[[nodiscard]] const_iterator end() const;
[[nodiscard]] size_t size() const;
[[nodiscard]] String format(char32 ch = U' ', size_t count = 2) const;
[[nodiscard]] String formatMinimum() const;
bool parse(StringView str);
bool load(FilePathView path);
template <class Reader, std::enable_if_t<std::is_base_of_v<IReader, Reader>> * = nullptr>
bool load(Reader&& reader)
{
return load(std::make_shared<Reader>(std::move(reader)));
}
bool load(const std::shared_ptr<IReader>& reader)
{
TextReader textReader(reader);
if (!textReader)
{
*this = nullptr;
return false;
}
return parse(textReader.readAll());
}
bool save(FilePathView path) const
{
TextWriter writer(path);
if (!writer)
{
return false;
}
writer.write(format());
return true;
}
bool saveMinimum(FilePathView path) const
{
TextWriter writer(path);
if (!writer)
{
return false;
}
writer.write(formatMinimum());
return true;
}
JSONData& operator = (int64 value);
JSONData& operator = (uint64 value);
JSONData& operator = (double value);
JSONData& operator = (bool value);
template <class Type, std::enable_if_t<std::is_integral_v<Type>> * = nullptr>
JSONData& operator = (Type value)
{
*this = static_cast<int64>(value);
return *this;
}
JSONData& operator = (StringView str);
template <class Type, std::enable_if_t<std::is_constructible_v<StringView, Type>> * = nullptr>
JSONData& operator = (Type&& value)
{
*this = StringView(std::forward<Type>(value));
return *this;
}
JSONData& operator = (const Array<JSONData>& array);
template <class Type, std::enable_if_t<!std::is_same_v<std::decay_t<Type>, JSONData> && std::is_constructible_v<JSONData, Type>> * = nullptr>
JSONData& operator = (const Array<Type>& arr)
{
m_data = arr.map([](auto&& v) { return JSONData(v); });
return *this;
}
template <class Type, std::enable_if_t<std::is_constructible_v<JSONData, Type>> * = nullptr>
JSONData& operator = (const std::initializer_list<Type>& list)
{
m_data = Array(list);
return *this;
}
JSONData& operator = (const std::initializer_list<std::pair<String, JSONData>>& list);
};
struct JSONItem
{
String key;
JSONData value;
};
JSONData LoadJSON(FilePathView path);
void Formatter(FormatData& formatData, const JSONData& json);
}
# include <Siv3D.hpp> // OpenSiv3D v0.4.2
void Main()
{
JSONData json = LoadJSON(U"example/config/config.json");
// これでも OK
json.load(U"example/config/config.json");
if (!json) // もし読み込みに失敗したら
{
throw Error(U"Failed to load `config.json`");
}
// アクセス
Print << json[U"Window"][U"title"];
// Optional を使ったアクセス
if (auto&& bg = json[U"Scene"][U"background"].getOpt<String>())
{
Print << *bg;
}
// JSON Pointer を使ったアクセス
Print << json.access(U"/Items/1");
// 再代入
json = {
{U"Window", {
{U"title", U"My application"},
{U"width", 800},
{U"height", 600},
{U"sizable", false}
}},
{U"Scene", {
{U"background", Format(ColorF(0.8, 0.9, 1.0))},
}},
{U"Array", {
{11, 22, 33, 44, 55}
}},
{U"Items", {
{{
{U"label", U"Forest"},
{U"pos", {
{U"x", 100},
{U"y", 100}
}}
},
{
{U"label", U"Ocean"},
{U"pos", {
{U"x", 300},
{U"y", 200}
}}
},
{
{U"label", U"Mountain"},
{U"pos", {
{U"x", 500},
{U"y", 100}
}}
}}
}}
};
// for ループ可能
for (auto&& j : json)
{
// size() 関数で value の持つ要素数が分かる
Print << U"size({}) = {}"_fmt(j.key, j.value.size());
}
// format() で文字列化可能
Print << json[U"Items"][2][U"pos"].format();
// 保存
json.save(U"test.json");
// 不要なスペースを消して保存
json.saveMinimum(U"minimum.json");
while (System::Update())
{
}
}
//-----------------------------------------------
//
// This file is part of the Siv3D Engine.
//
// Copyright (c) 2008-2019 Ryo Suzuki
// Copyright (c) 2016-2019 OpenSiv3D Project
//
// Licensed under the MIT License.
//
//-----------------------------------------------
# include <nlohmann/json.hpp>
# include <Siv3D/JSONData.hpp>
# include <Siv3D/JSONReader.hpp>
# include <Siv3D/TextReader.hpp>
# include <Siv3D/Array.hpp>
# include <Siv3D/Error.hpp>
namespace s3d
{
namespace detail
{
struct JSONDataIteratorDetail
{
nlohmann::json::iterator it;
JSONDataIteratorDetail() = default;
JSONDataIteratorDetail(nlohmann::json::iterator _it)
: it(_it) {}
};
struct JSONDataConstIteratorDetail
{
nlohmann::json::const_iterator it;
JSONDataConstIteratorDetail() = default;
JSONDataConstIteratorDetail(nlohmann::json::const_iterator _it)
: it(_it) {}
};
struct JSONDataDetail
{
using Owner = nlohmann::json;
using Child = std::reference_wrapper<nlohmann::json>;
std::variant<Owner, Child> m_json;
JSONDataDetail() = default;
JSONDataDetail(const JSONDataDetail&) = default;
JSONDataDetail& operator = (JSONDataDetail&&) = default;
JSONDataDetail(const nlohmann::json& owner) : m_json(owner) {}
JSONDataDetail(nlohmann::json&& owner) : m_json(std::move(owner)) {}
JSONDataDetail(nlohmann::json& child) : m_json(child) {}
nlohmann::json& get()
{
if (m_json.index() == 0)
{
return std::get<0>(m_json);
}
return std::get<1>(m_json).get();
}
const nlohmann::json& get() const
{
if (m_json.index() == 0)
{
return std::get<0>(m_json);
}
return std::get<1>(m_json).get();
}
nlohmann::json* operator ->()
{
if (m_json.index() == 0)
{
return &std::get<0>(m_json);
}
return &std::get<1>(m_json).get();
}
const nlohmann::json* operator ->() const
{
if (m_json.index() == 0)
{
return &std::get<0>(m_json);
}
return &std::get<1>(m_json).get();
}
};
}
////////////////////////////////
//
// JSONDataIterator
//
JSONDataIterator::JSONDataIterator(const JSONDataIterator& rhs)
: m_detail(std::make_shared<detail::JSONDataIteratorDetail>(*rhs.m_detail)) {}
JSONDataIterator::JSONDataIterator(const detail::JSONDataIteratorDetail& d)
: m_detail(std::make_shared<detail::JSONDataIteratorDetail>(d.it)) {}
JSONDataIterator& JSONDataIterator::operator++()
{
++m_detail->it;
return *this;
}
JSONDataIterator JSONDataIterator::operator++(int)
{
const detail::JSONDataIteratorDetail tmp{ m_detail->it++ };
return JSONDataIterator(tmp);
}
JSONDataIterator JSONDataIterator::operator+(size_t index) const
{
const detail::JSONDataIteratorDetail tmp{ m_detail->it + index };
return JSONDataIterator(tmp);
}
JSONItem JSONDataIterator::operator *() const
{
return { key(), JSONData(detail::JSONDataDetail(*m_detail->it)) };
}
String JSONDataIterator::key() const
{
return Unicode::FromUTF8(m_detail->it.key());
}
JSONData JSONDataIterator::value() const
{
return JSONData(detail::JSONDataDetail(m_detail->it.value()));
}
bool JSONDataIterator::operator ==(const JSONDataIterator& other) const noexcept
{
return m_detail->it == other.m_detail->it;
}
////////////////////////////////
//
// JSONDataConstIterator
//
JSONDataConstIterator::JSONDataConstIterator(const JSONDataConstIterator& rhs)
: m_detail(std::make_shared<detail::JSONDataConstIteratorDetail>(*rhs.m_detail)) {}
JSONDataConstIterator::JSONDataConstIterator(const detail::JSONDataConstIteratorDetail& d)
: m_detail(std::make_shared<detail::JSONDataConstIteratorDetail>(d.it)) {}
JSONDataConstIterator& JSONDataConstIterator::operator++()
{
++m_detail->it;
return *this;
}
JSONDataConstIterator JSONDataConstIterator::operator++(int)
{
const detail::JSONDataConstIteratorDetail tmp{ m_detail->it++ };
return JSONDataConstIterator(tmp);
}
JSONDataConstIterator JSONDataConstIterator::operator+(size_t index) const
{
const detail::JSONDataConstIteratorDetail tmp{ m_detail->it + index };
return JSONDataConstIterator(tmp);
}
const JSONItem JSONDataConstIterator::operator *() const
{
return { key(), JSONData(detail::JSONDataDetail(const_cast<nlohmann::json&>(*m_detail->it))) };
}
String JSONDataConstIterator::key() const
{
return Unicode::FromUTF8(m_detail->it.key());
}
const JSONData JSONDataConstIterator::value() const
{
return JSONData(detail::JSONDataDetail(const_cast<nlohmann::json&>(*m_detail->it)));
}
bool JSONDataConstIterator::operator ==(const JSONDataConstIterator& other) const noexcept
{
return m_detail->it == other.m_detail->it;
}
////////////////////////////////
//
// JSONData
//
Optional<int64> JSONData::getOptInt64() const
{
if (!isNumber())
{
return none;
}
if (isBool())
{
return static_cast<int64>(m_data->get().get<bool>());
}
return m_data->get().get<int64_t>();
}
Optional<double> JSONData::getOptDouble() const
{
if (!isNumber())
{
return none;
}
return m_data->get().get<double>();
}
Optional<String> JSONData::getOptString() const
{
if (!isString())
{
return none;
}
return Optional<String>(InPlace, getString());
}
Optional<bool> JSONData::getOptBool() const
{
if (!isBool()) {
return none;
}
return m_data->get().get<bool>();
}
JSONData::JSONData(const JSONData& data)
{
if (data.m_data)
{
m_data = std::make_shared<detail::JSONDataDetail>(nlohmann::json(data.m_data->get()));
}
}
JSONData::JSONData(std::nullptr_t)
: m_data(std::make_shared<detail::JSONDataDetail>()) {}
JSONData::JSONData(const detail::JSONDataDetail& data)
: m_data(std::make_shared<detail::JSONDataDetail>(data)) {}
JSONData::JSONData(int64 value)
: m_data(std::make_shared<detail::JSONDataDetail>(nlohmann::json(value))) {}
JSONData::JSONData(uint64 value)
: m_data(std::make_shared<detail::JSONDataDetail>(nlohmann::json(value))) {}
JSONData::JSONData(double value)
: m_data(std::make_shared<detail::JSONDataDetail>(nlohmann::json(value))) {}
JSONData::JSONData(bool value)
: m_data(std::make_shared<detail::JSONDataDetail>(nlohmann::json(value))) {}
JSONData::JSONData(StringView value)
: m_data(std::make_shared<detail::JSONDataDetail>(nlohmann::json(Unicode::ToUTF8(value)))) {}
JSONData::JSONData(const Array<JSONData>& array)
: m_data()
{
*this = array;
}
JSONData::JSONData(const std::initializer_list<std::pair<String, JSONData>>& list)
: m_data()
{
*this = list;
}
bool JSONData::isNull() const
{
return !isEmpty() && m_data->get().is_null();
}
bool JSONData::isBool() const
{
return !isEmpty() && m_data->get().is_boolean();
}
bool JSONData::isNumber() const
{
return !isEmpty() && m_data->get().is_number();
}
bool JSONData::isInteger() const
{
return !isEmpty() && m_data->get().is_number_integer();
}
bool JSONData::isUnsigned() const
{
return !isEmpty() && m_data->get().is_number_unsigned();
}
bool JSONData::isFloat() const
{
return !isEmpty() && m_data->get().is_number_float();
}
bool JSONData::isString() const
{
return !isEmpty() && m_data->get().is_string();
}
bool JSONData::isArray() const
{
return !isEmpty() && m_data->get().is_array();
}
bool JSONData::isObject() const
{
return !isEmpty() && m_data->get().is_object();
}
JSONValueType JSONData::getType() const
{
if (isEmpty())
{
return JSONValueType::Empty;
}
else if (isArray())
{
return JSONValueType::Array;
}
else if (isBool())
{
return JSONValueType::Bool;
}
else if (isNull())
{
return JSONValueType::Null;
}
else if (isNumber())
{
return JSONValueType::Number;
}
else if (isObject())
{
return JSONValueType::Object;
}
else if (isString())
{
return JSONValueType::String;
}
throw Error(U"Unknown JSONData");
}
bool JSONData::hasMember(StringView name) const
{
return !isEmpty() && m_data->get().contains(Unicode::ToUTF8(name));
}
String JSONData::getString() const
{
if (!isString())
{
return String();
}
return Unicode::FromUTF8(m_data->get().get<std::string>());
}
JSONData::reference JSONData::operator [](StringView name)
{
if (isObject() || isNull())
{
return JSONData(detail::JSONDataDetail(m_data->get()[Unicode::ToUTF8(name)]));
}
throw Error(U"JSONData::operator []() : Invalid JSON type");
}
JSONData::const_reference JSONData::operator [](StringView name) const
{
if (!isObject())
{
throw Error(U"JSONData::operator []() : Invalid JSON type");
}
auto it = m_data->get().find(Unicode::ToUTF8(name));
if (it != m_data->get().end())
{
return JSONData(detail::JSONDataDetail(const_cast<nlohmann::json&>(it.value())));
}
throw Error(U"JSONData::operator []() : The key named \"" + name + U"\" does not exsist.");
}
JSONData::reference JSONData::operator[](size_t idx)
{
if (isArray() || isNull())
{
return JSONData(detail::JSONDataDetail(m_data->get()[idx]));
}
throw Error(U"JSONData::operator []() : Invalid JSON type");
}
JSONData::const_reference JSONData::operator[](size_t idx) const
{
if (!isArray())
{
throw Error(U"JSONData::operator []() : Invalid JSON type");
}
if (m_data->get().size() <= idx)
{
return JSONData(detail::JSONDataDetail(const_cast<nlohmann::json&>(m_data->get()[idx])));
}
throw Error(U"JSONData::operator []() : Out of range.");
}
JSONData::reference JSONData::access(StringView jsonPointer)
{
if (jsonPointer.empty() || jsonPointer[0] != U'/')
{
throw Error(U"JSONData::access() : Invalid JSON pointer");
}
if (isObject() || isArray() || isNull())
{
return JSONData(detail::JSONDataDetail(m_data->get()[nlohmann::json::json_pointer(Unicode::ToUTF8(jsonPointer))]));
}
throw Error(U"JSONData::access() : Invalid JSON type");
}
JSONData::const_reference JSONData::access(StringView jsonPointer) const
{
if (jsonPointer.empty() || jsonPointer[0] != U'/')
{
throw Error(U"JSONData::access() : Invalid JSON pointer");
}
if (!isObject() && !isArray())
{
throw Error(U"JSONData::access() const : Invalid JSON type");
}
auto&& pointer = nlohmann::json::json_pointer(Unicode::ToUTF8(jsonPointer));
if (m_data->get().contains(pointer))
{
return JSONData(detail::JSONDataDetail(const_cast<nlohmann::json&>(m_data->get()[pointer])));
}
throw Error(U"JSONData::access() : The key specified by \"" + jsonPointer + U"\" does not exsist.");
}
JSONData::iterator JSONData::begin()
{
return iterator(detail::JSONDataIteratorDetail(m_data->get().begin()));
}
JSONData::const_iterator JSONData::begin() const
{
return const_iterator(detail::JSONDataConstIteratorDetail(m_data->get().begin()));
}
JSONData::iterator JSONData::end()
{
return iterator(detail::JSONDataIteratorDetail(m_data->get().end()));
}
JSONData::const_iterator JSONData::end() const
{
return const_iterator(detail::JSONDataConstIteratorDetail(m_data->get().end()));
}
size_t JSONData::size() const
{
if (!isArray())
{
return 0;
}
return m_data->get().size();
}
String JSONData::format(char32 ch, size_t count) const
{
if (isEmpty())
{
return String();
}
return Unicode::FromUTF8(m_data->get().dump(static_cast<int>(count), static_cast<char>(ch)));
}
String JSONData::formatMinimum() const
{
if (isEmpty())
{
return String();
}
return Unicode::FromUTF8(m_data->get().dump());
}
bool JSONData::parse(StringView str)
{
m_data = std::make_shared<detail::JSONDataDetail>(nlohmann::json::parse(Unicode::ToUTF8(str)));
return static_cast<bool>(*this);
}
bool JSONData::load(FilePathView path)
{
TextReader reader(path);
if (!reader)
{
*this = nullptr;
}
else
{
m_data = std::make_shared<detail::JSONDataDetail>(nlohmann::json::parse(Unicode::ToUTF8(reader.readAll())));
}
return static_cast<bool>(*this);
}
JSONData& JSONData::operator = (int64 value)
{
m_data = std::make_shared<detail::JSONDataDetail>(nlohmann::json(value));
return *this;
}
JSONData& JSONData::operator = (uint64 value)
{
m_data = std::make_shared<detail::JSONDataDetail>(nlohmann::json(value));
return *this;
}
JSONData& JSONData::operator = (double value)
{
m_data = std::make_shared<detail::JSONDataDetail>(nlohmann::json(value));
return *this;
}
JSONData& JSONData::operator = (bool value)
{
m_data = std::make_shared<detail::JSONDataDetail>(nlohmann::json(value));
return *this;
}
JSONData& JSONData::operator = (StringView str)
{
m_data = std::make_shared<detail::JSONDataDetail>(nlohmann::json(Unicode::ToUTF8(str)));
return *this;
}
JSONData& JSONData::operator = (const Array<JSONData>& array)
{
m_data = std::make_shared<detail::JSONDataDetail>(
array.map(
[](auto&& data)
{
return (data.m_data ? data.m_data->get() : nlohmann::json());
}
));
return *this;
}
JSONData& JSONData::operator = (const std::initializer_list<std::pair<String, JSONData>>& list)
{
m_data = std::make_shared<detail::JSONDataDetail>(nlohmann::json::object());
for (auto&& data : list)
{
m_data->get()[Unicode::ToUTF8(data.first)] = (data.second.m_data ? data.second.m_data->get() : nlohmann::json());
}
return *this;
}
JSONData LoadJSON(FilePathView path)
{
JSONData json;
json.load(path);
return std::move(json);
}
////////////////////////////////
//
// Format
//
void Formatter(FormatData& formatData, const JSONData& json)
{
if (json)
{
Formatter(formatData, json.format());
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment