diff --git a/include/nlohmann/detail/conversions/from_json.hpp b/include/nlohmann/detail/conversions/from_json.hpp index c7a37ad65..2c31e6331 100644 --- a/include/nlohmann/detail/conversions/from_json.hpp +++ b/include/nlohmann/detail/conversions/from_json.hpp @@ -59,7 +59,7 @@ void from_json(const BasicJsonType& j, std::optional& opt) } template -void from_json(const BasicJsonType& j, nlohmann::optional& opt) +void from_json(const BasicJsonType& j, optional& opt) { if (j.is_null()) { diff --git a/include/nlohmann/detail/conversions/to_json.hpp b/include/nlohmann/detail/conversions/to_json.hpp index 3e66c8ac2..5da41f059 100644 --- a/include/nlohmann/detail/conversions/to_json.hpp +++ b/include/nlohmann/detail/conversions/to_json.hpp @@ -275,6 +275,13 @@ void to_json(BasicJsonType& j, const std::optional& opt) noexcept j = nullptr; } } + +template::value, int> = 0> +void to_json(BasicJsonType& j, const optional& opt) noexcept +{ + to_json(j, opt.base()); +} #endif template #include -namespace nlohmann -{ +NLOHMANN_JSON_NAMESPACE_BEGIN template -class optional : public std::optional +class optional { // *INDENT-OFF* using base_type = std::optional; + using value_type = T; template struct has_conversion_operator : std::false_type { }; @@ -67,17 +67,29 @@ class optional : public std::optional struct noexcept_fix_t {}; + base_type base_value; + public: - const base_type& base() const + base_type& base() & { - return *this; + return base_value; + } + + const base_type& base() const & + { + return base_value; + } + + base_type&& base() && + { + return std::move(base_value); } constexpr optional() noexcept(noexcept(std::optional())) = default; constexpr optional(std::nullopt_t /* unused */) noexcept - : base_type(std::nullopt) + : base_value(std::nullopt) { } @@ -86,7 +98,7 @@ class optional : public std::optional noexcept(noexcept( base_type(std::forward(value).operator optional()) )) : - base_type(std::forward(value).operator optional()) + base_value(std::forward(value).operator optional()) { } @@ -95,7 +107,7 @@ class optional : public std::optional noexcept(noexcept( base_type(std::forward(value)) )) : - base_type(std::forward(value)) + base_value(std::forward(value)) { } @@ -105,7 +117,7 @@ class optional : public std::optional noexcept(noexcept( base_type(std::forward(value)) )) : - base_type(std::forward(value)) + base_value(std::forward(value)) { } @@ -115,7 +127,7 @@ class optional : public std::optional noexcept(noexcept( base_type(std::in_place, std::forward(u), std::forward(args)...) )) : - base_type(std::in_place, std::forward(u), std::forward(args)...) + base_value(std::in_place, std::forward(u), std::forward(args)...) { } @@ -125,49 +137,190 @@ class optional : public std::optional noexcept(noexcept( base_type(std::in_place, u, std::forward(args)...) )) : - base_type(std::in_place, u, std::forward(args)...) + base_value(std::in_place, u, std::forward(args)...) { } + constexpr T& operator *() & noexcept { return *base_value; } + constexpr const T& operator *() const& noexcept { return *base_value; } + + constexpr T&& operator *() && noexcept { return static_cast(*base_value); } + constexpr const T&& operator *() const&& noexcept { return static_cast(*base_value); } + + constexpr T* operator ->() noexcept { return base_value.operator ->(); } + constexpr const T* operator ->() const noexcept { return base_value.operator ->(); } + + operator base_type& () & { return base_value; } + operator base_type&& () && { return std::move(base_value); } + // *INDENT-ON* }; -template -constexpr bool operator == (const optional& lhs, const optional& rhs) +namespace detail::opt { - return lhs.base() == rhs.base(); + +template const T& cmp_val(const T& v) +{ + return v; +} +template const std::optional& cmp_val(const optional& v) +{ + return v.base(); +} +template void cmp_val(const std::optional& v) = delete; + +} // namespace detail::opt + +#ifdef JSON_HAS_CPP_20 + +template +auto operator == (const optional& lhs, const U& rhs) -> +decltype(detail::opt::cmp_val(lhs) == detail::opt::cmp_val(rhs)) +{ + return detail::opt::cmp_val(lhs) == detail::opt::cmp_val(rhs); +} + +// *INDENT-OFF* + +template +auto operator <=> (const optional& lhs, const U& rhs) -> +decltype(detail::opt::cmp_val(lhs) <=> detail::opt::cmp_val(rhs)) +{ + return detail::opt::cmp_val(lhs) <=> detail::opt::cmp_val(rhs); +} + +// *INDENT-ON* + +#else // JSON_HAS_CPP_20 + +template +constexpr auto operator == (const optional& lhs, const optional& rhs) -> +decltype(detail::opt::cmp_val(lhs) == detail::opt::cmp_val(rhs)) +{ + return detail::opt::cmp_val(lhs) == detail::opt::cmp_val(rhs); +} + +template +constexpr auto operator == (const optional& lhs, const U& rhs) -> +decltype(detail::opt::cmp_val(lhs) == detail::opt::cmp_val(rhs)) +{ + return detail::opt::cmp_val(lhs) == detail::opt::cmp_val(rhs); +} + +template +constexpr auto operator == (const T& lhs, const optional& rhs) -> +decltype(detail::opt::cmp_val(lhs) == detail::opt::cmp_val(rhs)) +{ + return detail::opt::cmp_val(lhs) == detail::opt::cmp_val(rhs); } template -constexpr bool operator != (const optional& lhs, const optional& rhs) +constexpr auto operator != (const optional& lhs, const optional& rhs) -> +decltype(detail::opt::cmp_val(lhs) != detail::opt::cmp_val(rhs)) { - return lhs.base() != rhs.base(); + return detail::opt::cmp_val(lhs) != detail::opt::cmp_val(rhs); +} + +template +constexpr auto operator != (const optional& lhs, const U& rhs) -> +decltype(detail::opt::cmp_val(lhs) != detail::opt::cmp_val(rhs)) +{ + return detail::opt::cmp_val(lhs) != detail::opt::cmp_val(rhs); +} + +template +constexpr auto operator != (const T& lhs, const optional& rhs) -> +decltype(detail::opt::cmp_val(lhs) != detail::opt::cmp_val(rhs)) +{ + return detail::opt::cmp_val(lhs) != detail::opt::cmp_val(rhs); } template -constexpr bool operator < (const optional& lhs, const optional& rhs) +constexpr auto operator < (const optional& lhs, const optional& rhs) -> +decltype(detail::opt::cmp_val(lhs) < detail::opt::cmp_val(rhs)) { - return lhs.base() < rhs.base(); + return detail::opt::cmp_val(lhs) < detail::opt::cmp_val(rhs); +} + +template +constexpr auto operator < (const optional& lhs, const U& rhs) -> +decltype(detail::opt::cmp_val(lhs) < detail::opt::cmp_val(rhs)) +{ + return detail::opt::cmp_val(lhs) < detail::opt::cmp_val(rhs); +} + +template +constexpr auto operator < (const T& lhs, const optional& rhs) -> +decltype(detail::opt::cmp_val(lhs) < detail::opt::cmp_val(rhs)) +{ + return detail::opt::cmp_val(lhs) < detail::opt::cmp_val(rhs); } template -constexpr bool operator <= (const optional& lhs, const optional& rhs) +constexpr auto operator <= (const optional& lhs, const optional& rhs) -> +decltype(detail::opt::cmp_val(lhs) <= detail::opt::cmp_val(rhs)) { - return lhs.base() <= rhs.base(); + return detail::opt::cmp_val(lhs) <= detail::opt::cmp_val(rhs); +} + +template +constexpr auto operator <= (const optional& lhs, const U& rhs) -> +decltype(detail::opt::cmp_val(lhs) <= detail::opt::cmp_val(rhs)) +{ + return detail::opt::cmp_val(lhs) <= detail::opt::cmp_val(rhs); +} + +template +constexpr auto operator <= (const T& lhs, const optional& rhs) -> +decltype(detail::opt::cmp_val(lhs) <= detail::opt::cmp_val(rhs)) +{ + return detail::opt::cmp_val(lhs) <= detail::opt::cmp_val(rhs); } template -constexpr bool operator > (const optional& lhs, const optional& rhs) +constexpr auto operator > (const optional& lhs, const optional& rhs) -> +decltype(detail::opt::cmp_val(lhs) > detail::opt::cmp_val(rhs)) { - return lhs.base() > rhs.base(); + return detail::opt::cmp_val(lhs) > detail::opt::cmp_val(rhs); +} + +template +constexpr auto operator > (const optional& lhs, const U& rhs) -> +decltype(detail::opt::cmp_val(lhs) > detail::opt::cmp_val(rhs)) +{ + return detail::opt::cmp_val(lhs) > detail::opt::cmp_val(rhs); +} + +template +constexpr auto operator > (const T& lhs, const optional& rhs) -> +decltype(detail::opt::cmp_val(lhs) > detail::opt::cmp_val(rhs)) +{ + return detail::opt::cmp_val(lhs) > detail::opt::cmp_val(rhs); } template -constexpr bool operator >= (const optional& lhs, const optional& rhs) +constexpr auto operator >= (const optional& lhs, const optional& rhs) -> +decltype(detail::opt::cmp_val(lhs) >= detail::opt::cmp_val(rhs)) { - return lhs.base() >= rhs.base(); + return detail::opt::cmp_val(lhs) >= detail::opt::cmp_val(rhs); } -} // namespace nlohmann +template +constexpr auto operator >= (const optional& lhs, const U& rhs) -> +decltype(detail::opt::cmp_val(lhs) >= detail::opt::cmp_val(rhs)) +{ + return detail::opt::cmp_val(lhs) >= detail::opt::cmp_val(rhs); +} + +template +constexpr auto operator >= (const T& lhs, const optional& rhs) -> +decltype(detail::opt::cmp_val(lhs) >= detail::opt::cmp_val(rhs)) +{ + return detail::opt::cmp_val(lhs) >= detail::opt::cmp_val(rhs); +} + +#endif // JSON_HAS_CPP_20 + +NLOHMANN_JSON_NAMESPACE_END #endif // JSON_HAS_CPP_17 diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index dbd5e1a6f..85e718af9 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -4599,15 +4599,15 @@ NLOHMANN_JSON_NAMESPACE_END #include #include -namespace nlohmann -{ +NLOHMANN_JSON_NAMESPACE_BEGIN template -class optional : public std::optional +class optional { // *INDENT-OFF* using base_type = std::optional; + using value_type = T; template struct has_conversion_operator : std::false_type { }; @@ -4659,17 +4659,29 @@ class optional : public std::optional struct noexcept_fix_t {}; + base_type base_value; + public: - const base_type& base() const + base_type& base() & { - return *this; + return base_value; + } + + const base_type& base() const & + { + return base_value; + } + + base_type&& base() && + { + return std::move(base_value); } constexpr optional() noexcept(noexcept(std::optional())) = default; constexpr optional(std::nullopt_t /* unused */) noexcept - : base_type(std::nullopt) + : base_value(std::nullopt) { } @@ -4678,7 +4690,7 @@ class optional : public std::optional noexcept(noexcept( base_type(std::forward(value).operator optional()) )) : - base_type(std::forward(value).operator optional()) + base_value(std::forward(value).operator optional()) { } @@ -4687,7 +4699,7 @@ class optional : public std::optional noexcept(noexcept( base_type(std::forward(value)) )) : - base_type(std::forward(value)) + base_value(std::forward(value)) { } @@ -4697,7 +4709,7 @@ class optional : public std::optional noexcept(noexcept( base_type(std::forward(value)) )) : - base_type(std::forward(value)) + base_value(std::forward(value)) { } @@ -4707,7 +4719,7 @@ class optional : public std::optional noexcept(noexcept( base_type(std::in_place, std::forward(u), std::forward(args)...) )) : - base_type(std::in_place, std::forward(u), std::forward(args)...) + base_value(std::in_place, std::forward(u), std::forward(args)...) { } @@ -4717,50 +4729,191 @@ class optional : public std::optional noexcept(noexcept( base_type(std::in_place, u, std::forward(args)...) )) : - base_type(std::in_place, u, std::forward(args)...) + base_value(std::in_place, u, std::forward(args)...) { } + constexpr T& operator *() & noexcept { return *base_value; } + constexpr const T& operator *() const& noexcept { return *base_value; } + + constexpr T&& operator *() && noexcept { return static_cast(*base_value); } + constexpr const T&& operator *() const&& noexcept { return static_cast(*base_value); } + + constexpr T* operator ->() noexcept { return base_value.operator ->(); } + constexpr const T* operator ->() const noexcept { return base_value.operator ->(); } + + operator base_type& () & { return base_value; } + operator base_type&& () && { return std::move(base_value); } + // *INDENT-ON* }; -template -constexpr bool operator == (const optional& lhs, const optional& rhs) +namespace detail::opt { - return lhs.base() == rhs.base(); + +template const T& cmp_val(const T& v) +{ + return v; +} +template const std::optional& cmp_val(const optional& v) +{ + return v.base(); +} +template void cmp_val(const std::optional& v) = delete; + +} // namespace detail::opt + +#ifdef JSON_HAS_CPP_20 + +template +auto operator == (const optional& lhs, const U& rhs) -> +decltype(detail::opt::cmp_val(lhs) == detail::opt::cmp_val(rhs)) +{ + return detail::opt::cmp_val(lhs) == detail::opt::cmp_val(rhs); +} + +// *INDENT-OFF* + +template +auto operator <=> (const optional& lhs, const U& rhs) -> +decltype(detail::opt::cmp_val(lhs) <=> detail::opt::cmp_val(rhs)) +{ + return detail::opt::cmp_val(lhs) <=> detail::opt::cmp_val(rhs); +} + +// *INDENT-ON* + +#else // JSON_HAS_CPP_20 + +template +constexpr auto operator == (const optional& lhs, const optional& rhs) -> +decltype(detail::opt::cmp_val(lhs) == detail::opt::cmp_val(rhs)) +{ + return detail::opt::cmp_val(lhs) == detail::opt::cmp_val(rhs); +} + +template +constexpr auto operator == (const optional& lhs, const U& rhs) -> +decltype(detail::opt::cmp_val(lhs) == detail::opt::cmp_val(rhs)) +{ + return detail::opt::cmp_val(lhs) == detail::opt::cmp_val(rhs); +} + +template +constexpr auto operator == (const T& lhs, const optional& rhs) -> +decltype(detail::opt::cmp_val(lhs) == detail::opt::cmp_val(rhs)) +{ + return detail::opt::cmp_val(lhs) == detail::opt::cmp_val(rhs); } template -constexpr bool operator != (const optional& lhs, const optional& rhs) +constexpr auto operator != (const optional& lhs, const optional& rhs) -> +decltype(detail::opt::cmp_val(lhs) != detail::opt::cmp_val(rhs)) { - return lhs.base() != rhs.base(); + return detail::opt::cmp_val(lhs) != detail::opt::cmp_val(rhs); +} + +template +constexpr auto operator != (const optional& lhs, const U& rhs) -> +decltype(detail::opt::cmp_val(lhs) != detail::opt::cmp_val(rhs)) +{ + return detail::opt::cmp_val(lhs) != detail::opt::cmp_val(rhs); +} + +template +constexpr auto operator != (const T& lhs, const optional& rhs) -> +decltype(detail::opt::cmp_val(lhs) != detail::opt::cmp_val(rhs)) +{ + return detail::opt::cmp_val(lhs) != detail::opt::cmp_val(rhs); } template -constexpr bool operator < (const optional& lhs, const optional& rhs) +constexpr auto operator < (const optional& lhs, const optional& rhs) -> +decltype(detail::opt::cmp_val(lhs) < detail::opt::cmp_val(rhs)) { - return lhs.base() < rhs.base(); + return detail::opt::cmp_val(lhs) < detail::opt::cmp_val(rhs); +} + +template +constexpr auto operator < (const optional& lhs, const U& rhs) -> +decltype(detail::opt::cmp_val(lhs) < detail::opt::cmp_val(rhs)) +{ + return detail::opt::cmp_val(lhs) < detail::opt::cmp_val(rhs); +} + +template +constexpr auto operator < (const T& lhs, const optional& rhs) -> +decltype(detail::opt::cmp_val(lhs) < detail::opt::cmp_val(rhs)) +{ + return detail::opt::cmp_val(lhs) < detail::opt::cmp_val(rhs); } template -constexpr bool operator <= (const optional& lhs, const optional& rhs) +constexpr auto operator <= (const optional& lhs, const optional& rhs) -> +decltype(detail::opt::cmp_val(lhs) <= detail::opt::cmp_val(rhs)) { - return lhs.base() <= rhs.base(); + return detail::opt::cmp_val(lhs) <= detail::opt::cmp_val(rhs); +} + +template +constexpr auto operator <= (const optional& lhs, const U& rhs) -> +decltype(detail::opt::cmp_val(lhs) <= detail::opt::cmp_val(rhs)) +{ + return detail::opt::cmp_val(lhs) <= detail::opt::cmp_val(rhs); +} + +template +constexpr auto operator <= (const T& lhs, const optional& rhs) -> +decltype(detail::opt::cmp_val(lhs) <= detail::opt::cmp_val(rhs)) +{ + return detail::opt::cmp_val(lhs) <= detail::opt::cmp_val(rhs); } template -constexpr bool operator > (const optional& lhs, const optional& rhs) +constexpr auto operator > (const optional& lhs, const optional& rhs) -> +decltype(detail::opt::cmp_val(lhs) > detail::opt::cmp_val(rhs)) { - return lhs.base() > rhs.base(); + return detail::opt::cmp_val(lhs) > detail::opt::cmp_val(rhs); +} + +template +constexpr auto operator > (const optional& lhs, const U& rhs) -> +decltype(detail::opt::cmp_val(lhs) > detail::opt::cmp_val(rhs)) +{ + return detail::opt::cmp_val(lhs) > detail::opt::cmp_val(rhs); +} + +template +constexpr auto operator > (const T& lhs, const optional& rhs) -> +decltype(detail::opt::cmp_val(lhs) > detail::opt::cmp_val(rhs)) +{ + return detail::opt::cmp_val(lhs) > detail::opt::cmp_val(rhs); } template -constexpr bool operator >= (const optional& lhs, const optional& rhs) +constexpr auto operator >= (const optional& lhs, const optional& rhs) -> +decltype(detail::opt::cmp_val(lhs) >= detail::opt::cmp_val(rhs)) { - return lhs.base() >= rhs.base(); + return detail::opt::cmp_val(lhs) >= detail::opt::cmp_val(rhs); } -} // namespace nlohmann +template +constexpr auto operator >= (const optional& lhs, const U& rhs) -> +decltype(detail::opt::cmp_val(lhs) >= detail::opt::cmp_val(rhs)) +{ + return detail::opt::cmp_val(lhs) >= detail::opt::cmp_val(rhs); +} + +template +constexpr auto operator >= (const T& lhs, const optional& rhs) -> +decltype(detail::opt::cmp_val(lhs) >= detail::opt::cmp_val(rhs)) +{ + return detail::opt::cmp_val(lhs) >= detail::opt::cmp_val(rhs); +} + +#endif // JSON_HAS_CPP_20 + +NLOHMANN_JSON_NAMESPACE_END #endif // JSON_HAS_CPP_17 @@ -4794,7 +4947,7 @@ void from_json(const BasicJsonType& j, std::optional& opt) } template -void from_json(const BasicJsonType& j, nlohmann::optional& opt) +void from_json(const BasicJsonType& j, optional& opt) { if (j.is_null()) { @@ -5790,6 +5943,13 @@ void to_json(BasicJsonType& j, const std::optional& opt) noexcept j = nullptr; } } + +template::value, int> = 0> +void to_json(BasicJsonType& j, const optional& opt) noexcept +{ + to_json(j, opt.base()); +} #endif template