From deeaebd6a6fdbe00f0a3a5aff77988ff1416d0d2 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Fri, 10 Feb 2023 23:09:52 +0700 Subject: [PATCH] new uvalue safe api --- develop/singles/headers/meta.hpp/meta_all.hpp | 61 +++++++ .../untests/meta_utilities/value3_tests.cpp | 8 +- .../untests/meta_utilities/value4_tests.cpp | 8 +- .../untests/meta_utilities/value5_tests.cpp | 169 ++++++++++++++++++ headers/meta.hpp/meta_base/base.hpp | 1 + headers/meta.hpp/meta_uvalue.hpp | 9 + headers/meta.hpp/meta_uvalue/uvalue.hpp | 51 ++++++ 7 files changed, 299 insertions(+), 8 deletions(-) create mode 100644 develop/untests/meta_utilities/value5_tests.cpp diff --git a/develop/singles/headers/meta.hpp/meta_all.hpp b/develop/singles/headers/meta.hpp/meta_all.hpp index 0832091..62232ff 100644 --- a/develop/singles/headers/meta.hpp/meta_all.hpp +++ b/develop/singles/headers/meta.hpp/meta_all.hpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -2857,6 +2858,15 @@ namespace meta_hpp [[nodiscard]] auto try_get_as() const noexcept // -> std::conditional_t, T, const T*>; + template < typename T > + [[nodiscard]] std::optional safe_get_as() &&; + + template < typename T > + [[nodiscard]] std::optional safe_get_as() &; + + template < typename T > + [[nodiscard]] std::optional safe_get_as() const&; + private: struct vtable_t; @@ -8647,4 +8657,55 @@ namespace meta_hpp return nullptr; } + + template < typename T > + std::optional uvalue::safe_get_as() && { + static_assert(std::is_same_v>); + + if constexpr ( detail::pointer_kind ) { + if ( T ptr = try_get_as(); ptr || get_type().is_nullptr() ) { + return ptr; + } + } else { + if ( T* ptr = try_get_as() ) { + return std::move(*ptr); + } + } + + return std::nullopt; + } + + template < typename T > + std::optional uvalue::safe_get_as() & { + static_assert(std::is_same_v>); + + if constexpr ( detail::pointer_kind ) { + if ( T ptr = try_get_as(); ptr || get_type().is_nullptr() ) { + return ptr; + } + } else { + if ( T* ptr = try_get_as() ) { + return *ptr; + } + } + + return std::nullopt; + } + + template < typename T > + std::optional uvalue::safe_get_as() const& { + static_assert(std::is_same_v>); + + if constexpr ( detail::pointer_kind ) { + if ( T ptr = try_get_as(); ptr || get_type().is_nullptr() ) { + return ptr; + } + } else { + if ( const T* ptr = try_get_as() ) { + return *ptr; + } + } + + return std::nullopt; + } } diff --git a/develop/untests/meta_utilities/value3_tests.cpp b/develop/untests/meta_utilities/value3_tests.cpp index d82010d..23ff0ba 100644 --- a/develop/untests/meta_utilities/value3_tests.cpp +++ b/develop/untests/meta_utilities/value3_tests.cpp @@ -30,7 +30,7 @@ namespace }; } -TEST_CASE("meta/meta_utilities/value4") { +TEST_CASE("meta/meta_utilities/value3") { namespace meta = meta_hpp; meta::class_(); @@ -50,7 +50,7 @@ TEST_CASE("meta/meta_utilities/value4") { .base_(); } -TEST_CASE("meta/meta_utilities/value4/get_type") { +TEST_CASE("meta/meta_utilities/value3/get_type") { namespace meta = meta_hpp; SUBCASE("from ref") { @@ -88,7 +88,7 @@ TEST_CASE("meta/meta_utilities/value4/get_type") { } } -TEST_CASE("meta/meta_utilities/value4/get_as") { +TEST_CASE("meta/meta_utilities/value3/get_as") { namespace meta = meta_hpp; static_assert(std::is_same_v().get_as()), derived&>); @@ -207,7 +207,7 @@ TEST_CASE("meta/meta_utilities/value4/get_as") { } } -TEST_CASE("meta/meta_utilities/value4/try_get_as") { +TEST_CASE("meta/meta_utilities/value3/try_get_as") { namespace meta = meta_hpp; static_assert(std::is_same_v().try_get_as()), derived*>); diff --git a/develop/untests/meta_utilities/value4_tests.cpp b/develop/untests/meta_utilities/value4_tests.cpp index f56c2e7..4e0f8b3 100644 --- a/develop/untests/meta_utilities/value4_tests.cpp +++ b/develop/untests/meta_utilities/value4_tests.cpp @@ -46,14 +46,14 @@ namespace }; } -TEST_CASE("meta/meta_utilities/value5") { +TEST_CASE("meta/meta_utilities/value4") { namespace meta = meta_hpp; meta::class_() .function_("make", &clazz_throw_dtor::make); } -TEST_CASE("meta/meta_utilities/value5/throw_dtor") { +TEST_CASE("meta/meta_utilities/value4/throw_dtor") { namespace meta = meta_hpp; SUBCASE("value") { @@ -97,7 +97,7 @@ TEST_CASE("meta/meta_utilities/value5/throw_dtor") { } } -TEST_CASE("meta/meta_utilities/value5/inplace") { +TEST_CASE("meta/meta_utilities/value4/inplace") { namespace meta = meta_hpp; clazz_throw_dtor::destructor_counter = 0; @@ -174,7 +174,7 @@ TEST_CASE("meta/meta_utilities/value5/inplace") { } } -TEST_CASE("meta/meta_utilities/value5/emplace") { +TEST_CASE("meta/meta_utilities/value4/emplace") { namespace meta = meta_hpp; clazz_throw_dtor::destructor_counter = 0; diff --git a/develop/untests/meta_utilities/value5_tests.cpp b/develop/untests/meta_utilities/value5_tests.cpp new file mode 100644 index 0000000..6cdd479 --- /dev/null +++ b/develop/untests/meta_utilities/value5_tests.cpp @@ -0,0 +1,169 @@ +/******************************************************************************* + * This file is part of the "https://github.com/blackmatov/meta.hpp" + * For conditions of distribution and use, see copyright notice in LICENSE.md + * Copyright (C) 2021-2023, by Matvey Cherevko (blackmatov@gmail.com) + ******************************************************************************/ + +#include +#include + +namespace +{ + struct ivec2 final { + int x{}; + int y{}; + + ivec2(int nx, int ny) + : x{nx}, y{ny} {} + + ivec2(ivec2&& other) noexcept + : x{other.x} + , y{other.y} { + other.x = 0; + other.y = 0; + } + + ivec2(const ivec2& other) + : x{other.x} + , y{other.y} {} + }; + + bool operator==(const ivec2& l, const ivec2& r) noexcept { + return l.x == r.x && l.y == r.y; + } +} + +TEST_CASE("meta/meta_utilities/value5/safe_get_as") { + namespace meta = meta_hpp; + + SUBCASE("&/val") { + { + meta::uvalue v{ivec2{1,2}}; + + REQUIRE(v.safe_get_as()); + CHECK(v.safe_get_as() == ivec2{1,2}); + + CHECK_FALSE(v.safe_get_as()); + } + { + const meta::uvalue v{ivec2{1,2}}; + + REQUIRE(v.safe_get_as()); + CHECK(v.safe_get_as() == ivec2{1,2}); + + CHECK_FALSE(v.safe_get_as()); + } + } + + SUBCASE("&&/val") { + { + meta::uvalue v{ivec2{1,2}}; + const ivec2 v2 = *std::move(v).safe_get_as(); + CHECK(v2 == ivec2{1,2}); + CHECK(v.get_as() == ivec2{0,0}); + } + { + meta::uvalue v{ivec2{1,2}}; + CHECK_FALSE(std::move(v).safe_get_as()); + CHECK(v.get_as() == ivec2{1,2}); + } + } + + SUBCASE("&/ptr") { + { + ivec2 v{1,2}; + meta::uvalue v2{&v}; + + REQUIRE(v2.safe_get_as()); + REQUIRE(*v2.safe_get_as()); + CHECK(*v2.safe_get_as() == &v); + + REQUIRE(v2.safe_get_as()); + REQUIRE(*v2.safe_get_as()); + CHECK(*v2.safe_get_as() == &v); + + CHECK_FALSE(v2.safe_get_as()); + CHECK_FALSE(v2.safe_get_as()); + CHECK_FALSE(v2.safe_get_as()); + } + { + ivec2 v{1,2}; + const meta::uvalue v2{&v}; + + REQUIRE(v2.safe_get_as()); + REQUIRE(*v2.safe_get_as()); + CHECK(*v2.safe_get_as() == &v); + + REQUIRE(v2.safe_get_as()); + REQUIRE(*v2.safe_get_as()); + CHECK(*v2.safe_get_as() == &v); + + CHECK_FALSE(v2.safe_get_as()); + CHECK_FALSE(v2.safe_get_as()); + CHECK_FALSE(v2.safe_get_as()); + } + } + + SUBCASE("&/const_ptr") { + { + const ivec2 v{1,2}; + meta::uvalue v2{&v}; + + CHECK_FALSE(v2.safe_get_as()); + + REQUIRE(v2.safe_get_as()); + REQUIRE(*v2.safe_get_as()); + CHECK(*v2.safe_get_as() == &v); + + CHECK_FALSE(v2.safe_get_as()); + CHECK_FALSE(v2.safe_get_as()); + CHECK_FALSE(v2.safe_get_as()); + } + { + const ivec2 v{1,2}; + const meta::uvalue v2{&v}; + + CHECK_FALSE(v2.safe_get_as()); + + REQUIRE(v2.safe_get_as()); + REQUIRE(*v2.safe_get_as()); + CHECK(*v2.safe_get_as() == &v); + + CHECK_FALSE(v2.safe_get_as()); + CHECK_FALSE(v2.safe_get_as()); + CHECK_FALSE(v2.safe_get_as()); + } + } + + SUBCASE("&&/ptr") { + { + ivec2 v{1,2}; + meta::uvalue v2{&v}; + REQUIRE(std::move(v2).safe_get_as()); + CHECK(*std::move(v2).safe_get_as() == &v); + } + { + ivec2 v{1,2}; + const meta::uvalue v2{&v}; + REQUIRE(std::move(v2).safe_get_as()); + CHECK(*std::move(v2).safe_get_as() == &v); + } + } + + SUBCASE("&&/const ptr") { + { + const ivec2 v{1,2}; + meta::uvalue v2{&v}; + CHECK_FALSE(std::move(v2).safe_get_as()); + REQUIRE(std::move(v2).safe_get_as()); + CHECK(*std::move(v2).safe_get_as() == &v); + } + { + const ivec2 v{1,2}; + const meta::uvalue v2{&v}; + CHECK_FALSE(std::move(v2).safe_get_as()); + REQUIRE(std::move(v2).safe_get_as()); + CHECK(*std::move(v2).safe_get_as() == &v); + } + } +} diff --git a/headers/meta.hpp/meta_base/base.hpp b/headers/meta.hpp/meta_base/base.hpp index 5ad07ce..887e59e 100644 --- a/headers/meta.hpp/meta_base/base.hpp +++ b/headers/meta.hpp/meta_base/base.hpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include diff --git a/headers/meta.hpp/meta_uvalue.hpp b/headers/meta.hpp/meta_uvalue.hpp index 52b627c..ddff0ad 100644 --- a/headers/meta.hpp/meta_uvalue.hpp +++ b/headers/meta.hpp/meta_uvalue.hpp @@ -110,6 +110,15 @@ namespace meta_hpp [[nodiscard]] auto try_get_as() const noexcept // -> std::conditional_t, T, const T*>; + template < typename T > + [[nodiscard]] std::optional safe_get_as() &&; + + template < typename T > + [[nodiscard]] std::optional safe_get_as() &; + + template < typename T > + [[nodiscard]] std::optional safe_get_as() const&; + private: struct vtable_t; diff --git a/headers/meta.hpp/meta_uvalue/uvalue.hpp b/headers/meta.hpp/meta_uvalue/uvalue.hpp index 762acf5..6a5b0db 100644 --- a/headers/meta.hpp/meta_uvalue/uvalue.hpp +++ b/headers/meta.hpp/meta_uvalue/uvalue.hpp @@ -619,4 +619,55 @@ namespace meta_hpp return nullptr; } + + template < typename T > + std::optional uvalue::safe_get_as() && { + static_assert(std::is_same_v>); + + if constexpr ( detail::pointer_kind ) { + if ( T ptr = try_get_as(); ptr || get_type().is_nullptr() ) { + return ptr; + } + } else { + if ( T* ptr = try_get_as() ) { + return std::move(*ptr); + } + } + + return std::nullopt; + } + + template < typename T > + std::optional uvalue::safe_get_as() & { + static_assert(std::is_same_v>); + + if constexpr ( detail::pointer_kind ) { + if ( T ptr = try_get_as(); ptr || get_type().is_nullptr() ) { + return ptr; + } + } else { + if ( T* ptr = try_get_as() ) { + return *ptr; + } + } + + return std::nullopt; + } + + template < typename T > + std::optional uvalue::safe_get_as() const& { + static_assert(std::is_same_v>); + + if constexpr ( detail::pointer_kind ) { + if ( T ptr = try_get_as(); ptr || get_type().is_nullptr() ) { + return ptr; + } + } else { + if ( const T* ptr = try_get_as() ) { + return *ptr; + } + } + + return std::nullopt; + } }