diff --git a/CMakeLists.txt b/CMakeLists.txt index f4a87a9..ac664fb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ project(iris VERSION 0.0.1 LANGUAGES CXX) get_directory_property(IRIS_PARENT_DIRECTORY PARENT_DIRECTORY) -if(DEFINED IRIS_ROOT AND NOT "${IRIS_ROOT}" PATH_EQUAL "${CMAKE_CURRENT_LIST_DIR}") +if(TARGET Iris::Iris) message(FATAL_ERROR "Cannot include Iris more than once") endif() diff --git a/include/iris/alloy/traits.hpp b/include/iris/alloy/traits.hpp index 3d9a379..d08e7f3 100644 --- a/include/iris/alloy/traits.hpp +++ b/include/iris/alloy/traits.hpp @@ -7,6 +7,7 @@ #include +#include #include #include diff --git a/include/iris/rvariant/detail/recursive_traits.hpp b/include/iris/rvariant/detail/recursive_traits.hpp index e53e2fa..0e2b27c 100644 --- a/include/iris/rvariant/detail/recursive_traits.hpp +++ b/include/iris/rvariant/detail/recursive_traits.hpp @@ -7,7 +7,7 @@ // IWYU pragma: private, include -#include +#include namespace iris::detail { @@ -45,7 +45,7 @@ struct select_maybe_wrapped : select_maybe_wrapped_impl { // Precondition: either T or recursive_wrapper occurs at least once in Ts... static_assert(sizeof...(Ts) > 0); - static_assert(!detail::is_recursive_wrapper_like_v); + static_assert(!is_recursive_wrapper_v); }; template diff --git a/include/iris/rvariant/detail/variant_storage.hpp b/include/iris/rvariant/detail/variant_storage.hpp index dc89dab..0af7de2 100644 --- a/include/iris/rvariant/detail/variant_storage.hpp +++ b/include/iris/rvariant/detail/variant_storage.hpp @@ -7,7 +7,7 @@ // IWYU pragma: private, include -#include +#include #include #include diff --git a/include/iris/rvariant/detail/visit.hpp b/include/iris/rvariant/detail/visit.hpp index b003d53..c336385 100644 --- a/include/iris/rvariant/detail/visit.hpp +++ b/include/iris/rvariant/detail/visit.hpp @@ -7,10 +7,10 @@ // IWYU pragma: private, include -#include #include #include #include +#include #include #include diff --git a/include/iris/rvariant/rvariant.hpp b/include/iris/rvariant/rvariant.hpp index 44e67de..b790646 100644 --- a/include/iris/rvariant/rvariant.hpp +++ b/include/iris/rvariant/rvariant.hpp @@ -5,12 +5,12 @@ #include // IWYU pragma: keep -#include #include #include #include #include // IWYU pragma: export #include +#include #include @@ -41,7 +41,7 @@ struct check_recursive_wrapper_duplicate_impl : std::true_type {}; template requires (!std::same_as) && - (is_recursive_wrapper_like_v || is_recursive_wrapper_like_v) && + (is_recursive_wrapper_v || is_recursive_wrapper_v) && std::same_as, unwrap_recursive_t> struct check_recursive_wrapper_duplicate_impl : std::false_type @@ -66,7 +66,7 @@ template struct non_wrapped_exactly_once : exactly_once { static_assert( - !detail::is_recursive_wrapper_like_v, + !is_recursive_wrapper_v, "Constructing a `recursive_wrapper` alternative with its full type as the tag is " "prohibited to avoid confusion; just specify `T` instead." ); @@ -167,9 +167,9 @@ struct rvariant_base IRIS_RVARIANT_ALWAYS_THROWING_UNREACHABLE_BEGIN // Primary constructor called from derived class template - requires std::is_constructible_v, Args...> + requires std::is_constructible_v constexpr explicit rvariant_base(std::in_place_index_t, Args&&... args) - noexcept(std::is_nothrow_constructible_v, Args...>) + noexcept(std::is_nothrow_constructible_v) : storage_(std::in_place_index, std::forward(args)...) , index_{static_cast>(I)} {} @@ -291,7 +291,7 @@ IRIS_RVARIANT_ALWAYS_THROWING_UNREACHABLE_END { if constexpr (need_destructor_call) { // ReSharper disable once CppTypeAliasNeverUsed - using T = pack_indexing_t; + using T = IRIS_PACK_INDEXING(I, Ts...); auto&& alt = raw_get(storage_); alt.~T(); } @@ -330,7 +330,7 @@ IRIS_RVARIANT_ALWAYS_THROWING_UNREACHABLE_END assert(index_ == I); if constexpr (I != std::variant_npos) { // ReSharper disable once CppTypeAliasNeverUsed - using T = pack_indexing_t; + using T = IRIS_PACK_INDEXING(I, Ts...); auto&& alt = raw_get(storage_); alt.~T(); index_ = variant_npos; @@ -340,7 +340,7 @@ IRIS_RVARIANT_ALWAYS_THROWING_UNREACHABLE_END IRIS_RVARIANT_ALWAYS_THROWING_UNREACHABLE_BEGIN template constexpr void construct_on_valueless(Args&&... args) - noexcept(std::is_nothrow_constructible_v, Args...>) + noexcept(std::is_nothrow_constructible_v) { static_assert(I != std::variant_npos); assert(index_ == variant_npos); @@ -350,7 +350,7 @@ IRIS_RVARIANT_ALWAYS_THROWING_UNREACHABLE_BEGIN template constexpr void reset_construct(Args&&... args) - noexcept(std::is_nothrow_constructible_v, Args...>) + noexcept(std::is_nothrow_constructible_v) { static_assert(I != std::variant_npos); visit_reset(); @@ -360,11 +360,11 @@ IRIS_RVARIANT_ALWAYS_THROWING_UNREACHABLE_BEGIN template constexpr void reset_construct(Args&&... args) - noexcept(std::is_nothrow_constructible_v, Args...>) + noexcept(std::is_nothrow_constructible_v) { if constexpr (i != std::variant_npos) { destroy(); - if constexpr (!std::is_nothrow_constructible_v, Args...>) { + if constexpr (!std::is_nothrow_constructible_v) { index_ = variant_npos; } } @@ -377,7 +377,7 @@ IRIS_RVARIANT_ALWAYS_THROWING_UNREACHABLE_BEGIN constexpr void reset_construct_never_valueless(Args&&... args) noexcept { static_assert(I != std::variant_npos); - static_assert(std::is_nothrow_constructible_v, Args...>); + static_assert(std::is_nothrow_constructible_v); static_assert(std::is_nothrow_constructible_v, Args...>); visit_destroy(); std::construct_at(&storage_, std::in_place_index, std::forward(args)...); @@ -406,13 +406,13 @@ IRIS_RVARIANT_ALWAYS_THROWING_UNREACHABLE_END IRIS_RVARIANT_ALWAYS_THROWING_UNREACHABLE_BEGIN template - requires std::is_constructible_v, Args...> + requires std::is_constructible_v constexpr variant_alternative_t>& emplace_impl(Args&&... args) - noexcept(std::is_nothrow_constructible_v, Args...>) IRIS_LIFETIMEBOUND + noexcept(std::is_nothrow_constructible_v) IRIS_LIFETIMEBOUND { static_assert(I < sizeof...(Ts)); - using T = pack_indexing_t; + using T = IRIS_PACK_INDEXING(I, Ts...); #ifndef NDEBUG // Self-emplace on non-valueless instance ALWAYS leads to UB. @@ -470,7 +470,7 @@ IRIS_RVARIANT_ALWAYS_THROWING_UNREACHABLE_BEGIN } else if constexpr (std::is_same_v) { // NOT type-changing if constexpr ( (sizeof(T) <= detail::never_valueless_trivial_size_limit && std::is_trivially_move_assignable_v) || - detail::is_recursive_wrapper_like_v + is_recursive_wrapper_v ) { T tmp{std::forward(args)...}; // may throw static_assert(noexcept(t_old_i = std::move(tmp))); @@ -493,7 +493,7 @@ IRIS_RVARIANT_ALWAYS_THROWING_UNREACHABLE_BEGIN } else { // type-changing if constexpr ( (sizeof(T) <= detail::never_valueless_trivial_size_limit && std::is_trivially_move_constructible_v) || - detail::is_recursive_wrapper_like_v + is_recursive_wrapper_v ) { T tmp{std::forward(args)...}; // may throw t_old_i.~T_old_i(); @@ -610,8 +610,8 @@ class rvariant : private detail::rvariant_base_t using base_type::index; // Default constructor - constexpr rvariant() noexcept(std::is_nothrow_default_constructible_v>) - requires std::is_default_constructible_v> + constexpr rvariant() noexcept(std::is_nothrow_default_constructible_v) + requires std::is_default_constructible_v : base_type(std::in_place_index<0>) // value-initialized {} @@ -840,9 +840,9 @@ IRIS_RVARIANT_ALWAYS_THROWING_UNREACHABLE_END template requires (I < sizeof...(Ts)) && - std::is_constructible_v, Args...> + std::is_constructible_v constexpr explicit rvariant(std::in_place_index_t, Args&&... args) // NOLINT - noexcept(std::is_nothrow_constructible_v, Args...>) + noexcept(std::is_nothrow_constructible_v) : base_type(std::in_place_index, std::forward(args)...) {} @@ -850,9 +850,9 @@ IRIS_RVARIANT_ALWAYS_THROWING_UNREACHABLE_END template requires (I < sizeof...(Ts)) && - std::is_constructible_v, std::initializer_list&, Args...> + std::is_constructible_v&, Args...> constexpr explicit rvariant(std::in_place_index_t, std::initializer_list il, Args&&... args) // NOLINT - noexcept(std::is_nothrow_constructible_v, std::initializer_list&, Args...>) + noexcept(std::is_nothrow_constructible_v&, Args...>) : base_type(std::in_place_index, il, std::forward(args)...) {} @@ -879,20 +879,20 @@ IRIS_RVARIANT_ALWAYS_THROWING_UNREACHABLE_END } template - requires std::is_constructible_v, Args...> + requires std::is_constructible_v constexpr variant_alternative_t& emplace(Args&&... args) - noexcept(std::is_nothrow_constructible_v, Args...>) IRIS_LIFETIMEBOUND + noexcept(std::is_nothrow_constructible_v) IRIS_LIFETIMEBOUND { static_assert(I < sizeof...(Ts)); return base_type::template emplace_impl(std::forward(args)...); } template - requires std::is_constructible_v, std::initializer_list&, Args...> + requires std::is_constructible_v&, Args...> constexpr variant_alternative_t& emplace(std::initializer_list il, Args&&... args) - noexcept(std::is_nothrow_constructible_v, std::initializer_list&, Args...>) IRIS_LIFETIMEBOUND + noexcept(std::is_nothrow_constructible_v&, Args...>) IRIS_LIFETIMEBOUND { static_assert(I < sizeof...(Ts)); return base_type::template emplace_impl(il, std::forward(args)...); @@ -1193,7 +1193,7 @@ IRIS_RVARIANT_ALWAYS_THROWING_UNREACHABLE_END // ------------------------------------------------- template - requires detail::is_recursive_wrapper_like_v + requires is_recursive_wrapper_v [[nodiscard]] constexpr bool holds_alternative(rvariant const& v) noexcept = delete; template @@ -1294,19 +1294,19 @@ get(rvariant const&& v IRIS_LIFETIMEBOUND) } template - requires detail::is_recursive_wrapper_like_v + requires is_recursive_wrapper_v constexpr T& get(rvariant&) = delete; template - requires detail::is_recursive_wrapper_like_v + requires is_recursive_wrapper_v constexpr T&& get(rvariant&&) = delete; template - requires detail::is_recursive_wrapper_like_v + requires is_recursive_wrapper_v constexpr T const& get(rvariant const&) = delete; template - requires detail::is_recursive_wrapper_like_v + requires is_recursive_wrapper_v constexpr T const&& get(rvariant const&&) = delete; // ------------------------------------------------- @@ -1375,19 +1375,19 @@ unsafe_get(rvariant const&& v IRIS_LIFETIMEBOUND) noexcept } template - requires detail::is_recursive_wrapper_like_v + requires is_recursive_wrapper_v constexpr T& unsafe_get(rvariant&) = delete; template - requires detail::is_recursive_wrapper_like_v + requires is_recursive_wrapper_v constexpr T&& unsafe_get(rvariant&&) = delete; template - requires detail::is_recursive_wrapper_like_v + requires is_recursive_wrapper_v constexpr T const& unsafe_get(rvariant const&) = delete; template - requires detail::is_recursive_wrapper_like_v + requires is_recursive_wrapper_v constexpr T const&& unsafe_get(rvariant const&&) = delete; // --------------------------------------------- diff --git a/include/iris/rvariant/detail/rvariant_fwd.hpp b/include/iris/rvariant/rvariant_fwd.hpp similarity index 52% rename from include/iris/rvariant/detail/rvariant_fwd.hpp rename to include/iris/rvariant/rvariant_fwd.hpp index 8aee95a..47bcae0 100644 --- a/include/iris/rvariant/detail/rvariant_fwd.hpp +++ b/include/iris/rvariant/rvariant_fwd.hpp @@ -1,12 +1,10 @@ -#ifndef IRIS_ZZ_RVARIANT_DETAIL_RVARIANT_FWD_HPP -#define IRIS_ZZ_RVARIANT_DETAIL_RVARIANT_FWD_HPP +#ifndef IRIS_ZZ_RVARIANT_RVARIANT_FWD_HPP +#define IRIS_ZZ_RVARIANT_RVARIANT_FWD_HPP // SPDX-License-Identifier: MIT #include // IWYU pragma: keep -#include // IWYU pragma: keep - namespace iris { template @@ -18,6 +16,14 @@ class recursive_wrapper; template class recursive_wrapper_alloca; +template +inline constexpr bool is_recursive_wrapper_v = false; + +template +inline constexpr bool is_recursive_wrapper_v> = true; + +template +inline constexpr bool is_recursive_wrapper_v> = true; namespace detail { diff --git a/include/iris/rvariant/subset.hpp b/include/iris/rvariant/subset.hpp index d86dc04..b2c2321 100644 --- a/include/iris/rvariant/subset.hpp +++ b/include/iris/rvariant/subset.hpp @@ -5,8 +5,8 @@ #include // IWYU pragma: keep -#include #include +#include #include #include diff --git a/include/iris/rvariant/variant_helper.hpp b/include/iris/rvariant/variant_helper.hpp index 7267371..d20bc78 100644 --- a/include/iris/rvariant/variant_helper.hpp +++ b/include/iris/rvariant/variant_helper.hpp @@ -11,13 +11,12 @@ #include // IWYU pragma: keep -#include +#include #include -#include -#include #include -#include + +#include // IWYU pragma: keep namespace iris { @@ -72,11 +71,6 @@ struct variant_size> : std::integral_constant -constexpr bool is_recursive_wrapper_like_v = - is_ttp_specialization_of_v || - is_ttp_specialization_of_v; - template struct unwrap_recursive_impl { @@ -119,10 +113,10 @@ struct unwrap_recursive_fn [[nodiscard]] IRIS_FORCEINLINE static constexpr auto&& operator()(T&& o IRIS_LIFETIMEBOUND) noexcept { - if constexpr (is_recursive_wrapper_like_v>) { - return *std::forward(o); + if constexpr (is_recursive_wrapper_v>) { + return *static_cast(o); } else { - return std::forward(o); + return static_cast(o); } } }; diff --git a/include/iris/type_list.hpp b/include/iris/type_list.hpp index e495b69..b4f19b5 100644 --- a/include/iris/type_list.hpp +++ b/include/iris/type_list.hpp @@ -61,6 +61,62 @@ struct concat_type_list, type_list, Rest...> namespace detail { +template +struct identity_bases : std::type_identity... +{ + template class TT> + using rebind = TT; +}; + +template +concept identity_base_of = requires(BasesT* bases) { + static_cast*>(bases); +}; + +template +struct unique_type_list_impl; + +template +struct unique_type_list_impl +{ + using type = BasesT; +}; + +template + requires identity_base_of +struct unique_type_list_impl + : unique_type_list_impl +{}; + +template + requires (!identity_base_of>) +struct unique_type_list_impl, T, Rest...> + : unique_type_list_impl, Rest...> +{}; + +} // detail + +template +struct unique_type_list; + +template<> +struct unique_type_list +{ + using type = type_list<>; +}; + +template +struct unique_type_list> +{ + using type = detail::unique_type_list_impl< + detail::identity_bases<>, Ts... + >::type::template rebind; +}; + +// ---------------------------------------------------------- + +namespace detail { + template struct do_pack_indexing; diff --git a/include/iris/type_traits.hpp b/include/iris/type_traits.hpp index 05098f5..a27fb64 100644 --- a/include/iris/type_traits.hpp +++ b/include/iris/type_traits.hpp @@ -8,8 +8,6 @@ #include // IWYU pragma: export #include // IWYU pragma: export -#include - #include #include // IWYU pragma: export #include @@ -189,6 +187,11 @@ template<> struct is_trivially_swappable : std::true_type {}; template inline constexpr bool is_trivially_swappable_v = is_trivially_swappable::value; +// ---------------------------------------------- + +template +concept weakly_assignable_from = std::is_assignable_v; + namespace detail { diff --git a/test/type_list.cpp b/test/type_list.cpp index ac5de05..19bb5e9 100644 --- a/test/type_list.cpp +++ b/test/type_list.cpp @@ -8,6 +8,7 @@ using iris::type_list; using iris::concat_type_list; +using iris::unique_type_list; TEST_CASE("type_list") { @@ -23,6 +24,35 @@ TEST_CASE("type_list") STATIC_CHECK(std::same_as, type_list<>, type_list<>>::type, type_list>); STATIC_CHECK(std::same_as, type_list, type_list<>>::type, type_list>); STATIC_CHECK(std::same_as, type_list<>, type_list>::type, type_list>); + + // ----------------------------------------------------------- + + STATIC_CHECK(std::same_as::type, type_list<>>); + STATIC_CHECK(std::same_as>::type, type_list<>>); + + struct A{}; + struct B{}; + + STATIC_CHECK(std::same_as>::type, type_list>); + + STATIC_CHECK(std::same_as>::type, type_list>); + STATIC_CHECK(std::same_as>::type, type_list>); + STATIC_CHECK(std::same_as>::type, type_list>); + + STATIC_CHECK(std::same_as>::type, type_list>); + STATIC_CHECK(std::same_as>::type, type_list>); + STATIC_CHECK(std::same_as>::type, type_list>); + + STATIC_CHECK(std::same_as>::type, type_list>); + STATIC_CHECK(std::same_as>::type, type_list>); + STATIC_CHECK(std::same_as>::type, type_list>); + + struct C{}; + + STATIC_CHECK(std::same_as>::type, type_list>); + STATIC_CHECK(std::same_as>::type, type_list>); + STATIC_CHECK(std::same_as>::type, type_list>); + STATIC_CHECK(std::same_as>::type, type_list>); } TEST_CASE("pack_indexing")