Magic_Game/Easy2D/common/Json.h

2693 lines
61 KiB
C
Raw Normal View History

// Copyright (c) 2016-2018 Easy2D - Nomango
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#pragma once
#include "helper.h"
#include <cstdint>
#include <cctype>
#include <array>
#include <iosfwd>
namespace easy2d
{
template <
template <class _Kty, class _Ty, class ..._Args> typename _ObjectTy = easy2d::Map,
template <class _Kty, class ..._Args> typename _ArrayTy = easy2d::Array,
typename _StringTy = easy2d::String,
typename _IntegerTy = std::int32_t,
typename _FloatTy = double,
typename _BooleanTy = bool,
template <class _Ty> typename _Allocator = std::allocator>
class basic_json;
using Json = basic_json<>;
//
// details of basic_json
//
#define E2D_DECLARE_BASIC_JSON_TEMPLATE\
template <\
template <class _Kty, class _Ty, class ..._Args> typename _ObjectTy, \
template <class _Kty, class ..._Args> typename _ArrayTy, \
typename _StringTy, \
typename _IntegerTy, \
typename _FloatTy, \
typename _BooleanTy, \
template <class _Ty> typename _Allocator>
#define E2D_DECLARE_BASIC_JSON_TPL_ARGS \
_ObjectTy, _ArrayTy, _StringTy, _IntegerTy, _FloatTy, _BooleanTy, _Allocator
//
// json value type
//
enum class JsonType
{
Integer,
Float,
String,
Array,
Object,
Boolean,
Null,
};
//
// is_basic_json
//
template <typename>
struct is_basic_json
: ::std::false_type
{
};
E2D_DECLARE_BASIC_JSON_TEMPLATE
struct is_basic_json< basic_json<E2D_DECLARE_BASIC_JSON_TPL_ARGS> >
: ::std::true_type
{
};
//
// exceptions
//
class json_exception
: public std::runtime_error
{
public:
json_exception(const char* message)
: std::runtime_error(message)
{}
};
class json_type_error
: public json_exception
{
public:
json_type_error(const char* message) : json_exception(message) {}
};
class json_invalid_key
: public json_exception
{
public:
json_invalid_key(const char* message) : json_exception(message) {}
};
class json_invalid_iterator
: public json_exception
{
public:
json_invalid_iterator(const char* message) : json_exception(message) {}
};
class json_parse_error
: public json_exception
{
public:
json_parse_error(const char* message) : json_exception(message) {}
};
namespace __json_detail
{
//
// json_value
//
template <typename _BasicJsonTy>
struct json_value
{
using string_type = typename _BasicJsonTy::string_type;
using char_type = typename _BasicJsonTy::char_type;
using integer_type = typename _BasicJsonTy::integer_type;
using float_type = typename _BasicJsonTy::float_type;
using boolean_type = typename _BasicJsonTy::boolean_type;
using array_type = typename _BasicJsonTy::array_type;
using object_type = typename _BasicJsonTy::object_type;
JsonType type;
union
{
object_type* object;
array_type* vector;
string_type* string;
integer_type number_integer;
float_type number_float;
boolean_type boolean;
} data;
json_value()
{
type = JsonType::Null;
data.object = nullptr;
}
json_value(std::nullptr_t)
{
type = JsonType::Null;
data.object = nullptr;
}
json_value(const object_type& value)
{
type = JsonType::Object;
data.object = create<object_type>(value);
}
json_value(const array_type& value)
{
type = JsonType::Array;
data.vector = create<array_type>(value);
}
json_value(const string_type& value)
{
type = JsonType::String;
data.string = create<string_type>(value);
}
template <typename _CharT>
json_value(const _CharT* str)
{
type = JsonType::String;
data.string = create<string_type>(str);
}
json_value(const integer_type value)
{
type = JsonType::Integer;
data.number_integer = value;
}
json_value(const float_type value)
{
type = JsonType::Float;
data.number_float = value;
}
json_value(const boolean_type value)
{
type = JsonType::Boolean;
data.boolean = value;
}
json_value(const JsonType value_type)
{
type = value_type;
switch (type)
{
case JsonType::Object:
data.object = create<object_type>();
break;
case JsonType::Array:
data.vector = create<array_type>();
break;
case JsonType::String:
data.string = create<string_type>();
break;
case JsonType::Integer:
data.number_integer = integer_type(0);
break;
case JsonType::Float:
data.number_float = float_type(0.0);
break;
case JsonType::Boolean:
data.boolean = boolean_type(false);
break;
default:
data.object = nullptr;
break;
}
}
json_value(json_value const& other)
{
type = other.type;
switch (other.type)
{
case JsonType::Object:
data.object = create<object_type>(*other.data.object);
break;
case JsonType::Array:
data.vector = create<array_type>(*other.data.vector);
break;
case JsonType::String:
data.string = create<string_type>(*other.data.string);
break;
case JsonType::Integer:
data.number_integer = other.data.number_integer;
break;
case JsonType::Float:
data.number_float = other.data.number_float;
break;
case JsonType::Boolean:
data.boolean = other.data.boolean;
break;
default:
data.object = nullptr;
break;
}
}
json_value(json_value&& other)
{
type = other.type;
data = other.data;
other.type = JsonType::Null;
other.data.object = nullptr;
}
~json_value()
{
clear();
}
void swap(json_value& other)
{
std::swap(type, other.type);
std::swap(data, other.data);
}
void clear()
{
switch (type)
{
case JsonType::Object:
destroy<object_type>(data.object);
break;
case JsonType::Array:
destroy<array_type>(data.vector);
break;
case JsonType::String:
destroy<string_type>(data.string);
break;
default:
break;
}
}
template <typename _Ty, typename ..._Args>
inline _Ty* create(_Args&&... args)
{
using allocator_type = typename _BasicJsonTy::template allocator_type<_Ty>;
using allocator_traits = std::allocator_traits<allocator_type>;
allocator_type allocator;
_Ty* ptr = allocator_traits::allocate(allocator, 1);
allocator_traits::construct(allocator, ptr, std::forward<_Args>(args)...);
return ptr;
}
template <typename _Ty>
inline void destroy(_Ty* ptr)
{
using allocator_type = typename _BasicJsonTy::template allocator_type<_Ty>;
using allocator_traits = std::allocator_traits<allocator_type>;
allocator_type allocator;
allocator_traits::destroy(allocator, ptr);
allocator_traits::deallocate(allocator, ptr, 1);
}
inline json_value& operator=(json_value const& other)
{
json_value{ other }.swap(*this);
return (*this);
}
inline json_value& operator=(json_value && other)
{
clear();
type = other.type;
data = std::move(other.data);
// invalidate payload
other.type = JsonType::Null;
other.data.object = nullptr;
return (*this);
}
};
} // end of namespace __json_detail
namespace __json_detail
{
//
// iterator for basic_json
//
2019-04-04 14:25:13 +08:00
struct primitive_iterator
{
using difference_type = std::ptrdiff_t;
2019-04-04 14:25:13 +08:00
inline primitive_iterator(int it = 0) : it_(it) {}
inline void set_begin() { it_ = 0; }
inline void set_end() { it_ = 1; }
2019-04-04 14:25:13 +08:00
inline primitive_iterator& operator++() { ++it_; return *this; }
2019-04-04 14:25:13 +08:00
inline primitive_iterator operator++(int) { primitive_iterator old(it_); ++(*this); return old; }
2019-04-04 14:25:13 +08:00
inline primitive_iterator& operator--() { --it_; return (*this); }
inline primitive_iterator operator--(int) { primitive_iterator old = (*this); --(*this); return old; }
2019-04-04 14:25:13 +08:00
inline bool operator==(primitive_iterator const& other) const { return it_ == other.it_; }
inline bool operator!=(primitive_iterator const& other) const { return !(*this == other); }
2019-04-04 14:25:13 +08:00
inline const primitive_iterator operator+(difference_type off) const { return primitive_iterator(it_ + off); }
inline const primitive_iterator operator-(difference_type off) const { return primitive_iterator(it_ - off); }
2019-04-04 14:25:13 +08:00
inline primitive_iterator& operator+=(difference_type off) { it_ += off; return (*this); }
inline primitive_iterator& operator-=(difference_type off) { it_ -= off; return (*this); }
2019-04-04 14:25:13 +08:00
inline difference_type operator-(primitive_iterator const& other) const { return it_ - other.it_; }
2019-04-04 14:25:13 +08:00
inline bool operator<(primitive_iterator const& other) const { return it_ < other.it_; }
inline bool operator<=(primitive_iterator const& other) const { return it_ <= other.it_; }
inline bool operator>(primitive_iterator const& other) const { return it_ > other.it_; }
inline bool operator>=(primitive_iterator const& other) const { return it_ >= other.it_; }
private:
int it_;
};
template <typename _BasicJsonTy>
struct internal_iterator
{
typename _BasicJsonTy::array_type::iterator array_iter;
typename _BasicJsonTy::object_type::iterator object_iter;
2019-04-04 14:25:13 +08:00
primitive_iterator original_iter = 0; // for other types
};
template <typename _BasicJsonTy>
struct iterator_impl
{
friend _BasicJsonTy;
using string_type = typename _BasicJsonTy::string_type;
using char_type = typename _BasicJsonTy::char_type;
using integer_type = typename _BasicJsonTy::integer_type;
using float_type = typename _BasicJsonTy::float_type;
using boolean_type = typename _BasicJsonTy::boolean_type;
using array_type = typename _BasicJsonTy::array_type;
using object_type = typename _BasicJsonTy::object_type;
using value_type = _BasicJsonTy;
using difference_type = std::ptrdiff_t;
using iterator_category = std::bidirectional_iterator_tag;
using pointer = value_type*;
using reference = value_type&;
inline iterator_impl(pointer json = nullptr) : data_(json) {}
inline reference operator*() const
{
check_data();
check_iterator();
switch (data_->type())
{
case JsonType::Object:
return (it_.object_iter->second);
case JsonType::Array:
return (*it_.array_iter);
default:
return *data_;
}
}
inline pointer operator->() const
{
check_data();
check_iterator();
switch (data_->type())
{
case JsonType::Object:
return &(it_.object_iter->second);
case JsonType::Array:
return &(*it_.array_iter);
default:
return data_;
}
}
inline const typename object_type::key_type& key() const
{
check_data();
check_iterator();
if (!data_->is_object())
throw json_invalid_iterator("cannot use key() with non-object type");
return it_.object_iter->first;
}
inline reference value() const
{
return operator*();
}
inline void set_begin()
{
check_data();
switch (data_->type())
{
case JsonType::Object:
{
it_.object_iter = data_->value_.data.object->begin();
break;
}
case JsonType::Array:
{
it_.array_iter = data_->value_.data.vector->begin();
break;
}
default:
{
it_.original_iter.set_begin();
break;
}
}
}
inline void set_end()
{
check_data();
switch (data_->type())
{
case JsonType::Object:
{
it_.object_iter = data_->value_.data.object->end();
break;
}
case JsonType::Array:
{
it_.array_iter = data_->value_.data.vector->end();
break;
}
default:
{
it_.original_iter.set_end();
break;
}
}
}
inline iterator_impl operator++(int) { iterator_impl old = (*this); ++(*this); return old; }
inline iterator_impl& operator++()
{
check_data();
switch (data_->type())
{
case JsonType::Object:
{
std::advance(it_.object_iter, 1);
break;
}
case JsonType::Array:
{
std::advance(it_.array_iter, 1);
break;
}
default:
{
++it_.original_iter;
break;
}
}
return *this;
}
inline iterator_impl operator--(int) { iterator_impl old = (*this); --(*this); return old; }
inline iterator_impl& operator--()
{
check_data();
switch (data_->type())
{
case JsonType::Object:
{
std::advance(it_.object_iter, -1);
break;
}
case JsonType::Array:
{
std::advance(it_.array_iter, -1);
break;
}
default:
{
--it_.original_iter;
break;
}
}
}
inline const iterator_impl operator-(difference_type off) const { return operator+(-off); }
inline const iterator_impl operator+(difference_type off) const { iterator_impl ret(*this); ret += off; return ret; }
inline iterator_impl& operator-=(difference_type off) { return operator+=(-off); }
inline iterator_impl& operator+=(difference_type off)
{
check_data();
switch (data_->type())
{
case JsonType::Object:
{
throw json_invalid_iterator("cannot use offsets with object type");
break;
}
case JsonType::Array:
{
std::advance(it_.array_iter, off);
break;
}
default:
{
it_.original_iter += off;
break;
}
}
return *this;
}
inline bool operator!=(iterator_impl const& other) const { return !(*this == other); }
inline bool operator==(iterator_impl const& other) const
{
check_data();
other.check_data();
if (data_ != other.data_)
throw json_invalid_iterator("cannot compare iterators of different objects");
switch (data_->type())
{
case JsonType::Object:
{
return it_.object_iter == other.it_.object_iter;
}
case JsonType::Array:
{
return it_.array_iter == other.it_.array_iter;
}
default:
{
return it_.original_iter == other.it_.original_iter;
}
}
}
inline bool operator>(iterator_impl const& other) const { return other.operator<(*this); }
inline bool operator>=(iterator_impl const& other) const { return !operator<(other); }
inline bool operator<=(iterator_impl const& other) const { return !other.operator<(*this); }
inline bool operator<(iterator_impl const& other) const
{
check_data();
other.check_data();
if (data_ != other.data_)
throw json_invalid_iterator("cannot compare iterators of different objects");
switch (data_->type())
{
case JsonType::Object:
throw json_invalid_iterator("cannot compare iterators with object type");
case JsonType::Array:
return it_.array_iter < other.it_.array_iter;
default:
return it_.original_iter < other.it_.original_iter;
}
}
private:
inline void check_data() const
{
if (data_ == nullptr)
{
throw json_invalid_iterator("iterator contains an empty object");
}
}
inline void check_iterator() const
{
switch (data_->type())
{
case JsonType::Object:
if (it_.object_iter == data_->value_.data.object->end())
{
throw std::out_of_range("iterator out of range");
}
break;
case JsonType::Array:
if (it_.array_iter == data_->value_.data.vector->end())
{
throw std::out_of_range("iterator out of range");
}
break;
default:
if (it_.original_iter == 1)
{
throw std::out_of_range("iterator out of range");
}
break;
}
}
private:
pointer data_;
internal_iterator<_BasicJsonTy> it_;
};
} // end of namespace __json_detail
namespace __json_detail
{
//
// output_adapter
//
template <typename _CharTy>
struct output_adapter
{
using char_type = _CharTy;
using char_traits = std::char_traits<char_type>;
virtual void write(const _CharTy ch) = 0;
virtual void write(const _CharTy* str, std::size_t size) = 0;
virtual void write(const _CharTy* str)
{
const auto size = char_traits::length(str);
write(str, static_cast<std::size_t>(size));
}
};
template <typename _StringTy>
struct string_output_adapter
: public output_adapter<typename _StringTy::value_type>
{
using char_type = typename _StringTy::value_type;
using size_type = typename _StringTy::size_type;
using char_traits = std::char_traits<char_type>;
string_output_adapter(_StringTy& str) : str_(str) {}
virtual void write(const char_type ch) override
{
str_.push_back(ch);
}
virtual void write(const char_type* str, std::size_t size) override
{
str_.append(str, static_cast<size_type>(size));
}
private:
_StringTy& str_;
};
template <typename _CharTy>
struct stream_output_adapter
: public output_adapter<_CharTy>
{
using char_type = _CharTy;
using size_type = typename std::streamsize;
using char_traits = std::char_traits<char_type>;
stream_output_adapter(std::basic_ostream<char_type>& stream) : stream_(stream) {}
virtual void write(const char_type ch) override
{
stream_.put(ch);
}
virtual void write(const char_type* str, std::size_t size) override
{
stream_.write(str, static_cast<size_type>(size));
}
private:
std::basic_ostream<char_type>& stream_;
};
} // end of namespace __json_detail
namespace __json_detail
{
//
// json_serializer
//
template <typename _BasicJsonTy>
struct json_serializer
{
using string_type = typename _BasicJsonTy::string_type;
using char_type = typename _BasicJsonTy::char_type;
using integer_type = typename _BasicJsonTy::integer_type;
using float_type = typename _BasicJsonTy::float_type;
using boolean_type = typename _BasicJsonTy::boolean_type;
using array_type = typename _BasicJsonTy::array_type;
using object_type = typename _BasicJsonTy::object_type;
json_serializer(output_adapter<char_type>* out, const wchar_t indent_char)
: out(out)
, indent_char(indent_char)
, indent_string(32, indent_char)
{}
void dump(
const _BasicJsonTy& json,
const bool pretty_print,
const unsigned int indent_step,
const unsigned int current_indent = 0)
{
switch (json.type())
{
case JsonType::Object:
{
auto& object = *json.value_.data.object;
if (object.empty())
{
out->write(L"{}");
return;
}
if (pretty_print)
{
out->write(L"{\n");
const auto new_indent = current_indent + indent_step;
if (indent_string.size() < new_indent)
{
indent_string.resize(indent_string.size() * 2, indent_char);
}
auto iter = object.cbegin();
const auto size = object.size();
for (std::size_t i = 0; i < size; ++i, ++iter)
{
out->write(indent_string.c_str(), new_indent);
out->write('\"');
out->write(iter->first.c_str());
out->write(L"\": ");
dump(iter->second, true, indent_step, new_indent);
// not last element
if (i != size - 1)
out->write(L",\n");
}
out->write('\n');
out->write(indent_string.c_str(), current_indent);
out->write('}');
}
else
{
out->write('{');
auto iter = object.cbegin();
const auto size = object.size();
for (std::size_t i = 0; i < size; ++i, ++iter)
{
out->write('\"');
out->write(iter->first.c_str());
out->write(L"\":");
dump(iter->second, false, indent_step, current_indent);
// not last element
if (i != size - 1)
out->write(',');
}
out->write('}');
}
return;
}
case JsonType::Array:
{
auto& vector = *json.value_.data.vector;
if (vector.empty())
{
out->write(L"[]");
return;
}
if (pretty_print)
{
out->write(L"[\n");
const auto new_indent = current_indent + indent_step;
if (indent_string.size() < new_indent)
{
indent_string.resize(indent_string.size() * 2, indent_char);
}
auto iter = vector.cbegin();
const auto size = vector.size();
for (std::size_t i = 0; i < size; ++i, ++iter)
{
out->write(indent_string.c_str(), new_indent);
dump(*iter, true, indent_step, new_indent);
// not last element
if (i != size - 1)
out->write(L",\n");
}
out->write('\n');
out->write(indent_string.c_str(), current_indent);
out->write(']');
}
else
{
out->write('[');
auto iter = vector.cbegin();
const auto size = vector.size();
for (std::size_t i = 0; i < size; ++i, ++iter)
{
dump(*iter, false, indent_step, current_indent);
// not last element
if (i != size - 1)
out->write(',');
}
out->write(']');
}
return;
}
case JsonType::String:
{
out->write('\"');
2019-03-31 13:56:05 +08:00
dump_string(*json.value_.data.string);
out->write('\"');
return;
}
case JsonType::Boolean:
{
if (json.value_.data.boolean)
{
out->write(L"true");
}
else
{
out->write(L"false");
}
return;
}
case JsonType::Integer:
{
dump_integer(json.value_.data.number_integer);
return;
}
case JsonType::Float:
{
dump_float(json.value_.data.number_float);
return;
}
case JsonType::Null:
{
out->write(L"null");
return;
}
}
}
void dump_integer(integer_type val)
{
if (val == 0)
{
out->write('0');
return;
}
auto uval = static_cast<std::make_unsigned_t<integer_type>>(val);
if (val < 0)
uval = 0 - uval;
auto next = number_buffer.rbegin();
*next = '\0';
do
{
*(++next) = static_cast<wchar_t>('0' + uval % 10);
uval /= 10;
} while (uval != 0);
if (val < 0)
*(++next) = '-';
out->write(&(*next));
}
void dump_float(float_type val)
{
const auto digits = std::numeric_limits<float_type>::max_digits10;
const auto len = ::_scwprintf(L"%.*g", digits, val);
if (len)
{
number_buffer[0] = '\0';
::swprintf_s(&number_buffer[0], len + 1, L"%.*g", digits, val);
}
else
{
number_buffer[0] = '0';
number_buffer[1] = '.';
number_buffer[2] = '0';
number_buffer[3] = '\0';
}
out->write(number_buffer.data());
}
2019-03-31 13:56:05 +08:00
void dump_string(const string_type & val)
{
for (const auto& ch : val)
{
switch (ch)
{
case '\t':
{
out->write(L"\\t");
2019-03-31 13:56:05 +08:00
break;
}
2019-03-31 13:56:05 +08:00
case '\r':
{
out->write(L"\\r");
2019-03-31 13:56:05 +08:00
break;
}
2019-03-31 13:56:05 +08:00
case '\n':
{
out->write(L"\\n");
break;
}
case '\b':
{
out->write(L"\\b");
break;
}
case '\f':
{
out->write(L"\\f");
break;
}
case '\"':
{
out->write(L"\\\"");
break;
}
case '\\':
{
out->write(L"\\\\");
2019-03-31 13:56:05 +08:00
break;
}
2019-03-31 13:56:05 +08:00
default:
{
const auto char_byte = static_cast<uint16_t>(ch);
if ((char_byte > 0x1F) && (char_byte < 0x7F))
{
out->write(ch);
}
else
{
wchar_t escaped[7] = { 0 };
::swprintf_s(escaped, 7, L"\\u%04x", char_byte);
out->write(escaped);
}
2019-03-31 13:56:05 +08:00
break;
}
}
2019-03-31 13:56:05 +08:00
}
}
private:
output_adapter<char_type>* out;
char_type indent_char;
string_type indent_string;
std::array<char_type, 21> number_buffer;
};
} // end of namespace __json_detail
namespace __json_detail
{
//
// input_adapter
//
template <typename _CharTy>
struct input_adapter
{
using char_type = _CharTy;
using char_traits = std::char_traits<char_type>;
virtual typename char_traits::int_type get_char() = 0;
virtual ~input_adapter() = default;
};
template <typename _CharTy>
struct file_input_adapter
: public input_adapter<_CharTy>
{
using char_type = typename input_adapter<_CharTy>::char_type;
using char_traits = typename input_adapter<_CharTy>::char_traits;
file_input_adapter(std::FILE* file) : file(file) {}
virtual typename char_traits::int_type get_char() override
{
return std::fgetc(file);
}
private:
std::FILE* file;
};
template <typename _CharTy>
struct stream_input_adapter
: public input_adapter<_CharTy>
{
using char_type = typename input_adapter<_CharTy>::char_type;
using char_traits = typename input_adapter<_CharTy>::char_traits;
stream_input_adapter(std::basic_istream<char_type>& stream) : stream(stream), streambuf(*stream.rdbuf()) {}
virtual typename char_traits::int_type get_char() override
{
auto ch = streambuf.sbumpc();
if (ch == EOF)
{
stream.clear(stream.rdstate() | std::ios::eofbit);
}
return ch;
}
virtual ~stream_input_adapter()
{
stream.clear(stream.rdstate() & std::ios::eofbit);
}
private:
std::basic_istream<char_type>& stream;
std::basic_streambuf<char_type>& streambuf;
};
template <typename _StringTy>
struct string_input_adapter
: public input_adapter<typename _StringTy::value_type>
{
using char_type = typename input_adapter<typename _StringTy::value_type>::char_type;
using char_traits = typename input_adapter<typename _StringTy::value_type>::char_traits;
string_input_adapter(const _StringTy& str) : str(str), index(0) {}
virtual typename char_traits::int_type get_char() override
{
if (index == str.size())
return char_traits::eof();
return str[index++];
}
private:
const _StringTy& str;
typename _StringTy::size_type index;
};
template <typename _CharTy>
struct buffer_input_adapter
: public input_adapter<_CharTy>
{
using char_type = typename input_adapter<_CharTy>::char_type;
using char_traits = typename input_adapter<_CharTy>::char_traits;
buffer_input_adapter(const _CharTy* str) : str(str), index(0) {}
virtual typename char_traits::int_type get_char() override
{
if (str[index] == '\0')
return char_traits::eof();
return str[index++];
}
private:
const char_type* str;
std::size_t index;
};
} // end of namespace __json_detail
namespace __json_detail
{
//
// json_lexer & json_parser
//
enum class token_type
{
uninitialized,
literal_true,
literal_false,
literal_null,
value_string,
value_integer,
value_float,
begin_array,
end_array,
begin_object,
end_object,
name_separator,
value_separator,
parse_error,
end_of_input
};
template <typename _BasicJsonTy>
struct json_lexer
{
using string_type = typename _BasicJsonTy::string_type;
using char_type = typename _BasicJsonTy::char_type;
using integer_type = typename _BasicJsonTy::integer_type;
using float_type = typename _BasicJsonTy::float_type;
using boolean_type = typename _BasicJsonTy::boolean_type;
using array_type = typename _BasicJsonTy::array_type;
using object_type = typename _BasicJsonTy::object_type;
using char_traits = std::char_traits<char_type>;
json_lexer(input_adapter<char_type>* adapter) : adapter(adapter)
{
// read first char
read_next();
}
typename char_traits::int_type read_next()
{
current = adapter->get_char();
return current;
}
void skip_spaces()
{
while (current == ' ' || current == '\t' || current == '\n' || current == '\r')
{
read_next();
}
}
token_type scan()
{
skip_spaces();
token_type result = token_type::uninitialized;
switch (current)
{
case '[':
result = token_type::begin_array;
break;
case ']':
result = token_type::end_array;
break;
case '{':
result = token_type::begin_object;
break;
case '}':
result = token_type::end_object;
break;
case ':':
result = token_type::name_separator;
break;
case ',':
result = token_type::value_separator;
break;
case 't':
return scan_literal(L"true", token_type::literal_true);
case 'f':
return scan_literal(L"false", token_type::literal_false);
case 'n':
return scan_literal(L"null", token_type::literal_null);
case '\"':
return scan_string();
case '-':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
return scan_number();
case '\0':
case char_traits::eof():
return token_type::end_of_input;
// unexpected char
default:
return token_type::parse_error;
}
// skip current char
read_next();
return result;
}
token_type scan_literal(const char_type* text, token_type result)
{
for (std::size_t i = 0; text[i] != '\0'; ++i)
{
if (text[i] != char_traits::to_char_type(current))
{
return token_type::parse_error;
}
read_next();
}
return result;
}
token_type scan_string()
{
if (current != '\"')
return token_type::parse_error;
string_buffer.clear();
while (true)
{
const auto ch = read_next();
switch (ch)
{
case char_traits::eof():
{
// unexpected end
return token_type::parse_error;
}
case '\"':
{
// skip last `\"`
read_next();
return token_type::value_string;
}
case 0x00:
case 0x01:
case 0x02:
case 0x03:
case 0x04:
case 0x05:
case 0x06:
case 0x07:
case 0x08:
case 0x09:
case 0x0A:
case 0x0B:
case 0x0C:
case 0x0D:
case 0x0E:
case 0x0F:
case 0x10:
case 0x11:
case 0x12:
case 0x13:
case 0x14:
case 0x15:
case 0x16:
case 0x17:
case 0x18:
case 0x19:
case 0x1A:
case 0x1B:
case 0x1C:
case 0x1D:
case 0x1E:
case 0x1F:
{
// invalid control character
return token_type::parse_error;
}
2019-03-31 13:56:05 +08:00
case '\\':
{
switch (read_next())
2019-03-31 13:56:05 +08:00
{
case '\"':
string_buffer.push_back('\"');
break;
case '\\':
string_buffer.push_back('\\');
break;
case '/':
string_buffer.push_back('/');
break;
case 'b':
string_buffer.push_back('\b');
break;
case 'f':
string_buffer.push_back('\f');
break;
case 'n':
string_buffer.push_back('\n');
break;
case 'r':
string_buffer.push_back('\r');
break;
case 't':
string_buffer.push_back('\t');
break;
case 'u':
{
// unicode escapes
uint16_t byte = 0;
for (const auto factor : { 12, 8, 4, 0 })
{
const auto n = read_next();
if (n >= L'0' && n <= L'9')
{
byte += ((n - L'0') << factor);
}
else if (n >= L'A' && n <= L'F')
{
byte += ((n - L'A' + 10) << factor);
}
else if (n >= L'a' && n <= L'f')
{
byte += ((n - L'a' + 10) << factor);
}
else
{
// '\u' must be followed by 4 hex digits
return token_type::parse_error;
}
}
string_buffer.push_back(char_traits::to_char_type(byte));
break;
2019-03-31 13:56:05 +08:00
}
default:
2019-03-31 13:56:05 +08:00
{
return token_type::parse_error;
}
2019-03-31 13:56:05 +08:00
}
break;
}
default:
{
if (ch > 0x1F && ch < 0x7F)
{
string_buffer.push_back(char_traits::to_char_type(ch));
break;
}
else
{
return token_type::parse_error;
}
}
}
}
}
token_type scan_number()
{
is_negative = false;
number_value = static_cast<float_type>(0.0);
if (current == '-')
{
return scan_negative();
}
if (current == '0')
{
return scan_zero();
}
return scan_integer();
}
token_type scan_negative()
{
if (current == '-')
{
is_negative = true;
read_next();
return scan_integer();
}
return token_type::parse_error;
}
token_type scan_zero()
{
if (current == '0')
{
if (read_next() == '.')
return scan_float();
else
return token_type::value_integer;
}
return token_type::parse_error;
}
token_type scan_integer()
{
if (std::isdigit(current))
{
number_value = static_cast<float_type>(current - '0');
while (true)
{
const auto ch = read_next();
if (ch == '.')
return scan_float();
if (ch == 'e' || ch == 'E')
return scan_exponent();
if (std::isdigit(ch))
number_value = number_value * 10 + (ch - '0');
else
break;
}
return token_type::value_integer;
}
return token_type::parse_error;
}
token_type scan_float()
{
if (current != '.')
return token_type::parse_error;
if (std::isdigit(read_next()))
{
float_type fraction = static_cast<float_type>(0.1);
number_value += static_cast<float_type>(current - '0') * fraction;
while (true)
{
const auto ch = read_next();
if (ch == 'e' || ch == 'E')
return scan_exponent();
if (std::isdigit(ch))
{
fraction *= static_cast<float_type>(0.1);
number_value += static_cast<float_type>(ch - '0') * fraction;
}
else
break;
}
return token_type::value_float;
}
return token_type::parse_error;
}
token_type scan_exponent()
{
if (current != 'e' && current != 'E')
return token_type::parse_error;
// skip current char
read_next();
if ((std::isdigit(current) && current != '0') || (current == '-') || (current == '+'))
{
float_type base = 10;
if (current == '+')
{
read_next();
}
else if (current == '-')
{
base = static_cast<float_type>(0.1);
read_next();
}
unsigned int exponent = static_cast<unsigned int>(current - '0');
while (std::isdigit(read_next()))
{
exponent = (exponent * 10) + static_cast<unsigned int>(current - '0');
}
float_type power = 1;
for (; exponent; exponent >>= 1, base *= base)
if (exponent & 1)
power *= base;
number_value *= power;
return token_type::value_float;
}
return token_type::parse_error;
}
integer_type token_to_integer() const
{
integer_type integer = static_cast<integer_type>(number_value);
return is_negative ? -integer : integer;
}
float_type token_to_float() const
{
return is_negative ? -number_value : number_value;
}
string_type token_to_string() const
{
return string_buffer;
}
private:
input_adapter<char_type>* adapter;
typename char_traits::int_type current;
bool is_negative;
float_type number_value;
string_type string_buffer;
};
template <typename _BasicJsonTy>
struct json_parser
{
using string_type = typename _BasicJsonTy::string_type;
using char_type = typename _BasicJsonTy::char_type;
using integer_type = typename _BasicJsonTy::integer_type;
using float_type = typename _BasicJsonTy::float_type;
using boolean_type = typename _BasicJsonTy::boolean_type;
using array_type = typename _BasicJsonTy::array_type;
using object_type = typename _BasicJsonTy::object_type;
using char_traits = std::char_traits<char_type>;
json_parser(input_adapter<char_type>* adapter)
: lexer(adapter)
, last_token(token_type::uninitialized)
{}
void parse(_BasicJsonTy& json)
{
parse_value(json);
if (get_token() != token_type::end_of_input)
throw json_parse_error("unexpected token, expect end");
}
private:
token_type get_token()
{
last_token = lexer.scan();
return last_token;
}
void parse_value(_BasicJsonTy& json)
{
switch (get_token())
{
case token_type::literal_true:
json = JsonType::Boolean;
json.value_.data.boolean = true;
break;
case token_type::literal_false:
json = JsonType::Boolean;
json.value_.data.boolean = false;
break;
case token_type::literal_null:
json = JsonType::Null;
break;
case token_type::value_string:
json = lexer.token_to_string();
break;
case token_type::value_integer:
json = lexer.token_to_integer();
break;
case token_type::value_float:
json = lexer.token_to_float();
break;
case token_type::begin_array:
json = JsonType::Array;
while (true)
{
json.value_.data.vector->push_back(_BasicJsonTy());
parse_value(json.value_.data.vector->back());
// read ','
if (get_token() != token_type::value_separator)
break;
}
if (last_token != token_type::end_array)
throw json_parse_error("unexpected token in array");
break;
case token_type::begin_object:
json = JsonType::Object;
while (true)
{
if (get_token() != token_type::value_string)
break;
string_type key = lexer.token_to_string();
if (get_token() != token_type::name_separator)
break;
_BasicJsonTy object;
parse_value(object);
json.value_.data.object->insert(std::make_pair(key, object));
// read ','
if (get_token() != token_type::value_separator)
break;
}
if (last_token != token_type::end_object)
throw json_parse_error("unexpected token in object");
break;
default:
// unexpected token
throw json_parse_error("unexpected token");
break;
}
}
private:
json_lexer<_BasicJsonTy> lexer;
token_type last_token;
};
} // end of namespace __json_detail
namespace __json_detail
{
//
// json_value_getter
//
template <typename _BasicJsonTy>
struct json_value_getter
{
using string_type = typename _BasicJsonTy::string_type;
using char_type = typename _BasicJsonTy::char_type;
using integer_type = typename _BasicJsonTy::integer_type;
using float_type = typename _BasicJsonTy::float_type;
using boolean_type = typename _BasicJsonTy::boolean_type;
using array_type = typename _BasicJsonTy::array_type;
using object_type = typename _BasicJsonTy::object_type;
static inline void assign(const _BasicJsonTy& json, object_type& value)
{
if (!json.is_object()) throw json_type_error("json value type must be object");
value = *json.value_.data.object;
}
static inline void assign(const _BasicJsonTy& json, array_type& value)
{
if (!json.is_array()) throw json_type_error("json value type must be array");
value = *json.value_.data.vector;
}
static inline void assign(const _BasicJsonTy& json, string_type& value)
{
if (!json.is_string()) throw json_type_error("json value type must be string");
value = *json.value_.data.string;
}
static inline void assign(const _BasicJsonTy& json, boolean_type& value)
{
if (!json.is_boolean()) throw json_type_error("json value type must be boolean");
value = json.value_.data.boolean;
}
static inline void assign(const _BasicJsonTy& json, integer_type& value)
{
if (!json.is_integer()) throw json_type_error("json value type must be integer");
value = json.value_.data.number_integer;
}
template <
typename _IntegerTy,
typename std::enable_if<std::is_integral<_IntegerTy>::value, int>::type = 0>
static inline void assign(const _BasicJsonTy& json, _IntegerTy& value)
{
if (!json.is_integer()) throw json_type_error("json value type must be integer");
value = static_cast<_IntegerTy>(json.value_.data.number_integer);
}
static inline void assign(const _BasicJsonTy& json, float_type& value)
{
if (!json.is_float()) throw json_type_error("json value type must be float");
value = json.value_.data.number_float;
}
template <
typename _FloatingTy,
typename std::enable_if<std::is_floating_point<_FloatingTy>::value, int>::type = 0>
static inline void assign(const _BasicJsonTy& json, _FloatingTy& value)
{
if (!json.is_float()) throw json_type_error("json value type must be float");
value = static_cast<_FloatingTy>(json.value_.data.number_float);
}
};
} // end of namespace __json_detail
//
// basic_json
//
E2D_DECLARE_BASIC_JSON_TEMPLATE
class basic_json
{
friend struct __json_detail::iterator_impl<basic_json>;
friend struct __json_detail::iterator_impl<const basic_json>;
friend struct __json_detail::json_serializer<basic_json>;
friend struct __json_detail::json_parser<basic_json>;
friend struct __json_detail::json_value_getter<basic_json>;
public:
template <typename _Ty>
using allocator_type = _Allocator<_Ty>;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using string_type = _StringTy;
using char_type = typename _StringTy::value_type;
using integer_type = _IntegerTy;
using float_type = _FloatTy;
using boolean_type = _BooleanTy;
using array_type = typename _ArrayTy<basic_json, allocator_type<basic_json>>;
using object_type = typename _ObjectTy<string_type, basic_json, std::less<string_type>, allocator_type<std::pair<const string_type, basic_json>>>;
using initializer_list = std::initializer_list<basic_json>;
using iterator = __json_detail::iterator_impl<basic_json>;
using const_iterator = __json_detail::iterator_impl<const basic_json>;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
public:
basic_json() {}
basic_json(std::nullptr_t) {}
basic_json(const JsonType type) : value_(type) {}
basic_json(basic_json const& other) : value_(other.value_) {}
basic_json(basic_json&& other) : value_(std::move(other.value_))
{
// invalidate payload
other.value_.type = JsonType::Null;
other.value_.data.object = nullptr;
}
basic_json(string_type const& value) : value_(value) {}
template <
typename _CompatibleTy,
typename std::enable_if<std::is_constructible<string_type, _CompatibleTy>::value, int>::type = 0>
basic_json(const _CompatibleTy& value)
{
value_.type = JsonType::String;
value_.data.string = value_.template create<string_type>(value);
}
basic_json(array_type const& arr)
: value_(arr)
{
}
basic_json(object_type const& object)
: value_(object)
{
}
basic_json(integer_type value)
: value_(value)
{
}
template <
typename _IntegerTy,
typename std::enable_if<std::is_integral<_IntegerTy>::value, int>::type = 0>
basic_json(_IntegerTy value)
: value_(static_cast<integer_type>(value))
{
}
basic_json(float_type value)
: value_(value)
{
}
template <
typename _FloatingTy,
typename std::enable_if<std::is_floating_point<_FloatingTy>::value, int>::type = 0>
basic_json(_FloatingTy value)
: value_(static_cast<float_type>(value))
{
}
basic_json(boolean_type value)
: value_(value)
{
}
basic_json(initializer_list const& init_list)
{
bool is_an_object = std::all_of(init_list.begin(), init_list.end(), [](const basic_json& json)
{
return (json.is_array() && json.size() == 2 && json[0].is_string());
});
if (is_an_object)
{
value_ = JsonType::Object;
std::for_each(init_list.begin(), init_list.end(), [this](const basic_json& json)
{
value_.data.object->emplace(
*((*json.value_.data.vector)[0].value_.data.string),
(*json.value_.data.vector)[1]
);
});
}
else
{
value_ = JsonType::Array;
value_.data.vector->reserve(init_list.size());
value_.data.vector->assign(init_list.begin(), init_list.end());
}
}
static inline basic_json object(initializer_list const& init_list)
{
if (init_list.size() != 2 || !(*init_list.begin()).is_string())
{
throw json_type_error("cannot create object from initializer_list");
}
basic_json json;
json.value_ = JsonType::Object;
json.value_.data.object->emplace(*((*init_list.begin()).value_.data.string), *(init_list.begin() + 1));
return json;
}
static inline basic_json array(initializer_list const& init_list)
{
basic_json json;
json.value_ = JsonType::Array;
if (init_list.size())
{
json.value_.data.vector->reserve(init_list.size());
json.value_.data.vector->assign(init_list.begin(), init_list.end());
}
return json;
}
inline bool is_object() const { return value_.type == JsonType::Object; }
inline bool is_array() const { return value_.type == JsonType::Array; }
inline bool is_string() const { return value_.type == JsonType::String; }
inline bool is_boolean() const { return value_.type == JsonType::Boolean; }
inline bool is_integer() const { return value_.type == JsonType::Integer; }
inline bool is_float() const { return value_.type == JsonType::Float; }
inline bool is_number() const { return is_integer() || is_float(); }
inline bool is_null() const { return value_.type == JsonType::Null; }
inline JsonType type() const { return value_.type; }
inline string_type type_name() const
{
switch (type())
{
case JsonType::Object:
return string_type(L"object");
case JsonType::Array:
return string_type(L"array");
case JsonType::String:
return string_type(L"string");
case JsonType::Integer:
return string_type(L"integer");
case JsonType::Float:
return string_type(L"float");
case JsonType::Boolean:
return string_type(L"boolean");
case JsonType::Null:
return string_type(L"null");
}
return string_type();
}
inline void swap(basic_json& rhs) { value_.swap(rhs.value_); }
public:
inline iterator begin() { iterator iter(this); iter.set_begin(); return iter; }
inline const_iterator begin() const { return cbegin(); }
inline const_iterator cbegin() const { const_iterator iter(this); iter.set_begin(); return iter; }
inline iterator end() { iterator iter(this); iter.set_end(); return iter; }
inline const_iterator end() const { return cend(); }
inline const_iterator cend() const { const_iterator iter(this); iter.set_end(); return iter; }
inline reverse_iterator rbegin() { return reverse_iterator(end()); }
inline const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
inline const_reverse_iterator crbegin() const { return rbegin(); }
inline reverse_iterator rend() { return reverse_iterator(begin()); }
inline const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
inline const_reverse_iterator crend() const { return rend(); }
public:
inline size_type size() const
{
switch (type())
{
case JsonType::Null:
return 0;
case JsonType::Array:
return value_.data.vector->size();
case JsonType::Object:
return value_.data.object->size();
default:
return 1;
}
}
inline bool empty() const
{
if (is_null())
return true;
if (is_object())
return value_.data.object->empty();
if (is_array())
return value_.data.vector->empty();
return false;
}
template <typename _Kty>
inline const_iterator find(_Kty && key) const
{
if (is_object())
{
const_iterator iter;
iter.it_.object_iter = value_.data.object->find(std::forward<_Kty>(key));
return iter;
}
return cend();
}
template <typename _Kty>
inline size_type count(_Kty && key) const
{
return is_object() ? value_.data.object->count(std::forward<_Kty>(key)) : 0;
}
inline size_type erase(const typename object_type::key_type& key)
{
if (!is_object())
{
throw json_invalid_key("cannot use erase() with non-object value");
}
return value_.data.object->erase(key);
}
inline void erase(const size_type index)
{
if (!is_array())
{
throw json_invalid_key("cannot use erase() with non-array value");
}
value_.data.vector->erase(value_.data.vector->begin() + static_cast<difference_type>(index));
}
template<
class _IteratorTy,
typename std::enable_if<
std::is_same<_IteratorTy, iterator>::value ||
std::is_same<_IteratorTy, const_iterator>::value, int
>::type = 0>
inline _IteratorTy erase(_IteratorTy pos)
{
_IteratorTy result = end();
switch (type())
{
case JsonType::Object:
{
result.it_.object_iter = value_.data.object->erase(pos.it_.object_iter);
break;
}
case JsonType::Array:
{
result.it_.array_iter = value_.data.vector->erase(pos.it_.array_iter);
break;
}
default:
throw json_invalid_iterator("cannot use erase() with non-object & non-array value");
}
return result;
}
template<
class _IteratorTy,
typename std::enable_if<
std::is_same<_IteratorTy, iterator>::value ||
std::is_same<_IteratorTy, const_iterator>::value, int
>::type = 0>
inline _IteratorTy erase(_IteratorTy first, _IteratorTy last)
{
_IteratorTy result = end();
switch (type())
{
case JsonType::Object:
{
result.it_.object_iter = value_.data.object->erase(first.it_.object_iter, last.it_.object_iter);
break;
}
case JsonType::Array:
{
result.it_.array_iter = value_.data.vector->erase(first.it_.array_iter, last.it_.array_iter);
break;
}
default:
throw json_invalid_iterator("cannot use erase() with non-object & non-array value");
}
return result;
}
inline void push_back(basic_json&& json)
{
if (!is_null() && !is_array())
{
throw json_type_error("cannot use push_back() with non-array value");
}
if (is_null())
{
value_ = JsonType::Array;
}
value_.data.vector->push_back(std::move(json));
}
inline basic_json& operator+=(basic_json&& json)
{
push_back(std::move(json));
return (*this);
}
inline void clear()
{
switch (type())
{
case JsonType::Integer:
{
value_.data.number_integer = 0;
break;
}
case JsonType::Float:
{
value_.data.number_float = static_cast<float_type>(0.0);
break;
}
case JsonType::Boolean:
{
value_.data.boolean = false;
break;
}
case JsonType::String:
{
value_.data.string->clear();
break;
}
case JsonType::Array:
{
value_.data.vector->clear();
break;
}
case JsonType::Object:
{
value_.data.object->clear();
break;
}
default:
break;
}
}
public:
// GET value functions
inline bool get_value(boolean_type& val) const
{
if (is_boolean())
{
val = value_.data.boolean;
return true;
}
return false;
}
inline bool get_value(integer_type& val) const
{
if (is_integer())
{
val = value_.data.number_integer;
return true;
}
return false;
}
inline bool get_value(float_type& val) const
{
if (is_float())
{
val = value_.data.number_float;
return true;
}
return false;
}
template <
typename _IntegerTy,
typename std::enable_if<std::is_integral<_IntegerTy>::value, int>::type = 0>
inline bool get_value(_IntegerTy& val) const
{
if (is_integer())
{
val = static_cast<_IntegerTy>(value_.data.number_integer);
return true;
}
return false;
}
template <
typename _FloatingTy,
typename std::enable_if<std::is_floating_point<_FloatingTy>::value, int>::type = 0>
inline bool get_value(_FloatingTy& val) const
{
if (is_float())
{
val = static_cast<_FloatingTy>(value_.data.number_float);
return true;
}
return false;
}
inline bool get_value(array_type& val) const
{
if (is_array())
{
val.assign((*value_.data.vector).begin(), (*value_.data.vector).end());
return true;
}
return false;
}
inline bool get_value(string_type& val) const
{
if (is_string())
{
val.assign(*value_.data.string);
return true;
}
return false;
}
inline bool get_value(object_type& val) const
{
if (is_object())
{
val.assign(*value_.data.object);
return true;
}
return false;
}
boolean_type as_bool() const
{
if (!is_boolean()) throw json_type_error("json value must be boolean");
return value_.data.boolean;
}
integer_type as_int() const
{
if (!is_integer()) throw json_type_error("json value must be integer");
return value_.data.number_integer;
}
float_type as_float() const
{
if (!is_float()) throw json_type_error("json value must be float");
return value_.data.number_float;
}
const array_type& as_array() const
{
if (!is_array()) throw json_type_error("json value must be array");
return *value_.data.vector;
}
const string_type& as_string() const
{
if (!is_string()) throw json_type_error("json value must be string");
return *value_.data.string;
}
const object_type& as_object() const
{
if (!is_object()) throw json_type_error("json value must be object");
return *value_.data.object;
}
template <typename _Ty>
_Ty get() const
{
_Ty value;
__json_detail::json_value_getter<basic_json>::assign(*this, value);
return value;
}
public:
// operator= functions
inline basic_json& operator=(basic_json const& other)
{
value_ = other.value_;
return (*this);
}
inline basic_json& operator=(basic_json&& other)
{
value_ = std::move(other.value_);
return (*this);
}
inline basic_json& operator=(std::nullptr_t)
{
value_ = nullptr;
return (*this);
}
public:
// operator[] functions
inline basic_json& operator[](size_type index)
{
if (is_null())
{
value_ = JsonType::Array;
}
if (!is_array())
{
throw json_invalid_key("operator[] called on a non-array object");
}
if (index >= value_.data.vector->size())
{
value_.data.vector->insert(value_.data.vector->end(),
index - value_.data.vector->size() + 1,
basic_json()
);
}
return (*value_.data.vector)[index];
}
inline basic_json& operator[](size_type index) const
{
if (!is_array())
{
throw json_invalid_key("operator[] called on a non-array type");
}
if (index >= value_.data.vector->size())
{
throw std::out_of_range("operator[] index out of range");
}
return (*value_.data.vector)[index];
}
inline basic_json& operator[](const typename object_type::key_type& key)
{
if (is_null())
{
value_ = JsonType::Object;
}
if (!is_object())
{
throw json_invalid_key("operator[] called on a non-object type");
}
return (*value_.data.object)[key];
}
inline basic_json& operator[](const typename object_type::key_type& key) const
{
if (!is_object())
{
throw json_invalid_key("operator[] called on a non-object object");
}
auto iter = value_.data.object->find(key);
if (iter == value_.data.object->end())
{
throw std::out_of_range("operator[] key out of range");
}
return iter->second;
}
template <typename _CharT>
inline basic_json& operator[](_CharT* key)
{
if (is_null())
{
value_ = JsonType::Object;
}
if (!is_object())
{
throw json_invalid_key("operator[] called on a non-object object");
}
return (*value_.data.object)[key];
}
template <typename _CharT>
inline basic_json& operator[](_CharT* key) const
{
if (!is_object())
{
throw json_invalid_key("operator[] called on a non-object object");
}
auto iter = value_.data.object->find(key);
if (iter == value_.data.object->end())
{
throw std::out_of_range("operator[] key out of range");
}
return iter->second;
}
public:
// implicitly convert functions
template <typename _Ty>
inline operator _Ty() const
{
return get<_Ty>();
}
public:
// dumps functions
friend std::basic_ostream<char_type>& operator<<(std::basic_ostream<char_type>& out, const basic_json& json)
{
using char_type = typename std::basic_ostream<char_type>::char_type;
const bool pretty_print = (out.width() > 0);
const auto indentation = (pretty_print ? out.width() : 0);
out.width(0);
__json_detail::stream_output_adapter<char_type> adapter(out);
__json_detail::json_serializer<basic_json>(&adapter, out.fill()).dump(json, pretty_print, static_cast<unsigned int>(indentation));
return out;
}
string_type dump(
const int indent = -1,
const char_type indent_char = ' ') const
{
string_type result;
__json_detail::string_output_adapter<string_type> adapter(result);
dump(&adapter, indent, indent_char);
return result;
}
void dump(
__json_detail::output_adapter<char_type>* adapter,
const int indent = -1,
const char_type indent_char = ' ') const
{
if (indent >= 0)
{
__json_detail::json_serializer<basic_json>(adapter, indent_char).dump(*this, true, static_cast<unsigned int>(indent));
}
else
{
__json_detail::json_serializer<basic_json>(adapter, indent_char).dump(*this, false, 0);
}
}
public:
// parse functions
friend std::basic_istream<char_type>&
operator>>(std::basic_istream<char_type>& in, basic_json& json)
{
__json_detail::stream_input_adapter<char_type> adapter(in);
__json_detail::json_parser<basic_json>(&adapter).parse(json);
return in;
}
static inline basic_json parse(const string_type& str)
{
__json_detail::string_input_adapter<string_type> adapter(str);
return parse(&adapter);
}
static inline basic_json parse(const char_type* str)
{
__json_detail::buffer_input_adapter<char_type> adapter(str);
return parse(&adapter);
}
static inline basic_json parse(std::FILE* file)
{
__json_detail::file_input_adapter<char_type> adapter(file);
return parse(&adapter);
}
static inline basic_json parse(__json_detail::input_adapter<char_type>* adapter)
{
basic_json result;
__json_detail::json_parser<basic_json>(adapter).parse(result);
return result;
}
public:
// compare functions
friend bool operator==(const basic_json& lhs, const basic_json& rhs)
{
const auto lhs_type = lhs.type();
const auto rhs_type = rhs.type();
if (lhs_type == rhs_type)
{
switch (lhs_type)
{
case JsonType::Array:
return (*lhs.value_.data.vector == *rhs.value_.data.vector);
case JsonType::Object:
return (*lhs.value_.data.object == *rhs.value_.data.object);
case JsonType::Null:
return true;
case JsonType::String:
return (*lhs.value_.data.string == *rhs.value_.data.string);
case JsonType::Boolean:
return (lhs.value_.data.boolean == rhs.value_.data.boolean);
case JsonType::Integer:
return (lhs.value_.data.number_integer == rhs.value_.data.number_integer);
case JsonType::Float:
return (lhs.value_.data.number_float == rhs.value_.data.number_float);
default:
return false;
}
}
else if (lhs_type == JsonType::Integer && rhs_type == JsonType::Float)
{
return (static_cast<float_type>(lhs.value_.data.number_integer) == rhs.value_.data.number_float);
}
else if (lhs_type == JsonType::Float && rhs_type == JsonType::Integer)
{
return (lhs.value_.data.number_float == static_cast<float_type>(rhs.value_.data.number_integer));
}
return false;
}
friend bool operator!=(const basic_json& lhs, const basic_json& rhs)
{
return !(lhs == rhs);
}
friend bool operator<(const basic_json& lhs, const basic_json& rhs)
{
const auto lhs_type = lhs.type();
const auto rhs_type = rhs.type();
if (lhs_type == rhs_type)
{
switch (lhs_type)
{
case JsonType::Array:
return (*lhs.value_.data.vector) < (*rhs.value_.data.vector);
case JsonType::Object:
return (*lhs.value_.data.object) < (*rhs.value_.data.object);
case JsonType::Null:
return false;
case JsonType::String:
return (*lhs.value_.data.string) < (*rhs.value_.data.string);
case JsonType::Boolean:
return (lhs.value_.data.boolean < rhs.value_.data.boolean);
case JsonType::Integer:
return (lhs.value_.data.number_integer < rhs.value_.data.number_integer);
case JsonType::Float:
return (lhs.value_.data.number_float < rhs.value_.data.number_float);
default:
return false;
}
}
else if (lhs_type == JsonType::Integer && rhs_type == JsonType::Float)
{
return (static_cast<float_type>(lhs.value_.data.number_integer) < rhs.value_.data.number_float);
}
else if (lhs_type == JsonType::Float && rhs_type == JsonType::Integer)
{
return (lhs.value_.data.number_float < static_cast<float_type>(rhs.value_.data.number_integer));
}
return false;
}
friend bool operator<=(const basic_json& lhs, const basic_json& rhs)
{
return !(rhs < lhs);
}
friend bool operator>(const basic_json& lhs, const basic_json& rhs)
{
return rhs < lhs;
}
friend bool operator>=(const basic_json& lhs, const basic_json& rhs)
{
return !(lhs < rhs);
}
private:
__json_detail::json_value<basic_json> value_;
};
}
namespace std
{
template<>
struct hash<::easy2d::Json>
{
std::size_t operator()(const ::easy2d::Json& json) const
{
return hash<::easy2d::Json::string_type>{}(json.dump());
}
};
template<>
inline void swap<::easy2d::Json>(::easy2d::Json& lhs, ::easy2d::Json& rhs)
{
lhs.swap(rhs);
}
}
2019-04-04 14:25:13 +08:00
#undef E2D_DECLARE_BASIC_JSON_TEMPLATE
#undef E2D_DECLARE_BASIC_JSON_TPL_ARGS