#pragma once #include #include #include #include #include #include #include "exception.hpp" #include "utils.hpp" namespace json { template class basic_array { friend class basic_value; friend class basic_object; public: using raw_array = std::vector>; 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& rhs) = default; basic_array(basic_array&& rhs) noexcept = default; basic_array(std::initializer_list init_list); basic_array(typename raw_array::size_type size); // explicit basic_array(const basic_value& val); // explicit basic_array(basic_value&& val); template && std::is_constructible_v>, bool> = true> basic_array(collection_t arr) : _array_data(std::make_move_iterator(arr.begin()), std::make_move_iterator(arr.end())) {} template ::value, bool> = true> basic_array(const jsonization_t& value) : basic_array(value.to_json()) {} template ::value, bool> = true> basic_array(const jsonization_t& value) : basic_array(ext::jsonization().to_json(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& at(size_t pos) const; string_t dumps(std::optional 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 bool all() const; template typename collection_t = std::vector> collection_t as_collection() const; // Usage: get(key_1, key_2, ..., default_value); template auto get(key_then_default_value_t&&... keys_then_default_value) const; template > std::optional find(size_t pos) const; template decltype(auto) emplace_back(args_t&&... args); template 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& operator[](size_t pos) const; basic_value& operator[](size_t pos); basic_array operator+(const basic_array& rhs) const&; basic_array operator+(basic_array&& rhs) const&; basic_array operator+(const basic_array& rhs) &&; basic_array operator+(basic_array&& rhs) &&; basic_array& operator+=(const basic_array& rhs); basic_array& operator+=(basic_array&& rhs); basic_array& operator=(const basic_array&) = default; basic_array& operator=(basic_array&&) noexcept = default; template >, bool> = true> basic_array& operator=(value_t rhs) { return *this = basic_array(std::move(rhs)); } bool operator==(const basic_array& rhs) const; bool operator!=(const basic_array& rhs) const { return !(*this == rhs); } template typename collection_t = std::vector, std::enable_if_t<_utils::is_collection>, bool> = true> explicit operator collection_t() const { return as_collection(); } template ::value, bool> = true> explicit operator jsonization_t() const { jsonization_t dst {}; if (!dst.from_json(*this)) { throw exception("Wrong JSON"); } return dst; } template ::value, bool> = true> explicit operator jsonization_t() const { jsonization_t dst {}; if (!ext::jsonization().from_json(*this, dst)) { throw exception("Wrong JSON"); } return dst; } private: template auto get(std::tuple keys_then_default_value, std::index_sequence) const; template auto get_helper(const value_t& default_value, size_t pos, rest_keys_t&&... rest) const; template 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 inline basic_array::basic_array(std::initializer_list init_list) : _array_data(init_list) {} template inline basic_array::basic_array(typename raw_array::size_type size) : _array_data(size) {} // template // inline basic_array::basic_array(const basic_value& val) : basic_array(val.as_array()) //{} // // template // inline basic_array::basic_array(basic_value&& val) // : basic_array(std::move(val.as_array())) //{} template inline void basic_array::clear() noexcept { _array_data.clear(); } template inline bool basic_array::erase(size_t pos) { return erase(_array_data.begin() + pos); } template inline bool basic_array::erase(iterator iter) { return _array_data.erase(iter) != _array_data.end(); } template template inline decltype(auto) basic_array::emplace_back(args_t&&... args) { static_assert(std::is_constructible_v, "Parameter can't be used to construct a raw_array::value_type"); return _array_data.emplace_back(std::forward(args)...); } template template inline decltype(auto) basic_array::push_back(args_t&&... args) { return emplace_back(std::forward(args)...); } template inline const basic_value& basic_array::at(size_t pos) const { return _array_data.at(pos); } template inline string_t basic_array::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 inline string_t basic_array::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 template inline bool basic_array::all() const { for (const auto& elem : _array_data) { if (!elem.template is()) { return false; } } return true; } namespace _as_collection_helper { template class has_emplace_back { template static auto test(int) -> decltype(std::declval().emplace_back(), std::true_type()); template static std::false_type test(...); public: static constexpr bool value = decltype(test(0))::value; }; } template template typename collection_t> inline collection_t basic_array::as_collection() const { collection_t result; if constexpr (_as_collection_helper::has_emplace_back>::value) { for (const auto& elem : _array_data) { result.emplace_back(elem.template as()); } } else { for (const auto& elem : _array_data) { result.emplace(elem.template as()); } } return result; } template template inline auto basic_array::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 {}); } template template inline auto basic_array::get(std::tuple keys_then_default_value, std::index_sequence) const { constexpr unsigned long default_value_index = sizeof...(key_then_default_value_t) - 1; return get_helper(std::get(keys_then_default_value), std::get(keys_then_default_value)...); } template template inline auto basic_array::get_helper(const value_t& default_value, size_t pos, rest_keys_t&&... rest) const { constexpr bool is_json = std::is_same_v, value_t> || std::is_same_v, value_t> || std::is_same_v, value_t>; constexpr bool is_string = std::is_constructible_v && !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)...); } template template inline auto basic_array::get_helper(const value_t& default_value, size_t pos) const { constexpr bool is_json = std::is_same_v, value_t> || std::is_same_v, value_t> || std::is_same_v, value_t>; constexpr bool is_string = std::is_constructible_v && !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()) { if constexpr (is_string) { return val.template as(); } else { return val.template as(); } } else { if constexpr (is_string) { return string_t(default_value); } else { return value_t(default_value); } } } template template inline std::optional basic_array::find(size_t pos) const { if (!contains(pos)) { return std::nullopt; } const auto& val = _array_data.at(pos); return val.template is() ? std::optional(val.template as()) : std::nullopt; } template inline typename basic_array::iterator basic_array::begin() noexcept { return _array_data.begin(); } template inline typename basic_array::iterator basic_array::end() noexcept { return _array_data.end(); } template inline typename basic_array::const_iterator basic_array::begin() const noexcept { return _array_data.begin(); } template inline typename basic_array::const_iterator basic_array::end() const noexcept { return _array_data.end(); } template inline typename basic_array::const_iterator basic_array::cbegin() const noexcept { return _array_data.cbegin(); } template inline typename basic_array::const_iterator basic_array::cend() const noexcept { return _array_data.cend(); } template inline typename basic_array::reverse_iterator basic_array::rbegin() noexcept { return _array_data.rbegin(); } template inline typename basic_array::reverse_iterator basic_array::rend() noexcept { return _array_data.rend(); } template inline typename basic_array::const_reverse_iterator basic_array::rbegin() const noexcept { return _array_data.rbegin(); } template inline typename basic_array::const_reverse_iterator basic_array::rend() const noexcept { return _array_data.rend(); } template inline typename basic_array::const_reverse_iterator basic_array::crbegin() const noexcept { return _array_data.crbegin(); } template inline typename basic_array::const_reverse_iterator basic_array::crend() const noexcept { return _array_data.crend(); } template inline basic_value& basic_array::operator[](size_t pos) { return _array_data[pos]; } template inline const basic_value& basic_array::operator[](size_t pos) const { return _array_data[pos]; } template inline basic_array basic_array::operator+(const basic_array& rhs) const& { basic_array temp = *this; temp._array_data.insert(_array_data.end(), rhs.begin(), rhs.end()); return temp; } template inline basic_array basic_array::operator+(basic_array&& rhs) const& { basic_array temp = *this; temp._array_data.insert(_array_data.end(), std::make_move_iterator(rhs.begin()), std::make_move_iterator(rhs.end())); return temp; } template inline basic_array basic_array::operator+(const basic_array& rhs) && { _array_data.insert(_array_data.end(), rhs.begin(), rhs.end()); return std::move(*this); } template inline basic_array basic_array::operator+(basic_array&& rhs) && { _array_data.insert(_array_data.end(), std::make_move_iterator(rhs.begin()), std::make_move_iterator(rhs.end())); return std::move(*this); } template inline basic_array& basic_array::operator+=(const basic_array& rhs) { _array_data.insert(_array_data.end(), rhs.begin(), rhs.end()); return *this; } template inline basic_array& basic_array::operator+=(basic_array&& rhs) { _array_data.insert(_array_data.end(), std::make_move_iterator(rhs.begin()), std::make_move_iterator(rhs.end())); return *this; } template inline bool basic_array::operator==(const basic_array& rhs) const { return _array_data == rhs._array_data; } template >, typename enable_t = std::enable_if_t || std::is_base_of_v>> ostream_t& operator<<(ostream_t& out, const basic_array& arr) { out << arr.format(); return out; } } // namespace json