new uvalue safe api

This commit is contained in:
BlackMATov
2023-02-10 23:09:52 +07:00
parent 214920da44
commit deeaebd6a6
7 changed files with 299 additions and 8 deletions

View File

@@ -20,6 +20,7 @@
#include <map>
#include <memory>
#include <mutex>
#include <optional>
#include <set>
#include <span>
#include <string>
@@ -2857,6 +2858,15 @@ namespace meta_hpp
[[nodiscard]] auto try_get_as() const noexcept //
-> std::conditional_t<detail::pointer_kind<T>, T, const T*>;
template < typename T >
[[nodiscard]] std::optional<T> safe_get_as() &&;
template < typename T >
[[nodiscard]] std::optional<T> safe_get_as() &;
template < typename T >
[[nodiscard]] std::optional<T> safe_get_as() const&;
private:
struct vtable_t;
@@ -8647,4 +8657,55 @@ namespace meta_hpp
return nullptr;
}
template < typename T >
std::optional<T> uvalue::safe_get_as() && {
static_assert(std::is_same_v<T, std::decay_t<T>>);
if constexpr ( detail::pointer_kind<T> ) {
if ( T ptr = try_get_as<T>(); ptr || get_type().is_nullptr() ) {
return ptr;
}
} else {
if ( T* ptr = try_get_as<T>() ) {
return std::move(*ptr);
}
}
return std::nullopt;
}
template < typename T >
std::optional<T> uvalue::safe_get_as() & {
static_assert(std::is_same_v<T, std::decay_t<T>>);
if constexpr ( detail::pointer_kind<T> ) {
if ( T ptr = try_get_as<T>(); ptr || get_type().is_nullptr() ) {
return ptr;
}
} else {
if ( T* ptr = try_get_as<T>() ) {
return *ptr;
}
}
return std::nullopt;
}
template < typename T >
std::optional<T> uvalue::safe_get_as() const& {
static_assert(std::is_same_v<T, std::decay_t<T>>);
if constexpr ( detail::pointer_kind<T> ) {
if ( T ptr = try_get_as<T>(); ptr || get_type().is_nullptr() ) {
return ptr;
}
} else {
if ( const T* ptr = try_get_as<T>() ) {
return *ptr;
}
}
return std::nullopt;
}
}

View File

@@ -30,7 +30,7 @@ namespace
};
}
TEST_CASE("meta/meta_utilities/value4") {
TEST_CASE("meta/meta_utilities/value3") {
namespace meta = meta_hpp;
meta::class_<base0>();
@@ -50,7 +50,7 @@ TEST_CASE("meta/meta_utilities/value4") {
.base_<base2>();
}
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<decltype(std::declval<meta::uvalue&>().get_as<derived>()), 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<decltype(std::declval<meta::uvalue&>().try_get_as<derived>()), derived*>);

View File

@@ -46,14 +46,14 @@ namespace
};
}
TEST_CASE("meta/meta_utilities/value5") {
TEST_CASE("meta/meta_utilities/value4") {
namespace meta = meta_hpp;
meta::class_<clazz_throw_dtor>()
.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;

View File

@@ -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 <meta.hpp/meta_all.hpp>
#include <doctest/doctest.h>
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<ivec2>());
CHECK(v.safe_get_as<ivec2>() == ivec2{1,2});
CHECK_FALSE(v.safe_get_as<int>());
}
{
const meta::uvalue v{ivec2{1,2}};
REQUIRE(v.safe_get_as<ivec2>());
CHECK(v.safe_get_as<ivec2>() == ivec2{1,2});
CHECK_FALSE(v.safe_get_as<int>());
}
}
SUBCASE("&&/val") {
{
meta::uvalue v{ivec2{1,2}};
const ivec2 v2 = *std::move(v).safe_get_as<ivec2>();
CHECK(v2 == ivec2{1,2});
CHECK(v.get_as<ivec2>() == ivec2{0,0});
}
{
meta::uvalue v{ivec2{1,2}};
CHECK_FALSE(std::move(v).safe_get_as<int>());
CHECK(v.get_as<ivec2>() == ivec2{1,2});
}
}
SUBCASE("&/ptr") {
{
ivec2 v{1,2};
meta::uvalue v2{&v};
REQUIRE(v2.safe_get_as<ivec2*>());
REQUIRE(*v2.safe_get_as<ivec2*>());
CHECK(*v2.safe_get_as<ivec2*>() == &v);
REQUIRE(v2.safe_get_as<const ivec2*>());
REQUIRE(*v2.safe_get_as<const ivec2*>());
CHECK(*v2.safe_get_as<const ivec2*>() == &v);
CHECK_FALSE(v2.safe_get_as<ivec2>());
CHECK_FALSE(v2.safe_get_as<int*>());
CHECK_FALSE(v2.safe_get_as<const int*>());
}
{
ivec2 v{1,2};
const meta::uvalue v2{&v};
REQUIRE(v2.safe_get_as<ivec2*>());
REQUIRE(*v2.safe_get_as<ivec2*>());
CHECK(*v2.safe_get_as<ivec2*>() == &v);
REQUIRE(v2.safe_get_as<const ivec2*>());
REQUIRE(*v2.safe_get_as<const ivec2*>());
CHECK(*v2.safe_get_as<const ivec2*>() == &v);
CHECK_FALSE(v2.safe_get_as<ivec2>());
CHECK_FALSE(v2.safe_get_as<int*>());
CHECK_FALSE(v2.safe_get_as<const int*>());
}
}
SUBCASE("&/const_ptr") {
{
const ivec2 v{1,2};
meta::uvalue v2{&v};
CHECK_FALSE(v2.safe_get_as<ivec2*>());
REQUIRE(v2.safe_get_as<const ivec2*>());
REQUIRE(*v2.safe_get_as<const ivec2*>());
CHECK(*v2.safe_get_as<const ivec2*>() == &v);
CHECK_FALSE(v2.safe_get_as<ivec2>());
CHECK_FALSE(v2.safe_get_as<int*>());
CHECK_FALSE(v2.safe_get_as<const int*>());
}
{
const ivec2 v{1,2};
const meta::uvalue v2{&v};
CHECK_FALSE(v2.safe_get_as<ivec2*>());
REQUIRE(v2.safe_get_as<const ivec2*>());
REQUIRE(*v2.safe_get_as<const ivec2*>());
CHECK(*v2.safe_get_as<const ivec2*>() == &v);
CHECK_FALSE(v2.safe_get_as<ivec2>());
CHECK_FALSE(v2.safe_get_as<int*>());
CHECK_FALSE(v2.safe_get_as<const int*>());
}
}
SUBCASE("&&/ptr") {
{
ivec2 v{1,2};
meta::uvalue v2{&v};
REQUIRE(std::move(v2).safe_get_as<ivec2*>());
CHECK(*std::move(v2).safe_get_as<ivec2*>() == &v);
}
{
ivec2 v{1,2};
const meta::uvalue v2{&v};
REQUIRE(std::move(v2).safe_get_as<ivec2*>());
CHECK(*std::move(v2).safe_get_as<ivec2*>() == &v);
}
}
SUBCASE("&&/const ptr") {
{
const ivec2 v{1,2};
meta::uvalue v2{&v};
CHECK_FALSE(std::move(v2).safe_get_as<ivec2*>());
REQUIRE(std::move(v2).safe_get_as<const ivec2*>());
CHECK(*std::move(v2).safe_get_as<const ivec2*>() == &v);
}
{
const ivec2 v{1,2};
const meta::uvalue v2{&v};
CHECK_FALSE(std::move(v2).safe_get_as<ivec2*>());
REQUIRE(std::move(v2).safe_get_as<const ivec2*>());
CHECK(*std::move(v2).safe_get_as<const ivec2*>() == &v);
}
}
}

View File

@@ -31,6 +31,7 @@
#include <map>
#include <memory>
#include <mutex>
#include <optional>
#include <set>
#include <span>
#include <string>

View File

@@ -110,6 +110,15 @@ namespace meta_hpp
[[nodiscard]] auto try_get_as() const noexcept //
-> std::conditional_t<detail::pointer_kind<T>, T, const T*>;
template < typename T >
[[nodiscard]] std::optional<T> safe_get_as() &&;
template < typename T >
[[nodiscard]] std::optional<T> safe_get_as() &;
template < typename T >
[[nodiscard]] std::optional<T> safe_get_as() const&;
private:
struct vtable_t;

View File

@@ -619,4 +619,55 @@ namespace meta_hpp
return nullptr;
}
template < typename T >
std::optional<T> uvalue::safe_get_as() && {
static_assert(std::is_same_v<T, std::decay_t<T>>);
if constexpr ( detail::pointer_kind<T> ) {
if ( T ptr = try_get_as<T>(); ptr || get_type().is_nullptr() ) {
return ptr;
}
} else {
if ( T* ptr = try_get_as<T>() ) {
return std::move(*ptr);
}
}
return std::nullopt;
}
template < typename T >
std::optional<T> uvalue::safe_get_as() & {
static_assert(std::is_same_v<T, std::decay_t<T>>);
if constexpr ( detail::pointer_kind<T> ) {
if ( T ptr = try_get_as<T>(); ptr || get_type().is_nullptr() ) {
return ptr;
}
} else {
if ( T* ptr = try_get_as<T>() ) {
return *ptr;
}
}
return std::nullopt;
}
template < typename T >
std::optional<T> uvalue::safe_get_as() const& {
static_assert(std::is_same_v<T, std::decay_t<T>>);
if constexpr ( detail::pointer_kind<T> ) {
if ( T ptr = try_get_as<T>(); ptr || get_type().is_nullptr() ) {
return ptr;
}
} else {
if ( const T* ptr = try_get_as<T>() ) {
return *ptr;
}
}
return std::nullopt;
}
}