diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ddac2d..b82c403 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,17 @@ if (BUILD_TESTING) test/*.hpp ) add_executable(testing ${testing_src} include/json.hpp) + + file(GLOB testing20_src + test20/*.cpp + test20/*.h + test20/*.hpp + ) + add_executable(testing20 ${testing20_src} include/json.hpp) + set_target_properties(testing20 + PROPERTIES + CXX_STANDARD 20 + ) endif() if (BUILD_BENCHMARK) diff --git a/include/constexpr_helper.hpp b/include/constexpr_helper.hpp new file mode 100644 index 0000000..22e61d2 --- /dev/null +++ b/include/constexpr_helper.hpp @@ -0,0 +1,163 @@ +#pragma once + +#include + +#include "constexpr_map.hpp" +#include "constexpr_unique_ptr.hpp" +#include "constexpr_variant.hpp" + +namespace json +{ + +namespace soft_impl +{ + + constexpr int to_string_double_precision = 14; + + template + constexpr bool is_digit(elem_t ch) + { + return '0' <= ch && ch <= '9'; + } + + template + constexpr string_t to_string(unsigned long long value) + { + string_t result; + do { + result.push_back('0' + value % 10); + value /= 10; + } while (value > 0); + return string_t(result.rbegin(), result.rend()); + } + + template + constexpr string_t to_string(long long value) + { + string_t result; + bool nega = false; + if (value == INT64_MIN) { + return to_string(0x8000000000000000ull); + } + if (value < 0) { + nega = true; + value = -value; + } + do { + result.push_back('0' + value % 10); + value /= 10; + } while (value > 0); + if (nega) { + result.push_back('-'); + } + return string_t(result.rbegin(), result.rend()); + } + + template + constexpr string_t to_string(double value) + { + string_t result; + if (value < 0) { + result.push_back('-'); + value = -value; + } + int precision = to_string_double_precision; + double base = 1; + int log_base = 0; + while (base <= value) { + base *= 10; + log_base++; + } + if (log_base == 0) { + while (base > value) { + base /= 10; + log_base--; + } + log_base++; + base *= 10; + + result.push_back('0'); + result.push_back('.'); + for (int k = 0; k > log_base; k--) { + result.push_back('0'); + } + } + while (precision--) { + log_base--; + base /= 10; + char c = '0'; + while (value >= base) { + value -= base; + c++; + } + result.push_back(c); + if (log_base == 0) { + result.push_back('.'); + } + } + if (log_base > 0) { + while (log_base > 0) { + result.push_back('0'); + log_base--; + } + result.push_back('.'); + } + return result; + } + + template + constexpr string_t to_string(signed char v) + { + return to_string(static_cast(v)); + } + template + constexpr string_t to_string(short v) + { + return to_string(static_cast(v)); + } + template + constexpr string_t to_string(int v) + { + return to_string(static_cast(v)); + } + template + constexpr string_t to_string(long v) + { + return to_string(static_cast(v)); + } + + template + constexpr string_t to_string(unsigned char v) + { + return to_string(static_cast(v)); + } + template + constexpr string_t to_string(unsigned short v) + { + return to_string(static_cast(v)); + } + template + constexpr string_t to_string(unsigned int v) + { + return to_string(static_cast(v)); + } + template + constexpr string_t to_string(unsigned long v) + { + return to_string(static_cast(v)); + } + + template + constexpr string_t to_string(float v) + { + return to_string(static_cast(v)); + } + template + constexpr string_t to_string(long double v) + { + return to_string(static_cast(v)); + } + +} // namespace soft_impl + +}; // namespace json diff --git a/include/constexpr_map.hpp b/include/constexpr_map.hpp new file mode 100644 index 0000000..95360a4 --- /dev/null +++ b/include/constexpr_map.hpp @@ -0,0 +1,184 @@ +#pragma once + +#include +#include + +namespace json +{ + +template +inline constexpr Iter lower_bound_fix(Iter begin, Iter end, const Val& val, Pred pred) +{ +#ifdef __GLIBCXX__ + // lower_bound实现的有问题 + // https://github.com/gcc-mirror/gcc/blob/d9375e490072d1aae73a93949aa158fcd2a27018/libstdc%2B%2B-v3/include/bits/stl_algobase.h#L1023 + return std::__lower_bound(begin, end, val, [&pred](auto iter, const auto& val) { return pred(*iter, val); }); +#else + return std::lower_bound(begin, end, val, pred); +#endif +} + +template +class constexpr_map +{ + using container_type = std::vector>; + +public: + using key_type = key_t; + using mapped_type = value_t; + using value_type = typename container_type::value_type; + + struct iterator + { + typename container_type::iterator _iter; + + using iterator_category = std::bidirectional_iterator_tag; + using value_type = typename container_type::iterator::value_type; + using difference_type = typename container_type::iterator::difference_type; + using pointer = typename container_type::iterator::pointer; + using reference = typename container_type::iterator::reference; + + constexpr iterator(typename container_type::iterator&& it) : _iter(it) {} + + constexpr iterator& operator++() + { + ++_iter; + return *this; + } + + constexpr iterator operator++(int) { return iterator { _iter++ }; } + + constexpr iterator& operator--() + { + --_iter; + return *this; + } + + constexpr iterator operator--(int) { return iterator { _iter-- }; } + + constexpr value_type& operator*() const { return *_iter; } + + constexpr value_type* operator->() const { return &*_iter; } + + friend constexpr bool operator==(const iterator& x, const iterator& y) { return x._iter == y._iter; } + + friend constexpr bool operator!=(const iterator& x, const iterator& y) { return x._iter != y._iter; } + }; + + struct const_iterator + { + typename container_type::const_iterator _iter; + + using value_type = typename container_type::const_iterator::value_type; + using difference_type = typename container_type::const_iterator::difference_type; + using pointer = typename container_type::const_iterator::pointer; + using reference = typename container_type::const_iterator::reference; + + constexpr const_iterator(typename container_type::const_iterator&& it) : _iter(it) {} + + constexpr const_iterator& operator++() + { + ++_iter; + return *this; + } + + constexpr const_iterator operator++(int) { return const_iterator { _iter++ }; } + + constexpr const_iterator& operator--() + { + --_iter; + return *this; + } + + constexpr const_iterator operator--(int) { return const_iterator { _iter-- }; } + + constexpr const value_type& operator*() const { return *_iter; } + + constexpr const value_type* operator->() const { return &*_iter; } + + friend constexpr bool operator==(const const_iterator& x, const const_iterator& y) + { + return x._iter == y._iter; + } + + friend constexpr bool operator!=(const const_iterator& x, const const_iterator& y) + { + return x._iter != y._iter; + } + }; + + constexpr constexpr_map() = default; + constexpr constexpr_map(const constexpr_map&) = default; + constexpr constexpr_map(constexpr_map&&) = default; + constexpr ~constexpr_map() = default; + constexpr constexpr_map& operator=(const constexpr_map&) = default; + constexpr constexpr_map& operator=(constexpr_map&&) = default; + + template + constexpr constexpr_map(Args&&... args) : _data(args...) + {} + + constexpr iterator begin() { return _data.begin(); } + + constexpr const_iterator begin() const { return _data.begin(); } + + constexpr const_iterator cbegin() const { return _data.cbegin(); } + + constexpr iterator end() { return _data.end(); } + + constexpr const_iterator end() const { return _data.end(); } + + constexpr const_iterator cend() const { return _data.cend(); } + + constexpr mapped_type& operator[](const key_t& key) { return emplace(key, mapped_type {}).first->second; } + + constexpr mapped_type& operator[](key_t&& key) + { + return emplace(std::forward(key), mapped_type {}).first->second; + } + + constexpr iterator find(const key_t& key) + { + auto ptr = lower_bound_fix(begin(), end(), key, + [](const value_type& elem, const key_type& val) { return elem.first < val; }); + return ptr->first == key ? ptr : end(); + } + + constexpr const_iterator find(const key_t& key) const + { + auto ptr = lower_bound_fix(cbegin(), cend(), key, + [](const value_type& elem, const key_type& val) { return elem.first < val; }); + return ptr->first == key ? ptr : cend(); + } + + template + constexpr std::pair emplace(Args&&... args) + { + value_type p(std::forward(args)...); + auto ptr = lower_bound_fix(begin(), end(), p.first, + [](const value_type& elem, const key_type& val) { return elem.first < val; }); + if (ptr != end() && ptr->first == p.first) { + return std::make_pair(ptr, false); + } + else { + return std::make_pair(_data.insert(ptr._iter, std::move(p)), true); + } + } + +private: + container_type _data; +}; + +} // namespace json + +template +constexpr bool operator==(const json::constexpr_map& x, const json::constexpr_map& y) +{ + return x._data == y._data; +} + +template +constexpr bool operator!=(const json::constexpr_map& x, const json::constexpr_map& y) +{ + return !(x == y); +} diff --git a/include/constexpr_unique_ptr.hpp b/include/constexpr_unique_ptr.hpp new file mode 100644 index 0000000..b4d46f1 --- /dev/null +++ b/include/constexpr_unique_ptr.hpp @@ -0,0 +1,63 @@ +#pragma once + +#include + +namespace json +{ + +template +class constexpr_unique_ptr +{ +public: + constexpr void reset() + { + delete _data; + _data = nullptr; + } + + constexpr constexpr_unique_ptr() = default; + constexpr constexpr_unique_ptr(elem_t* p) : _data(p) {} + + constexpr constexpr_unique_ptr(const constexpr_unique_ptr&) = delete; + constexpr constexpr_unique_ptr(constexpr_unique_ptr&& another) : _data(std::exchange(another._data, nullptr)) {} + + constexpr constexpr_unique_ptr& operator=(const constexpr_unique_ptr&) = delete; + constexpr constexpr_unique_ptr& operator=(constexpr_unique_ptr&& another) + { + if (this == &another) { + return *this; + } + reset(); + _data = std::exchange(another._data, nullptr); + return *this; + } + + constexpr ~constexpr_unique_ptr() { reset(); } + + constexpr elem_t* operator->() const { return _data; } + constexpr elem_t& operator*() const { return *_data; } + constexpr elem_t* get() const { return _data; } + +private: + elem_t* _data = nullptr; +}; + +} + +template +constexpr bool operator==(const json::constexpr_unique_ptr& x, const json::constexpr_unique_ptr& y) +{ + if (!x.get() || !y.get()) { + return false; + } + if (x.get() == y.get()) { + return true; + } + return *x == *y; +} + +template +constexpr bool operator!=(const json::constexpr_unique_ptr& x, const json::constexpr_unique_ptr& y) +{ + return !(x == y); +} diff --git a/include/constexpr_variant.hpp b/include/constexpr_variant.hpp new file mode 100644 index 0000000..6883192 --- /dev/null +++ b/include/constexpr_variant.hpp @@ -0,0 +1,168 @@ +#pragma once + +#include + +namespace json +{ + +template +concept contains_type = (std::same_as || ...); + +template +class constexpr_variant +{ +public: + constexpr constexpr_variant() = default; + + constexpr constexpr_variant(const constexpr_variant& v) : _data(v._data), _index(v._index) {} + + constexpr constexpr_variant(constexpr_variant&& v) : _data(std::move(v._data)), _index(v._index) {} + + constexpr constexpr_variant& operator=(const constexpr_variant& v) + { + _index = v._index; + _data = v._data; + return *this; + } + + constexpr constexpr_variant& operator=(constexpr_variant&& v) + { + _index = v._index; + _data = std::move(v._data); + return *this; + } + + constexpr ~constexpr_variant() = default; + + template + requires contains_type + constexpr constexpr_variant(elem_t&& elem) + { + constexpr size_t index = index_of(); + std::get(_data) = std::forward(elem); + _index = index; + } + + template + requires contains_type + constexpr constexpr_variant& operator=(elem_t&& elem) + { + constexpr size_t index = index_of(); + std::get(_data) = std::forward(elem); + _index = index; + return *this; + } + + template + requires contains_type + constexpr static size_t index_of() + { + constexpr size_t N = sizeof...(elems_t); + constexpr bool found[] = { std::is_same_v... }; + constexpr size_t index = ([&] { + size_t index = N; + for (size_t i = 0; i < N; ++i) { + if (found[i]) { + index = i; + break; + } + } + return index; + })(); + static_assert(index != N, "error!"); + return index; + } + + template + requires contains_type + constexpr const elem_t* get_if() const + { + constexpr size_t index = index_of(); + if (_index == index) { + return &std::get(_data); + } + else { + return nullptr; + } + } + + template + requires contains_type + constexpr const elem_t& get() const + { + constexpr size_t index = index_of(); + if (_index == index) { + return std::get(_data); + } + else { + throw std::bad_variant_access(); + } + } + + constexpr size_t index() const { return _index; } + + constexpr const std::tuple& data() const { return _data; } + +private: + std::tuple _data; + size_t _index = 0; +}; + +#ifndef _MSC_VER +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-value" +#endif + +template +constexpr bool compare_at_indexs(const tuple_t& t1, const tuple_t& t2, std::size_t index, std::index_sequence) +{ + bool result = false; + (..., (Is == index ? (result = (std::get(t1) == std::get(t2)), true) : false)); + return result; +} + +#ifndef _MSC_VER +#pragma GCC diagnostic pop +#endif + +template +constexpr bool compare_at_index(const std::tuple& t1, const std::tuple& t2, std::size_t index) +{ + return compare_at_indexs(t1, t2, index, std::index_sequence_for {}); +} + +} // namespace json + +namespace std +{ + +template +requires json::contains_type +constexpr const elem_t* get_if(const json::constexpr_variant* v) +{ + return v->template get_if(); +} + +template +requires json::contains_type +constexpr const elem_t& get(const json::constexpr_variant& v) +{ + return v.template get(); +} + +} + +template +constexpr bool operator==(const json::constexpr_variant& x, const json::constexpr_variant& y) +{ + if (x.index() != y.index()) { + return false; + } + return compare_at_index(x.data(), y.data(), x.index()); +} + +template +constexpr bool operator!=(const json::constexpr_variant& x, const json::constexpr_variant& y) +{ + return !(x == y); +} diff --git a/include/json.hpp b/include/json.hpp index 4790ae2..3811f29 100644 --- a/include/json.hpp +++ b/include/json.hpp @@ -14,24 +14,70 @@ #include "packed_bytes.hpp" +#if __cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) +#define __json_enable_constexpr +#include "constexpr_helper.hpp" + +#define __json_constexpr constexpr +#else +#define __json_constexpr +#endif + namespace json { -template + +struct default_container_traits +{ + template + using map_t = std::map<_...>; + template + using unique_ptr_t = std::unique_ptr<_...>; + template + using variant_t = std::variant<_...>; +}; + +#ifdef __json_enable_constexpr +struct constexpr_container_traits +{ + template + using map_t = constexpr_map<_...>; + template + using unique_ptr_t = constexpr_unique_ptr<_...>; + template + using variant_t = constexpr_variant<_...>; +}; +#endif + +template class basic_value; -template +template class basic_array; -template +template class basic_object; using default_string_t = std::string; +template +using default_map_t = std::map<_...>; +template +using default_unique_ptr_t = std::unique_ptr<_...>; +template +using default_variant_t = std::variant<_...>; + +using value = basic_value; +using array = basic_array; +using object = basic_object; -using value = basic_value; -using array = basic_array; -using object = basic_object; +using wvalue = basic_value; +using warray = basic_array; +using wobject = basic_object; -using wvalue = basic_value; -using warray = basic_array; -using wobject = basic_object; +#ifdef __json_enable_constexpr + +using cvalue = basic_value; +using carray = basic_array; +using cobject = basic_object; + +#endif namespace utils { @@ -49,11 +95,11 @@ namespace utils // * basic_value declare * // ********************************* -template +template class basic_value { - using array_ptr = std::unique_ptr>; - using object_ptr = std::unique_ptr>; + using array_ptr = typename traits_t::template unique_ptr_t>; + using object_ptr = typename traits_t::template unique_ptr_t>; public: enum class value_type : char @@ -67,50 +113,55 @@ class basic_value object }; - using var_t = std::variant; + using var_t = typename traits_t::template variant_t; using char_t = typename string_t::value_type; public: - basic_value(); - basic_value(const basic_value& rhs); - basic_value(basic_value&& 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(basic_array arr); - basic_value(basic_object obj); - basic_value(std::initializer_list::value_type> init_list); + __json_constexpr basic_value(); + __json_constexpr basic_value(const basic_value& rhs); + __json_constexpr basic_value(basic_value&& rhs) noexcept; + + __json_constexpr basic_value(bool b); + + __json_constexpr basic_value(int num); + __json_constexpr basic_value(unsigned num); + __json_constexpr basic_value(long num); + __json_constexpr basic_value(unsigned long num); + __json_constexpr basic_value(long long num); + __json_constexpr basic_value(unsigned long long num); + __json_constexpr basic_value(float num); + __json_constexpr basic_value(double num); + __json_constexpr basic_value(long double num); + + __json_constexpr basic_value(const char_t* str); + __json_constexpr basic_value(string_t str); + + __json_constexpr basic_value(basic_array arr); + __json_constexpr basic_value(basic_object obj); + __json_constexpr basic_value( + std::initializer_list::value_type> init_list); // Constructed from raw data template - basic_value(value_type type, args_t&&... args); + __json_constexpr basic_value(value_type type, args_t&&... args); template ::value_type, + std::enable_if_t::value_type, utils::range_value_t>, bool> = true> - basic_value(collection_t&& collection) : basic_value(basic_array(std::forward(collection))) + __json_constexpr basic_value(collection_t&& collection) + : basic_value(basic_array(std::forward(collection))) {} - template ::value_type, - utils::range_value_t>, - bool> = true> - basic_value(map_t&& map) : basic_value(basic_object(std::forward(map))) + template ::value_type, + utils::range_value_t>, + bool> = true> + __json_constexpr basic_value(another_map_t&& map) + : basic_value(basic_object(std::forward(map))) {} - template >, bool> = true> + template >, bool> = true> basic_value(value_t) = delete; // I don't know if you want to convert char to string or number, so I delete these constructors. @@ -119,146 +170,149 @@ class basic_value basic_value(char16_t) = delete; basic_value(char32_t) = delete; - ~basic_value(); + __json_constexpr ~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; } + __json_constexpr bool valid() const noexcept { return _type != value_type::invalid; } + __json_constexpr bool empty() const noexcept { return is_null(); } + __json_constexpr bool is_null() const noexcept { return _type == value_type::null; } + __json_constexpr bool is_number() const noexcept { return _type == value_type::number; } + __json_constexpr bool is_boolean() const noexcept { return _type == value_type::boolean; } + __json_constexpr bool is_string() const noexcept { return _type == value_type::string; } + __json_constexpr bool is_array() const noexcept { return _type == value_type::array; } + __json_constexpr bool is_object() const noexcept { return _type == value_type::object; } template - bool is() const noexcept; + __json_constexpr bool is() const noexcept; - 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& at(size_t pos) const; - const basic_value& at(const string_t& key) const; + __json_constexpr bool contains(const string_t& key) const; + __json_constexpr bool contains(size_t pos) const; + __json_constexpr bool exists(const string_t& key) const { return contains(key); } + __json_constexpr bool exists(size_t pos) const { return contains(pos); } + __json_constexpr value_type type() const noexcept { return _type; } + __json_constexpr const basic_value& at(size_t pos) const; + __json_constexpr const basic_value& at(const string_t& key) const; - bool erase(size_t pos); - bool erase(const string_t& key); + __json_constexpr bool erase(size_t pos); + __json_constexpr bool erase(const string_t& key); // 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 > - std::optional 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& as_array() const; - const basic_object& as_object() const; + __json_constexpr auto get(key_then_default_value_t&&... keys_then_default_value) const; + + template > + __json_constexpr std::optional find(size_t pos) const; + template > + __json_constexpr std::optional find(const string_t& key) const; + + __json_constexpr bool as_boolean() const; + __json_constexpr int as_integer() const; + __json_constexpr unsigned as_unsigned() const; + __json_constexpr long as_long() const; + __json_constexpr unsigned long as_unsigned_long() const; + __json_constexpr long long as_long_long() const; + __json_constexpr unsigned long long as_unsigned_long_long() const; + __json_constexpr float as_float() const; + __json_constexpr double as_double() const; + __json_constexpr long double as_long_double() const; + __json_constexpr string_t as_string() const; + __json_constexpr const basic_array& as_array() const; + __json_constexpr const basic_object& as_object() const; template - value_t as() const; + __json_constexpr value_t as() const; - basic_array& as_array(); - basic_object& as_object(); + __json_constexpr basic_array& as_array(); + __json_constexpr basic_object& as_object(); template - decltype(auto) emplace(args_t&&... args); + __json_constexpr decltype(auto) emplace(args_t&&... args); template /*will be deprecated, please use `emplace` instead.*/ - decltype(auto) array_emplace(args_t&&... args); + __json_constexpr decltype(auto) array_emplace(args_t&&... args); template /*will be deprecated, please use `emplace` instead.*/ - decltype(auto) object_emplace(args_t&&... args); + __json_constexpr decltype(auto) object_emplace(args_t&&... args); - void clear() noexcept; + __json_constexpr void clear() noexcept; - string_t dumps(std::optional indent = std::nullopt) const { return indent ? format(*indent) : to_string(); } + __json_constexpr string_t dumps(std::optional indent = std::nullopt) const + { + return indent ? format(*indent) : to_string(); + } // return raw string - string_t to_string() const; - string_t format() const { return format(4, 0); } + __json_constexpr string_t to_string() const; + __json_constexpr string_t format() const { return format(4, 0); } // format(bool) is deprecated now. template && !std::is_same_v>> - string_t format(sz_t indent) const + __json_constexpr string_t format(sz_t indent) const { return format(indent, 0); } template - bool all() const; + __json_constexpr bool all() const; template typename vector_t = std::vector> - vector_t to_vector() const; - template typename map_t = std::map> - map_t to_map() const; - - basic_value& operator=(const basic_value& rhs); - basic_value& operator=(basic_value&&) noexcept; - - bool operator==(const basic_value& rhs) const; - bool operator!=(const basic_value& rhs) const { return !(*this == rhs); } - - const basic_value& operator[](size_t pos) const; - basic_value& operator[](size_t pos); - basic_value& operator[](const string_t& key); - basic_value& operator[](string_t&& key); - - basic_value operator|(const basic_object& rhs) const&; - basic_value operator|(basic_object&& rhs) const&; - basic_value operator|(const basic_object& rhs) &&; - basic_value operator|(basic_object&& rhs) &&; - - basic_value& operator|=(const basic_object& rhs); - basic_value& operator|=(basic_object&& rhs); - - basic_value operator+(const basic_array& rhs) const&; - basic_value operator+(basic_array&& rhs) const&; - basic_value operator+(const basic_array& rhs) &&; - basic_value operator+(basic_array&& rhs) &&; - - basic_value& operator+=(const basic_array& rhs); - basic_value& operator+=(basic_array&& 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(); } + __json_constexpr vector_t to_vector() const; + template typename another_map_t = std::map> + __json_constexpr another_map_t to_map() const; + + __json_constexpr basic_value& operator=(const basic_value& rhs); + __json_constexpr basic_value& operator=(basic_value&&) noexcept; + + __json_constexpr bool operator==(const basic_value& rhs) const; + __json_constexpr bool operator!=(const basic_value& rhs) const { return !(*this == rhs); } + + __json_constexpr const basic_value& operator[](size_t pos) const; + __json_constexpr basic_value& operator[](size_t pos); + __json_constexpr basic_value& operator[](const string_t& key); + __json_constexpr basic_value& operator[](string_t&& key); + + __json_constexpr basic_value operator|(const basic_object& rhs) const&; + __json_constexpr basic_value operator|(basic_object&& rhs) const&; + __json_constexpr basic_value operator|(const basic_object& rhs) &&; + __json_constexpr basic_value operator|(basic_object&& rhs) &&; + + __json_constexpr basic_value& operator|=(const basic_object& rhs); + __json_constexpr basic_value& operator|=(basic_object&& rhs); + + __json_constexpr basic_value operator+(const basic_array& rhs) const&; + __json_constexpr basic_value operator+(basic_array&& rhs) const&; + __json_constexpr basic_value operator+(const basic_array& rhs) &&; + __json_constexpr basic_value operator+(basic_array&& rhs) &&; + + __json_constexpr basic_value& operator+=(const basic_array& rhs); + __json_constexpr basic_value& operator+=(basic_array&& rhs); + + __json_constexpr explicit operator bool() const { return as_boolean(); } + __json_constexpr explicit operator int() const { return as_integer(); } + __json_constexpr explicit operator unsigned() const { return as_unsigned(); } + __json_constexpr explicit operator long() const { return as_long(); } + __json_constexpr explicit operator unsigned long() const { return as_unsigned_long(); } + __json_constexpr explicit operator long long() const { return as_long_long(); } + __json_constexpr explicit operator unsigned long long() const { return as_unsigned_long_long(); } + __json_constexpr explicit operator float() const { return as_float(); } + __json_constexpr explicit operator double() const { return as_double(); } + __json_constexpr explicit operator long double() const { return as_long_double(); } + __json_constexpr explicit operator string_t() const { return as_string(); } private: - friend class basic_array; - friend class basic_object; + friend class basic_array; + friend class basic_object; - string_t format(size_t indent, size_t indent_times) const; + __json_constexpr string_t format(size_t indent, size_t indent_times) const; - static var_t deep_copy(const var_t& src); + __json_constexpr static var_t deep_copy(const var_t& src); template - auto get(std::tuple keys_then_default_value, - std::index_sequence) const; + __json_constexpr auto get(std::tuple keys_then_default_value, + std::index_sequence) const; template - auto get_helper(const value_t& default_value, first_key_t&& first, rest_keys_t&&... rest) const; + __json_constexpr auto get_helper(const value_t& default_value, first_key_t&& first, rest_keys_t&&... rest) const; template - auto get_helper(const value_t& default_value, unique_key_t&& first) const; + __json_constexpr 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(); + __json_constexpr const string_t& as_basic_type_str() const; + __json_constexpr string_t& as_basic_type_str(); value_type _type = value_type::null; var_t _raw_data; @@ -268,14 +322,14 @@ class basic_value // * basic_array declare * // ********************************* -template +template class basic_array { - friend class basic_value; - friend class basic_object; + friend class basic_value; + friend class basic_object; public: - using raw_array = std::vector>; + 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; @@ -284,99 +338,102 @@ class basic_array 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); + __json_constexpr basic_array() = default; + __json_constexpr basic_array(const basic_array& rhs) = default; + __json_constexpr basic_array(basic_array&& rhs) noexcept = default; + __json_constexpr basic_array(std::initializer_list init_list); + __json_constexpr basic_array(typename raw_array::size_type size); - explicit basic_array(const basic_value& val); - explicit basic_array(basic_value&& val); + __json_constexpr explicit basic_array(const basic_value& val); + __json_constexpr explicit basic_array(basic_value&& val); template >>> - basic_array(collection_t arr) + __json_constexpr basic_array(collection_t arr) : _array_data(std::make_move_iterator(arr.begin()), std::make_move_iterator(arr.end())) {} - ~basic_array() noexcept = default; + __json_constexpr ~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; + __json_constexpr bool empty() const noexcept { return _array_data.empty(); } + __json_constexpr size_t size() const noexcept { return _array_data.size(); } + __json_constexpr bool contains(size_t pos) const { return pos < _array_data.size(); } + __json_constexpr bool exists(size_t pos) const { return contains(pos); } + __json_constexpr 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() const { return format(4, 0); } + __json_constexpr string_t dumps(std::optional indent = std::nullopt) const + { + return indent ? format(*indent) : to_string(); + } + __json_constexpr string_t to_string() const; + __json_constexpr string_t format() const { return format(4, 0); } template && !std::is_same_v>> - string_t format(sz_t indent) const + __json_constexpr string_t format(sz_t indent) const { return format(indent, 0); } template - bool all() const; + __json_constexpr bool all() const; template typename vector_t = std::vector> - vector_t to_vector() const; + __json_constexpr vector_t to_vector() const; // Usage: get(key_1, key_2, ..., default_value); template - auto get(key_then_default_value_t&&... keys_then_default_value) const; + __json_constexpr auto get(key_then_default_value_t&&... keys_then_default_value) const; - template > - std::optional find(size_t pos) const; + template > + __json_constexpr std::optional find(size_t pos) const; template - decltype(auto) emplace_back(args_t&&... args); + __json_constexpr decltype(auto) emplace_back(args_t&&... args); template - decltype(auto) push_back(args_t&&... args); + __json_constexpr decltype(auto) push_back(args_t&&... args); - void clear() noexcept; - bool erase(size_t pos); - bool erase(iterator iter); + __json_constexpr void clear() noexcept; + __json_constexpr bool erase(size_t pos); + __json_constexpr 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; + __json_constexpr iterator begin() noexcept; + __json_constexpr iterator end() noexcept; + __json_constexpr const_iterator begin() const noexcept; + __json_constexpr const_iterator end() const noexcept; + __json_constexpr const_iterator cbegin() const noexcept; + __json_constexpr 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; + __json_constexpr reverse_iterator rbegin() noexcept; + __json_constexpr reverse_iterator rend() noexcept; + __json_constexpr const_reverse_iterator rbegin() const noexcept; + __json_constexpr const_reverse_iterator rend() const noexcept; + __json_constexpr const_reverse_iterator crbegin() const noexcept; + __json_constexpr const_reverse_iterator crend() const noexcept; - const basic_value& operator[](size_t pos) const; - basic_value& operator[](size_t pos); + __json_constexpr const basic_value& operator[](size_t pos) const; + __json_constexpr 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) &&; + __json_constexpr basic_array operator+(const basic_array& rhs) const&; + __json_constexpr basic_array operator+(basic_array&& rhs) const&; + __json_constexpr basic_array operator+(const basic_array& rhs) &&; + __json_constexpr basic_array operator+(basic_array&& rhs) &&; - basic_array& operator+=(const basic_array& rhs); - basic_array& operator+=(basic_array&& rhs); + __json_constexpr basic_array& operator+=(const basic_array& rhs); + __json_constexpr basic_array& operator+=(basic_array&& rhs); - basic_array& operator=(const basic_array&) = default; - basic_array& operator=(basic_array&&) noexcept = default; + __json_constexpr basic_array& operator=(const basic_array&) = default; + __json_constexpr basic_array& operator=(basic_array&&) noexcept = default; - bool operator==(const basic_array& rhs) const; - bool operator!=(const basic_array& rhs) const { return !(*this == rhs); } + __json_constexpr bool operator==(const basic_array& rhs) const; + __json_constexpr bool operator!=(const basic_array& rhs) const { return !(*this == rhs); } private: template - auto get(std::tuple keys_then_default_value, - std::index_sequence) const; + __json_constexpr 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; + __json_constexpr 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; + __json_constexpr auto get_helper(const value_t& default_value, size_t pos) const; - string_t format(size_t indent, size_t indent_times) const; + __json_constexpr string_t format(size_t indent, size_t indent_times) const; private: raw_array _array_data; @@ -386,14 +443,14 @@ class basic_array // * basic_object declare * // ********************************** -template +template class basic_object { - friend class basic_value; - friend class basic_array; + friend class basic_value; + friend class basic_array; public: - using raw_object = std::map>; + using raw_object = typename traits_t::template map_t>; using key_type = typename raw_object::key_type; using mapped_type = typename raw_object::mapped_type; using value_type = typename raw_object::value_type; @@ -402,88 +459,92 @@ class basic_object using char_t = typename string_t::value_type; public: - basic_object() = default; - basic_object(const basic_object& rhs) = default; - basic_object(basic_object&& rhs) noexcept = default; - basic_object(std::initializer_list init_list); - explicit basic_object(const basic_value& val); - explicit basic_object(basic_value&& val); - template >>> - basic_object(map_t map) : _object_data(std::make_move_iterator(map.begin()), std::make_move_iterator(map.end())) + __json_constexpr basic_object() = default; + __json_constexpr basic_object(const basic_object& rhs) = default; + __json_constexpr basic_object(basic_object&& rhs) noexcept = default; + __json_constexpr basic_object(std::initializer_list init_list); + __json_constexpr explicit basic_object(const basic_value& val); + __json_constexpr explicit basic_object(basic_value&& val); + template >>> + __json_constexpr basic_object(another_map_t map) + : _object_data(std::make_move_iterator(map.begin()), std::make_move_iterator(map.end())) {} - ~basic_object() = default; + __json_constexpr ~basic_object() = default; - bool empty() const noexcept { return _object_data.empty(); } - size_t size() const noexcept { return _object_data.size(); } - bool contains(const string_t& key) const; - bool exists(const string_t& key) const { return contains(key); } - const basic_value& at(const string_t& key) const; + __json_constexpr bool empty() const noexcept { return _object_data.empty(); } + __json_constexpr size_t size() const noexcept { return _object_data.size(); } + __json_constexpr bool contains(const string_t& key) const; + __json_constexpr bool exists(const string_t& key) const { return contains(key); } + __json_constexpr const basic_value& at(const string_t& key) const; - string_t dumps(std::optional indent = std::nullopt) const { return indent ? format(*indent) : to_string(); } - string_t to_string() const; - string_t format() const { return format(4, 0); } + __json_constexpr string_t dumps(std::optional indent = std::nullopt) const + { + return indent ? format(*indent) : to_string(); + } + __json_constexpr string_t to_string() const; + __json_constexpr string_t format() const { return format(4, 0); } template && !std::is_same_v>> - string_t format(sz_t indent) const + __json_constexpr string_t format(sz_t indent) const { return format(indent, 0); } template - bool all() const; - template typename map_t = std::map> - map_t to_map() const; + __json_constexpr bool all() const; + template typename another_map_t = default_map_t> + __json_constexpr another_map_t to_map() const; // Usage: get(key_1, key_2, ..., default_value); template - auto get(key_then_default_value_t&&... keys_then_default_value) const; + __json_constexpr auto get(key_then_default_value_t&&... keys_then_default_value) const; - template > - std::optional find(const string_t& key) const; + template > + __json_constexpr std::optional find(const string_t& key) const; template - decltype(auto) emplace(args_t&&... args); + __json_constexpr decltype(auto) emplace(args_t&&... args); template - decltype(auto) insert(args_t&&... args); + __json_constexpr decltype(auto) insert(args_t&&... args); - void clear() noexcept; - bool erase(const string_t& key); - bool erase(iterator iter); + __json_constexpr void clear() noexcept; + __json_constexpr bool erase(const string_t& key); + __json_constexpr 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; + __json_constexpr iterator begin() noexcept; + __json_constexpr iterator end() noexcept; + __json_constexpr const_iterator begin() const noexcept; + __json_constexpr const_iterator end() const noexcept; + __json_constexpr const_iterator cbegin() const noexcept; + __json_constexpr const_iterator cend() const noexcept; - basic_value& operator[](const string_t& key); - basic_value& operator[](string_t&& key); + __json_constexpr basic_value& operator[](const string_t& key); + __json_constexpr basic_value& operator[](string_t&& key); - basic_object operator|(const basic_object& rhs) const&; - basic_object operator|(basic_object&& rhs) const&; - basic_object operator|(const basic_object& rhs) &&; - basic_object operator|(basic_object&& rhs) &&; + __json_constexpr basic_object operator|(const basic_object& rhs) const&; + __json_constexpr basic_object operator|(basic_object&& rhs) const&; + __json_constexpr basic_object operator|(const basic_object& rhs) &&; + __json_constexpr basic_object operator|(basic_object&& rhs) &&; - basic_object& operator|=(const basic_object& rhs); - basic_object& operator|=(basic_object&& rhs); + __json_constexpr basic_object& operator|=(const basic_object& rhs); + __json_constexpr basic_object& operator|=(basic_object&& rhs); - basic_object& operator=(const basic_object&) = default; - basic_object& operator=(basic_object&&) = default; + __json_constexpr basic_object& operator=(const basic_object&) = default; + __json_constexpr basic_object& operator=(basic_object&&) = default; - bool operator==(const basic_object& rhs) const; - bool operator!=(const basic_object& rhs) const { return !(*this == rhs); } + __json_constexpr bool operator==(const basic_object& rhs) const; + __json_constexpr bool operator!=(const basic_object& rhs) const { return !(*this == rhs); } private: template - auto get(std::tuple keys_then_default_value, - std::index_sequence) const; + __json_constexpr auto get(std::tuple keys_then_default_value, + std::index_sequence) const; template - auto get_helper(const value_t& default_value, const string_t& key, rest_keys_t&&... rest) const; + __json_constexpr auto get_helper(const value_t& default_value, const string_t& key, rest_keys_t&&... rest) const; template - auto get_helper(const value_t& default_value, const string_t& key) const; + __json_constexpr auto get_helper(const value_t& default_value, const string_t& key) const; - string_t format(size_t indent, size_t indent_times) const; + __json_constexpr string_t format(size_t indent, size_t indent_times) const; private: raw_object _object_data; @@ -493,7 +554,7 @@ class basic_object // * parser declare * // **************************** -template class parser { @@ -501,30 +562,30 @@ class parser using parsing_iter_t = typename parsing_t::const_iterator; public: - ~parser() noexcept = default; + __json_constexpr ~parser() noexcept = default; - static std::optional> parse(const parsing_t& content); + __json_constexpr static std::optional> parse(const parsing_t& content); private: - parser(parsing_iter_t cbegin, parsing_iter_t cend) noexcept : _cur(cbegin), _end(cend) { ; } + __json_constexpr parser(parsing_iter_t cbegin, parsing_iter_t cend) noexcept : _cur(cbegin), _end(cend) { ; } - std::optional> parse(); - basic_value parse_value(); + __json_constexpr std::optional> parse(); + __json_constexpr basic_value parse_value(); - basic_value parse_null(); - basic_value parse_boolean(); - basic_value parse_number(); - // parse and return a basic_value whose type is value_type::string - basic_value parse_string(); - basic_value parse_array(); - basic_value parse_object(); + __json_constexpr basic_value parse_null(); + __json_constexpr basic_value parse_boolean(); + __json_constexpr basic_value parse_number(); + // parse and return a basic_value whose type is value_type::string + __json_constexpr basic_value parse_string(); + __json_constexpr basic_value parse_array(); + __json_constexpr basic_value parse_object(); // parse and return a string_t - std::optional parse_stdstring(); + __json_constexpr std::optional parse_stdstring(); - bool skip_string_literal_with_accel(); - bool skip_whitespace() noexcept; - bool skip_digit(); + __json_constexpr bool skip_string_literal_with_accel(); + __json_constexpr bool skip_whitespace() noexcept; + __json_constexpr bool skip_digit(); private: parsing_iter_t _cur; @@ -559,14 +620,19 @@ class exception : public std::exception // *************************** template -auto parse(const parsing_t& content); +__json_constexpr auto parse(const parsing_t& content); + +#ifdef __json_enable_constexpr +template +__json_constexpr auto cparse(const parsing_t& content); +#endif template -auto parse(char_t* content); +__json_constexpr auto parse(char_t* content); template , istream_t>>> -auto parse(istream_t& istream, bool check_bom); +__json_constexpr auto parse(istream_t& istream, bool check_bom); template auto open(const path_t& path, bool check_bom = false); @@ -584,10 +650,17 @@ namespace literals object operator""_jobject(const char* str, size_t len); wobject operator""_jobject(const wchar_t* str, size_t len); + +#ifdef __json_enable_constexpr + __json_constexpr cvalue operator""_cjson(const char* str, size_t len); + __json_constexpr cvalue operator""_cjvalue(const char* str, size_t len); + __json_constexpr carray operator""_cjarray(const char* str, size_t len); + __json_constexpr cobject operator""_cjobject(const char* str, size_t len); +#endif } -template -const basic_value invalid_value(); +template +__json_constexpr const basic_value invalid_value(); namespace _serialization_helper { @@ -595,8 +668,9 @@ namespace _serialization_helper struct string_converter; } template > -basic_value serialize(any_t&& arg, string_converter_t&& string_converter = {}); +__json_constexpr basic_value serialize(any_t&& arg, string_converter_t&& string_converter = {}); // ****************************** // * basic_value impl * @@ -621,8 +695,13 @@ static constexpr string_t null_string() } template -string_t to_basic_string(any_t&& arg) +__json_constexpr string_t to_basic_string(any_t&& arg) { +#ifdef __json_enable_constexpr + if (std::is_constant_evaluated()) { + return soft_impl::to_string(std::forward(arg)); + } +#endif if constexpr (std::is_same_v) { return std::to_string(std::forward(arg)); } @@ -637,99 +716,106 @@ string_t to_basic_string(any_t&& arg) template static constexpr string_t unescape_string(const string_t& str); -template -inline basic_value::basic_value() = default; +template +inline __json_constexpr basic_value::basic_value() = default; -template -inline basic_value::basic_value(const basic_value& rhs) +template +inline __json_constexpr basic_value::basic_value(const basic_value& rhs) : _type(rhs._type), _raw_data(deep_copy(rhs._raw_data)) {} -template -inline basic_value::basic_value(basic_value&& rhs) noexcept = default; +template +inline __json_constexpr basic_value::basic_value(basic_value&& rhs) noexcept = + default; -template -inline basic_value::basic_value(bool b) +template +inline __json_constexpr basic_value::basic_value(bool b) : _type(value_type::boolean), _raw_data(string_t(b ? true_string() : false_string())) {} -template -inline basic_value::basic_value(int num) +template +inline __json_constexpr basic_value::basic_value(int num) : _type(value_type::number), _raw_data(to_basic_string(num)) {} -template -inline basic_value::basic_value(unsigned num) +template +inline __json_constexpr basic_value::basic_value(unsigned num) : _type(value_type::number), _raw_data(to_basic_string(num)) {} -template -inline basic_value::basic_value(long num) +template +inline __json_constexpr basic_value::basic_value(long num) : _type(value_type::number), _raw_data(to_basic_string(num)) {} -template -inline basic_value::basic_value(unsigned long num) +template +inline __json_constexpr basic_value::basic_value(unsigned long num) : _type(value_type::number), _raw_data(to_basic_string(num)) {} -template -inline basic_value::basic_value(long long num) +template +inline __json_constexpr basic_value::basic_value(long long num) : _type(value_type::number), _raw_data(to_basic_string(num)) {} -template -inline basic_value::basic_value(unsigned long long num) +template +inline __json_constexpr basic_value::basic_value(unsigned long long num) : _type(value_type::number), _raw_data(to_basic_string(num)) {} -template -inline basic_value::basic_value(float num) +template +inline __json_constexpr basic_value::basic_value(float num) : _type(value_type::number), _raw_data(to_basic_string(num)) {} -template -inline basic_value::basic_value(double num) +template +inline __json_constexpr basic_value::basic_value(double num) : _type(value_type::number), _raw_data(to_basic_string(num)) {} -template -inline basic_value::basic_value(long double num) +template +inline __json_constexpr basic_value::basic_value(long double num) : _type(value_type::number), _raw_data(to_basic_string(num)) {} -template -inline basic_value::basic_value(const char_t* str) : _type(value_type::string), _raw_data(string_t(str)) +template +inline __json_constexpr basic_value::basic_value(const char_t* str) + : _type(value_type::string), _raw_data(string_t(str)) {} -template -inline basic_value::basic_value(string_t str) : _type(value_type::string), _raw_data(std::move(str)) +template +inline __json_constexpr basic_value::basic_value(string_t str) + : _type(value_type::string), _raw_data(std::move(str)) {} -template -inline basic_value::basic_value(basic_array arr) - : _type(value_type::array), _raw_data(std::make_unique>(std::move(arr))) +template +inline __json_constexpr basic_value::basic_value(basic_array arr) + : _type(value_type::array), _raw_data(typename traits_t::template unique_ptr_t>( + new basic_array(std::move(arr)))) {} -template -inline basic_value::basic_value(basic_object obj) - : _type(value_type::object), _raw_data(std::make_unique>(std::move(obj))) +template +inline __json_constexpr basic_value::basic_value(basic_object obj) + : _type(value_type::object), _raw_data(typename traits_t::template unique_ptr_t>( + new basic_object(std::move(obj)))) {} -template -inline basic_value::basic_value(std::initializer_list::value_type> init_list) - : _type(value_type::object), _raw_data(std::make_unique>(init_list)) +template +inline __json_constexpr basic_value::basic_value( + std::initializer_list::value_type> init_list) + : _type(value_type::object), _raw_data(typename traits_t::template unique_ptr_t>( + new basic_object(init_list))) {} // for Pimpl -template -inline basic_value::~basic_value() = default; +template +inline __json_constexpr basic_value::~basic_value() = default; -template +template template -inline bool basic_value::is() const noexcept +inline __json_constexpr bool basic_value::is() const noexcept { - if constexpr (std::is_same_v, value_t>) { + if constexpr (std::is_same_v, value_t>) { return true; } else if constexpr (std::is_same_v) { @@ -738,10 +824,10 @@ inline bool basic_value::is() const noexcept else if constexpr (std::is_arithmetic_v) { return _type == value_type::number; } - else if constexpr (std::is_same_v, value_t>) { + else if constexpr (std::is_same_v, value_t>) { return _type == value_type::array; } - else if constexpr (std::is_same_v, value_t>) { + else if constexpr (std::is_same_v, value_t>) { return _type == value_type::object; } else if constexpr (std::is_constructible_v) { @@ -752,64 +838,67 @@ inline bool basic_value::is() const noexcept } } -template -inline bool basic_value::contains(const string_t& key) const +template +inline __json_constexpr bool basic_value::contains(const string_t& key) const { return is_object() && as_object().contains(key); } -template -inline bool basic_value::contains(size_t pos) const +template +inline __json_constexpr bool basic_value::contains(size_t pos) const { return is_array() && as_array().contains(pos); } -template -inline const basic_value& basic_value::at(size_t pos) const +template +inline __json_constexpr const basic_value& basic_value::at(size_t pos) const { return as_array().at(pos); } -template -inline const basic_value& basic_value::at(const string_t& key) const +template +inline __json_constexpr const basic_value& basic_value::at( + const string_t& key) const { return as_object().at(key); } -template -inline bool basic_value::erase(size_t pos) +template +inline __json_constexpr bool basic_value::erase(size_t pos) { return as_array().erase(pos); } -template -inline bool basic_value::erase(const string_t& key) +template +inline __json_constexpr bool basic_value::erase(const string_t& key) { return as_object().erase(key); } -template +template template -inline auto basic_value::get(key_then_default_value_t&&... keys_then_default_value) const +inline __json_constexpr auto basic_value::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 template -inline auto basic_value::get(std::tuple keys_then_default_value, - std::index_sequence) const +inline __json_constexpr auto basic_value::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 template -inline auto basic_value::get_helper(const value_t& default_value, first_key_t&& first, - rest_keys_t&&... rest) const +inline __json_constexpr auto basic_value::get_helper(const value_t& default_value, + first_key_t&& first, + rest_keys_t&&... rest) const { if constexpr (std::is_constructible_v) { return is_object() ? as_object().get_helper(default_value, std::forward(first), @@ -826,9 +915,10 @@ inline auto basic_value::get_helper(const value_t& default_value, firs } } -template +template template -inline auto basic_value::get_helper(const value_t& default_value, unique_key_t&& first) const +inline __json_constexpr auto basic_value::get_helper(const value_t& default_value, + unique_key_t&& first) const { if constexpr (std::is_constructible_v) { return is_object() ? as_object().get_helper(default_value, std::forward(first)) : default_value; @@ -841,58 +931,60 @@ inline auto basic_value::get_helper(const value_t& default_value, uniq } } -template +template template -inline auto basic_array::get(key_then_default_value_t&&... keys_then_default_value) const +inline __json_constexpr 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 template -inline auto basic_array::get(std::tuple keys_then_default_value, - std::index_sequence) const +inline __json_constexpr 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 template -inline auto basic_object::get(key_then_default_value_t&&... keys_then_default_value) const +inline __json_constexpr auto basic_object::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 template -inline auto basic_object::get(std::tuple keys_then_default_value, - std::index_sequence) const +inline __json_constexpr auto basic_object::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 template -inline std::optional basic_value::find(size_t pos) const +inline __json_constexpr std::optional basic_value::find(size_t pos) const { return is_array() ? as_array().template find(pos) : std::nullopt; } -template +template template -inline std::optional basic_value::find(const string_t& key) const +inline __json_constexpr std::optional basic_value::find(const string_t& key) const { return is_object() ? as_object().template find(key) : std::nullopt; } -template -inline bool basic_value::as_boolean() const +template +inline __json_constexpr bool basic_value::as_boolean() const { if (is_boolean()) { if (const string_t& b_str = as_basic_type_str(); b_str == true_string()) { @@ -910,8 +1002,8 @@ inline bool basic_value::as_boolean() const } } -template -inline int basic_value::as_integer() const +template +inline __json_constexpr int basic_value::as_integer() const { if (is_number()) { return std::stoi(as_basic_type_str()); @@ -921,15 +1013,15 @@ inline int basic_value::as_integer() const } } -template -inline unsigned basic_value::as_unsigned() const +template +inline __json_constexpr unsigned basic_value::as_unsigned() const { // I don't know why there is no std::stou. return static_cast(as_unsigned_long()); } -template -inline long basic_value::as_long() const +template +inline __json_constexpr long basic_value::as_long() const { if (is_number()) { return std::stol(as_basic_type_str()); @@ -939,8 +1031,8 @@ inline long basic_value::as_long() const } } -template -inline unsigned long basic_value::as_unsigned_long() const +template +inline __json_constexpr unsigned long basic_value::as_unsigned_long() const { if (is_number()) { return std::stoul(as_basic_type_str()); @@ -950,8 +1042,8 @@ inline unsigned long basic_value::as_unsigned_long() const } } -template -inline long long basic_value::as_long_long() const +template +inline __json_constexpr long long basic_value::as_long_long() const { if (is_number()) { return std::stoll(as_basic_type_str()); @@ -961,8 +1053,8 @@ inline long long basic_value::as_long_long() const } } -template -inline unsigned long long basic_value::as_unsigned_long_long() const +template +inline __json_constexpr unsigned long long basic_value::as_unsigned_long_long() const { if (is_number()) { return std::stoull(as_basic_type_str()); @@ -972,8 +1064,8 @@ inline unsigned long long basic_value::as_unsigned_long_long() const } } -template -inline float basic_value::as_float() const +template +inline __json_constexpr float basic_value::as_float() const { if (is_number()) { return std::stof(as_basic_type_str()); @@ -983,8 +1075,8 @@ inline float basic_value::as_float() const } } -template -inline double basic_value::as_double() const +template +inline __json_constexpr double basic_value::as_double() const { if (is_number()) { return std::stod(as_basic_type_str()); @@ -994,8 +1086,8 @@ inline double basic_value::as_double() const } } -template -inline long double basic_value::as_long_double() const +template +inline __json_constexpr long double basic_value::as_long_double() const { if (is_number()) { return std::stold(as_basic_type_str()); @@ -1005,8 +1097,8 @@ inline long double basic_value::as_long_double() const } } -template -inline string_t basic_value::as_string() const +template +inline __json_constexpr string_t basic_value::as_string() const { if (is_string()) { return as_basic_type_str(); @@ -1016,8 +1108,8 @@ inline string_t basic_value::as_string() const } } -template -inline const basic_array& basic_value::as_array() const +template +inline __json_constexpr const basic_array& basic_value::as_array() const { if (is_array()) { return *std::get(_raw_data); @@ -1026,8 +1118,8 @@ inline const basic_array& basic_value::as_array() const throw exception("Wrong Type"); } -template -inline const basic_object& basic_value::as_object() const +template +inline __json_constexpr const basic_object& basic_value::as_object() const { if (is_object()) { return *std::get(_raw_data); @@ -1036,11 +1128,11 @@ inline const basic_object& basic_value::as_object() const throw exception("Wrong Type or data empty"); } -template -inline basic_array& basic_value::as_array() +template +inline __json_constexpr basic_array& basic_value::as_array() { if (empty()) { - *this = basic_array(); + *this = basic_array(); } if (is_array()) { @@ -1050,11 +1142,11 @@ inline basic_array& basic_value::as_array() throw exception("Wrong Type"); } -template -inline basic_object& basic_value::as_object() +template +inline __json_constexpr basic_object& basic_value::as_object() { if (empty()) { - *this = basic_object(); + *this = basic_object(); } if (is_object()) { @@ -1064,31 +1156,33 @@ inline basic_object& basic_value::as_object() throw exception("Wrong Type or data empty"); } -template +template template -inline value_t basic_value::as() const +inline __json_constexpr value_t basic_value::as() const { return static_cast(*this); } -template -inline const string_t& basic_value::as_basic_type_str() const +template +inline __json_constexpr const string_t& basic_value::as_basic_type_str() const { return std::get(_raw_data); } -template -inline string_t& basic_value::as_basic_type_str() +template +inline __json_constexpr string_t& basic_value::as_basic_type_str() { return std::get(_raw_data); } -template +template template -inline decltype(auto) basic_value::emplace(args_t&&... args) +inline __json_constexpr decltype(auto) basic_value::emplace(args_t&&... args) { - constexpr bool is_array_args = std::is_constructible_v::value_type, args_t...>; - constexpr bool is_object_args = std::is_constructible_v::value_type, args_t...>; + constexpr bool is_array_args = + std::is_constructible_v::value_type, args_t...>; + constexpr bool is_object_args = + std::is_constructible_v::value_type, args_t...>; static_assert(is_array_args || is_object_args, "Args can not constructure a array or object value"); @@ -1100,28 +1194,28 @@ inline decltype(auto) basic_value::emplace(args_t&&... args) } } -template +template template -inline decltype(auto) basic_value::array_emplace(args_t&&... args) +inline __json_constexpr decltype(auto) basic_value::array_emplace(args_t&&... args) { return emplace(std::forward(args)...); } -template +template template -inline decltype(auto) basic_value::object_emplace(args_t&&... args) +inline __json_constexpr decltype(auto) basic_value::object_emplace(args_t&&... args) { return emplace(std::forward(args)...); } -template -inline void basic_value::clear() noexcept +template +inline __json_constexpr void basic_value::clear() noexcept { - *this = basic_value(); + *this = basic_value(); } -template -inline string_t basic_value::to_string() const +template +inline __json_constexpr string_t basic_value::to_string() const { switch (_type) { case value_type::null: @@ -1140,8 +1234,8 @@ inline string_t basic_value::to_string() const } } -template -inline string_t basic_value::format(size_t indent, size_t indent_times) const +template +inline __json_constexpr string_t basic_value::format(size_t indent, size_t indent_times) const { switch (_type) { case value_type::null: @@ -1158,9 +1252,9 @@ inline string_t basic_value::format(size_t indent, size_t indent_times } } -template +template template -inline bool basic_value::all() const +inline __json_constexpr bool basic_value::all() const { if (is_array()) { return as_array().template all(); @@ -1173,22 +1267,23 @@ inline bool basic_value::all() const } } -template +template template typename vector_t> -inline vector_t basic_value::to_vector() const +inline __json_constexpr vector_t basic_value::to_vector() const { return as_array().template to_vector(); } -template -template typename map_t> -inline map_t basic_value::to_map() const +template +template typename another_map_t> +inline __json_constexpr another_map_t basic_value::to_map() const { - return as_object().template to_map(); + return as_object().template to_map(); } -template -inline basic_value& basic_value::operator=(const basic_value& rhs) +template +inline __json_constexpr basic_value& basic_value::operator=( + const basic_value& rhs) { _type = rhs._type; _raw_data = deep_copy(rhs._raw_data); @@ -1196,11 +1291,13 @@ inline basic_value& basic_value::operator=(const basic_value return *this; } -template -inline basic_value& basic_value::operator=(basic_value&& rhs) noexcept = default; +template +inline __json_constexpr basic_value& basic_value::operator=( + basic_value&& rhs) noexcept = default; -template -inline bool basic_value::operator==(const basic_value& rhs) const +template +inline __json_constexpr bool basic_value::operator==( + const basic_value& rhs) const { if (_type != rhs._type) return false; @@ -1220,138 +1317,155 @@ inline bool basic_value::operator==(const basic_value& rhs) } } -template -inline const basic_value& basic_value::operator[](size_t pos) const +template +inline __json_constexpr const basic_value& basic_value::operator[]( + size_t pos) const { // basic_array not support to create by operator[] return as_array()[pos]; } -template -inline basic_value& basic_value::operator[](size_t pos) +template +inline __json_constexpr basic_value& basic_value::operator[](size_t pos) { // basic_array not support to create by operator[] return as_array()[pos]; } -template -inline basic_value& basic_value::operator[](const string_t& key) +template +inline __json_constexpr basic_value& basic_value::operator[]( + const string_t& key) { if (empty()) { - *this = basic_object(); + *this = basic_object(); } return as_object()[key]; } -template -inline basic_value& basic_value::operator[](string_t&& key) +template +inline __json_constexpr basic_value& basic_value::operator[](string_t&& key) { if (empty()) { - *this = basic_object(); + *this = basic_object(); } return as_object()[std::move(key)]; } -template -inline basic_value basic_value::operator|(const basic_object& rhs) const& +template +inline __json_constexpr basic_value basic_value::operator|( + const basic_object& rhs) const& { return as_object() | rhs; } -template -inline basic_value basic_value::operator|(basic_object&& rhs) const& +template +inline __json_constexpr basic_value basic_value::operator|( + basic_object&& rhs) const& { return as_object() | std::move(rhs); } -template -inline basic_value basic_value::operator|(const basic_object& rhs) && +template +inline __json_constexpr basic_value basic_value::operator|( + const basic_object& rhs) && { return std::move(as_object()) | rhs; } -template -inline basic_value basic_value::operator|(basic_object&& rhs) && +template +inline __json_constexpr basic_value basic_value::operator|( + basic_object&& rhs) && { return std::move(as_object()) | std::move(rhs); } -template -inline basic_value& basic_value::operator|=(const basic_object& rhs) +template +inline __json_constexpr basic_value& basic_value::operator|=( + const basic_object& rhs) { as_object() |= rhs; return *this; } -template -inline basic_value& basic_value::operator|=(basic_object&& rhs) +template +inline __json_constexpr basic_value& basic_value::operator|=( + basic_object&& rhs) { as_object() |= std::move(rhs); return *this; } -template -inline basic_value basic_value::operator+(const basic_array& rhs) const& +template +inline __json_constexpr basic_value basic_value::operator+( + const basic_array& rhs) const& { return as_array() + rhs; } -template -inline basic_value basic_value::operator+(basic_array&& rhs) const& +template +inline __json_constexpr basic_value basic_value::operator+( + basic_array&& rhs) const& { return as_array() + std::move(rhs); } -template -inline basic_value basic_value::operator+(const basic_array& rhs) && +template +inline __json_constexpr basic_value basic_value::operator+( + const basic_array& rhs) && { return std::move(as_array()) + rhs; } -template -inline basic_value basic_value::operator+(basic_array&& rhs) && +template +inline __json_constexpr basic_value basic_value::operator+( + basic_array&& rhs) && { return std::move(as_array()) + std::move(rhs); } -template -inline basic_value& basic_value::operator+=(const basic_array& rhs) +template +inline __json_constexpr basic_value& basic_value::operator+=( + const basic_array& rhs) { as_array() += rhs; return *this; } -template -inline basic_value& basic_value::operator+=(basic_array&& rhs) +template +inline __json_constexpr basic_value& basic_value::operator+=( + basic_array&& rhs) { as_array() += std::move(rhs); return *this; } -template +template template -inline basic_value::basic_value(value_type type, args_t&&... args) +inline __json_constexpr basic_value::basic_value(value_type type, args_t&&... args) : _type(type), _raw_data(std::forward(args)...) { static_assert(std::is_constructible_v, "Parameter can't be used to construct a var_t"); } -template -inline typename basic_value::var_t basic_value::deep_copy(const var_t& src) +template +inline __json_constexpr typename basic_value::var_t basic_value::deep_copy( + const var_t& src) { var_t dst; if (const auto string_ptr = std::get_if(&src)) { - dst = *string_ptr; + dst = string_t(*string_ptr); } else if (const auto arr_ptr = std::get_if(&src)) { - dst = std::make_unique>(**arr_ptr); + dst = typename traits_t::template unique_ptr_t>( + new basic_array(**arr_ptr)); } else if (const auto obj_ptr = std::get_if(&src)) { - dst = std::make_unique>(**obj_ptr); + dst = typename traits_t::template unique_ptr_t>( + new basic_object(**obj_ptr)); } else { // maybe invalid_value @@ -1364,65 +1478,68 @@ inline typename basic_value::var_t basic_value::deep_copy(co // * basic_array impl * // ****************************** -template -inline basic_array::basic_array(std::initializer_list init_list) : _array_data(init_list) +template +inline __json_constexpr 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 __json_constexpr 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 __json_constexpr 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 __json_constexpr basic_array::basic_array(basic_value&& val) + : basic_array(std::move(val.as_array())) {} -template -inline void basic_array::clear() noexcept +template +inline __json_constexpr void basic_array::clear() noexcept { _array_data.clear(); } -template -inline bool basic_array::erase(size_t pos) +template +inline __json_constexpr bool basic_array::erase(size_t pos) { return erase(_array_data.begin() + pos); } -template -inline bool basic_array::erase(iterator iter) +template +inline __json_constexpr bool basic_array::erase(iterator iter) { return _array_data.erase(iter) != _array_data.end(); } -template +template template -inline decltype(auto) basic_array::emplace_back(args_t&&... args) +inline __json_constexpr 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 template -inline decltype(auto) basic_array::push_back(args_t&&... args) +inline __json_constexpr 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 +template +inline __json_constexpr const basic_value& basic_array::at(size_t pos) const { return _array_data.at(pos); } -template -inline string_t basic_array::to_string() const +template +inline __json_constexpr string_t basic_array::to_string() const { string_t str { '[' }; for (auto iter = _array_data.cbegin(); iter != _array_data.cend();) { @@ -1435,8 +1552,8 @@ inline string_t basic_array::to_string() const return str; } -template -inline string_t basic_array::format(size_t indent, size_t indent_times) const +template +inline __json_constexpr 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), ' '); @@ -1453,9 +1570,9 @@ inline string_t basic_array::format(size_t indent, size_t indent_times return str; } -template +template template -inline bool basic_array::all() const +inline __json_constexpr bool basic_array::all() const { for (const auto& elem : _array_data) { if (!elem.template is()) { @@ -1481,9 +1598,9 @@ namespace _to_vector_helper }; } -template +template template typename vector_t> -inline vector_t basic_array::to_vector() const +inline __json_constexpr vector_t basic_array::to_vector() const { vector_t result; @@ -1500,13 +1617,14 @@ inline vector_t basic_array::to_vector() const return result; } -template +template template -inline auto basic_array::get_helper(const value_t& default_value, size_t pos, rest_keys_t&&... rest) const +inline __json_constexpr 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_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)) { @@ -1521,13 +1639,13 @@ inline auto basic_array::get_helper(const value_t& default_value, size return at(pos).get_helper(default_value, std::forward(rest)...); } -template +template template -inline auto basic_array::get_helper(const value_t& default_value, size_t pos) const +inline __json_constexpr 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_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)) { @@ -1558,11 +1676,11 @@ inline auto basic_array::get_helper(const value_t& default_value, size } } -template +template template -inline std::optional basic_array::find(size_t pos) const +inline __json_constexpr std::optional basic_array::find(size_t pos) const { - static_assert(std::is_constructible_v>, + static_assert(std::is_constructible_v>, "Type can NOT be constructed by basic_value"); if (!contains(pos)) { return std::nullopt; @@ -1571,137 +1689,157 @@ inline std::optional basic_array::find(size_t pos) const return val.template is() ? std::optional(val.template as()) : std::nullopt; } -template -inline typename basic_array::iterator basic_array::begin() noexcept +template +inline __json_constexpr typename basic_array::iterator basic_array::begin() noexcept { return _array_data.begin(); } -template -inline typename basic_array::iterator basic_array::end() noexcept +template +inline __json_constexpr typename basic_array::iterator basic_array::end() noexcept { return _array_data.end(); } -template -inline typename basic_array::const_iterator basic_array::begin() const noexcept +template +inline __json_constexpr typename basic_array::const_iterator basic_array< + string_t, traits_t>::begin() const noexcept { return _array_data.begin(); } -template -inline typename basic_array::const_iterator basic_array::end() const noexcept +template +inline __json_constexpr 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 +template +inline __json_constexpr typename basic_array::const_iterator basic_array< + string_t, traits_t>::cbegin() const noexcept { return _array_data.cbegin(); } -template -inline typename basic_array::const_iterator basic_array::cend() const noexcept +template +inline __json_constexpr 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 +template +inline __json_constexpr typename basic_array::reverse_iterator basic_array< + string_t, traits_t>::rbegin() noexcept { return _array_data.rbegin(); } -template -inline typename basic_array::reverse_iterator basic_array::rend() noexcept +template +inline __json_constexpr typename basic_array::reverse_iterator basic_array< + string_t, traits_t>::rend() noexcept { return _array_data.rend(); } -template -inline typename basic_array::const_reverse_iterator basic_array::rbegin() const noexcept +template +inline __json_constexpr typename basic_array::const_reverse_iterator basic_array< + string_t, traits_t>::rbegin() const noexcept { return _array_data.rbegin(); } -template -inline typename basic_array::const_reverse_iterator basic_array::rend() const noexcept +template +inline __json_constexpr typename basic_array::const_reverse_iterator basic_array< + string_t, traits_t>::rend() const noexcept { return _array_data.rend(); } -template -inline typename basic_array::const_reverse_iterator basic_array::crbegin() const noexcept +template +inline __json_constexpr typename basic_array::const_reverse_iterator basic_array< + string_t, traits_t>::crbegin() const noexcept { return _array_data.crbegin(); } -template -inline typename basic_array::const_reverse_iterator basic_array::crend() const noexcept +template +inline __json_constexpr typename basic_array::const_reverse_iterator basic_array< + string_t, traits_t>::crend() const noexcept { return _array_data.crend(); } -template -inline basic_value& basic_array::operator[](size_t pos) +template +inline __json_constexpr basic_value& basic_array::operator[](size_t pos) { return _array_data[pos]; } -template -inline const basic_value& basic_array::operator[](size_t pos) const +template +inline __json_constexpr 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& +template +inline __json_constexpr basic_array basic_array::operator+( + const basic_array& rhs) const& { - basic_array temp = *this; + 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& +template +inline __json_constexpr basic_array basic_array::operator+( + basic_array&& rhs) const& { - basic_array temp = *this; + 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) && +template +inline __json_constexpr 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) && +template +inline __json_constexpr 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) +template +inline __json_constexpr 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) +template +inline __json_constexpr 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 +template +inline __json_constexpr bool basic_array::operator==( + const basic_array& rhs) const { return _array_data == rhs._array_data; } @@ -1710,68 +1848,70 @@ inline bool basic_array::operator==(const basic_array& rhs) // * basic_object impl * // ******************************* -template -inline basic_object::basic_object(std::initializer_list init_list) +template +inline __json_constexpr basic_object::basic_object(std::initializer_list init_list) : _object_data(std::make_move_iterator(init_list.begin()), std::make_move_iterator(init_list.end())) {} -template -inline basic_object::basic_object(const basic_value& val) : basic_object(val.as_object()) +template +inline __json_constexpr basic_object::basic_object(const basic_value& val) + : basic_object(val.as_object()) {} -template -inline basic_object::basic_object(basic_value&& val) - : basic_object(std::move(val.as_object())) +template +inline __json_constexpr basic_object::basic_object(basic_value&& val) + : basic_object(std::move(val.as_object())) {} -template -inline bool basic_object::contains(const string_t& key) const +template +inline __json_constexpr bool basic_object::contains(const string_t& key) const { return _object_data.find(key) != _object_data.cend(); } -template -inline const basic_value& basic_object::at(const string_t& key) const +template +inline __json_constexpr const basic_value& basic_object::at( + const string_t& key) const { return _object_data.at(key); } -template -inline void basic_object::clear() noexcept +template +inline __json_constexpr void basic_object::clear() noexcept { _object_data.clear(); } -template -inline bool basic_object::erase(const string_t& key) +template +inline __json_constexpr bool basic_object::erase(const string_t& key) { return _object_data.erase(key) > 0 ? true : false; } -template -inline bool basic_object::erase(iterator iter) +template +inline __json_constexpr bool basic_object::erase(iterator iter) { return _object_data.erase(iter) != _object_data.end(); } -template +template template -inline decltype(auto) basic_object::emplace(args_t&&... args) +inline __json_constexpr decltype(auto) basic_object::emplace(args_t&&... args) { static_assert(std::is_constructible_v, "Parameter can't be used to construct a raw_object::value_type"); return _object_data.emplace(std::forward(args)...); } -template +template template -inline decltype(auto) basic_object::insert(args_t&&... args) +inline __json_constexpr decltype(auto) basic_object::insert(args_t&&... args) { return emplace(std::forward(args)...); } -template -inline string_t basic_object::to_string() const +template +inline __json_constexpr string_t basic_object::to_string() const { string_t str { '{' }; for (auto iter = _object_data.cbegin(); iter != _object_data.cend();) { @@ -1785,8 +1925,8 @@ inline string_t basic_object::to_string() const return str; } -template -inline string_t basic_object::format(size_t indent, size_t indent_times) const +template +inline __json_constexpr string_t basic_object::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), ' '); @@ -1805,9 +1945,9 @@ inline string_t basic_object::format(size_t indent, size_t indent_time return str; } -template +template template -inline bool basic_object::all() const +inline __json_constexpr bool basic_object::all() const { for (const auto& [_, val] : _object_data) { if (!val.template is()) { @@ -1817,25 +1957,26 @@ inline bool basic_object::all() const return true; } -template -template typename map_t> -inline map_t basic_object::to_map() const +template +template typename another_map_t> +inline __json_constexpr another_map_t basic_object::to_map() const { - map_t result; + another_map_t result; for (const auto& [key, val] : _object_data) { result.emplace(key, val.template as()); } return result; } -template +template template -inline auto basic_object::get_helper(const value_t& default_value, const string_t& key, - rest_keys_t&&... rest) const +inline __json_constexpr auto basic_object::get_helper(const value_t& default_value, + const string_t& key, + 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_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(key)) { @@ -1850,13 +1991,14 @@ inline auto basic_object::get_helper(const value_t& default_value, con return at(key).get_helper(default_value, std::forward(rest)...); } -template +template template -inline auto basic_object::get_helper(const value_t& default_value, const string_t& key) const +inline __json_constexpr auto basic_object::get_helper(const value_t& default_value, + const string_t& key) 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_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(key)) { @@ -1887,11 +2029,11 @@ inline auto basic_object::get_helper(const value_t& default_value, con } } -template +template template -inline std::optional basic_object::find(const string_t& key) const +inline __json_constexpr std::optional basic_object::find(const string_t& key) const { - static_assert(std::is_constructible_v>, + static_assert(std::is_constructible_v>, "value_t can NOT be constructed by basic_value"); auto iter = _object_data.find(key); if (iter == _object_data.end()) { @@ -1901,102 +2043,116 @@ inline std::optional basic_object::find(const string_t& key) return val.template is() ? std::optional(val.template as()) : std::nullopt; } -template -inline typename basic_object::iterator basic_object::begin() noexcept +template +inline __json_constexpr typename basic_object::iterator basic_object::begin() noexcept { return _object_data.begin(); } -template -inline typename basic_object::iterator basic_object::end() noexcept +template +inline __json_constexpr typename basic_object::iterator basic_object::end() noexcept { return _object_data.end(); } -template -inline typename basic_object::const_iterator basic_object::begin() const noexcept +template +inline __json_constexpr typename basic_object::const_iterator basic_object< + string_t, traits_t>::begin() const noexcept { return _object_data.begin(); } -template -inline typename basic_object::const_iterator basic_object::end() const noexcept +template +inline __json_constexpr typename basic_object::const_iterator basic_object< + string_t, traits_t>::end() const noexcept { return _object_data.end(); } -template -inline typename basic_object::const_iterator basic_object::cbegin() const noexcept +template +inline __json_constexpr typename basic_object::const_iterator basic_object< + string_t, traits_t>::cbegin() const noexcept { return _object_data.cbegin(); } -template -inline typename basic_object::const_iterator basic_object::cend() const noexcept +template +inline __json_constexpr typename basic_object::const_iterator basic_object< + string_t, traits_t>::cend() const noexcept { return _object_data.cend(); } -template -inline basic_value& basic_object::operator[](const string_t& key) +template +inline __json_constexpr basic_value& basic_object::operator[]( + const string_t& key) { return _object_data[key]; } -template -inline basic_value& basic_object::operator[](string_t&& key) +template +inline __json_constexpr basic_value& basic_object::operator[](string_t&& key) { return _object_data[std::move(key)]; } -template -inline basic_object basic_object::operator|(const basic_object& rhs) const& +template +inline __json_constexpr basic_object basic_object::operator|( + const basic_object& rhs) const& { - basic_object temp = *this; + basic_object temp = *this; temp._object_data.insert(rhs.begin(), rhs.end()); return temp; } -template -inline basic_object basic_object::operator|(basic_object&& rhs) const& +template +inline __json_constexpr basic_object basic_object::operator|( + basic_object&& rhs) const& { - basic_object temp = *this; + basic_object temp = *this; // temp._object_data.merge(std::move(rhs._object_data)); temp._object_data.insert(std::make_move_iterator(rhs.begin()), std::make_move_iterator(rhs.end())); return temp; } -template -inline basic_object basic_object::operator|(const basic_object& rhs) && +template +inline __json_constexpr basic_object basic_object::operator|( + const basic_object& rhs) && { _object_data.insert(rhs.begin(), rhs.end()); return std::move(*this); } -template -inline basic_object basic_object::operator|(basic_object&& rhs) && +template +inline __json_constexpr basic_object basic_object::operator|( + basic_object&& rhs) && { //_object_data.merge(std::move(rhs._object_data)); _object_data.insert(std::make_move_iterator(rhs.begin()), std::make_move_iterator(rhs.end())); return std::move(*this); } -template -inline basic_object& basic_object::operator|=(const basic_object& rhs) +template +inline __json_constexpr basic_object& basic_object::operator|=( + const basic_object& rhs) { _object_data.insert(rhs.begin(), rhs.end()); return *this; } -template -inline basic_object& basic_object::operator|=(basic_object&& rhs) +template +inline __json_constexpr basic_object& basic_object::operator|=( + basic_object&& rhs) { _object_data.insert(std::make_move_iterator(rhs.begin()), std::make_move_iterator(rhs.end())); return *this; } -template -inline bool basic_object::operator==(const basic_object& rhs) const +template +inline __json_constexpr bool basic_object::operator==( + const basic_object& rhs) const { return _object_data == rhs._object_data; } @@ -2005,20 +2161,22 @@ inline bool basic_object::operator==(const basic_object& rhs // * parser impl * // ************************* -template -inline std::optional> parser::parse(const parsing_t& content) +template +inline __json_constexpr std::optional> parser< + string_t, traits_t, parsing_t, accel_traits>::parse(const parsing_t& content) { - return parser(content.cbegin(), content.cend()).parse(); + return parser(content.cbegin(), content.cend()).parse(); } -template -inline std::optional> parser::parse() +template +inline __json_constexpr std::optional> parser::parse() { if (!skip_whitespace()) { return std::nullopt; } - basic_value result_value; + basic_value result_value; switch (*_cur) { case '[': result_value = parse_array(); @@ -2043,8 +2201,9 @@ inline std::optional> parser -inline basic_value parser::parse_value() +template +inline __json_constexpr basic_value parser::parse_value() { switch (*_cur) { case 'n': @@ -2071,27 +2230,29 @@ inline basic_value parser::parse_va case '{': return parse_object(); default: - return invalid_value(); + return invalid_value(); } } -template -inline basic_value parser::parse_null() +template +inline __json_constexpr basic_value parser::parse_null() { for (const auto& ch : null_string()) { if (_cur != _end && *_cur == ch) { ++_cur; } else { - return invalid_value(); + return invalid_value(); } } - return basic_value(); + return basic_value(); } -template -inline basic_value parser::parse_boolean() +template +inline __json_constexpr basic_value parser::parse_boolean() { switch (*_cur) { case 't': @@ -2100,7 +2261,7 @@ inline basic_value parser::parse_bo ++_cur; } else { - return invalid_value(); + return invalid_value(); } } return true; @@ -2110,17 +2271,18 @@ inline basic_value parser::parse_bo ++_cur; } else { - return invalid_value(); + return invalid_value(); } } return false; default: - return invalid_value(); + return invalid_value(); } } -template -inline basic_value parser::parse_number() +template +inline __json_constexpr basic_value parser::parse_number() { const auto first = _cur; if (*_cur == '-') { @@ -2129,74 +2291,77 @@ inline basic_value parser::parse_nu // numbers cannot have leading zeroes if (_cur != _end && *_cur == '0' && _cur + 1 != _end && std::isdigit(*(_cur + 1))) { - return invalid_value(); + return invalid_value(); } if (!skip_digit()) { - return invalid_value(); + return invalid_value(); } if (*_cur == '.') { ++_cur; if (!skip_digit()) { - return invalid_value(); + return invalid_value(); } } if (*_cur == 'e' || *_cur == 'E') { if (++_cur == _end) { - return invalid_value(); + return invalid_value(); } if (*_cur == '+' || *_cur == '-') { ++_cur; } if (!skip_digit()) { - return invalid_value(); + return invalid_value(); } } - return basic_value(basic_value::value_type::number, string_t(first, _cur)); + return basic_value(basic_value::value_type::number, string_t(first, _cur)); } -template -inline basic_value parser::parse_string() +template +inline __json_constexpr basic_value parser::parse_string() { auto string_opt = parse_stdstring(); if (!string_opt) { - return invalid_value(); + return invalid_value(); } - return basic_value(basic_value::value_type::string, std::move(string_opt).value()); + return basic_value(basic_value::value_type::string, + std::move(string_opt).value()); } -template -inline basic_value parser::parse_array() +template +inline __json_constexpr basic_value parser::parse_array() { if (*_cur == '[') { ++_cur; } else { - return invalid_value(); + return invalid_value(); } if (!skip_whitespace()) { - return invalid_value(); + return invalid_value(); } else if (*_cur == ']') { ++_cur; // empty basic_array - return basic_array(); + return basic_array(); } - typename basic_array::raw_array result; + typename basic_array::raw_array result; while (true) { if (!skip_whitespace()) { - return invalid_value(); + return invalid_value(); } - basic_value val = parse_value(); + basic_value val = parse_value(); if (!val.valid() || !skip_whitespace()) { - return invalid_value(); + return invalid_value(); } result.emplace_back(std::move(val)); @@ -2213,35 +2378,36 @@ inline basic_value parser::parse_ar ++_cur; } else { - return invalid_value(); + return invalid_value(); } - return basic_array(std::move(result)); + return basic_array(std::move(result)); } -template -inline basic_value parser::parse_object() +template +inline __json_constexpr basic_value parser::parse_object() { if (*_cur == '{') { ++_cur; } else { - return invalid_value(); + return invalid_value(); } if (!skip_whitespace()) { - return invalid_value(); + return invalid_value(); } else if (*_cur == '}') { ++_cur; // empty basic_object - return basic_object(); + return basic_object(); } - typename basic_object::raw_object result; + typename basic_object::raw_object result; while (true) { if (!skip_whitespace()) { - return invalid_value(); + return invalid_value(); } auto key_opt = parse_stdstring(); @@ -2250,17 +2416,17 @@ inline basic_value parser::parse_ob ++_cur; } else { - return invalid_value(); + return invalid_value(); } if (!skip_whitespace()) { - return invalid_value(); + return invalid_value(); } - basic_value val = parse_value(); + basic_value val = parse_value(); if (!val.valid() || !skip_whitespace()) { - return invalid_value(); + return invalid_value(); } result.emplace(std::move(*key_opt), std::move(val)); @@ -2277,14 +2443,14 @@ inline basic_value parser::parse_ob ++_cur; } else { - return invalid_value(); + return invalid_value(); } - return basic_object(std::move(result)); + return basic_object(std::move(result)); } -template -inline std::optional parser::parse_stdstring() +template +inline __json_constexpr std::optional parser::parse_stdstring() { if (*_cur == '"') { ++_cur; @@ -2359,8 +2525,8 @@ inline std::optional parser::parse_ return std::nullopt; } -template -inline bool parser::skip_string_literal_with_accel() +template +inline __json_constexpr bool parser::skip_string_literal_with_accel() { if constexpr (sizeof(*_cur) != 1) { return false; @@ -2385,8 +2551,8 @@ inline bool parser::skip_string_literal_with_ return _cur != _end; } -template -inline bool parser::skip_whitespace() noexcept +template +inline __json_constexpr bool parser::skip_whitespace() noexcept { while (_cur != _end) { switch (*_cur) { @@ -2405,18 +2571,29 @@ inline bool parser::skip_whitespace() noexcep return false; } -template -inline bool parser::skip_digit() +template +__json_constexpr bool dispatch_is_digit(elem_t ch) +{ +#ifdef __json_enable_constexpr + if (std::is_constant_evaluated()) { + return soft_impl::is_digit(ch); + } +#endif + return std::isdigit(ch); +} + +template +inline __json_constexpr bool parser::skip_digit() { // At least one digit - if (_cur != _end && std::isdigit(*_cur)) { + if (_cur != _end && dispatch_is_digit(*_cur)) { ++_cur; } else { return false; } - while (_cur != _end && std::isdigit(*_cur)) { + while (_cur != _end && dispatch_is_digit(*_cur)) { ++_cur; } @@ -2433,20 +2610,37 @@ inline bool parser::skip_digit() // ************************* template -auto parse(const parsing_t& content) +__json_constexpr auto parse(const parsing_t& content) +{ + using string_t = std::basic_string; + return parser::parse(content); +} + +#ifdef __json_enable_constexpr +template +__json_constexpr auto cparse(const parsing_t& content) { using string_t = std::basic_string; - return parser::parse(content); + return parser::parse(content); } +#endif template -auto parse(char_t* content) +__json_constexpr auto parse(char_t* content) { return parse(std::basic_string_view> { content }); } +#ifdef __json_enable_constexpr +template +__json_constexpr auto cparse(char_t* content) +{ + return cparse(std::basic_string_view> { content }); +} +#endif + template -auto parse(istream_t& ifs, bool check_bom) +__json_constexpr auto parse(istream_t& ifs, bool check_bom) { using string_t = std::basic_string; @@ -2460,9 +2654,9 @@ auto parse(istream_t& ifs, bool check_bom) if (check_bom) { using uchar = unsigned char; - static constexpr uchar Bom_0 = 0xEF; - static constexpr uchar Bom_1 = 0xBB; - static constexpr uchar Bom_2 = 0xBF; + constexpr uchar Bom_0 = 0xEF; + constexpr uchar Bom_1 = 0xBB; + constexpr uchar Bom_2 = 0xBF; if (str.size() >= 3 && static_cast(str.at(0)) == Bom_0 && static_cast(str.at(1)) == Bom_1 && static_cast(str.at(2)) == Bom_2) { @@ -2477,7 +2671,7 @@ auto open(const path_t& filepath, bool check_bom) { using char_t = typename ifstream_t::char_type; using string_t = std::basic_string; - using json_t = json::basic_value; + using json_t = json::basic_value; using return_t = std::optional; ifstream_t ifs(filepath, std::ios::in); @@ -2489,32 +2683,32 @@ auto open(const path_t& filepath, bool check_bom) return opt; } -template >, typename enable_t = typename std::enable_if_t || std::is_base_of_v>> -ostream_t& operator<<(ostream_t& out, const basic_value& val) +ostream_t& operator<<(ostream_t& out, const basic_value& val) { out << val.format(); return out; } -template >, typename enable_t = std::enable_if_t || std::is_base_of_v>> -ostream_t& operator<<(ostream_t& out, const basic_array& arr) +ostream_t& operator<<(ostream_t& out, const basic_array& arr) { out << arr.format(); return out; } -template >, typename enable_t = std::enable_if_t || std::is_base_of_v>> -ostream_t& operator<<(ostream_t& out, const basic_object& obj) +ostream_t& operator<<(ostream_t& out, const basic_object& obj) { out << obj.format(); return out; @@ -2561,12 +2755,37 @@ namespace literals auto val = parse(std::wstring_view(str, len)).value_or(wvalue()); return val.is_object() ? val.as_object() : wobject(); } + +#ifdef __json_enable_constexpr + inline __json_constexpr cvalue operator""_cjson(const char* str, size_t len) + { + return operator""_cjvalue(str, len); + } + + inline __json_constexpr cvalue operator""_cjvalue(const char* str, size_t len) + { + return cparse(std::string_view(str, len)).value_or(cvalue()); + } + + inline __json_constexpr carray operator""_cjarray(const char* str, size_t len) + { + auto val = cparse(std::string_view(str, len)).value_or(cvalue()); + return val.is_array() ? val.as_array() : carray(); + } + + inline __json_constexpr cobject operator""_cjobject(const char* str, size_t len) + { + auto val = cparse(std::string_view(str, len)).value_or(cvalue()); + return val.is_object() ? val.as_object() : cobject(); + } +#endif } // namespace literals -template -const basic_value invalid_value() +template +__json_constexpr const basic_value invalid_value() { - return basic_value(basic_value::value_type::invalid, typename basic_value::var_t()); + return basic_value(basic_value::value_type::invalid, + typename basic_value::var_t()); } namespace _serialization_helper @@ -2647,25 +2866,25 @@ namespace _serialization_helper } } // namespace _serialization_helper -template -basic_value serialize(any_t&& arg, string_converter_t&& string_converter) +template +__json_constexpr basic_value serialize(any_t&& arg, string_converter_t&& string_converter) { using namespace _serialization_helper; - if constexpr (std::is_constructible_v, any_t>) { - return basic_value(std::forward(arg)); + if constexpr (std::is_constructible_v, any_t>) { + return basic_value(std::forward(arg)); } - else if constexpr (std::is_constructible_v, any_t>) { - return basic_array(std::forward(arg)); + else if constexpr (std::is_constructible_v, any_t>) { + return basic_array(std::forward(arg)); } - else if constexpr (std::is_constructible_v, any_t>) { - return basic_object(std::forward(arg)); + else if constexpr (std::is_constructible_v, any_t>) { + return basic_object(std::forward(arg)); } else if constexpr (std::decay_t::template is_convertible) { return string_converter(std::forward(arg)); } else if constexpr (is_collection>) { - basic_value result; + basic_value result; for (auto&& val : arg) { using value_t = decltype(val); @@ -2675,7 +2894,7 @@ basic_value serialize(any_t&& arg, string_converter_t&& string_convert return result; } else if constexpr (is_map>) { - basic_value result; + basic_value result; for (auto&& [key, val] : arg) { using key_t = decltype(key); using value_t = decltype(val); diff --git a/test20/constexpr_test.cpp b/test20/constexpr_test.cpp new file mode 100644 index 0000000..b0be252 --- /dev/null +++ b/test20/constexpr_test.cpp @@ -0,0 +1,49 @@ +#include +#include + +#include "json.hpp" + +using namespace json::literals; + +// constexpr json::object wrap_obj(json::value v) +// { +// return json::object { { "kkk", v } }; +// } + +// constexpr json::value empty; +// constexpr json::object wempty = wrap_obj(empty); + +constexpr std::string test() +{ + auto empty = "{ \"abc\": 1 }"_cjobject; + constexpr auto obj2 = json::cparse("{ \"axxbc\": {} }").value().to_string().size(); + // json::cobject empty = { { "abc", 1 } }; + + empty["def"] = obj2; + empty["float"] = -1234.567890987654321; + empty["float2"] = 0.00012345678998765; + empty["float3"] = 123456789876543211234.; + empty.emplace("float", 1); + + return empty.to_string(); +} + +template +constexpr auto auto_get() +{ + constexpr size_t N = F().size(); + constexpr std::array arr = ([] { + std::array res; + std::string str = F(); + std::copy(str.begin(), str.end(), res.begin()); + res[N] = 0; + return res; + })(); + return arr; +} + +int main() +{ + constexpr auto data = auto_get(); + std::cout << data.data() << std::endl; +}