diff --git a/develop/untests/meta_issues/random_issue_6.cpp b/develop/untests/meta_issues/random_issue_6.cpp new file mode 100644 index 0000000..7e219d5 --- /dev/null +++ b/develop/untests/meta_issues/random_issue_6.cpp @@ -0,0 +1,217 @@ +/******************************************************************************* + * 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-2024, by Matvey Cherevko (blackmatov@gmail.com) + ******************************************************************************/ + +#include +#include + +namespace +{ + template < auto v0 > + struct v {}; + template < typename t0 > + struct t {}; + + template < auto v1, auto v0 > + struct vv {}; + template < auto v0, typename t0 > + struct vt {}; + template < typename t0, auto v0 > + struct tv {}; + template < typename t1, typename t0 > + struct tt {}; + + template < auto v2, auto v1, auto v0 > + struct vvv {}; + template < auto v1, auto v0, typename t0 > + struct vvt {}; + template < auto v1, typename t0, auto v0 > + struct vtv {}; + template < auto v0, typename t1, typename t0 > + struct vtt {}; + template < typename t0, auto v1, auto v0 > + struct tvv {}; + template < typename t1, auto v0, typename t0 > + struct tvt {}; + template < typename t1, typename t0, auto v0 > + struct ttv {}; + template < typename t2, typename t1, typename t0 > + struct ttt {}; + + template < auto v2, auto v1, auto v0, typename t0, typename t1 > + struct vvvtt {}; + template < typename t2, typename t1, typename t0, auto v0, auto v1 > + struct tttvv {}; +} + +TEST_CASE("meta/meta_issues/random/6") { + namespace meta = meta_hpp; + + { + meta::class_type type = meta::resolve_type>(); + CHECK(type.get_argument_types() == meta::any_type_list{ + meta::resolve_type()}); + CHECK(type.get_argument_value(0).is()); + } + { + meta::class_type type = meta::resolve_type>(); + CHECK(type.get_argument_types() == meta::any_type_list{ + meta::resolve_type()}); + CHECK_FALSE(type.get_argument_value(0)); + } + // + { + meta::class_type type = meta::resolve_type>(); + CHECK(type.get_argument_types() == meta::any_type_list{ + meta::resolve_type(), + meta::resolve_type()}); + CHECK(type.get_argument_value(0).is()); + CHECK(type.get_argument_value(1).is()); + } + { + meta::class_type type = meta::resolve_type>(); + CHECK(type.get_argument_types() == meta::any_type_list{ + meta::resolve_type(), + meta::resolve_type()}); + CHECK(type.get_argument_value(0).is()); + CHECK_FALSE(type.get_argument_value(1).has_value()); + } + { + meta::class_type type = meta::resolve_type>(); + CHECK(type.get_argument_types() == meta::any_type_list{ + meta::resolve_type(), + meta::resolve_type()}); + CHECK_FALSE(type.get_argument_value(0).has_value()); + CHECK(type.get_argument_value(1).is()); + } + { + meta::class_type type = meta::resolve_type>(); + CHECK(type.get_argument_types() == meta::any_type_list{ + meta::resolve_type(), + meta::resolve_type()}); + CHECK_FALSE(type.get_argument_value(0).has_value()); + CHECK_FALSE(type.get_argument_value(1).has_value()); + } + // + { + meta::class_type type = meta::resolve_type>(); + CHECK(type.get_argument_types() == meta::any_type_list{ + meta::resolve_type(), + meta::resolve_type(), + meta::resolve_type(), + }); + CHECK(type.get_argument_value(0).as() == 42); + CHECK(type.get_argument_value(1).as() == 21); + CHECK(type.get_argument_value(2).as() == 10); + } + { + meta::class_type type = meta::resolve_type>(); + CHECK(type.get_argument_types() == meta::any_type_list{ + meta::resolve_type(), + meta::resolve_type(), + meta::resolve_type(), + }); + CHECK(type.get_argument_value(0).as() == 42); + CHECK(type.get_argument_value(1).as() == 21); + CHECK_FALSE(type.get_argument_value(2).has_value()); + } + { + meta::class_type type = meta::resolve_type>(); + CHECK(type.get_argument_types() == meta::any_type_list{ + meta::resolve_type(), + meta::resolve_type(), + meta::resolve_type(), + }); + CHECK(type.get_argument_value(0).as() == 42); + CHECK_FALSE(type.get_argument_value(1).has_value()); + CHECK(type.get_argument_value(2).as() == 21); + } + { + meta::class_type type = meta::resolve_type>(); + CHECK(type.get_argument_types() == meta::any_type_list{ + meta::resolve_type(), + meta::resolve_type(), + meta::resolve_type(), + }); + CHECK(type.get_argument_value(0).as() == 42); + CHECK_FALSE(type.get_argument_value(1).has_value()); + CHECK_FALSE(type.get_argument_value(2).has_value()); + } + { + meta::class_type type = meta::resolve_type>(); + CHECK(type.get_argument_types() == meta::any_type_list{ + meta::resolve_type(), + meta::resolve_type(), + meta::resolve_type(), + }); + CHECK_FALSE(type.get_argument_value(0).has_value()); + CHECK(type.get_argument_value(1).as() == 42); + CHECK(type.get_argument_value(2).as() == 21); + } + { + meta::class_type type = meta::resolve_type>(); + CHECK(type.get_argument_types() == meta::any_type_list{ + meta::resolve_type(), + meta::resolve_type(), + meta::resolve_type(), + }); + CHECK_FALSE(type.get_argument_value(0).has_value()); + CHECK(type.get_argument_value(1).as() == 42); + CHECK_FALSE(type.get_argument_value(2).has_value()); + } + { + meta::class_type type = meta::resolve_type>(); + CHECK(type.get_argument_types() == meta::any_type_list{ + meta::resolve_type(), + meta::resolve_type(), + meta::resolve_type(), + }); + CHECK_FALSE(type.get_argument_value(0).has_value()); + CHECK_FALSE(type.get_argument_value(1).has_value()); + CHECK(type.get_argument_value(2).as() == 42); + } + { + meta::class_type type = meta::resolve_type>(); + CHECK(type.get_argument_types() == meta::any_type_list{ + meta::resolve_type(), + meta::resolve_type(), + meta::resolve_type(), + }); + CHECK_FALSE(type.get_argument_value(0).has_value()); + CHECK_FALSE(type.get_argument_value(1).has_value()); + CHECK_FALSE(type.get_argument_value(2).has_value()); + } + // + { + meta::class_type type = meta::resolve_type>(); + CHECK(type.get_argument_types() == meta::any_type_list{ + meta::resolve_type(), + meta::resolve_type(), + meta::resolve_type(), + meta::resolve_type(), + meta::resolve_type(), + }); + CHECK(type.get_argument_value(0).as() == 42); + CHECK(type.get_argument_value(1).as() == 21); + CHECK(type.get_argument_value(2).as() == 10); + CHECK_FALSE(type.get_argument_value(3).has_value()); + CHECK_FALSE(type.get_argument_value(4).has_value()); + } + { + meta::class_type type = meta::resolve_type>(); + CHECK(type.get_argument_types() == meta::any_type_list{ + meta::resolve_type(), + meta::resolve_type(), + meta::resolve_type(), + meta::resolve_type(), + meta::resolve_type(), + }); + CHECK_FALSE(type.get_argument_value(0).has_value()); + CHECK_FALSE(type.get_argument_value(1).has_value()); + CHECK_FALSE(type.get_argument_value(2).has_value()); + CHECK(type.get_argument_value(3).as() == 42); + CHECK(type.get_argument_value(4).as() == 21); + } +} diff --git a/headers/meta.hpp/meta_base.hpp b/headers/meta.hpp/meta_base.hpp index 695f590..ab7dcb6 100644 --- a/headers/meta.hpp/meta_base.hpp +++ b/headers/meta.hpp/meta_base.hpp @@ -204,6 +204,7 @@ namespace meta_hpp using metadata_map = std::map>; using typedef_map = std::map>; + using uvalue_list = std::vector; using any_type_list = std::vector; using class_list = std::vector; diff --git a/headers/meta.hpp/meta_detail/type_traits/class_traits.hpp b/headers/meta.hpp/meta_detail/type_traits/class_traits.hpp index f675f36..9fb7d4b 100644 --- a/headers/meta.hpp/meta_detail/type_traits/class_traits.hpp +++ b/headers/meta.hpp/meta_detail/type_traits/class_traits.hpp @@ -27,33 +27,242 @@ namespace meta_hpp::detail namespace impl { template < class_kind Class > - struct class_traits_impl { - static constexpr std::size_t arity{0}; - + struct class_argument_traits_impl { using argument_types = type_list<>; - - [[nodiscard]] static constexpr class_bitflags make_flags() noexcept { - return {}; - } + static constexpr std::tuple argument_values{}; }; - template < template < typename... > typename Class, typename... Args > - struct class_traits_impl> { - static constexpr std::size_t arity{sizeof...(Args)}; + template < typename T > + inline constexpr decltype(std::ignore) type_to_ignore_v = std::ignore; - using argument_types = type_list; + // + // typename... + // - [[nodiscard]] static constexpr class_bitflags make_flags() noexcept { - return class_flags::is_template_instantiation; - } + template < // + template < typename... > + typename Class, + typename... Ts > + struct class_argument_traits_impl> { + using argument_types = type_list; + static constexpr std::tuple argument_values = std::make_tuple(type_to_ignore_v...); + }; + + // + // auto, typename... + // + + template < // + template < auto, typename... > + typename Class, + auto A, + typename... Zs > + struct class_argument_traits_impl> { + using argument_types = type_list; + static constexpr std::tuple argument_values = std::make_tuple(A, type_to_ignore_v...); + }; + + // + // auto, auto, typename... + // typename, auto, typename... + // + + template < // + template < auto, auto, typename... > + typename Class, + auto A, + auto B, + typename... Zs > + struct class_argument_traits_impl> { + using argument_types = type_list; + static constexpr std::tuple argument_values = std::make_tuple(A, B, type_to_ignore_v...); + }; + + template < // + template < typename, auto, typename... > + typename Class, + typename A, + auto B, + typename... Zs > + struct class_argument_traits_impl> { + using argument_types = type_list; + static constexpr std::tuple argument_values = std::make_tuple(std::ignore, B, type_to_ignore_v...); + }; + + // + // auto, auto, auto, typename... + // typename, auto, auto, typename... + // auto, typename, auto, typename... + // typename, typename, auto, typename... + // + + template < // + template < auto, auto, auto, typename... > + typename Class, + auto A, + auto B, + auto C, + typename... Zs > + struct class_argument_traits_impl> { + using argument_types = type_list; + static constexpr std::tuple argument_values = std::make_tuple(A, B, C, type_to_ignore_v...); + }; + + template < // + template < typename, auto, auto, typename... > + typename Class, + typename A, + auto B, + auto C, + typename... Zs > + struct class_argument_traits_impl> { + using argument_types = type_list; + static constexpr std::tuple argument_values = std::make_tuple(std::ignore, B, C, type_to_ignore_v...); + }; + + template < // + template < auto, typename, auto, typename... > + typename Class, + auto A, + typename B, + auto C, + typename... Zs > + struct class_argument_traits_impl> { + using argument_types = type_list; + static constexpr std::tuple argument_values = std::make_tuple(A, std::ignore, C, type_to_ignore_v...); + }; + + template < // + template < typename, typename, auto, typename... > + typename Class, + typename A, + typename B, + auto C, + typename... Zs > + struct class_argument_traits_impl> { + using argument_types = type_list; + static constexpr std::tuple argument_values = std::make_tuple(std::ignore, std::ignore, C, type_to_ignore_v...); + }; + + // + // auto... + // + + template < // + template < auto... > + typename Class, + auto... Zs > + struct class_argument_traits_impl> { + using argument_types = type_list; + static constexpr std::tuple argument_values = std::make_tuple(Zs...); + }; + + // + // typename, auto... + // + + template < // + template < typename, auto... > + typename Class, + typename A, + auto... Zs > + struct class_argument_traits_impl> { + using argument_types = type_list; + static constexpr std::tuple argument_values = std::make_tuple(std::ignore, Zs...); + }; + + // + // auto, typename, auto... + // typename, typename, auto... + // + + template < // + template < auto, typename, auto... > + typename Class, + auto A, + typename B, + auto... Zs > + struct class_argument_traits_impl> { + using argument_types = type_list; + static constexpr std::tuple argument_values = std::make_tuple(A, std::ignore, Zs...); + }; + + template < // + template < typename, typename, auto... > + typename Class, + typename A, + typename B, + auto... Zs > + struct class_argument_traits_impl> { + using argument_types = type_list; + static constexpr std::tuple argument_values = std::make_tuple(std::ignore, std::ignore, Zs...); + }; + + // + // auto, auto, typename, auto... + // typename, auto, typename, auto... + // auto, typename, typename, auto... + // typename, typename, typename, auto... + // + + template < // + template < auto, auto, typename, auto... > + typename Class, + auto A, + auto B, + typename C, + auto... Zs > + struct class_argument_traits_impl> { + using argument_types = type_list; + static constexpr std::tuple argument_values = std::make_tuple(A, B, std::ignore, Zs...); + }; + + template < // + template < typename, auto, typename, auto... > + typename Class, + typename A, + auto B, + typename C, + auto... Zs > + struct class_argument_traits_impl> { + using argument_types = type_list; + static constexpr std::tuple argument_values = std::make_tuple(std::ignore, B, std::ignore, Zs...); + }; + + template < // + template < auto, typename, typename, auto... > + typename Class, + auto A, + typename B, + typename C, + auto... Zs > + struct class_argument_traits_impl> { + using argument_types = type_list; + static constexpr std::tuple argument_values = std::make_tuple(A, std::ignore, std::ignore, Zs...); + }; + + template < // + template < typename, typename, typename, auto... > + typename Class, + typename A, + typename B, + typename C, + auto... Zs > + struct class_argument_traits_impl> { + using argument_types = type_list; + static constexpr std::tuple argument_values = std::make_tuple(std::ignore, std::ignore, std::ignore, Zs...); }; } template < class_kind Class > - struct class_traits : impl::class_traits_impl { + struct class_traits { static constexpr std::size_t size{sizeof(Class)}; static constexpr std::size_t align{alignof(Class)}; + using argument_types = impl::class_argument_traits_impl::argument_types; + static constexpr std::tuple argument_values = impl::class_argument_traits_impl::argument_values; + static_assert(type_list_arity_v == std::tuple_size_v); + [[nodiscard]] static constexpr class_bitflags make_flags() noexcept { class_bitflags flags{}; @@ -73,7 +282,11 @@ namespace meta_hpp::detail flags.set(class_flags::is_polymorphic); } - return flags | impl::class_traits_impl::make_flags(); + if constexpr ( type_list_arity_v ) { + flags.set(class_flags::is_template_instantiation); + } + + return flags; } }; } diff --git a/headers/meta.hpp/meta_types.hpp b/headers/meta.hpp/meta_types.hpp index cb15ada..9e4d1a5 100644 --- a/headers/meta.hpp/meta_types.hpp +++ b/headers/meta.hpp/meta_types.hpp @@ -208,7 +208,9 @@ namespace meta_hpp [[nodiscard]] std::size_t get_arity() const noexcept; [[nodiscard]] any_type get_argument_type(std::size_t position) const noexcept; + [[nodiscard]] const uvalue& get_argument_value(std::size_t position) const noexcept; [[nodiscard]] const any_type_list& get_argument_types() const noexcept; + [[nodiscard]] const uvalue_list& get_argument_values() const noexcept; [[nodiscard]] const class_list& get_base_classes() const noexcept; [[nodiscard]] const constructor_list& get_constructors() const noexcept; @@ -492,6 +494,7 @@ namespace meta_hpp::detail const std::size_t size; const std::size_t align; const any_type_list argument_types; + const uvalue_list argument_values; // NOLINTEND(*-avoid-const-or-ref-data-members) class_list base_classes; diff --git a/headers/meta.hpp/meta_types/class_type.hpp b/headers/meta.hpp/meta_types/class_type.hpp index 638b88d..031f535 100644 --- a/headers/meta.hpp/meta_types/class_type.hpp +++ b/headers/meta.hpp/meta_types/class_type.hpp @@ -60,6 +60,45 @@ namespace meta_hpp::detail::class_type_data_impl }); } } + + template < class_kind Class > + any_type_list make_argument_types() { + using ct = class_traits; + using ct_argument_types = typename ct::argument_types; + + return [](std::index_sequence) { + any_type_list argument_types; + argument_types.reserve(type_list_arity_v); + + [[maybe_unused]] const auto make_argument_type = [](index_constant) { + return resolve_type>(); + }; + + (argument_types.emplace_back(make_argument_type(index_constant{})), ...); + return argument_types; + }(std::make_index_sequence>()); + } + + template < class_kind Class > + uvalue_list make_argument_values() { + using ct = class_traits; + using ct_argument_values = decltype(ct::argument_values); + + return [](std::index_sequence) { + uvalue_list argument_values; + argument_values.reserve(std::tuple_size_v); + + [[maybe_unused]] const auto make_argument_value = [](index_constant) { + return overloaded{ + [](decltype(std::ignore)) { return uvalue{}; }, + [](auto&& value) { return uvalue{META_HPP_FWD(value)}; }, + }(std::get(ct::argument_values)); + }; + + (argument_values.emplace_back(make_argument_value(index_constant{})), ...); + return argument_values; + }(std::make_index_sequence>()); + } } namespace meta_hpp::detail @@ -70,7 +109,8 @@ namespace meta_hpp::detail , flags{class_traits::make_flags()} , size{class_traits::size} , align{class_traits::align} - , argument_types{resolve_types(typename class_traits::argument_types{})} { + , argument_types{class_type_data_impl::make_argument_types()} + , argument_values{class_type_data_impl::make_argument_values()} { class_type_data_impl::new_base_info_t new_base_info; class_type_data_impl::fill_upcast_info(new_base_info); base_classes.swap(new_base_info.base_classes); @@ -112,10 +152,18 @@ namespace meta_hpp return position < data_->argument_types.size() ? data_->argument_types[position] : any_type{}; } + inline const uvalue& class_type::get_argument_value(std::size_t position) const noexcept { + return position < data_->argument_values.size() ? data_->argument_values[position] : uvalue::empty_value; + } + inline const any_type_list& class_type::get_argument_types() const noexcept { return data_->argument_types; } + inline const uvalue_list& class_type::get_argument_values() const noexcept { + return data_->argument_values; + } + inline const class_list& class_type::get_base_classes() const noexcept { return data_->base_classes; }