From fc69b71779721e9ba92fc8e46d461cf46b1a1ae8 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Mon, 24 Jan 2022 04:13:20 +0700 Subject: [PATCH] nullable value type --- headers/meta.hpp/meta_utilities.hpp | 7 ++- headers/meta.hpp/meta_utilities/value.hpp | 56 ++++++++++++++++++--- untests/meta_utilities/value_tests.cpp | 59 +++++++++++++++++++++++ 3 files changed, 113 insertions(+), 9 deletions(-) diff --git a/headers/meta.hpp/meta_utilities.hpp b/headers/meta.hpp/meta_utilities.hpp index 5e9701c..c4ec2bb 100644 --- a/headers/meta.hpp/meta_utilities.hpp +++ b/headers/meta.hpp/meta_utilities.hpp @@ -104,7 +104,7 @@ namespace meta_hpp { class value final { public: - value() = delete; + value() = default; value(value&& other) noexcept = default; value(const value& other) = default; @@ -122,9 +122,12 @@ namespace meta_hpp requires detail::stdex::copy_constructible> value& operator=(T&& val); + [[nodiscard]] bool is_valid() const noexcept; + [[nodiscard]] explicit operator bool() const noexcept; + void swap(value& other) noexcept; - [[nodiscard]] const any_type& get_type() const noexcept; + [[nodiscard]] any_type get_type() const noexcept; [[nodiscard]] void* data() noexcept; [[nodiscard]] const void* data() const noexcept; diff --git a/headers/meta.hpp/meta_utilities/value.hpp b/headers/meta.hpp/meta_utilities/value.hpp index 753ff6f..9364fb0 100644 --- a/headers/meta.hpp/meta_utilities/value.hpp +++ b/headers/meta.hpp/meta_utilities/value.hpp @@ -137,34 +137,44 @@ namespace meta_hpp return *this; } + inline bool value::is_valid() const noexcept { + return raw_.has_value(); + } + + inline value::operator bool() const noexcept { + return is_valid(); + } + inline void value::swap(value& other) noexcept { using std::swap; swap(raw_, other.raw_); swap(traits_, other.traits_); } - inline const any_type& value::get_type() const noexcept { - return traits_->type; + inline any_type value::get_type() const noexcept { + return traits_ != nullptr + ? traits_->type + : resolve_type(); } inline void* value::data() noexcept { - return traits_->data(*this); + return traits_ != nullptr ? traits_->data(*this) : nullptr; } inline const void* value::data() const noexcept { - return traits_->cdata(*this); + return traits_ != nullptr ? traits_->cdata(*this) : nullptr; } inline const void* value::cdata() const noexcept { - return traits_->cdata(*this); + return traits_ != nullptr ? traits_->cdata(*this) : nullptr; } inline value value::operator*() const { - return traits_->deref(*this); + return traits_ != nullptr ? traits_->deref(*this) : value{}; } inline value value::operator[](std::size_t index) const { - return traits_->index(*this, index); + return traits_ != nullptr ? traits_->index(*this, index) : value{}; } template < typename T > @@ -208,6 +218,10 @@ namespace meta_hpp { template < typename T > [[nodiscard]] bool operator<(const value& l, const T& r) { + if ( !static_cast(l) ) { + return true; + } + const any_type& r_type = resolve_type(); return (l.get_type() < r_type) || (l.get_type() == r_type && std::less<>{}(l.cast(), r)); @@ -215,12 +229,24 @@ namespace meta_hpp template < typename T > [[nodiscard]] bool operator<(const T& l, const value& r) { + if ( !static_cast(r) ) { + return false; + } + const any_type& l_type = resolve_type(); return (l_type < r.get_type()) || (l_type == r.get_type() && std::less<>{}(l, r.cast())); } [[nodiscard]] inline bool operator<(const value& l, const value& r) { + if ( !static_cast(r) ) { + return false; + } + + if ( !static_cast(l) ) { + return true; + } + return (l.get_type() < r.get_type()) || (l.get_type() == r.get_type() && l.traits_->less(l, r)); } @@ -230,17 +256,33 @@ namespace meta_hpp { template < typename T > [[nodiscard]] bool operator==(const value& l, const T& r) { + if ( !static_cast(l) ) { + return false; + } + return l.get_type() == resolve_type() && std::equal_to<>{}(l.cast(), r); } template < typename T > [[nodiscard]] bool operator==(const T& l, const value& r) { + if ( !static_cast(r) ) { + return false; + } + return resolve_type() == r.get_type() && std::equal_to<>{}(l, r.cast()); } [[nodiscard]] inline bool operator==(const value& l, const value& r) { + if ( static_cast(l) != static_cast(r) ) { + return false; + } + + if ( !static_cast(l) ) { + return true; + } + return l.get_type() == r.get_type() && l.traits_->equals(l, r); } diff --git a/untests/meta_utilities/value_tests.cpp b/untests/meta_utilities/value_tests.cpp index 38b2e44..4f97bd6 100644 --- a/untests/meta_utilities/value_tests.cpp +++ b/untests/meta_utilities/value_tests.cpp @@ -127,6 +127,65 @@ TEST_CASE("meta/meta_utilities/value") { const ivec2*>); } + SUBCASE("ivec2{}") { + { + meta::value val{}; + + CHECK(!val); + CHECK_FALSE(val); + + CHECK_FALSE(val.is_valid()); + CHECK(val.data() == nullptr); + CHECK(std::as_const(val).data() == nullptr); + CHECK(std::as_const(val).cdata() == nullptr); + + CHECK_FALSE(*val); + CHECK_FALSE(val[0]); + + CHECK(val.try_cast() == nullptr); + CHECK(std::as_const(val).try_cast() == nullptr); + + CHECK_THROWS(std::ignore = val.cast()); + CHECK_THROWS(std::ignore = std::as_const(val).cast()); + CHECK_THROWS(std::ignore = std::move(val).cast()); + CHECK_THROWS(std::ignore = std::move(std::as_const(val)).cast()); + } + + { + CHECK_FALSE(meta::value{1} < meta::value{}); + CHECK(meta::value{} < meta::value{1}); + CHECK_FALSE(meta::value{} < meta::value{}); + + CHECK_FALSE(1 < meta::value{}); + CHECK(meta::value{} < 1); + CHECK_FALSE(meta::value{} < meta::value{}); + } + + { + CHECK_FALSE(meta::value{1} == meta::value{}); + CHECK_FALSE(meta::value{} == meta::value{1}); + CHECK(meta::value{} == meta::value{}); + + CHECK_FALSE(1 == meta::value{}); + CHECK_FALSE(meta::value{} == 1); + CHECK(meta::value{} == meta::value{}); + } + + { + CHECK(meta::value{1} != meta::value{}); + CHECK(meta::value{} != meta::value{1}); + CHECK_FALSE(meta::value{} != meta::value{}); + + CHECK(1 != meta::value{}); + CHECK(meta::value{} != 1); + CHECK_FALSE(meta::value{} != meta::value{}); + } + + CHECK_FALSE(meta::value{} == 0); + CHECK_FALSE(meta::value{} == nullptr); + CHECK(meta::value{}.get_type() == meta::resolve_type()); + } + SUBCASE("ivec2&") { ivec2 v{1,2}; ivec2& vr = v;