Files
MaaAssistantArknights/3rdparty/include/meojson/common/value.hpp
MistEO 5c0445d3ab refactor: 依赖大更新 (#13908)
Co-authored-by: status102 <102887808+status102@users.noreply.github.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-09-08 21:17:47 +08:00

1143 lines
32 KiB
C++

// IWYU pragma: private, include <meojson/json.hpp>
#pragma once
#include <cstddef>
#include <initializer_list>
#include <map>
#include <memory>
#include <optional>
#include <ostream>
#include <string>
#include <tuple>
#include <type_traits>
#include <utility>
#include <variant>
#include <vector>
#include "exception.hpp"
#include "utils.hpp"
namespace json
{
template <typename string_t>
class basic_value
{
using array_ptr = std::unique_ptr<basic_array<string_t>>;
using object_ptr = std::unique_ptr<basic_object<string_t>>;
public:
enum class value_type : char
{
invalid,
null,
boolean,
string,
number,
array,
object
};
using var_t = std::variant<string_t, array_ptr, object_ptr>;
using char_t = typename string_t::value_type;
public:
basic_value();
basic_value(const basic_value<string_t>& rhs);
basic_value(basic_value<string_t>&& rhs) noexcept;
basic_value(bool b);
basic_value(int num);
basic_value(unsigned num);
basic_value(long num);
basic_value(unsigned long num);
basic_value(long long num);
basic_value(unsigned long long num);
basic_value(float num);
basic_value(double num);
basic_value(long double num);
basic_value(const char_t* str);
basic_value(string_t str);
basic_value(std::nullptr_t);
basic_value(basic_array<string_t> arr);
basic_value(basic_object<string_t> obj);
basic_value(std::initializer_list<typename basic_object<string_t>::value_type> init_list);
// Constructed from raw data
template <typename... args_t>
basic_value(value_type type, args_t&&... args);
template <typename enum_t, std::enable_if_t<std::is_enum_v<enum_t>, bool> = true>
basic_value(enum_t e)
: basic_value(static_cast<std::underlying_type_t<enum_t>>(e))
{
}
template <
typename jsonization_t,
std::enable_if_t<_utils::has_to_json_in_templ_spec<jsonization_t, string_t>::value, bool> =
true>
basic_value(const jsonization_t& value)
: basic_value(ext::jsonization<string_t, jsonization_t>().to_json(value))
{
}
template <
typename jsonization_t,
std::enable_if_t<
std::is_rvalue_reference_v<jsonization_t&&>
&& _utils::has_move_to_json_in_templ_spec<jsonization_t, string_t>::value,
bool> = true>
basic_value(jsonization_t&& value)
: basic_value(ext::jsonization<string_t, jsonization_t>().move_to_json(std::move(value)))
{
}
// I don't know if you want to convert char to string or number, so I delete these constructors.
basic_value(char) = delete;
basic_value(wchar_t) = delete;
basic_value(char16_t) = delete;
basic_value(char32_t) = delete;
~basic_value();
bool valid() const noexcept { return _type != value_type::invalid; }
bool empty() const noexcept { return is_null(); }
bool is_null() const noexcept { return _type == value_type::null; }
bool is_number() const noexcept { return _type == value_type::number; }
bool is_boolean() const noexcept { return _type == value_type::boolean; }
bool is_string() const noexcept { return _type == value_type::string; }
bool is_array() const noexcept { return _type == value_type::array; }
bool is_object() const noexcept { return _type == value_type::object; }
template <typename value_t>
bool is() const noexcept;
template <typename value_t>
bool all() const;
bool contains(const string_t& key) const;
bool contains(size_t pos) const;
bool exists(const string_t& key) const { return contains(key); }
bool exists(size_t pos) const { return contains(pos); }
value_type type() const noexcept { return _type; }
const basic_value<string_t>& at(size_t pos) const;
const basic_value<string_t>& at(const string_t& key) const;
bool erase(size_t pos);
bool erase(const string_t& key);
// Usage: get(key_1, key_2, ..., default_value);
template <typename... key_then_default_value_t>
auto get(key_then_default_value_t&&... keys_then_default_value) const;
template <typename value_t = basic_value<string_t>>
std::optional<value_t> find(size_t pos) const;
template <typename value_t = basic_value<string_t>>
std::optional<value_t> find(const string_t& key) const;
bool as_boolean() const;
int as_integer() const;
unsigned as_unsigned() const;
long as_long() const;
unsigned long as_unsigned_long() const;
long long as_long_long() const;
unsigned long long as_unsigned_long_long() const;
float as_float() const;
double as_double() const;
long double as_long_double() const;
string_t as_string() const;
const basic_array<string_t>& as_array() const;
const basic_object<string_t>& as_object() const;
template <typename value_t, template <typename...> typename collection_t = std::vector>
collection_t<value_t> as_collection() const;
template <
typename value_t,
size_t Size,
template <typename, size_t> typename fixed_array_t = std::array>
fixed_array_t<value_t, Size> as_fixed_array() const;
template <typename value_t, template <typename...> typename map_t = std::map>
map_t<string_t, value_t> as_map() const;
template <typename value_t>
value_t as() const&;
template <typename value_t>
value_t as() &&;
basic_array<string_t>& as_array();
basic_object<string_t>& as_object();
template <typename... args_t>
decltype(auto) emplace(args_t&&... args);
void clear() noexcept;
string_t dumps(std::optional<size_t> indent = std::nullopt) const
{
return indent ? format(*indent) : to_string();
}
// return raw string
string_t to_string() const;
string_t format(size_t indent = 4) const { return format(indent, 0); }
basic_value<string_t>& operator=(const basic_value<string_t>& rhs);
basic_value<string_t>& operator=(basic_value<string_t>&&) noexcept;
// template <
// typename value_t,
// std::enable_if_t<std::is_convertible_v<value_t, basic_value<string_t>>, bool> = true>
// basic_value<string_t>& operator=(value_t rhs)
// {
// return *this = basic_value<string_t>(std::move(rhs));
// }
bool operator==(const basic_value<string_t>& rhs) const;
bool operator!=(const basic_value<string_t>& rhs) const { return !(*this == rhs); }
const basic_value<string_t>& operator[](size_t pos) const;
basic_value<string_t>& operator[](size_t pos);
basic_value<string_t>& operator[](const string_t& key);
basic_value<string_t>& operator[](string_t&& key);
basic_value<string_t> operator|(const basic_object<string_t>& rhs) const&;
basic_value<string_t> operator|(basic_object<string_t>&& rhs) const&;
basic_value<string_t> operator|(const basic_object<string_t>& rhs) &&;
basic_value<string_t> operator|(basic_object<string_t>&& rhs) &&;
basic_value<string_t>& operator|=(const basic_object<string_t>& rhs);
basic_value<string_t>& operator|=(basic_object<string_t>&& rhs);
basic_value<string_t> operator+(const basic_array<string_t>& rhs) const&;
basic_value<string_t> operator+(basic_array<string_t>&& rhs) const&;
basic_value<string_t> operator+(const basic_array<string_t>& rhs) &&;
basic_value<string_t> operator+(basic_array<string_t>&& rhs) &&;
basic_value<string_t>& operator+=(const basic_array<string_t>& rhs);
basic_value<string_t>& operator+=(basic_array<string_t>&& rhs);
explicit operator bool() const { return as_boolean(); }
explicit operator int() const { return as_integer(); }
explicit operator unsigned() const { return as_unsigned(); }
explicit operator long() const { return as_long(); }
explicit operator unsigned long() const { return as_unsigned_long(); }
explicit operator long long() const { return as_long_long(); }
explicit operator unsigned long long() const { return as_unsigned_long_long(); }
explicit operator float() const { return as_float(); }
explicit operator double() const { return as_double(); }
explicit operator long double() const { return as_long_double(); }
explicit operator string_t() const { return as_string(); }
explicit operator basic_array<string_t>() const { return as_array(); }
explicit operator basic_object<string_t>() const { return as_object(); }
template <
typename value_t,
template <typename...> typename collection_t = std::vector,
std::enable_if_t<_utils::is_collection<collection_t<value_t>>, bool> = true>
explicit operator collection_t<value_t>() const
{
return as_collection<value_t, collection_t>();
}
template <
typename value_t,
template <typename...> typename map_t = std::map,
std::enable_if_t<_utils::is_map<map_t<string_t, value_t>>, bool> = true>
explicit operator map_t<string_t, value_t>() const
{
return as_map<value_t, map_t>();
}
template <typename enum_t, std::enable_if_t<std::is_enum_v<enum_t>, bool> = true>
explicit operator enum_t() const
{
return static_cast<enum_t>(static_cast<std::underlying_type_t<enum_t>>(*this));
}
template <
typename jsonization_t,
std::enable_if_t<
_utils::has_from_json_in_templ_spec<jsonization_t, string_t>::value,
bool> = true>
explicit operator jsonization_t() const&
{
jsonization_t dst {};
if (!ext::jsonization<string_t, jsonization_t>().from_json(*this, dst)) {
throw exception("Wrong JSON");
}
return dst;
}
template <
typename jsonization_t,
std::enable_if_t<
_utils::has_move_from_json_in_templ_spec<jsonization_t, string_t>::value,
bool> = true>
explicit operator jsonization_t() &&
{
jsonization_t dst {};
if (!ext::jsonization<string_t, jsonization_t>().move_from_json(std::move(*this), dst)) {
throw exception("Wrong JSON");
}
return dst;
}
private:
friend class basic_array<string_t>;
friend class basic_object<string_t>;
string_t format(size_t indent, size_t indent_times) const;
static var_t deep_copy(const var_t& src);
template <typename... key_then_default_value_t, size_t... keys_indexes_t>
auto
get(std::tuple<key_then_default_value_t...> keys_then_default_value,
std::index_sequence<keys_indexes_t...>) const;
template <typename value_t, typename first_key_t, typename... rest_keys_t>
auto get_helper(const value_t& default_value, first_key_t&& first, rest_keys_t&&... rest) const;
template <typename value_t, typename unique_key_t>
auto get_helper(const value_t& default_value, unique_key_t&& first) const;
const string_t& as_basic_type_str() const;
string_t& as_basic_type_str();
value_type _type = value_type::null;
var_t _raw_data;
};
template <typename string_t>
inline basic_value<string_t>::basic_value() = default;
template <typename string_t>
inline basic_value<string_t>::basic_value(const basic_value<string_t>& rhs)
: _type(rhs._type)
, _raw_data(deep_copy(rhs._raw_data))
{
}
template <typename string_t>
inline basic_value<string_t>::basic_value(basic_value<string_t>&& rhs) noexcept = default;
template <typename string_t>
inline basic_value<string_t>::basic_value(bool b)
: _type(value_type::boolean)
, _raw_data(string_t(b ? _utils::true_string<string_t>() : _utils::false_string<string_t>()))
{
}
template <typename string_t>
inline basic_value<string_t>::basic_value(int num)
: _type(value_type::number)
, _raw_data(_utils::to_basic_string<string_t>(num))
{
}
template <typename string_t>
inline basic_value<string_t>::basic_value(unsigned num)
: _type(value_type::number)
, _raw_data(_utils::to_basic_string<string_t>(num))
{
}
template <typename string_t>
inline basic_value<string_t>::basic_value(long num)
: _type(value_type::number)
, _raw_data(_utils::to_basic_string<string_t>(num))
{
}
template <typename string_t>
inline basic_value<string_t>::basic_value(unsigned long num)
: _type(value_type::number)
, _raw_data(_utils::to_basic_string<string_t>(num))
{
}
template <typename string_t>
inline basic_value<string_t>::basic_value(long long num)
: _type(value_type::number)
, _raw_data(_utils::to_basic_string<string_t>(num))
{
}
template <typename string_t>
inline basic_value<string_t>::basic_value(unsigned long long num)
: _type(value_type::number)
, _raw_data(_utils::to_basic_string<string_t>(num))
{
}
template <typename string_t>
inline basic_value<string_t>::basic_value(float num)
: _type(value_type::number)
, _raw_data(_utils::to_basic_string<string_t>(num))
{
}
template <typename string_t>
inline basic_value<string_t>::basic_value(double num)
: _type(value_type::number)
, _raw_data(_utils::to_basic_string<string_t>(num))
{
}
template <typename string_t>
inline basic_value<string_t>::basic_value(long double num)
: _type(value_type::number)
, _raw_data(_utils::to_basic_string<string_t>(num))
{
}
template <typename string_t>
inline basic_value<string_t>::basic_value(const char_t* str)
: _type(value_type::string)
, _raw_data(string_t(str))
{
}
template <typename string_t>
inline basic_value<string_t>::basic_value(string_t str)
: _type(value_type::string)
, _raw_data(std::move(str))
{
}
template <typename string_t>
inline basic_value<string_t>::basic_value(std::nullptr_t)
: _type(value_type::null)
{
}
template <typename string_t>
inline basic_value<string_t>::basic_value(basic_array<string_t> arr)
: _type(value_type::array)
, _raw_data(std::make_unique<basic_array<string_t>>(std::move(arr)))
{
}
template <typename string_t>
inline basic_value<string_t>::basic_value(basic_object<string_t> obj)
: _type(value_type::object)
, _raw_data(std::make_unique<basic_object<string_t>>(std::move(obj)))
{
}
template <typename string_t>
inline basic_value<string_t>::basic_value(
std::initializer_list<typename basic_object<string_t>::value_type> init_list)
: _type(value_type::object)
, _raw_data(std::make_unique<basic_object<string_t>>(init_list))
{
}
// for Pimpl
template <typename string_t>
inline basic_value<string_t>::~basic_value() = default;
template <typename string_t>
template <typename value_t>
inline bool basic_value<string_t>::is() const noexcept
{
if constexpr (std::is_same_v<basic_value<string_t>, value_t>) {
return true;
}
else if constexpr (_utils::has_check_json_in_templ_spec<value_t, string_t>::value) {
return ext::jsonization<string_t, value_t>().check_json(*this);
}
else if constexpr (std::is_same_v<bool, value_t>) {
return is_boolean();
}
else if constexpr (std::is_arithmetic_v<value_t> || std::is_enum_v<value_t>) {
return is_number();
}
else if constexpr (std::is_constructible_v<string_t, value_t>) {
return is_string();
}
else if constexpr (std::is_same_v<basic_array<string_t>, value_t>) {
return is_array();
}
else if constexpr (_utils::is_collection<value_t>) {
return is_array() && all<typename value_t::value_type>();
}
else if constexpr (std::is_same_v<basic_object<string_t>, value_t>) {
return is_object();
}
else if constexpr (_utils::is_map<value_t>) {
return is_object() && std::is_constructible_v<string_t, typename value_t::key_type>
&& all<typename value_t::mapped_type>();
}
else {
static_assert(!sizeof(value_t), "Unsupported type");
}
}
template <typename string_t>
inline bool basic_value<string_t>::contains(const string_t& key) const
{
return is_object() && as_object().contains(key);
}
template <typename string_t>
inline bool basic_value<string_t>::contains(size_t pos) const
{
return is_array() && as_array().contains(pos);
}
template <typename string_t>
inline const basic_value<string_t>& basic_value<string_t>::at(size_t pos) const
{
return as_array().at(pos);
}
template <typename string_t>
inline const basic_value<string_t>& basic_value<string_t>::at(const string_t& key) const
{
return as_object().at(key);
}
template <typename string_t>
inline bool basic_value<string_t>::erase(size_t pos)
{
return as_array().erase(pos);
}
template <typename string_t>
inline bool basic_value<string_t>::erase(const string_t& key)
{
return as_object().erase(key);
}
template <typename string_t>
template <typename... key_then_default_value_t>
inline auto basic_value<string_t>::get(key_then_default_value_t&&... keys_then_default_value) const
{
return get(
std::forward_as_tuple(keys_then_default_value...),
std::make_index_sequence<sizeof...(keys_then_default_value) - 1> {});
}
template <typename string_t>
template <typename... key_then_default_value_t, size_t... keys_indexes_t>
inline auto basic_value<string_t>::get(
std::tuple<key_then_default_value_t...> keys_then_default_value,
std::index_sequence<keys_indexes_t...>) const
{
constexpr unsigned long default_value_index = sizeof...(key_then_default_value_t) - 1;
return get_helper(
std::get<default_value_index>(keys_then_default_value),
std::get<keys_indexes_t>(keys_then_default_value)...);
}
template <typename string_t>
template <typename value_t, typename first_key_t, typename... rest_keys_t>
inline auto basic_value<string_t>::get_helper(
const value_t& default_value,
first_key_t&& first,
rest_keys_t&&... rest) const
{
if constexpr (std::is_constructible_v<string_t, first_key_t>) {
return is_object() ? as_object().get_helper(
default_value,
std::forward<first_key_t>(first),
std::forward<rest_keys_t>(rest)...)
: default_value;
}
else if constexpr (std::is_integral_v<std::decay_t<first_key_t>>) {
return is_array() ? as_array().get_helper(
default_value,
std::forward<first_key_t>(first),
std::forward<rest_keys_t>(rest)...)
: default_value;
}
else {
static_assert(!sizeof(first_key_t), "Parameter must be integral or string_t constructible");
}
}
template <typename string_t>
template <typename value_t, typename unique_key_t>
inline auto
basic_value<string_t>::get_helper(const value_t& default_value, unique_key_t&& first) const
{
if constexpr (std::is_constructible_v<string_t, unique_key_t>) {
return is_object()
? as_object().get_helper(default_value, std::forward<unique_key_t>(first))
: default_value;
}
else if constexpr (std::is_integral_v<std::decay_t<unique_key_t>>) {
return is_array() ? as_array().get_helper(default_value, std::forward<unique_key_t>(first))
: default_value;
}
else {
static_assert(
!sizeof(unique_key_t),
"Parameter must be integral or string_t constructible");
}
}
template <typename string_t>
template <typename value_t>
inline std::optional<value_t> basic_value<string_t>::find(size_t pos) const
{
return is_array() ? as_array().template find<value_t>(pos) : std::nullopt;
}
template <typename string_t>
template <typename value_t>
inline std::optional<value_t> basic_value<string_t>::find(const string_t& key) const
{
return is_object() ? as_object().template find<value_t>(key) : std::nullopt;
}
template <typename string_t>
inline bool basic_value<string_t>::as_boolean() const
{
if (is_boolean()) {
if (const string_t& b_str = as_basic_type_str(); b_str == _utils::true_string<string_t>()) {
return true;
}
else if (b_str == _utils::false_string<string_t>()) {
return false;
}
else {
throw exception("Unknown Parse Error");
}
}
else {
throw exception("Wrong Type");
}
}
template <typename string_t>
inline int basic_value<string_t>::as_integer() const
{
if (is_number()) {
return std::stoi(as_basic_type_str());
}
else {
throw exception("Wrong Type");
}
}
template <typename string_t>
inline unsigned basic_value<string_t>::as_unsigned() const
{
// I don't know why there is no std::stou.
return static_cast<unsigned>(as_unsigned_long());
}
template <typename string_t>
inline long basic_value<string_t>::as_long() const
{
if (is_number()) {
return std::stol(as_basic_type_str());
}
else {
throw exception("Wrong Type");
}
}
template <typename string_t>
inline unsigned long basic_value<string_t>::as_unsigned_long() const
{
if (is_number()) {
return std::stoul(as_basic_type_str());
}
else {
throw exception("Wrong Type");
}
}
template <typename string_t>
inline long long basic_value<string_t>::as_long_long() const
{
if (is_number()) {
return std::stoll(as_basic_type_str());
}
else {
throw exception("Wrong Type");
}
}
template <typename string_t>
inline unsigned long long basic_value<string_t>::as_unsigned_long_long() const
{
if (is_number()) {
return std::stoull(as_basic_type_str());
}
else {
throw exception("Wrong Type");
}
}
template <typename string_t>
inline float basic_value<string_t>::as_float() const
{
if (is_number()) {
return std::stof(as_basic_type_str());
}
else {
throw exception("Wrong Type");
}
}
template <typename string_t>
inline double basic_value<string_t>::as_double() const
{
if (is_number()) {
return std::stod(as_basic_type_str());
}
else {
throw exception("Wrong Type");
}
}
template <typename string_t>
inline long double basic_value<string_t>::as_long_double() const
{
if (is_number()) {
return std::stold(as_basic_type_str());
}
else {
throw exception("Wrong Type");
}
}
template <typename string_t>
inline string_t basic_value<string_t>::as_string() const
{
if (is_string()) {
return as_basic_type_str();
}
else {
throw exception("Wrong Type");
}
}
template <typename string_t>
inline const basic_array<string_t>& basic_value<string_t>::as_array() const
{
if (is_array()) {
return *std::get<array_ptr>(_raw_data);
}
throw exception("Wrong Type");
}
template <typename string_t>
inline const basic_object<string_t>& basic_value<string_t>::as_object() const
{
if (is_object()) {
return *std::get<object_ptr>(_raw_data);
}
throw exception("Wrong Type or data empty");
}
template <typename string_t>
inline basic_array<string_t>& basic_value<string_t>::as_array()
{
if (empty()) {
*this = basic_array<string_t>();
}
if (is_array()) {
return *std::get<array_ptr>(_raw_data);
}
throw exception("Wrong Type");
}
template <typename string_t>
inline basic_object<string_t>& basic_value<string_t>::as_object()
{
if (empty()) {
*this = basic_object<string_t>();
}
if (is_object()) {
return *std::get<object_ptr>(_raw_data);
}
throw exception("Wrong Type or data empty");
}
template <typename string_t>
template <typename value_t>
inline value_t basic_value<string_t>::as() const&
{
if constexpr (std::is_same_v<basic_value<string_t>, value_t>) {
return *this;
}
else if constexpr (_utils::has_from_json_in_templ_spec<value_t, string_t>::value) {
value_t dst {};
if (!ext::jsonization<string_t, value_t>().from_json(*this, dst)) {
throw exception("Wrong JSON");
}
return dst;
}
else {
return static_cast<value_t>(*this);
}
}
template <typename string_t>
template <typename value_t>
inline value_t basic_value<string_t>::as() &&
{
if constexpr (std::is_same_v<basic_value<string_t>, value_t>) {
return std::move(*this);
}
else if constexpr (_utils::has_move_from_json_in_templ_spec<value_t, string_t>::value) {
value_t dst {};
if (!ext::jsonization<string_t, value_t>().move_from_json(std::move(*this), dst)) {
throw exception("Wrong JSON");
}
return dst;
}
else {
return static_cast<value_t>(*this);
}
}
template <typename string_t>
inline const string_t& basic_value<string_t>::as_basic_type_str() const
{
return std::get<string_t>(_raw_data);
}
template <typename string_t>
inline string_t& basic_value<string_t>::as_basic_type_str()
{
return std::get<string_t>(_raw_data);
}
template <typename string_t>
template <typename... args_t>
inline decltype(auto) basic_value<string_t>::emplace(args_t&&... args)
{
constexpr bool is_array_args =
std::is_constructible_v<typename basic_array<string_t>::value_type, args_t...>;
constexpr bool is_object_args =
std::is_constructible_v<typename basic_object<string_t>::value_type, args_t...>;
static_assert(
is_array_args || is_object_args,
"Args can not constructure a array or object value");
if constexpr (is_array_args) {
return as_array().emplace_back(std::forward<args_t>(args)...);
}
else if constexpr (is_object_args) {
return as_object().emplace(std::forward<args_t>(args)...);
}
}
template <typename string_t>
inline void basic_value<string_t>::clear() noexcept
{
*this = basic_value<string_t>();
}
template <typename string_t>
inline string_t basic_value<string_t>::to_string() const
{
switch (_type) {
case value_type::null:
return _utils::null_string<string_t>();
case value_type::boolean:
case value_type::number:
return as_basic_type_str();
case value_type::string:
return char_t('"') + _utils::unescape_string(as_basic_type_str()) + char_t('"');
case value_type::array:
return as_array().to_string();
case value_type::object:
return as_object().to_string();
default:
throw exception("Unknown basic_value Type");
}
}
template <typename string_t>
inline string_t basic_value<string_t>::format(size_t indent, size_t indent_times) const
{
switch (_type) {
case value_type::null:
case value_type::boolean:
case value_type::number:
case value_type::string:
return to_string();
case value_type::array:
return as_array().format(indent, indent_times);
case value_type::object:
return as_object().format(indent, indent_times);
default:
throw exception("Unknown basic_value Type");
}
}
template <typename string_t>
template <typename value_t>
inline bool basic_value<string_t>::all() const
{
if (is_array()) {
return as_array().template all<value_t>();
}
else if (is_object()) {
return as_object().template all<value_t>();
}
else {
return false;
}
}
template <typename string_t>
template <typename value_t, template <typename...> typename collection_t>
inline collection_t<value_t> basic_value<string_t>::as_collection() const
{
return as_array().template as_collection<value_t, collection_t>();
}
template <typename string_t>
template <typename value_t, size_t Size, template <typename, size_t> typename fixed_array_t>
inline fixed_array_t<value_t, Size> basic_value<string_t>::as_fixed_array() const
{
return as_array().template as_fixed_array<value_t, Size>();
}
template <typename string_t>
template <typename value_t, template <typename...> typename map_t>
inline map_t<string_t, value_t> basic_value<string_t>::as_map() const
{
return as_object().template as_map<value_t, map_t>();
}
template <typename string_t>
inline basic_value<string_t>& basic_value<string_t>::operator=(const basic_value<string_t>& rhs)
{
_type = rhs._type;
_raw_data = deep_copy(rhs._raw_data);
return *this;
}
template <typename string_t>
inline basic_value<string_t>&
basic_value<string_t>::operator=(basic_value<string_t>&& rhs) noexcept = default;
template <typename string_t>
inline bool basic_value<string_t>::operator==(const basic_value<string_t>& rhs) const
{
if (_type != rhs._type) {
return false;
}
switch (_type) {
case value_type::null:
return rhs.is_null();
case value_type::boolean:
case value_type::number:
case value_type::string:
return _raw_data == rhs._raw_data;
case value_type::array:
return as_array() == rhs.as_array();
case value_type::object:
return as_object() == rhs.as_object();
default:
throw exception("Unknown basic_value Type");
}
}
template <typename string_t>
inline const basic_value<string_t>& basic_value<string_t>::operator[](size_t pos) const
{
// basic_array not support to create by operator[]
return as_array()[pos];
}
template <typename string_t>
inline basic_value<string_t>& basic_value<string_t>::operator[](size_t pos)
{
// basic_array not support to create by operator[]
return as_array()[pos];
}
template <typename string_t>
inline basic_value<string_t>& basic_value<string_t>::operator[](const string_t& key)
{
if (empty()) {
*this = basic_object<string_t>();
}
return as_object()[key];
}
template <typename string_t>
inline basic_value<string_t>& basic_value<string_t>::operator[](string_t&& key)
{
if (empty()) {
*this = basic_object<string_t>();
}
return as_object()[std::move(key)];
}
template <typename string_t>
inline basic_value<string_t>
basic_value<string_t>::operator|(const basic_object<string_t>& rhs) const&
{
return as_object() | rhs;
}
template <typename string_t>
inline basic_value<string_t> basic_value<string_t>::operator|(basic_object<string_t>&& rhs) const&
{
return as_object() | std::move(rhs);
}
template <typename string_t>
inline basic_value<string_t> basic_value<string_t>::operator|(const basic_object<string_t>& rhs) &&
{
return std::move(as_object()) | rhs;
}
template <typename string_t>
inline basic_value<string_t> basic_value<string_t>::operator|(basic_object<string_t>&& rhs) &&
{
return std::move(as_object()) | std::move(rhs);
}
template <typename string_t>
inline basic_value<string_t>& basic_value<string_t>::operator|=(const basic_object<string_t>& rhs)
{
as_object() |= rhs;
return *this;
}
template <typename string_t>
inline basic_value<string_t>& basic_value<string_t>::operator|=(basic_object<string_t>&& rhs)
{
as_object() |= std::move(rhs);
return *this;
}
template <typename string_t>
inline basic_value<string_t>
basic_value<string_t>::operator+(const basic_array<string_t>& rhs) const&
{
return as_array() + rhs;
}
template <typename string_t>
inline basic_value<string_t> basic_value<string_t>::operator+(basic_array<string_t>&& rhs) const&
{
return as_array() + std::move(rhs);
}
template <typename string_t>
inline basic_value<string_t> basic_value<string_t>::operator+(const basic_array<string_t>& rhs) &&
{
return std::move(as_array()) + rhs;
}
template <typename string_t>
inline basic_value<string_t> basic_value<string_t>::operator+(basic_array<string_t>&& rhs) &&
{
return std::move(as_array()) + std::move(rhs);
}
template <typename string_t>
inline basic_value<string_t>& basic_value<string_t>::operator+=(const basic_array<string_t>& rhs)
{
as_array() += rhs;
return *this;
}
template <typename string_t>
inline basic_value<string_t>& basic_value<string_t>::operator+=(basic_array<string_t>&& rhs)
{
as_array() += std::move(rhs);
return *this;
}
template <typename string_t>
template <typename... args_t>
inline basic_value<string_t>::basic_value(value_type type, args_t&&... args)
: _type(type)
, _raw_data(std::forward<args_t>(args)...)
{
static_assert(
std::is_constructible_v<var_t, args_t...>,
"Parameter can't be used to construct a var_t");
}
template <typename string_t>
inline typename basic_value<string_t>::var_t basic_value<string_t>::deep_copy(const var_t& src)
{
var_t dst;
if (const auto string_ptr = std::get_if<string_t>(&src)) {
dst = *string_ptr;
}
else if (const auto arr_ptr = std::get_if<array_ptr>(&src)) {
dst = std::make_unique<basic_array<string_t>>(**arr_ptr);
}
else if (const auto obj_ptr = std::get_if<object_ptr>(&src)) {
dst = std::make_unique<basic_object<string_t>>(**obj_ptr);
}
else {
// maybe invalid_value
}
return dst;
}
template <
typename ostream_t,
typename string_t,
typename std_ostream_t = std::basic_ostream<
typename string_t::value_type,
std::char_traits<typename string_t::value_type>>,
typename = std::enable_if_t<
std::is_same_v<std_ostream_t, ostream_t> || std::is_base_of_v<std_ostream_t, ostream_t>>>
ostream_t& operator<<(ostream_t& out, const basic_value<string_t>& val)
{
out << val.format();
return out;
}
} // namespace json