diff --git a/develop/singles/headers/meta.hpp/meta_all.hpp b/develop/singles/headers/meta.hpp/meta_all.hpp index ed40887..41a4a14 100644 --- a/develop/singles/headers/meta.hpp/meta_all.hpp +++ b/develop/singles/headers/meta.hpp/meta_all.hpp @@ -2542,6 +2542,9 @@ namespace meta_hpp [[nodiscard]] uvalue operator[](std::size_t index) const; [[nodiscard]] bool has_index_op() const noexcept; + [[nodiscard]] uvalue unmap() const; + [[nodiscard]] bool has_unmap_op() const noexcept; + template < typename T > [[nodiscard]] T get_as() &&; @@ -8239,6 +8242,41 @@ namespace meta_hpp::detail }; } +namespace meta_hpp::detail +{ + template < typename T > + struct unmap_traits; + + template < typename T > + concept has_unmap_traits = requires(const T& v) { + { unmap_traits{}(v) } -> std::convertible_to; + }; +} + +namespace meta_hpp::detail +{ + template < typename T > + struct unmap_traits> { + uvalue operator()(const std::shared_ptr& v) const { + return uvalue{v.get()}; + } + }; + + template < typename T, typename D > + struct unmap_traits> { + uvalue operator()(const std::unique_ptr& v) const { + return uvalue{v.get()}; + } + }; + + template < typename T > + struct unmap_traits> { + uvalue operator()(const std::reference_wrapper& v) const { + return uvalue{std::addressof(v.get())}; + } + }; +} + namespace meta_hpp { struct uvalue::vtable_t final { @@ -8253,6 +8291,7 @@ namespace meta_hpp uvalue (*const deref)(const storage_u& from); uvalue (*const index)(const storage_u& from, std::size_t); + uvalue (*const unmap)(const storage_u& from); template < typename T > static T* buffer_cast(buffer_t& buffer) noexcept { @@ -8404,7 +8443,6 @@ namespace meta_hpp self.vtable_ = nullptr; }, - .deref = [](){ if constexpr ( detail::has_deref_traits ) { return +[](const storage_u& from) -> uvalue { @@ -8424,6 +8462,16 @@ namespace meta_hpp return nullptr; } }(), + + .unmap = [](){ + if constexpr ( detail::has_unmap_traits ) { + return +[](const storage_u& from) -> uvalue { + return detail::unmap_traits{}(*storage_cast(from)); + }; + } else { + return nullptr; + } + }(), }; return &table; @@ -8562,6 +8610,14 @@ namespace meta_hpp return vtable_ != nullptr && vtable_->index != nullptr; } + inline uvalue uvalue::unmap() const { + return has_unmap_op() ? vtable_->unmap(storage_) : uvalue{}; + } + + inline bool uvalue::has_unmap_op() const noexcept { + return vtable_ != nullptr && vtable_->unmap != nullptr; + } + template < typename T > T uvalue::get_as() && { static_assert(std::is_same_v>); diff --git a/develop/untests/meta_utilities/value_tests.cpp b/develop/untests/meta_utilities/value_tests.cpp index c8bab4d..7991c8f 100644 --- a/develop/untests/meta_utilities/value_tests.cpp +++ b/develop/untests/meta_utilities/value_tests.cpp @@ -382,6 +382,50 @@ TEST_CASE("meta/meta_utilities/value") { CHECK(val2.get_as() == ivec2{1,2}); } + SUBCASE("unmap") { + { + const meta::uvalue u{42}; + CHECK_FALSE(u.has_unmap_op()); + CHECK_FALSE(u.unmap()); + } + { + int i{42}; + const meta::uvalue u{std::ref(i)}; + CHECK(u.has_unmap_op()); + + const meta::uvalue v{u.unmap()}; + CHECK(v.get_type() == meta::resolve_type()); + CHECK(v.get_as() == &i); + } + { + const int i{42}; + const meta::uvalue u{std::ref(i)}; + CHECK(u.has_unmap_op()); + + const meta::uvalue v{u.unmap()}; + CHECK(v.get_type() == meta::resolve_type()); + CHECK(v.get_as() == &i); + } + { + const auto i = std::make_shared(3, 4); + const meta::uvalue u{i}; + CHECK(u.has_unmap_op()); + + const meta::uvalue v{u.unmap()}; + CHECK(v.get_type() == meta::resolve_type()); + CHECK(v.get_as() == i.get()); + } + { + const auto i = std::make_shared(3, 4); + const meta::uvalue u{i}; + CHECK(u.has_unmap_op()); + + const meta::uvalue v{u.unmap()}; + CHECK(v.get_type() == meta::resolve_type()); + CHECK(v.get_as() == i.get()); + } + } + SUBCASE("deref") { { int i{42}; @@ -389,8 +433,7 @@ TEST_CASE("meta/meta_utilities/value") { CHECK(u.has_deref_op()); const meta::uvalue v{*u}; - CHECK(v.get_type() == meta::resolve_type()); - CHECK(v.get_data() != &i); + CHECK(v.get_as() == i); } { const char i{42}; @@ -398,8 +441,7 @@ TEST_CASE("meta/meta_utilities/value") { CHECK(u.has_deref_op()); const meta::uvalue v{*u}; - CHECK(v.get_type() == meta::resolve_type()); - CHECK(v.get_data() != &i); + CHECK(v.get_as() == i); } { const int i{42}; @@ -408,7 +450,6 @@ TEST_CASE("meta/meta_utilities/value") { CHECK(u.has_deref_op()); const meta::uvalue v{*u}; - CHECK(v.get_type() == meta::resolve_type() ); CHECK(v.get_as() == pi); } { diff --git a/headers/meta.hpp/meta_detail/value_traits/unmap_traits.hpp b/headers/meta.hpp/meta_detail/value_traits/unmap_traits.hpp new file mode 100644 index 0000000..71f649f --- /dev/null +++ b/headers/meta.hpp/meta_detail/value_traits/unmap_traits.hpp @@ -0,0 +1,45 @@ +/******************************************************************************* + * 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) + ******************************************************************************/ + +#pragma once + +#include "../../meta_base.hpp" +#include "../../meta_uvalue.hpp" + +namespace meta_hpp::detail +{ + template < typename T > + struct unmap_traits; + + template < typename T > + concept has_unmap_traits = requires(const T& v) { + { unmap_traits{}(v) } -> std::convertible_to; + }; +} + +namespace meta_hpp::detail +{ + template < typename T > + struct unmap_traits> { + uvalue operator()(const std::shared_ptr& v) const { + return uvalue{v.get()}; + } + }; + + template < typename T, typename D > + struct unmap_traits> { + uvalue operator()(const std::unique_ptr& v) const { + return uvalue{v.get()}; + } + }; + + template < typename T > + struct unmap_traits> { + uvalue operator()(const std::reference_wrapper& v) const { + return uvalue{std::addressof(v.get())}; + } + }; +} diff --git a/headers/meta.hpp/meta_uvalue.hpp b/headers/meta.hpp/meta_uvalue.hpp index 83ff9ef..3b50121 100644 --- a/headers/meta.hpp/meta_uvalue.hpp +++ b/headers/meta.hpp/meta_uvalue.hpp @@ -88,6 +88,9 @@ namespace meta_hpp [[nodiscard]] uvalue operator[](std::size_t index) const; [[nodiscard]] bool has_index_op() const noexcept; + [[nodiscard]] uvalue unmap() const; + [[nodiscard]] bool has_unmap_op() const noexcept; + template < typename T > [[nodiscard]] T get_as() &&; diff --git a/headers/meta.hpp/meta_uvalue/uvalue.hpp b/headers/meta.hpp/meta_uvalue/uvalue.hpp index a499094..1765730 100644 --- a/headers/meta.hpp/meta_uvalue/uvalue.hpp +++ b/headers/meta.hpp/meta_uvalue/uvalue.hpp @@ -12,6 +12,7 @@ #include "../meta_detail/value_traits/deref_traits.hpp" #include "../meta_detail/value_traits/index_traits.hpp" +#include "../meta_detail/value_traits/unmap_traits.hpp" #include "../meta_detail/value_utilities/utraits.hpp" @@ -29,6 +30,7 @@ namespace meta_hpp uvalue (*const deref)(const storage_u& from); uvalue (*const index)(const storage_u& from, std::size_t); + uvalue (*const unmap)(const storage_u& from); template < typename T > static T* buffer_cast(buffer_t& buffer) noexcept { @@ -180,7 +182,6 @@ namespace meta_hpp self.vtable_ = nullptr; }, - .deref = [](){ if constexpr ( detail::has_deref_traits ) { return +[](const storage_u& from) -> uvalue { @@ -200,6 +201,16 @@ namespace meta_hpp return nullptr; } }(), + + .unmap = [](){ + if constexpr ( detail::has_unmap_traits ) { + return +[](const storage_u& from) -> uvalue { + return detail::unmap_traits{}(*storage_cast(from)); + }; + } else { + return nullptr; + } + }(), }; return &table; @@ -338,6 +349,14 @@ namespace meta_hpp return vtable_ != nullptr && vtable_->index != nullptr; } + inline uvalue uvalue::unmap() const { + return has_unmap_op() ? vtable_->unmap(storage_) : uvalue{}; + } + + inline bool uvalue::has_unmap_op() const noexcept { + return vtable_ != nullptr && vtable_->unmap != nullptr; + } + template < typename T > T uvalue::get_as() && { static_assert(std::is_same_v>);