Files
MaaAssistantArknights/3rdparty/include/meojson/common/array.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

689 lines
21 KiB
C++

// IWYU pragma: private, include <meojson/json.hpp>
#pragma once
#include <initializer_list>
#include <optional>
#include <ostream>
#include <string>
#include <tuple>
#include <type_traits>
#include <vector>
#include "exception.hpp"
#include "utils.hpp"
namespace json
{
template <typename string_t>
class basic_array
{
friend class basic_value<string_t>;
friend class basic_object<string_t>;
public:
using raw_array = std::vector<basic_value<string_t>>;
using value_type = typename raw_array::value_type;
using iterator = typename raw_array::iterator;
using const_iterator = typename raw_array::const_iterator;
using reverse_iterator = typename raw_array::reverse_iterator;
using const_reverse_iterator = typename raw_array::const_reverse_iterator;
using char_t = typename string_t::value_type;
public:
basic_array() = default;
basic_array(const basic_array<string_t>& rhs) = default;
basic_array(basic_array<string_t>&& rhs) noexcept = default;
basic_array(std::initializer_list<value_type> init_list);
basic_array(typename raw_array::size_type size);
// explicit basic_array(const basic_value<string_t>& val);
// explicit basic_array(basic_value<string_t>&& val);
template <
typename jsonization_t,
std::enable_if_t<
_utils::has_to_json_in_templ_spec<jsonization_t, string_t>::value
&& !_utils::has_to_json_array_in_templ_spec<jsonization_t, string_t>::value,
bool> = true>
basic_array(const jsonization_t& value)
: basic_array(ext::jsonization<string_t, jsonization_t>().to_json(value))
{
}
template <
typename jsonization_t,
std::enable_if_t<
_utils::has_to_json_array_in_templ_spec<jsonization_t, string_t>::value,
bool> = true>
basic_array(const jsonization_t& value)
: basic_array(ext::jsonization<string_t, jsonization_t>().to_json_array(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
&& !_utils::has_move_to_json_array_in_templ_spec<jsonization_t, string_t>::value,
bool> = true>
basic_array(jsonization_t&& value)
: basic_array(ext::jsonization<string_t, jsonization_t>().move_to_json(std::move(value)))
{
}
//template <
// typename jsonization_t,
// std::enable_if_t<
// std::is_rvalue_reference_v<jsonization_t&&>
// && _utils::has_move_to_json_array_in_templ_spec<jsonization_t, string_t>::value,
// bool> = true>
//basic_array(jsonization_t&& value)
// : basic_array(
// ext::jsonization<string_t, jsonization_t>().move_to_json_array(std::move(value)))
//{
//}
~basic_array() noexcept = default;
bool empty() const noexcept { return _array_data.empty(); }
size_t size() const noexcept { return _array_data.size(); }
bool contains(size_t pos) const { return pos < _array_data.size(); }
bool exists(size_t pos) const { return contains(pos); }
const basic_value<string_t>& at(size_t pos) const;
string_t dumps(std::optional<size_t> indent = std::nullopt) const
{
return indent ? format(*indent) : to_string();
}
string_t to_string() const;
string_t format(size_t indent = 4) const { return format(indent, 0); }
template <typename value_t>
bool all() 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... elem_ts>
std::tuple<elem_ts...> as_tuple() const;
template <typename first_t, typename second_t>
std::pair<first_t, second_t> as_pair() const;
template <
typename value_t,
std::enable_if_t<
_utils::has_from_json_array_in_templ_spec<value_t, string_t>::value,
bool> = true>
value_t as() const&
{
value_t res;
ext::jsonization<string_t, value_t>().from_json_array(*this, res);
return res;
}
template <
typename value_t,
std::enable_if_t<
_utils::has_move_from_json_array_in_templ_spec<value_t, string_t>::value,
bool> = true>
value_t as() &&
{
value_t res;
ext::jsonization<string_t, value_t>().move_from_json_array(std::move(*this), res);
return res;
}
// 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... args_t>
decltype(auto) emplace_back(args_t&&... args);
template <typename... args_t>
decltype(auto) push_back(args_t&&... args);
void clear() noexcept;
bool erase(size_t pos);
bool erase(iterator iter);
iterator begin() noexcept;
iterator end() noexcept;
const_iterator begin() const noexcept;
const_iterator end() const noexcept;
const_iterator cbegin() const noexcept;
const_iterator cend() const noexcept;
reverse_iterator rbegin() noexcept;
reverse_iterator rend() noexcept;
const_reverse_iterator rbegin() const noexcept;
const_reverse_iterator rend() const noexcept;
const_reverse_iterator crbegin() const noexcept;
const_reverse_iterator crend() const noexcept;
const basic_value<string_t>& operator[](size_t pos) const;
basic_value<string_t>& operator[](size_t pos);
basic_array<string_t> operator+(const basic_array<string_t>& rhs) const&;
basic_array<string_t> operator+(basic_array<string_t>&& rhs) const&;
basic_array<string_t> operator+(const basic_array<string_t>& rhs) &&;
basic_array<string_t> operator+(basic_array<string_t>&& rhs) &&;
basic_array<string_t>& operator+=(const basic_array<string_t>& rhs);
basic_array<string_t>& operator+=(basic_array<string_t>&& rhs);
basic_array<string_t>& operator=(const basic_array<string_t>&) = default;
basic_array<string_t>& operator=(basic_array<string_t>&&) noexcept = default;
template <
typename value_t,
std::enable_if_t<std::is_convertible_v<value_t, basic_array<string_t>>, bool> = true>
basic_array<string_t>& operator=(value_t rhs)
{
return *this = basic_array<string_t>(std::move(rhs));
}
bool operator==(const basic_array<string_t>& rhs) const;
bool operator!=(const basic_array<string_t>& rhs) const { return !(*this == rhs); }
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,
size_t Size,
template <typename, size_t> typename fixed_array_t = std::array,
std::enable_if_t<_utils::is_fixed_array<fixed_array_t<value_t, Size>>, bool> = true>
explicit operator fixed_array_t<value_t, Size>() const
{
return as<fixed_array_t<value_t, Size>>();
}
template <
typename jsonization_t,
std::enable_if_t<
_utils::has_from_json_in_templ_spec<jsonization_t, string_t>::value
&& !_utils::has_from_json_array_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_from_json_array_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_array(*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
&& !_utils::has_move_from_json_array_in_templ_spec<jsonization_t, string_t>::value,
bool> = true>
explicit operator jsonization_t() &&
{
jsonization_t dst {};
if (!ext::jsonization<string_t, jsonization_t>().from_json(std::move(*this), dst)) {
throw exception("Wrong JSON");
}
return dst;
}
template <
typename jsonization_t,
std::enable_if_t<
_utils::has_move_from_json_array_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_array(
std::move(*this),
dst)) {
throw exception("Wrong JSON");
}
return dst;
}
private:
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... rest_keys_t>
auto get_helper(const value_t& default_value, size_t pos, rest_keys_t&&... rest) const;
template <typename value_t>
auto get_helper(const value_t& default_value, size_t pos) const;
string_t format(size_t indent, size_t indent_times) const;
private:
raw_array _array_data;
};
template <typename string_t>
inline basic_array<string_t>::basic_array(std::initializer_list<value_type> init_list)
: _array_data(init_list)
{
}
template <typename string_t>
inline basic_array<string_t>::basic_array(typename raw_array::size_type size)
: _array_data(size)
{
}
// template <typename string_t>
// inline basic_array<string_t>::basic_array(const basic_value<string_t>& val) :
// basic_array<string_t>(val.as_array())
//{}
//
// template <typename string_t>
// inline basic_array<string_t>::basic_array(basic_value<string_t>&& val)
// : basic_array<string_t>(std::move(val.as_array()))
//{}
template <typename string_t>
inline void basic_array<string_t>::clear() noexcept
{
_array_data.clear();
}
template <typename string_t>
inline bool basic_array<string_t>::erase(size_t pos)
{
return erase(_array_data.begin() + pos);
}
template <typename string_t>
inline bool basic_array<string_t>::erase(iterator iter)
{
return _array_data.erase(iter) != _array_data.end();
}
template <typename string_t>
template <typename... args_t>
inline decltype(auto) basic_array<string_t>::emplace_back(args_t&&... args)
{
static_assert(
std::is_constructible_v<value_type, args_t...>,
"Parameter can't be used to construct a raw_array::value_type");
return _array_data.emplace_back(std::forward<args_t>(args)...);
}
template <typename string_t>
template <typename... args_t>
inline decltype(auto) basic_array<string_t>::push_back(args_t&&... args)
{
return emplace_back(std::forward<args_t>(args)...);
}
template <typename string_t>
inline const basic_value<string_t>& basic_array<string_t>::at(size_t pos) const
{
return _array_data.at(pos);
}
template <typename string_t>
inline string_t basic_array<string_t>::to_string() const
{
string_t str { '[' };
for (auto iter = _array_data.cbegin(); iter != _array_data.cend();) {
str += iter->to_string();
if (++iter != _array_data.cend()) {
str += ',';
}
}
str += char_t(']');
return str;
}
template <typename string_t>
inline string_t basic_array<string_t>::format(size_t indent, size_t indent_times) const
{
const string_t tail_indent(indent * indent_times, ' ');
const string_t body_indent(indent * (indent_times + 1), ' ');
string_t str { '[', '\n' };
for (auto iter = _array_data.cbegin(); iter != _array_data.cend();) {
str += body_indent + iter->format(indent, indent_times + 1);
if (++iter != _array_data.cend()) {
str += ',';
}
str += '\n';
}
str += tail_indent + char_t(']');
return str;
}
template <typename string_t>
template <typename value_t>
inline bool basic_array<string_t>::all() const
{
for (const auto& elem : _array_data) {
if (!elem.template is<value_t>()) {
return false;
}
}
return true;
}
template <typename string_t>
template <typename value_t, template <typename...> typename collection_t>
inline collection_t<value_t> basic_array<string_t>::as_collection() const
{
return as<collection_t<value_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_array<string_t>::as_fixed_array() const
{
return as<fixed_array_t<value_t, Size>>();
}
template <typename string_t>
template <typename... elem_ts>
inline std::tuple<elem_ts...> basic_array<string_t>::as_tuple() const
{
return as<std::tuple<elem_ts...>>();
}
template <typename string_t>
template <typename first_t, typename second_t>
inline std::pair<first_t, second_t> basic_array<string_t>::as_pair() const
{
return as<std::pair<first_t, second_t>>();
}
template <typename string_t>
template <typename... key_then_default_value_t>
inline auto basic_array<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_array<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... rest_keys_t>
inline auto basic_array<string_t>::get_helper(
const value_t& default_value,
size_t pos,
rest_keys_t&&... rest) const
{
constexpr bool is_json = std::is_same_v<basic_value<string_t>, value_t>
|| std::is_same_v<basic_array<string_t>, value_t>
|| std::is_same_v<basic_object<string_t>, value_t>;
constexpr bool is_string = std::is_constructible_v<string_t, value_t> && !is_json;
if (!contains(pos)) {
if constexpr (is_string) {
return string_t(default_value);
}
else {
return value_t(default_value);
}
}
return at(pos).get_helper(default_value, std::forward<rest_keys_t>(rest)...);
}
template <typename string_t>
template <typename value_t>
inline auto basic_array<string_t>::get_helper(const value_t& default_value, size_t pos) const
{
constexpr bool is_json = std::is_same_v<basic_value<string_t>, value_t>
|| std::is_same_v<basic_array<string_t>, value_t>
|| std::is_same_v<basic_object<string_t>, value_t>;
constexpr bool is_string = std::is_constructible_v<string_t, value_t> && !is_json;
if (!contains(pos)) {
if constexpr (is_string) {
return string_t(default_value);
}
else {
return value_t(default_value);
}
}
auto val = _array_data.at(pos);
if (val.template is<value_t>()) {
if constexpr (is_string) {
return val.template as<string_t>();
}
else {
return val.template as<value_t>();
}
}
else {
if constexpr (is_string) {
return string_t(default_value);
}
else {
return value_t(default_value);
}
}
}
template <typename string_t>
template <typename value_t>
inline std::optional<value_t> basic_array<string_t>::find(size_t pos) const
{
if (!contains(pos)) {
return std::nullopt;
}
const auto& val = _array_data.at(pos);
return val.template is<value_t>() ? std::optional<value_t>(val.template as<value_t>())
: std::nullopt;
}
template <typename string_t>
inline typename basic_array<string_t>::iterator basic_array<string_t>::begin() noexcept
{
return _array_data.begin();
}
template <typename string_t>
inline typename basic_array<string_t>::iterator basic_array<string_t>::end() noexcept
{
return _array_data.end();
}
template <typename string_t>
inline typename basic_array<string_t>::const_iterator basic_array<string_t>::begin() const noexcept
{
return _array_data.begin();
}
template <typename string_t>
inline typename basic_array<string_t>::const_iterator basic_array<string_t>::end() const noexcept
{
return _array_data.end();
}
template <typename string_t>
inline typename basic_array<string_t>::const_iterator basic_array<string_t>::cbegin() const noexcept
{
return _array_data.cbegin();
}
template <typename string_t>
inline typename basic_array<string_t>::const_iterator basic_array<string_t>::cend() const noexcept
{
return _array_data.cend();
}
template <typename string_t>
inline typename basic_array<string_t>::reverse_iterator basic_array<string_t>::rbegin() noexcept
{
return _array_data.rbegin();
}
template <typename string_t>
inline typename basic_array<string_t>::reverse_iterator basic_array<string_t>::rend() noexcept
{
return _array_data.rend();
}
template <typename string_t>
inline typename basic_array<string_t>::const_reverse_iterator
basic_array<string_t>::rbegin() const noexcept
{
return _array_data.rbegin();
}
template <typename string_t>
inline typename basic_array<string_t>::const_reverse_iterator
basic_array<string_t>::rend() const noexcept
{
return _array_data.rend();
}
template <typename string_t>
inline typename basic_array<string_t>::const_reverse_iterator
basic_array<string_t>::crbegin() const noexcept
{
return _array_data.crbegin();
}
template <typename string_t>
inline typename basic_array<string_t>::const_reverse_iterator
basic_array<string_t>::crend() const noexcept
{
return _array_data.crend();
}
template <typename string_t>
inline basic_value<string_t>& basic_array<string_t>::operator[](size_t pos)
{
return _array_data[pos];
}
template <typename string_t>
inline const basic_value<string_t>& basic_array<string_t>::operator[](size_t pos) const
{
return _array_data[pos];
}
template <typename string_t>
inline basic_array<string_t>
basic_array<string_t>::operator+(const basic_array<string_t>& rhs) const&
{
basic_array<string_t> temp = *this;
temp._array_data.insert(_array_data.end(), rhs.begin(), rhs.end());
return temp;
}
template <typename string_t>
inline basic_array<string_t> basic_array<string_t>::operator+(basic_array<string_t>&& rhs) const&
{
basic_array<string_t> temp = *this;
temp._array_data.insert(
_array_data.end(),
std::make_move_iterator(rhs.begin()),
std::make_move_iterator(rhs.end()));
return temp;
}
template <typename string_t>
inline basic_array<string_t> basic_array<string_t>::operator+(const basic_array<string_t>& rhs) &&
{
_array_data.insert(_array_data.end(), rhs.begin(), rhs.end());
return std::move(*this);
}
template <typename string_t>
inline basic_array<string_t> basic_array<string_t>::operator+(basic_array<string_t>&& rhs) &&
{
_array_data.insert(
_array_data.end(),
std::make_move_iterator(rhs.begin()),
std::make_move_iterator(rhs.end()));
return std::move(*this);
}
template <typename string_t>
inline basic_array<string_t>& basic_array<string_t>::operator+=(const basic_array<string_t>& rhs)
{
_array_data.insert(_array_data.end(), rhs.begin(), rhs.end());
return *this;
}
template <typename string_t>
inline basic_array<string_t>& basic_array<string_t>::operator+=(basic_array<string_t>&& rhs)
{
_array_data.insert(
_array_data.end(),
std::make_move_iterator(rhs.begin()),
std::make_move_iterator(rhs.end()));
return *this;
}
template <typename string_t>
inline bool basic_array<string_t>::operator==(const basic_array<string_t>& rhs) const
{
return _array_data == rhs._array_data;
}
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 enable_t = 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_array<string_t>& arr)
{
out << arr.format();
return out;
}
} // namespace json