diff --git a/develop/manuals/meta_manuals/metadata_manual.cpp b/develop/manuals/meta_manuals/metadata_manual.cpp index 0d2bfc4..b57fd7a 100644 --- a/develop/manuals/meta_manuals/metadata_manual.cpp +++ b/develop/manuals/meta_manuals/metadata_manual.cpp @@ -33,29 +33,31 @@ TEST_CASE("meta/meta_manuals/metadata") { // key: std::string // value: meta::uvalue - meta::class_({ - {"tooltip", "3D Vector"s} // for class type - }) + meta::class_(meta::metadata_() // for class type + ("tooltip", "3D Vector"s) + ) .member_("x", &ivec3::x, { - .metadata { {"tooltip", "X-Coordinate"s} } // for class members + .metadata = meta::metadata_() // for class members + ("tooltip", "X-Coordinate"s) }) .member_("y", &ivec3::y, { - .metadata { {"tooltip", "Y-Coordinate"s} } + .metadata = meta::metadata_() + ("tooltip", "Y-Coordinate"s) }) .member_("z", &ivec3::z, { - .metadata { {"tooltip", "Z-Coordinate"s} } + .metadata = meta::metadata_() + ("tooltip", "Z-Coordinate"s) }); const meta::scope math_scope = meta::local_scope_("math") .typedef_("ivec3") .function_("cross", &cross, { - .arguments {{ - .name = "first vector", - .metadata {} // even function arguments can have metadata - },{ - .name = "second vector" - }}, - .metadata { {"tooltip", "Cross product of vectors"s} } // for functions in a scope + .arguments = meta::arguments_() + ("first vector") + ("second vector", meta::metadata_() // even function arguments can have metadata + ("tooltip", "The second cross product argument"s)), + .metadata = meta::metadata_() // for functions in a scope + ("tooltip", "Cross product of vectors"s), }); // after binding, you can use it as you wish diff --git a/develop/manuals/meta_manuals/uvalue_manual.cpp b/develop/manuals/meta_manuals/uvalue_manual.cpp index e3fb7cd..6546c42 100644 --- a/develop/manuals/meta_manuals/uvalue_manual.cpp +++ b/develop/manuals/meta_manuals/uvalue_manual.cpp @@ -61,7 +61,7 @@ TEST_CASE("meta/meta_manuals/uvalue") { TEST_CASE("meta/meta_manuals/uvalue/usage") { namespace meta = meta_hpp; - // the 'uvalue' class allows to store any copyable value inside + // the 'uvalue' class allows to store any typed value inside // it's widely used as return value types and as containers for storing metadata meta::uvalue val{42}; diff --git a/develop/singles/headers/meta.hpp/meta_all.hpp b/develop/singles/headers/meta.hpp/meta_all.hpp index ae251cc..8bf02c2 100644 --- a/develop/singles/headers/meta.hpp/meta_all.hpp +++ b/develop/singles/headers/meta.hpp/meta_all.hpp @@ -1674,15 +1674,18 @@ namespace meta_hpp namespace meta_hpp { class uvalue final { + public: + static const uvalue empty_value; + public: uvalue() = default; ~uvalue() noexcept; uvalue(uvalue&& other) noexcept; - uvalue(const uvalue& other); + uvalue(const uvalue& other) = delete; uvalue& operator=(uvalue&& other) noexcept; - uvalue& operator=(const uvalue& other); + uvalue& operator=(const uvalue& other) = delete; template < // typename T, // @@ -1690,35 +1693,31 @@ namespace meta_hpp typename = std::enable_if_t< // !uvalue_family && // !detail::is_in_place_type_v && // - std::is_copy_constructible_v>> // + std::is_constructible_v>> // uvalue(T&& val); - template < // - typename T, // - typename Tp = std::decay_t, // - typename = std::enable_if_t< // - !uvalue_family && // - std::is_copy_constructible_v>> // + template < // + typename T, // + typename Tp = std::decay_t, // + typename = std::enable_if_t< // + !uvalue_family && // + std::is_constructible_v>> // uvalue& operator=(T&& val); template < typename T, typename... Args, typename Tp = std::decay_t > - requires std::is_copy_constructible_v // - && std::is_constructible_v // + requires std::is_constructible_v // explicit uvalue(std::in_place_type_t, Args&&... args); template < typename T, typename U, typename... Args, typename Tp = std::decay_t > - requires std::is_copy_constructible_v // - && std::is_constructible_v&, Args...> // + requires std::is_constructible_v&, Args...> // explicit uvalue(std::in_place_type_t, std::initializer_list ilist, Args&&... args); template < typename T, typename... Args, typename Tp = std::decay_t > - requires std::is_copy_constructible_v // - && std::is_constructible_v // + requires std::is_constructible_v // Tp& emplace(Args&&... args); template < typename T, typename U, typename... Args, typename Tp = std::decay_t > - requires std::is_copy_constructible_v // - && std::is_constructible_v&, Args...> // + requires std::is_constructible_v&, Args...> // Tp& emplace(std::initializer_list ilist, Args&&... args); [[nodiscard]] bool has_value() const noexcept; @@ -1739,6 +1738,9 @@ namespace meta_hpp [[nodiscard]] uvalue operator[](std::size_t index) const; [[nodiscard]] bool has_index_op() const noexcept; + [[nodiscard]] uvalue copy() const; + [[nodiscard]] bool has_copy_op() const noexcept; + [[nodiscard]] uvalue unmap() const; [[nodiscard]] bool has_unmap_op() const noexcept; @@ -2761,7 +2763,7 @@ namespace meta_hpp template < detail::enum_kind Enum > [[nodiscard]] std::string_view value_to_name(Enum value) const noexcept; - [[nodiscard]] uvalue name_to_value(std::string_view name) const noexcept; + [[nodiscard]] const uvalue& name_to_value(std::string_view name) const noexcept; }; class function_type final : public type_base { @@ -3307,10 +3309,10 @@ namespace meta_hpp ~uresult() = default; uresult(uresult&&) noexcept = default; - uresult(const uresult&) = default; + uresult(const uresult&) = delete; uresult& operator=(uresult&&) noexcept = default; - uresult& operator=(const uresult&) = default; + uresult& operator=(const uresult&) = delete; explicit(false) uresult(uerror error) noexcept; explicit(false) uresult(uvalue value) noexcept; @@ -3324,35 +3326,31 @@ namespace meta_hpp typename = std::enable_if_t< // !uvalue_family && // !detail::is_in_place_type_v && // - std::is_copy_constructible_v>> // + std::is_constructible_v>> // uresult(T&& val); - template < // - typename T, // - typename Tp = std::decay_t, // - typename = std::enable_if_t< // - !uvalue_family && // - std::is_copy_constructible_v>> // + template < // + typename T, // + typename Tp = std::decay_t, // + typename = std::enable_if_t< // + !uvalue_family && // + std::is_constructible_v>> // uresult& operator=(T&& val); template < typename T, typename... Args, typename Tp = std::decay_t > - requires std::is_copy_constructible_v // - && std::is_constructible_v // + requires std::is_constructible_v // explicit uresult(std::in_place_type_t, Args&&... args); template < typename T, typename U, typename... Args, typename Tp = std::decay_t > - requires std::is_copy_constructible_v // - && std::is_constructible_v&, Args...> // + requires std::is_constructible_v&, Args...> // explicit uresult(std::in_place_type_t, std::initializer_list ilist, Args&&... args); template < typename T, typename... Args, typename Tp = std::decay_t > - requires std::is_copy_constructible_v // - && std::is_constructible_v // + requires std::is_constructible_v // Tp& emplace(Args&&... args); template < typename T, typename U, typename... Args, typename Tp = std::decay_t > - requires std::is_copy_constructible_v // - && std::is_constructible_v&, Args...> // + requires std::is_constructible_v&, Args...> // Tp& emplace(std::initializer_list ilist, Args&&... args); [[nodiscard]] bool has_error() const noexcept; @@ -3475,9 +3473,12 @@ namespace meta_hpp struct as_shared_pointer_t final {}; + struct as_unique_pointer_t final {}; + inline constexpr as_object_t as_object{}; inline constexpr as_raw_pointer_t as_raw_pointer{}; inline constexpr as_shared_pointer_t as_shared_pointer{}; + inline constexpr as_unique_pointer_t as_unique_pointer{}; } namespace function_policy @@ -3533,34 +3534,35 @@ namespace meta_hpp } template < typename Policy > - concept constructor_policy_family // - = std::is_same_v // - || std::is_same_v // - || std::is_same_v; + concept constructor_policy_family // + = std::is_same_v // + || std::is_same_v // + || std::is_same_v // + || std::is_same_v; // template < typename Policy > - concept function_policy_family // - = std::is_same_v // - || std::is_same_v // - || std::is_same_v; + concept function_policy_family // + = std::is_same_v // + || std::is_same_v // + || std::is_same_v; // template < typename Policy > - concept member_policy_family // - = std::is_same_v // - || std::is_same_v // - || std::is_same_v; + concept member_policy_family // + = std::is_same_v // + || std::is_same_v // + || std::is_same_v; // template < typename Policy > - concept method_policy_family // - = std::is_same_v // - || std::is_same_v // - || std::is_same_v; + concept method_policy_family // + = std::is_same_v // + || std::is_same_v // + || std::is_same_v; // template < typename Policy > - concept variable_policy_family // - = std::is_same_v // - || std::is_same_v // - || std::is_same_v; + concept variable_policy_family // + = std::is_same_v // + || std::is_same_v // + || std::is_same_v; // } namespace meta_hpp @@ -4475,7 +4477,7 @@ namespace meta_hpp }; struct method_opts final { - argument_opts_list arguments; + argument_opts_list arguments{}; metadata_map metadata{}; }; @@ -4818,6 +4820,98 @@ namespace meta_hpp } } +namespace meta_hpp +{ + class arguments_bind final { + public: + arguments_bind() = default; + ~arguments_bind() = default; + + arguments_bind(arguments_bind&&) = default; + arguments_bind(const arguments_bind&) = delete; + + arguments_bind& operator=(arguments_bind&&) = default; + arguments_bind& operator=(const arguments_bind&) = delete; + + arguments_bind& operator()(std::string name) & { + arguments_.push_back(argument_opts{ + .name = std::move(name), + }); + return *this; + } + + arguments_bind operator()(std::string name) && { + arguments_.push_back(argument_opts{ + .name = std::move(name), + }); + return std::move(*this); + } + + arguments_bind& operator()(std::string name, metadata_map metadata) & { + arguments_.push_back(argument_opts{ + .name = std::move(name), + .metadata = std::move(metadata), + }); + return *this; + } + + arguments_bind operator()(std::string name, metadata_map metadata) && { + arguments_.push_back(argument_opts{ + .name = std::move(name), + .metadata = std::move(metadata), + }); + return std::move(*this); + } + + operator argument_opts_list() && { + return std::move(arguments_); + } + + private: + argument_opts_list arguments_; + }; + + inline arguments_bind arguments_() { + return arguments_bind{}; + } +} + +namespace meta_hpp +{ + class metadata_bind final { + public: + metadata_bind() = default; + ~metadata_bind() = default; + + metadata_bind(metadata_bind&&) = default; + metadata_bind(const metadata_bind&) = delete; + + metadata_bind& operator=(metadata_bind&&) = default; + metadata_bind& operator=(const metadata_bind&) = delete; + + metadata_bind& operator()(std::string name, uvalue value) & { + metadata_.insert_or_assign(std::move(name), std::move(value)); + return *this; + } + + metadata_bind operator()(std::string name, uvalue value) && { + metadata_.insert_or_assign(std::move(name), std::move(value)); + return std::move(*this); + } + + operator metadata_map() && { + return std::move(metadata_); + } + + private: + metadata_map metadata_; + }; + + inline metadata_bind metadata_() { + return metadata_bind{}; + } +} + namespace meta_hpp { template < detail::array_kind Array > @@ -6267,8 +6361,8 @@ namespace meta_hpp::detail using return_type = typename ft::return_type; using argument_types = typename ft::argument_types; - constexpr bool as_copy // - = std::is_copy_constructible_v // + constexpr bool as_copy // + = std::is_constructible_v // && std::is_same_v; constexpr bool as_void // @@ -6725,7 +6819,7 @@ namespace meta_hpp::detail using value_type = typename mt::value_type; constexpr bool as_copy // - = std::is_copy_constructible_v // + = std::is_constructible_v // && std::is_same_v; // constexpr bool as_ptr // @@ -7090,8 +7184,8 @@ namespace meta_hpp::detail using qualified_type = typename mt::qualified_type; using argument_types = typename mt::argument_types; - constexpr bool as_copy // - = std::is_copy_constructible_v // + constexpr bool as_copy // + = std::is_constructible_v // && std::is_same_v; constexpr bool as_void // @@ -7634,9 +7728,8 @@ namespace meta_hpp::detail using class_type = typename ct::class_type; using argument_types = typename ct::argument_types; - constexpr bool as_object // - = std::is_copy_constructible_v // - && std::is_same_v; + constexpr bool as_object // + = std::is_same_v; constexpr bool as_raw_ptr // = std::is_same_v; @@ -7644,7 +7737,10 @@ namespace meta_hpp::detail constexpr bool as_shared_ptr // = std::is_same_v; - static_assert(as_object || as_raw_ptr || as_shared_ptr); + constexpr bool as_unique_ptr // + = std::is_same_v; + + static_assert(as_object || as_raw_ptr || as_shared_ptr || as_unique_ptr); META_HPP_ASSERT( // args.size() == ct::arity // @@ -7668,6 +7764,10 @@ namespace meta_hpp::detail if constexpr ( as_shared_ptr ) { return std::make_shared(META_HPP_FWD(all_args)...); } + + if constexpr ( as_unique_ptr ) { + return std::make_unique(META_HPP_FWD(all_args)...); + } }); } @@ -8078,12 +8178,11 @@ namespace meta_hpp return std::string_view{}; } - inline uvalue enum_type::name_to_value(std::string_view name) const noexcept { + inline const uvalue& enum_type::name_to_value(std::string_view name) const noexcept { if ( const evalue& value = get_evalue(name) ) { return value.get_value(); } - - return uvalue{}; + return uvalue::empty_value; } } @@ -8156,7 +8255,7 @@ namespace meta_hpp::detail using data_type = typename pt::data_type; constexpr bool as_copy // - = std::is_copy_constructible_v // + = std::is_constructible_v // && std::is_same_v; // constexpr bool as_ptr // @@ -9246,6 +9345,29 @@ namespace meta_hpp } } +namespace meta_hpp::detail +{ + template < typename T > + struct copy_traits; + + template < typename T > + concept has_copy_traits // + = requires(const T& v) { + { copy_traits{}(v) } -> std::convertible_to; + }; +} + +namespace meta_hpp::detail +{ + template < typename T > + requires std::is_copy_constructible_v + struct copy_traits { + uvalue operator()(const T& v) const { + return uvalue{v}; + } + }; +} + namespace meta_hpp::detail { template < typename T > @@ -9268,14 +9390,6 @@ namespace meta_hpp::detail } }; - template < typename T > - requires std::is_copy_constructible_v - struct deref_traits { - uvalue operator()(const T* v) const { - return v != nullptr ? uvalue{*v} : uvalue{}; - } - }; - template < typename T > requires std::is_copy_constructible_v struct deref_traits> { @@ -9316,15 +9430,6 @@ namespace meta_hpp::detail } }; - template < typename T > - requires std::is_copy_constructible_v - struct index_traits { - uvalue operator()(const T* v, std::size_t i) const { - // NOLINTNEXTLINE(*-pointer-arithmetic) - return v != nullptr ? uvalue{v[i]} : uvalue{}; - } - }; - template < typename T, std::size_t Size > requires std::is_copy_constructible_v struct index_traits> { @@ -9409,9 +9514,9 @@ namespace meta_hpp const any_type type; void (*const move)(uvalue&& self, uvalue& to) noexcept; - void (*const copy)(const uvalue& self, uvalue& to); void (*const reset)(uvalue& self) noexcept; + uvalue (*const copy)(const storage_u& self); uvalue (*const deref)(const storage_u& self); uvalue (*const index)(const storage_u& self, std::size_t i); uvalue (*const unmap)(const storage_u& self); @@ -9496,24 +9601,6 @@ namespace meta_hpp } } - static void do_copy(const uvalue& self, uvalue& to) { - META_HPP_DEV_ASSERT(!to); - - auto&& [tag, vtable] = unpack_vtag(self); - - switch ( tag ) { - case storage_e::nothing: - break; - case storage_e::trivial: - to.storage_ = self.storage_; - break; - case storage_e::internal: - case storage_e::external: - vtable->copy(self, to); - break; - } - } - static void do_reset(uvalue& self) noexcept { auto&& [tag, vtable] = unpack_vtag(self); @@ -9580,21 +9667,6 @@ namespace meta_hpp } }}, - .copy{[](const uvalue& self, uvalue& to) { - META_HPP_DEV_ASSERT(!to); - META_HPP_DEV_ASSERT(self); - - const Tp* src = storage_cast(self.storage_); - - if constexpr ( in_internal_v ) { - do_ctor(to, *src); - } else { - // NOLINTNEXTLINE(*-union-access, *-owning-memory) - to.storage_.external.ptr = new Tp(*src); - to.storage_.vtag = self.storage_.vtag; - } - }}, - .reset{[](uvalue& self) noexcept { META_HPP_DEV_ASSERT(self); @@ -9610,6 +9682,16 @@ namespace meta_hpp self.storage_.vtag = 0; }}, + .copy{[]() { + if constexpr ( detail::has_copy_traits ) { + return +[](const storage_u& self) -> uvalue { + return detail::copy_traits{}(*storage_cast(self)); + }; + } else { + return nullptr; + } + }()}, + .deref{[]() { if constexpr ( detail::has_deref_traits ) { return +[](const storage_u& self) -> uvalue { @@ -9648,6 +9730,8 @@ namespace meta_hpp namespace meta_hpp { + inline const uvalue uvalue::empty_value; + inline uvalue::~uvalue() noexcept { reset(); } @@ -9656,10 +9740,6 @@ namespace meta_hpp vtable_t::do_move(std::move(other), *this); } - inline uvalue::uvalue(const uvalue& other) { - vtable_t::do_copy(other, *this); - } - inline uvalue& uvalue::operator=(uvalue&& other) noexcept { if ( this != &other ) { uvalue{std::move(other)}.swap(*this); @@ -9667,13 +9747,6 @@ namespace meta_hpp return *this; } - inline uvalue& uvalue::operator=(const uvalue& other) { - if ( this != &other ) { - uvalue{other}.swap(*this); - } - return *this; - } - template < typename T, typename Tp, typename > uvalue::uvalue(T&& val) { vtable_t::do_ctor(*this, std::forward(val)); @@ -9686,30 +9759,26 @@ namespace meta_hpp } template < typename T, typename... Args, typename Tp > - requires std::is_copy_constructible_v // - && std::is_constructible_v + requires std::is_constructible_v uvalue::uvalue(std::in_place_type_t, Args&&... args) { vtable_t::do_ctor(*this, std::forward(args)...); } template < typename T, typename U, typename... Args, typename Tp > - requires std::is_copy_constructible_v // - && std::is_constructible_v&, Args...> + requires std::is_constructible_v&, Args...> uvalue::uvalue(std::in_place_type_t, std::initializer_list ilist, Args&&... args) { vtable_t::do_ctor(*this, ilist, std::forward(args)...); } template < typename T, typename... Args, typename Tp > - requires std::is_copy_constructible_v // - && std::is_constructible_v + requires std::is_constructible_v Tp& uvalue::emplace(Args&&... args) { vtable_t::do_reset(*this); return vtable_t::do_ctor(*this, std::forward(args)...); } template < typename T, typename U, typename... Args, typename Tp > - requires std::is_copy_constructible_v // - && std::is_constructible_v&, Args...> + requires std::is_constructible_v&, Args...> Tp& uvalue::emplace(std::initializer_list ilist, Args&&... args) { vtable_t::do_reset(*this); return vtable_t::do_ctor(*this, ilist, std::forward(args)...); @@ -9811,6 +9880,18 @@ namespace meta_hpp return tag != storage_e::nothing && vtable->index != nullptr; } + inline uvalue uvalue::copy() const { + auto&& [tag, vtable] = vtable_t::unpack_vtag(*this); + return tag != storage_e::nothing && vtable->copy != nullptr // + ? vtable->copy(storage_) + : uvalue{}; + } + + inline bool uvalue::has_copy_op() const noexcept { + auto&& [tag, vtable] = vtable_t::unpack_vtag(*this); + return tag != storage_e::nothing && vtable->copy != nullptr; + } + inline uvalue uvalue::unmap() const { auto&& [tag, vtable] = vtable_t::unpack_vtag(*this); return tag != storage_e::nothing && vtable->unmap != nullptr // @@ -10024,20 +10105,17 @@ namespace meta_hpp } template < typename T, typename... Args, typename Tp > - requires std::is_copy_constructible_v // - && std::is_constructible_v // + requires std::is_constructible_v // uresult::uresult(std::in_place_type_t, Args&&... args) : value_{std::in_place_type, std::forward(args)...} {} template < typename T, typename U, typename... Args, typename Tp > - requires std::is_copy_constructible_v // - && std::is_constructible_v&, Args...> // + requires std::is_constructible_v&, Args...> // uresult::uresult(std::in_place_type_t, std::initializer_list ilist, Args&&... args) : value_{std::in_place_type, ilist, std::forward(args)...} {} template < typename T, typename... Args, typename Tp > - requires std::is_copy_constructible_v // - && std::is_constructible_v // + requires std::is_constructible_v // Tp& uresult::emplace(Args&&... args) { Tp& val{value_.emplace(std::forward(args)...)}; error_ = error_code::no_error; @@ -10045,8 +10123,7 @@ namespace meta_hpp } template < typename T, typename U, typename... Args, typename Tp > - requires std::is_copy_constructible_v // - && std::is_constructible_v&, Args...> // + requires std::is_constructible_v&, Args...> // Tp& uresult::emplace(std::initializer_list ilist, Args&&... args) { Tp& val{value_.emplace(ilist, std::forward(args)...)}; error_ = error_code::no_error; diff --git a/develop/untests/meta_features/move_only_tests.cpp b/develop/untests/meta_features/move_only_tests.cpp new file mode 100644 index 0000000..c3c37b1 --- /dev/null +++ b/develop/untests/meta_features/move_only_tests.cpp @@ -0,0 +1,64 @@ +/******************************************************************************* + * 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 move_only_clazz { + int v{}; + + move_only_clazz(int nv) : v{nv} {} + + move_only_clazz(move_only_clazz&&) = default; + move_only_clazz(const move_only_clazz&) = delete; + + move_only_clazz& operator=(move_only_clazz&&) = default; + move_only_clazz& operator=(const move_only_clazz&) = delete; + + static move_only_clazz static_ctor(int nv) { + return move_only_clazz{nv}; + } + + move_only_clazz clone() { + return move_only_clazz{v}; + } + }; +} + +TEST_CASE("meta/meta_features/move_only/_") { + namespace meta = meta_hpp; + + meta::class_() + .constructor_() + .function_("static_ctor", &move_only_clazz::static_ctor) + .method_("clone", &move_only_clazz::clone); +} + +TEST_CASE("meta/meta_features/move_only") { + namespace meta = meta_hpp; + + const meta::class_type move_only_clazz_type = meta::resolve_type(); + + SUBCASE("constructor") { + meta::uvalue v = move_only_clazz_type.create(42); + REQUIRE(v.get_type() == move_only_clazz_type); + CHECK(v.as().v == 42); + } + + SUBCASE("function") { + meta::uvalue v = move_only_clazz_type.get_function("static_ctor").invoke(42); + REQUIRE(v.get_type() == move_only_clazz_type); + CHECK(v.as().v == 42); + } + + SUBCASE("method") { + meta::uvalue v = move_only_clazz_type.get_method("clone").invoke(move_only_clazz{42}); + REQUIRE(v.get_type() == move_only_clazz_type); + CHECK(v.as().v == 42); + } +} diff --git a/develop/untests/meta_issues/random_issue_4.cpp b/develop/untests/meta_issues/random_issue_4.cpp index 1a00c5a..7222d08 100644 --- a/develop/untests/meta_issues/random_issue_4.cpp +++ b/develop/untests/meta_issues/random_issue_4.cpp @@ -50,7 +50,7 @@ TEST_CASE("meta/meta_issues/random/4") { SUBCASE("3") { meta::uvalue v2{std::in_place_type}; - CHECK_THROWS(v = v2); + CHECK_THROWS(v = v2.copy()); CHECK(v.get_type() == meta::resolve_type()); CHECK_NOTHROW(v = std::move(v2)); CHECK(v.get_type() == meta::resolve_type()); @@ -58,7 +58,7 @@ TEST_CASE("meta/meta_issues/random/4") { SUBCASE("4") { meta::uvalue v2{std::in_place_type}; - CHECK_THROWS(v = v2); + CHECK_THROWS(v = v2.copy()); CHECK(v.get_type() == meta::resolve_type()); CHECK_NOTHROW(v = std::move(v2)); CHECK(v.get_type() == meta::resolve_type()); diff --git a/develop/untests/meta_states/ctor_tests.cpp b/develop/untests/meta_states/ctor_tests.cpp index 9c8d25e..641848d 100644 --- a/develop/untests/meta_states/ctor_tests.cpp +++ b/develop/untests/meta_states/ctor_tests.cpp @@ -443,3 +443,78 @@ TEST_CASE("meta/meta_states/ctor/as_shared_pointer") { CHECK(clazz_t::copy_constructor_counter == 1); } } + +TEST_CASE("meta/meta_states/ctor/as_unique_pointer") { + namespace meta = meta_hpp; + + using clazz_t = clazz; + + meta::class_() + .constructor_(meta::constructor_policy::as_unique_pointer) + .constructor_(meta::constructor_policy::as_unique_pointer) + .constructor_(meta::constructor_policy::as_unique_pointer); + + clazz_t::constructor_counter = 0; + clazz_t::destructor_counter = 0; + clazz_t::move_constructor_counter = 0; + clazz_t::copy_constructor_counter = 0; + + const meta::class_type clazz_type = meta::resolve_type(); + REQUIRE(clazz_type); + + SUBCASE("int") { + { + const meta::constructor ctor = clazz_type.get_constructor_with(); + REQUIRE(ctor); + CHECK(ctor.get_type() == meta::resolve_constructor_type()); + } + { + const meta::uvalue v = clazz_type.create(42); + CHECK(v.get_type() == meta::resolve_type>()); + CHECK(v.as>()->i == 42); + CHECK_FALSE(clazz_type.destroy(v)); + } + CHECK(clazz_t::constructor_counter == 1); + CHECK(clazz_t::destructor_counter == 1); + CHECK(clazz_t::move_constructor_counter == 0); + CHECK(clazz_t::copy_constructor_counter == 0); + } + + SUBCASE("clazz_t&&") { + { + const meta::constructor ctor = clazz_type.get_constructor_with(); + REQUIRE(ctor); + CHECK(ctor.get_type() == meta::resolve_constructor_type()); + } + { + clazz_t o{42}; + const meta::uvalue v = clazz_type.create(std::move(o)); + CHECK(v.get_type() == meta::resolve_type>()); + CHECK(v.as>()->i == 42); + CHECK_FALSE(clazz_type.destroy(v)); + } + CHECK(clazz_t::constructor_counter == 1); + CHECK(clazz_t::destructor_counter == 2); + CHECK(clazz_t::move_constructor_counter == 1); + CHECK(clazz_t::copy_constructor_counter == 0); + } + + SUBCASE("const clazz_t&") { + { + const meta::constructor ctor = clazz_type.get_constructor_with(); + REQUIRE(ctor); + CHECK(ctor.get_type() == meta::resolve_constructor_type()); + } + { + clazz_t o{42}; + const meta::uvalue v = clazz_type.create(std::as_const(o)); + CHECK(v.get_type() == meta::resolve_type>()); + CHECK(v.as>()->i == 42); + CHECK_FALSE(clazz_type.destroy(v)); + } + CHECK(clazz_t::constructor_counter == 1); + CHECK(clazz_t::destructor_counter == 2); + CHECK(clazz_t::move_constructor_counter == 0); + CHECK(clazz_t::copy_constructor_counter == 1); + } +} diff --git a/develop/untests/meta_states/dtor_tests.cpp b/develop/untests/meta_states/dtor_tests.cpp index ea0ec3d..7ea775b 100644 --- a/develop/untests/meta_states/dtor_tests.cpp +++ b/develop/untests/meta_states/dtor_tests.cpp @@ -38,9 +38,8 @@ TEST_CASE("meta/meta_states/dtor") { meta::class_() .destructor_({ - .metadata{ - {"desc", "virtual dtor"s} - } + .metadata = meta::metadata_() + ("desc", "virtual dtor"s) }); SUBCASE("closed_dtor") { diff --git a/develop/untests/meta_states/metadata_tests.cpp b/develop/untests/meta_states/metadata_tests.cpp index 0d983e6..bcad0d2 100644 --- a/develop/untests/meta_states/metadata_tests.cpp +++ b/develop/untests/meta_states/metadata_tests.cpp @@ -38,32 +38,29 @@ TEST_CASE("meta/meta_states/metadata/enum") { namespace meta = meta_hpp; using namespace std::string_literals; - meta::enum_({ - {"desc1", "enum-desc1"s}, - {"desc2", "enum-desc2"s}, - }) + meta::enum_(meta::metadata_() + ("desc1", "enum-desc1"s) + ("desc2", "enum-desc2"s)) .evalue_("red", color::red, { - .metadata{{"desc1", "red-color"s}} + .metadata{meta::metadata_()("desc1", "red-color"s)} }) .evalue_("green", color::green, { - .metadata{{"desc1", "green-color"s}} + .metadata{meta::metadata_()("desc1", "green-color"s)} }) .evalue_("blue", color::blue, { - .metadata{{"desc1", "blue-color"s}} + .metadata{meta::metadata_()("desc1", "blue-color"s)} }); // metadata override - meta::enum_({ - {"desc2", "new-enum-desc2"s}, - {"desc3", "new-enum-desc3"s}, - }); + meta::enum_(meta::metadata_() + ("desc2", "new-enum-desc2"s) + ("desc3", "new-enum-desc3"s)); meta::enum_() .evalue_("red", color::red, { - .metadata{ - {"desc2", "new-red-color"s}, - } + .metadata = meta::metadata_() + ("desc2", "new-red-color"s) }); // @@ -89,57 +86,45 @@ TEST_CASE("meta/meta_states/metadata/class") { namespace meta = meta_hpp; using namespace std::string_literals; - meta::class_({ - {"desc1", "class-desc1"s}, - {"desc2", "class-desc2"s}, - }) + meta::class_(meta::metadata_() + ("desc1", "class-desc1"s) + ("desc2", "class-desc2"s)) .constructor_({ - .arguments{{ - .name{"v"}, - .metadata{{"desc", "the ctor arg"s}}, - }}, - .metadata{{"desc", "one arg 2d vector ctor"s}}, + .arguments{meta::arguments_() + ("v", meta::metadata_()("desc", "the ctor arg"s))}, + .metadata{meta::metadata_()("desc", "one arg 2d vector ctor"s)}, }) .constructor_({ - .arguments{{ - .name{"x"}, - .metadata{{"desc", "the 1st ctor arg"s}}, - },{ - .name{"y"}, - .metadata{{"desc", "the 2nd ctor arg"s}}, - }}, - .metadata{{"desc", "two args 2d vector ctor"s}} + .arguments{meta::arguments_() + ("x", meta::metadata_()("desc", "the 1st ctor arg"s)) + ("y", meta::metadata_()("desc", "the 2nd ctor arg"s)) + }, + .metadata{meta::metadata_()("desc", "two args 2d vector ctor"s)} }) .member_("x", &ivec2::x, { - .metadata{{"desc", "x-member"s}} + .metadata{meta::metadata_()("desc", "x-member"s)} }) .member_("y", &ivec2::y, { - .metadata{{"desc", "y-member"s}} + .metadata{meta::metadata_()("desc", "y-member"s)} }) .method_("add", &ivec2::add, { - .arguments{{ - .name{"other"}, - .metadata{{"desc", "other-arg"s}} - }}, - .metadata{{"desc", "add-method"s}} + .arguments{meta::arguments_() + ("other", meta::metadata_()("desc", "other-arg"s))}, + .metadata{meta::metadata_()("desc", "add-method"s)} }) .function_("iadd", &ivec2::iadd, { - .arguments{{ - .name{"l"}, - .metadata{{"desc", "l-arg"s}} - },{ - .name{"r"}, - .metadata{{"desc", "r-arg"s}} - }}, - .metadata{{"desc", "iadd-function"s}} + .arguments{meta::arguments_() + ("l", meta::metadata_()("desc", "l-arg"s)) + ("r", meta::metadata_()("desc", "r-arg"s)) + }, + .metadata{meta::metadata_()("desc", "iadd-function"s)} }); // metadata override - meta::class_({ - {"desc2", "new-class-desc2"s}, - {"desc3", "new-class-desc3"s}, - }); + meta::class_(meta::metadata_() + ("desc2", "new-class-desc2"s) + ("desc3", "new-class-desc3"s)); // @@ -243,16 +228,14 @@ TEST_CASE("meta/meta_states/metadata/scope") { using namespace std::string_literals; SUBCASE("local_scope") { - const meta::scope lscope = meta::local_scope_("local-scope", { - {"desc", "scope-desc"s} - }); + const meta::scope lscope = meta::local_scope_("local-scope", meta::metadata_() + ("desc", "scope-desc"s)); CHECK(lscope.get_metadata().at("desc").as() == "scope-desc"s); } SUBCASE("static_scope") { - meta::static_scope_("meta/meta_states/metadata/scope/static-scope", { - {"desc", "scope-desc"s} - }); + meta::static_scope_("meta/meta_states/metadata/scope/static-scope", meta::metadata_() + ("desc", "scope-desc"s)); CHECK(meta::resolve_scope("meta/meta_states/metadata/scope/static-scope").get_metadata().at("desc").as() == "scope-desc"s); } } @@ -262,65 +245,56 @@ TEST_CASE("meta/meta_states/metadata/other") { using namespace std::string_literals; SUBCASE("array") { - meta::array_({ - {"desc", "int[]-type"s} - }); + meta::array_(meta::metadata_() + ("desc", "int[]-type"s)); CHECK(meta::resolve_type().get_metadata().at("desc").as() == "int[]-type"s); } SUBCASE("function") { - meta::function_({ - {"desc", "int->int"s} - }); + meta::function_(meta::metadata_() + ("desc", "int->int"s)); CHECK(meta::resolve_type().get_metadata().at("desc").as() == "int->int"s); } SUBCASE("member") { - meta::member_({ - {"desc", "ivec2::int"s} - }); + meta::member_(meta::metadata_() + ("desc", "ivec2::int"s)); CHECK(meta::resolve_type().get_metadata().at("desc").as() == "ivec2::int"s); } SUBCASE("method") { - meta::method_({ - {"desc", "ivec2(int -> int)"s} - }); + meta::method_(meta::metadata_() + ("desc", "ivec2(int -> int)"s)); CHECK(meta::resolve_type().get_metadata().at("desc").as() == "ivec2(int -> int)"s); } SUBCASE("nullptr") { - meta::nullptr_({ - {"desc", "nullptr_t"s} - }); + meta::nullptr_(meta::metadata_() + ("desc", "nullptr_t"s)); CHECK(meta::resolve_type().get_metadata().at("desc").as() == "nullptr_t"s); } SUBCASE("number") { - meta::number_({ - {"desc", "int-type"s} - }); + meta::number_(meta::metadata_() + ("desc", "int-type"s)); CHECK(meta::resolve_type().get_metadata().at("desc").as() == "int-type"s); } SUBCASE("pointer") { - meta::pointer_({ - {"desc", "int*-type"s} - }); + meta::pointer_(meta::metadata_() + ("desc", "int*-type"s)); CHECK(meta::resolve_type().get_metadata().at("desc").as() == "int*-type"s); } SUBCASE("reference") { - meta::reference_({ - {"desc", "int&-type"s} - }); + meta::reference_(meta::metadata_() + ("desc", "int&-type"s)); CHECK(meta::resolve_type().get_metadata().at("desc").as() == "int&-type"s); } SUBCASE("void") { - meta::void_({ - {"desc", "void-type"s} - }); + meta::void_(meta::metadata_() + ("desc", "void-type"s)); CHECK(meta::resolve_type().get_metadata().at("desc").as() == "void-type"s); } } diff --git a/develop/untests/meta_utilities/arg_tests.cpp b/develop/untests/meta_utilities/arg_tests.cpp index 5e7a477..4549812 100644 --- a/develop/untests/meta_utilities/arg_tests.cpp +++ b/develop/untests/meta_utilities/arg_tests.cpp @@ -1342,8 +1342,8 @@ TEST_CASE("meta/meta_utilities/arg/ptr_values") { } { - auto PRV_PTR = []() -> meta::uvalue { static clazz v; static clazz* p{&v}; static meta::uvalue vv{p}; return vv; }; - auto PRV2_PTR = []() -> meta::uvalue { static dclazz v; static dclazz* p{&v}; static meta::uvalue vv{p}; return vv; }; + auto PRV_PTR = []() -> meta::uvalue { static clazz v; static clazz* p{&v}; static meta::uvalue vv{p}; return vv.copy(); }; + auto PRV2_PTR = []() -> meta::uvalue { static dclazz v; static dclazz* p{&v}; static meta::uvalue vv{p}; return vv.copy(); }; uarg a{r, PRV_PTR()}; CHECK(a.get_raw_type() == meta::resolve_type()); @@ -1379,8 +1379,8 @@ TEST_CASE("meta/meta_utilities/arg/ptr_values") { } { - auto PRV_CPTR = []() -> meta::uvalue { static clazz v; static const clazz* p{&v}; static meta::uvalue vv{p}; return vv; }; - auto PRV2_CPTR = []() -> meta::uvalue { static dclazz v; static const dclazz* p{&v}; static meta::uvalue vv{p}; return vv; }; + auto PRV_CPTR = []() -> meta::uvalue { static clazz v; static const clazz* p{&v}; static meta::uvalue vv{p}; return vv.copy(); }; + auto PRV2_CPTR = []() -> meta::uvalue { static dclazz v; static const dclazz* p{&v}; static meta::uvalue vv{p}; return vv.copy(); }; uarg a{r, PRV_CPTR()}; CHECK(a.get_raw_type() == meta::resolve_type()); @@ -1416,8 +1416,8 @@ TEST_CASE("meta/meta_utilities/arg/ptr_values") { } { - auto CPRV_PTR = []() -> const meta::uvalue { static clazz v; static clazz* p{&v}; static meta::uvalue vv{p}; return vv; }; - auto CPRV2_PTR = []() -> const meta::uvalue { static dclazz v; static dclazz* p{&v}; static meta::uvalue vv{p}; return vv; }; + auto CPRV_PTR = []() -> const meta::uvalue { static clazz v; static clazz* p{&v}; static meta::uvalue vv{p}; return vv.copy(); }; + auto CPRV2_PTR = []() -> const meta::uvalue { static dclazz v; static dclazz* p{&v}; static meta::uvalue vv{p}; return vv.copy(); }; uarg a{r, CPRV_PTR()}; CHECK(a.get_raw_type() == meta::resolve_type()); @@ -1453,8 +1453,8 @@ TEST_CASE("meta/meta_utilities/arg/ptr_values") { } { - auto CPRV_CPTR = []() -> const meta::uvalue { static clazz v; static const clazz* p{&v}; static meta::uvalue vv{p}; return vv; }; - auto CPRV2_CPTR = []() -> const meta::uvalue { static dclazz v; static const dclazz* p{&v}; static meta::uvalue vv{p}; return vv; }; + auto CPRV_CPTR = []() -> const meta::uvalue { static clazz v; static const clazz* p{&v}; static meta::uvalue vv{p}; return vv.copy(); }; + auto CPRV2_CPTR = []() -> const meta::uvalue { static dclazz v; static const dclazz* p{&v}; static meta::uvalue vv{p}; return vv.copy(); }; uarg a{r, CPRV_CPTR()}; CHECK(a.get_raw_type() == meta::resolve_type()); diff --git a/develop/untests/meta_utilities/value2_tests.cpp b/develop/untests/meta_utilities/value2_tests.cpp index 25742f5..9664565 100644 --- a/develop/untests/meta_utilities/value2_tests.cpp +++ b/develop/untests/meta_utilities/value2_tests.cpp @@ -161,7 +161,7 @@ TEST_CASE("meta/meta_utilities/value2/counters/small") { SUBCASE("copy ctor") { { meta::uvalue v1{ivec2{1,2}}; - meta::uvalue v2{std::as_const(v1)}; + meta::uvalue v2{std::as_const(v1).copy()}; CHECK(v1.as().x == 1); CHECK(v2.as().y == 2); @@ -248,7 +248,7 @@ TEST_CASE("meta/meta_utilities/value2/counters/big") { SUBCASE("copy ctor") { { meta::uvalue v1{ivec2_big{1,2}}; - meta::uvalue v2{std::as_const(v1)}; + meta::uvalue v2{std::as_const(v1).copy()}; CHECK(v1.as().x == 1); CHECK(v2.as().y == 2); diff --git a/develop/untests/meta_utilities/value_tests.cpp b/develop/untests/meta_utilities/value_tests.cpp index ee81cd6..4778d48 100644 --- a/develop/untests/meta_utilities/value_tests.cpp +++ b/develop/untests/meta_utilities/value_tests.cpp @@ -202,11 +202,11 @@ TEST_CASE("meta/meta_utilities/value") { CHECK(std::as_const(val).as() == ivec2{1,2}); { - meta::uvalue val_copy{val}; + meta::uvalue val_copy{val.copy()}; CHECK(std::move(val_copy).as() == ivec2{1,2}); } { - meta::uvalue val_copy{val}; + meta::uvalue val_copy{val.copy()}; CHECK(std::move(std::as_const(val_copy)).as() == ivec2{1,2}); } @@ -242,11 +242,11 @@ TEST_CASE("meta/meta_utilities/value") { CHECK(std::as_const(val).as() == ivec2{1,2}); { - meta::uvalue val_copy{val}; + meta::uvalue val_copy{val.copy()}; CHECK(std::move(val_copy).as() == ivec2{1,2}); } { - meta::uvalue val_copy{val}; + meta::uvalue val_copy{val.copy()}; CHECK(std::move(std::as_const(val_copy)).as() == ivec2{1,2}); } @@ -276,11 +276,11 @@ TEST_CASE("meta/meta_utilities/value") { CHECK(std::as_const(val).as() == ivec2{1,2}); { - meta::uvalue val_copy{val}; + meta::uvalue val_copy{val.copy()}; CHECK(std::move(val_copy).as() == ivec2{1,2}); } { - meta::uvalue val_copy{val}; + meta::uvalue val_copy{val.copy()}; CHECK(std::move(std::as_const(val_copy)).as() == ivec2{1,2}); } @@ -310,11 +310,11 @@ TEST_CASE("meta/meta_utilities/value") { CHECK(std::as_const(val).as() == ivec2{1,2}); { - meta::uvalue val_copy{val}; + meta::uvalue val_copy{val.copy()}; CHECK(std::move(val_copy).as() == ivec2{1,2}); } { - meta::uvalue val_copy{val}; + meta::uvalue val_copy{val.copy()}; CHECK(std::move(std::as_const(val_copy)).as() == ivec2{1,2}); } @@ -341,21 +341,6 @@ TEST_CASE("meta/meta_utilities/value") { CHECK(ivec2::copy_constructor_counter == 0); } - SUBCASE("value(const meta::value&)") { - const ivec2 v{1,2}; - meta::uvalue val_src{v}; - CHECK(ivec2::move_constructor_counter == 0); - CHECK(ivec2::copy_constructor_counter == 1); - - meta::uvalue val_dst{val_src}; - CHECK(val_dst.as() == ivec2{1,2}); - CHECK(ivec2::move_constructor_counter == 0); - CHECK(ivec2::copy_constructor_counter == 2); - - CHECK(val_src.as() == ivec2{1,2}); - CHECK(val_src.get_data() != val_dst.get_data()); - } - SUBCASE("value& operator=(T&&)") { meta::uvalue val{10}; @@ -385,28 +370,6 @@ TEST_CASE("meta/meta_utilities/value") { CHECK(ivec2::copy_constructor_counter == 0); } - SUBCASE("value& operator=(const meta::value&)") { - meta::uvalue val_src1{"world"s}; - meta::uvalue val_src2{ivec2{1,2}}; - CHECK(ivec2::move_constructor_counter == 1); - CHECK(ivec2::copy_constructor_counter == 0); - - meta::uvalue val_dst{"hello"s}; - - val_dst = val_src1; - CHECK(val_dst.as() == "world"s); - CHECK(ivec2::move_constructor_counter == 1); - CHECK(ivec2::copy_constructor_counter == 0); - - val_dst = val_src2; - CHECK(val_dst.as() == ivec2{1,2}); - CHECK(ivec2::move_constructor_counter == 2); - CHECK(ivec2::copy_constructor_counter == 1); - - CHECK(val_src2.as() == ivec2{1,2}); - CHECK(val_src2.get_data() != val_dst.get_data()); - } - SUBCASE("swap/0") { meta::uvalue val1{"world"s}; meta::uvalue val2{ivec2{1,2}}; diff --git a/headers/meta.hpp/meta_binds.hpp b/headers/meta.hpp/meta_binds.hpp index 9cf3369..8f39f5a 100644 --- a/headers/meta.hpp/meta_binds.hpp +++ b/headers/meta.hpp/meta_binds.hpp @@ -70,7 +70,7 @@ namespace meta_hpp }; struct method_opts final { - argument_opts_list arguments; + argument_opts_list arguments{}; metadata_map metadata{}; }; @@ -412,3 +412,95 @@ namespace meta_hpp return scope_bind{scope, std::move(metadata)}; } } + +namespace meta_hpp +{ + class arguments_bind final { + public: + arguments_bind() = default; + ~arguments_bind() = default; + + arguments_bind(arguments_bind&&) = default; + arguments_bind(const arguments_bind&) = delete; + + arguments_bind& operator=(arguments_bind&&) = default; + arguments_bind& operator=(const arguments_bind&) = delete; + + arguments_bind& operator()(std::string name) & { + arguments_.push_back(argument_opts{ + .name = std::move(name), + }); + return *this; + } + + arguments_bind operator()(std::string name) && { + arguments_.push_back(argument_opts{ + .name = std::move(name), + }); + return std::move(*this); + } + + arguments_bind& operator()(std::string name, metadata_map metadata) & { + arguments_.push_back(argument_opts{ + .name = std::move(name), + .metadata = std::move(metadata), + }); + return *this; + } + + arguments_bind operator()(std::string name, metadata_map metadata) && { + arguments_.push_back(argument_opts{ + .name = std::move(name), + .metadata = std::move(metadata), + }); + return std::move(*this); + } + + operator argument_opts_list() && { + return std::move(arguments_); + } + + private: + argument_opts_list arguments_; + }; + + inline arguments_bind arguments_() { + return arguments_bind{}; + } +} + +namespace meta_hpp +{ + class metadata_bind final { + public: + metadata_bind() = default; + ~metadata_bind() = default; + + metadata_bind(metadata_bind&&) = default; + metadata_bind(const metadata_bind&) = delete; + + metadata_bind& operator=(metadata_bind&&) = default; + metadata_bind& operator=(const metadata_bind&) = delete; + + metadata_bind& operator()(std::string name, uvalue value) & { + metadata_.insert_or_assign(std::move(name), std::move(value)); + return *this; + } + + metadata_bind operator()(std::string name, uvalue value) && { + metadata_.insert_or_assign(std::move(name), std::move(value)); + return std::move(*this); + } + + operator metadata_map() && { + return std::move(metadata_); + } + + private: + metadata_map metadata_; + }; + + inline metadata_bind metadata_() { + return metadata_bind{}; + } +} diff --git a/headers/meta.hpp/meta_detail/value_traits/copy_traits.hpp b/headers/meta.hpp/meta_detail/value_traits/copy_traits.hpp new file mode 100644 index 0000000..af24cfd --- /dev/null +++ b/headers/meta.hpp/meta_detail/value_traits/copy_traits.hpp @@ -0,0 +1,33 @@ +/******************************************************************************* + * 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 copy_traits; + + template < typename T > + concept has_copy_traits // + = requires(const T& v) { + { copy_traits{}(v) } -> std::convertible_to; + }; +} + +namespace meta_hpp::detail +{ + template < typename T > + requires std::is_copy_constructible_v + struct copy_traits { + uvalue operator()(const T& v) const { + return uvalue{v}; + } + }; +} diff --git a/headers/meta.hpp/meta_detail/value_traits/deref_traits.hpp b/headers/meta.hpp/meta_detail/value_traits/deref_traits.hpp index deb32e8..5f5e03f 100644 --- a/headers/meta.hpp/meta_detail/value_traits/deref_traits.hpp +++ b/headers/meta.hpp/meta_detail/value_traits/deref_traits.hpp @@ -31,14 +31,6 @@ namespace meta_hpp::detail } }; - template < typename T > - requires std::is_copy_constructible_v - struct deref_traits { - uvalue operator()(const T* v) const { - return v != nullptr ? uvalue{*v} : uvalue{}; - } - }; - template < typename T > requires std::is_copy_constructible_v struct deref_traits> { diff --git a/headers/meta.hpp/meta_detail/value_traits/index_traits.hpp b/headers/meta.hpp/meta_detail/value_traits/index_traits.hpp index 22f4336..5217e27 100644 --- a/headers/meta.hpp/meta_detail/value_traits/index_traits.hpp +++ b/headers/meta.hpp/meta_detail/value_traits/index_traits.hpp @@ -32,15 +32,6 @@ namespace meta_hpp::detail } }; - template < typename T > - requires std::is_copy_constructible_v - struct index_traits { - uvalue operator()(const T* v, std::size_t i) const { - // NOLINTNEXTLINE(*-pointer-arithmetic) - return v != nullptr ? uvalue{v[i]} : uvalue{}; - } - }; - template < typename T, std::size_t Size > requires std::is_copy_constructible_v struct index_traits> { diff --git a/headers/meta.hpp/meta_states.hpp b/headers/meta.hpp/meta_states.hpp index ea3683f..4d43a0a 100644 --- a/headers/meta.hpp/meta_states.hpp +++ b/headers/meta.hpp/meta_states.hpp @@ -24,9 +24,12 @@ namespace meta_hpp struct as_shared_pointer_t final {}; + struct as_unique_pointer_t final {}; + inline constexpr as_object_t as_object{}; inline constexpr as_raw_pointer_t as_raw_pointer{}; inline constexpr as_shared_pointer_t as_shared_pointer{}; + inline constexpr as_unique_pointer_t as_unique_pointer{}; } namespace function_policy @@ -82,34 +85,35 @@ namespace meta_hpp } template < typename Policy > - concept constructor_policy_family // - = std::is_same_v // - || std::is_same_v // - || std::is_same_v; + concept constructor_policy_family // + = std::is_same_v // + || std::is_same_v // + || std::is_same_v // + || std::is_same_v; // template < typename Policy > - concept function_policy_family // - = std::is_same_v // - || std::is_same_v // - || std::is_same_v; + concept function_policy_family // + = std::is_same_v // + || std::is_same_v // + || std::is_same_v; // template < typename Policy > - concept member_policy_family // - = std::is_same_v // - || std::is_same_v // - || std::is_same_v; + concept member_policy_family // + = std::is_same_v // + || std::is_same_v // + || std::is_same_v; // template < typename Policy > - concept method_policy_family // - = std::is_same_v // - || std::is_same_v // - || std::is_same_v; + concept method_policy_family // + = std::is_same_v // + || std::is_same_v // + || std::is_same_v; // template < typename Policy > - concept variable_policy_family // - = std::is_same_v // - || std::is_same_v // - || std::is_same_v; + concept variable_policy_family // + = std::is_same_v // + || std::is_same_v // + || std::is_same_v; // } namespace meta_hpp diff --git a/headers/meta.hpp/meta_states/constructor.hpp b/headers/meta.hpp/meta_states/constructor.hpp index a6aa398..0ac7ebd 100644 --- a/headers/meta.hpp/meta_states/constructor.hpp +++ b/headers/meta.hpp/meta_states/constructor.hpp @@ -21,9 +21,8 @@ namespace meta_hpp::detail using class_type = typename ct::class_type; using argument_types = typename ct::argument_types; - constexpr bool as_object // - = std::is_copy_constructible_v // - && std::is_same_v; + constexpr bool as_object // + = std::is_same_v; constexpr bool as_raw_ptr // = std::is_same_v; @@ -31,7 +30,10 @@ namespace meta_hpp::detail constexpr bool as_shared_ptr // = std::is_same_v; - static_assert(as_object || as_raw_ptr || as_shared_ptr); + constexpr bool as_unique_ptr // + = std::is_same_v; + + static_assert(as_object || as_raw_ptr || as_shared_ptr || as_unique_ptr); META_HPP_ASSERT( // args.size() == ct::arity // @@ -55,6 +57,10 @@ namespace meta_hpp::detail if constexpr ( as_shared_ptr ) { return std::make_shared(META_HPP_FWD(all_args)...); } + + if constexpr ( as_unique_ptr ) { + return std::make_unique(META_HPP_FWD(all_args)...); + } }); } diff --git a/headers/meta.hpp/meta_states/function.hpp b/headers/meta.hpp/meta_states/function.hpp index 6237b74..ef91c22 100644 --- a/headers/meta.hpp/meta_states/function.hpp +++ b/headers/meta.hpp/meta_states/function.hpp @@ -21,8 +21,8 @@ namespace meta_hpp::detail using return_type = typename ft::return_type; using argument_types = typename ft::argument_types; - constexpr bool as_copy // - = std::is_copy_constructible_v // + constexpr bool as_copy // + = std::is_constructible_v // && std::is_same_v; constexpr bool as_void // diff --git a/headers/meta.hpp/meta_states/member.hpp b/headers/meta.hpp/meta_states/member.hpp index b9cc45d..1ad4c0d 100644 --- a/headers/meta.hpp/meta_states/member.hpp +++ b/headers/meta.hpp/meta_states/member.hpp @@ -23,7 +23,7 @@ namespace meta_hpp::detail using value_type = typename mt::value_type; constexpr bool as_copy // - = std::is_copy_constructible_v // + = std::is_constructible_v // && std::is_same_v; // constexpr bool as_ptr // diff --git a/headers/meta.hpp/meta_states/method.hpp b/headers/meta.hpp/meta_states/method.hpp index 2ea6c17..d04214e 100644 --- a/headers/meta.hpp/meta_states/method.hpp +++ b/headers/meta.hpp/meta_states/method.hpp @@ -23,8 +23,8 @@ namespace meta_hpp::detail using qualified_type = typename mt::qualified_type; using argument_types = typename mt::argument_types; - constexpr bool as_copy // - = std::is_copy_constructible_v // + constexpr bool as_copy // + = std::is_constructible_v // && std::is_same_v; constexpr bool as_void // diff --git a/headers/meta.hpp/meta_states/variable.hpp b/headers/meta.hpp/meta_states/variable.hpp index 822d914..8c567d9 100644 --- a/headers/meta.hpp/meta_states/variable.hpp +++ b/headers/meta.hpp/meta_states/variable.hpp @@ -21,7 +21,7 @@ namespace meta_hpp::detail using data_type = typename pt::data_type; constexpr bool as_copy // - = std::is_copy_constructible_v // + = std::is_constructible_v // && std::is_same_v; // constexpr bool as_ptr // diff --git a/headers/meta.hpp/meta_types.hpp b/headers/meta.hpp/meta_types.hpp index ff6eefe..bc12442 100644 --- a/headers/meta.hpp/meta_types.hpp +++ b/headers/meta.hpp/meta_types.hpp @@ -350,7 +350,7 @@ namespace meta_hpp template < detail::enum_kind Enum > [[nodiscard]] std::string_view value_to_name(Enum value) const noexcept; - [[nodiscard]] uvalue name_to_value(std::string_view name) const noexcept; + [[nodiscard]] const uvalue& name_to_value(std::string_view name) const noexcept; }; class function_type final : public type_base { diff --git a/headers/meta.hpp/meta_types/enum_type.hpp b/headers/meta.hpp/meta_types/enum_type.hpp index 5895b8c..92e7587 100644 --- a/headers/meta.hpp/meta_types/enum_type.hpp +++ b/headers/meta.hpp/meta_types/enum_type.hpp @@ -62,11 +62,10 @@ namespace meta_hpp return std::string_view{}; } - inline uvalue enum_type::name_to_value(std::string_view name) const noexcept { + inline const uvalue& enum_type::name_to_value(std::string_view name) const noexcept { if ( const evalue& value = get_evalue(name) ) { return value.get_value(); } - - return uvalue{}; + return uvalue::empty_value; } } diff --git a/headers/meta.hpp/meta_uresult.hpp b/headers/meta.hpp/meta_uresult.hpp index 3ae8768..bb19544 100644 --- a/headers/meta.hpp/meta_uresult.hpp +++ b/headers/meta.hpp/meta_uresult.hpp @@ -68,10 +68,10 @@ namespace meta_hpp ~uresult() = default; uresult(uresult&&) noexcept = default; - uresult(const uresult&) = default; + uresult(const uresult&) = delete; uresult& operator=(uresult&&) noexcept = default; - uresult& operator=(const uresult&) = default; + uresult& operator=(const uresult&) = delete; explicit(false) uresult(uerror error) noexcept; explicit(false) uresult(uvalue value) noexcept; @@ -85,35 +85,31 @@ namespace meta_hpp typename = std::enable_if_t< // !uvalue_family && // !detail::is_in_place_type_v && // - std::is_copy_constructible_v>> // + std::is_constructible_v>> // uresult(T&& val); - template < // - typename T, // - typename Tp = std::decay_t, // - typename = std::enable_if_t< // - !uvalue_family && // - std::is_copy_constructible_v>> // + template < // + typename T, // + typename Tp = std::decay_t, // + typename = std::enable_if_t< // + !uvalue_family && // + std::is_constructible_v>> // uresult& operator=(T&& val); template < typename T, typename... Args, typename Tp = std::decay_t > - requires std::is_copy_constructible_v // - && std::is_constructible_v // + requires std::is_constructible_v // explicit uresult(std::in_place_type_t, Args&&... args); template < typename T, typename U, typename... Args, typename Tp = std::decay_t > - requires std::is_copy_constructible_v // - && std::is_constructible_v&, Args...> // + requires std::is_constructible_v&, Args...> // explicit uresult(std::in_place_type_t, std::initializer_list ilist, Args&&... args); template < typename T, typename... Args, typename Tp = std::decay_t > - requires std::is_copy_constructible_v // - && std::is_constructible_v // + requires std::is_constructible_v // Tp& emplace(Args&&... args); template < typename T, typename U, typename... Args, typename Tp = std::decay_t > - requires std::is_copy_constructible_v // - && std::is_constructible_v&, Args...> // + requires std::is_constructible_v&, Args...> // Tp& emplace(std::initializer_list ilist, Args&&... args); [[nodiscard]] bool has_error() const noexcept; diff --git a/headers/meta.hpp/meta_uresult/uresult.hpp b/headers/meta.hpp/meta_uresult/uresult.hpp index c836439..5e3fc43 100644 --- a/headers/meta.hpp/meta_uresult/uresult.hpp +++ b/headers/meta.hpp/meta_uresult/uresult.hpp @@ -83,20 +83,17 @@ namespace meta_hpp } template < typename T, typename... Args, typename Tp > - requires std::is_copy_constructible_v // - && std::is_constructible_v // + requires std::is_constructible_v // uresult::uresult(std::in_place_type_t, Args&&... args) : value_{std::in_place_type, std::forward(args)...} {} template < typename T, typename U, typename... Args, typename Tp > - requires std::is_copy_constructible_v // - && std::is_constructible_v&, Args...> // + requires std::is_constructible_v&, Args...> // uresult::uresult(std::in_place_type_t, std::initializer_list ilist, Args&&... args) : value_{std::in_place_type, ilist, std::forward(args)...} {} template < typename T, typename... Args, typename Tp > - requires std::is_copy_constructible_v // - && std::is_constructible_v // + requires std::is_constructible_v // Tp& uresult::emplace(Args&&... args) { Tp& val{value_.emplace(std::forward(args)...)}; error_ = error_code::no_error; @@ -104,8 +101,7 @@ namespace meta_hpp } template < typename T, typename U, typename... Args, typename Tp > - requires std::is_copy_constructible_v // - && std::is_constructible_v&, Args...> // + requires std::is_constructible_v&, Args...> // Tp& uresult::emplace(std::initializer_list ilist, Args&&... args) { Tp& val{value_.emplace(ilist, std::forward(args)...)}; error_ = error_code::no_error; diff --git a/headers/meta.hpp/meta_uvalue.hpp b/headers/meta.hpp/meta_uvalue.hpp index 8a7d9da..589d575 100644 --- a/headers/meta.hpp/meta_uvalue.hpp +++ b/headers/meta.hpp/meta_uvalue.hpp @@ -11,15 +11,18 @@ namespace meta_hpp { class uvalue final { + public: + static const uvalue empty_value; + public: uvalue() = default; ~uvalue() noexcept; uvalue(uvalue&& other) noexcept; - uvalue(const uvalue& other); + uvalue(const uvalue& other) = delete; uvalue& operator=(uvalue&& other) noexcept; - uvalue& operator=(const uvalue& other); + uvalue& operator=(const uvalue& other) = delete; template < // typename T, // @@ -27,35 +30,31 @@ namespace meta_hpp typename = std::enable_if_t< // !uvalue_family && // !detail::is_in_place_type_v && // - std::is_copy_constructible_v>> // + std::is_constructible_v>> // uvalue(T&& val); - template < // - typename T, // - typename Tp = std::decay_t, // - typename = std::enable_if_t< // - !uvalue_family && // - std::is_copy_constructible_v>> // + template < // + typename T, // + typename Tp = std::decay_t, // + typename = std::enable_if_t< // + !uvalue_family && // + std::is_constructible_v>> // uvalue& operator=(T&& val); template < typename T, typename... Args, typename Tp = std::decay_t > - requires std::is_copy_constructible_v // - && std::is_constructible_v // + requires std::is_constructible_v // explicit uvalue(std::in_place_type_t, Args&&... args); template < typename T, typename U, typename... Args, typename Tp = std::decay_t > - requires std::is_copy_constructible_v // - && std::is_constructible_v&, Args...> // + requires std::is_constructible_v&, Args...> // explicit uvalue(std::in_place_type_t, std::initializer_list ilist, Args&&... args); template < typename T, typename... Args, typename Tp = std::decay_t > - requires std::is_copy_constructible_v // - && std::is_constructible_v // + requires std::is_constructible_v // Tp& emplace(Args&&... args); template < typename T, typename U, typename... Args, typename Tp = std::decay_t > - requires std::is_copy_constructible_v // - && std::is_constructible_v&, Args...> // + requires std::is_constructible_v&, Args...> // Tp& emplace(std::initializer_list ilist, Args&&... args); [[nodiscard]] bool has_value() const noexcept; @@ -76,6 +75,9 @@ namespace meta_hpp [[nodiscard]] uvalue operator[](std::size_t index) const; [[nodiscard]] bool has_index_op() const noexcept; + [[nodiscard]] uvalue copy() const; + [[nodiscard]] bool has_copy_op() const noexcept; + [[nodiscard]] uvalue unmap() const; [[nodiscard]] bool has_unmap_op() const noexcept; diff --git a/headers/meta.hpp/meta_uvalue/uvalue.hpp b/headers/meta.hpp/meta_uvalue/uvalue.hpp index 675b21d..bf11cd1 100644 --- a/headers/meta.hpp/meta_uvalue/uvalue.hpp +++ b/headers/meta.hpp/meta_uvalue/uvalue.hpp @@ -10,6 +10,7 @@ #include "../meta_registry.hpp" #include "../meta_uvalue.hpp" +#include "../meta_detail/value_traits/copy_traits.hpp" #include "../meta_detail/value_traits/deref_traits.hpp" #include "../meta_detail/value_traits/index_traits.hpp" #include "../meta_detail/value_traits/unmap_traits.hpp" @@ -24,9 +25,9 @@ namespace meta_hpp const any_type type; void (*const move)(uvalue&& self, uvalue& to) noexcept; - void (*const copy)(const uvalue& self, uvalue& to); void (*const reset)(uvalue& self) noexcept; + uvalue (*const copy)(const storage_u& self); uvalue (*const deref)(const storage_u& self); uvalue (*const index)(const storage_u& self, std::size_t i); uvalue (*const unmap)(const storage_u& self); @@ -111,24 +112,6 @@ namespace meta_hpp } } - static void do_copy(const uvalue& self, uvalue& to) { - META_HPP_DEV_ASSERT(!to); - - auto&& [tag, vtable] = unpack_vtag(self); - - switch ( tag ) { - case storage_e::nothing: - break; - case storage_e::trivial: - to.storage_ = self.storage_; - break; - case storage_e::internal: - case storage_e::external: - vtable->copy(self, to); - break; - } - } - static void do_reset(uvalue& self) noexcept { auto&& [tag, vtable] = unpack_vtag(self); @@ -195,21 +178,6 @@ namespace meta_hpp } }}, - .copy{[](const uvalue& self, uvalue& to) { - META_HPP_DEV_ASSERT(!to); - META_HPP_DEV_ASSERT(self); - - const Tp* src = storage_cast(self.storage_); - - if constexpr ( in_internal_v ) { - do_ctor(to, *src); - } else { - // NOLINTNEXTLINE(*-union-access, *-owning-memory) - to.storage_.external.ptr = new Tp(*src); - to.storage_.vtag = self.storage_.vtag; - } - }}, - .reset{[](uvalue& self) noexcept { META_HPP_DEV_ASSERT(self); @@ -225,6 +193,16 @@ namespace meta_hpp self.storage_.vtag = 0; }}, + .copy{[]() { + if constexpr ( detail::has_copy_traits ) { + return +[](const storage_u& self) -> uvalue { + return detail::copy_traits{}(*storage_cast(self)); + }; + } else { + return nullptr; + } + }()}, + .deref{[]() { if constexpr ( detail::has_deref_traits ) { return +[](const storage_u& self) -> uvalue { @@ -263,6 +241,8 @@ namespace meta_hpp namespace meta_hpp { + inline const uvalue uvalue::empty_value; + inline uvalue::~uvalue() noexcept { reset(); } @@ -271,10 +251,6 @@ namespace meta_hpp vtable_t::do_move(std::move(other), *this); } - inline uvalue::uvalue(const uvalue& other) { - vtable_t::do_copy(other, *this); - } - inline uvalue& uvalue::operator=(uvalue&& other) noexcept { if ( this != &other ) { uvalue{std::move(other)}.swap(*this); @@ -282,13 +258,6 @@ namespace meta_hpp return *this; } - inline uvalue& uvalue::operator=(const uvalue& other) { - if ( this != &other ) { - uvalue{other}.swap(*this); - } - return *this; - } - template < typename T, typename Tp, typename > uvalue::uvalue(T&& val) { vtable_t::do_ctor(*this, std::forward(val)); @@ -301,30 +270,26 @@ namespace meta_hpp } template < typename T, typename... Args, typename Tp > - requires std::is_copy_constructible_v // - && std::is_constructible_v + requires std::is_constructible_v uvalue::uvalue(std::in_place_type_t, Args&&... args) { vtable_t::do_ctor(*this, std::forward(args)...); } template < typename T, typename U, typename... Args, typename Tp > - requires std::is_copy_constructible_v // - && std::is_constructible_v&, Args...> + requires std::is_constructible_v&, Args...> uvalue::uvalue(std::in_place_type_t, std::initializer_list ilist, Args&&... args) { vtable_t::do_ctor(*this, ilist, std::forward(args)...); } template < typename T, typename... Args, typename Tp > - requires std::is_copy_constructible_v // - && std::is_constructible_v + requires std::is_constructible_v Tp& uvalue::emplace(Args&&... args) { vtable_t::do_reset(*this); return vtable_t::do_ctor(*this, std::forward(args)...); } template < typename T, typename U, typename... Args, typename Tp > - requires std::is_copy_constructible_v // - && std::is_constructible_v&, Args...> + requires std::is_constructible_v&, Args...> Tp& uvalue::emplace(std::initializer_list ilist, Args&&... args) { vtable_t::do_reset(*this); return vtable_t::do_ctor(*this, ilist, std::forward(args)...); @@ -426,6 +391,18 @@ namespace meta_hpp return tag != storage_e::nothing && vtable->index != nullptr; } + inline uvalue uvalue::copy() const { + auto&& [tag, vtable] = vtable_t::unpack_vtag(*this); + return tag != storage_e::nothing && vtable->copy != nullptr // + ? vtable->copy(storage_) + : uvalue{}; + } + + inline bool uvalue::has_copy_op() const noexcept { + auto&& [tag, vtable] = vtable_t::unpack_vtag(*this); + return tag != storage_e::nothing && vtable->copy != nullptr; + } + inline uvalue uvalue::unmap() const { auto&& [tag, vtable] = vtable_t::unpack_vtag(*this); return tag != storage_e::nothing && vtable->unmap != nullptr //