Skip to content

Commit da9c66c

Browse files
committed
Refactor of is() - part 2 (std::variant)
1 parent f803109 commit da9c66c

File tree

1 file changed

+145
-85
lines changed

1 file changed

+145
-85
lines changed

include/cpp2util.h

Lines changed: 145 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,11 @@ concept specialization_of_template_type_and_nttp = requires (X x) {
379379
template <template <typename...> class C>
380380
concept type_trait = std::derived_from<C<int>, std::true_type> || std::derived_from<C<int>, std::false_type>;
381381

382+
template<typename X>
383+
concept boolean_testable = std::convertible_to<X, bool> && requires(X&& x) {
384+
{ !std::forward<X>(x) } -> std::convertible_to<bool>;
385+
};
386+
382387
template <typename X>
383388
concept polymorphic = std::is_polymorphic_v<std::remove_cvref_t<X>>;
384389

@@ -484,6 +489,66 @@ struct aligned_storage {
484489
alignas(Align) unsigned char data[Len];
485490
};
486491

492+
//-----------------------------------------------------------------------
493+
//
494+
// A type_find_if for iterating over types in parameter packs
495+
//
496+
// Note: the current implementation is a workaround for clang-12 internal error.
497+
// Original implementation does not need type_it and is implemented
498+
// using lambda with explicit parameter type list in the following way:
499+
//
500+
// template <typename... Ts, typename F>
501+
// constexpr auto type_find_if(F&& fun)
502+
// {
503+
// std::size_t found = std::variant_npos;
504+
// [&]<std::size_t... Is>(std::index_sequence<Is...>){
505+
// if constexpr ((requires { {CPP2_FORWARD(fun).template operator()<Is, Ts>()} -> std::convertible_to<bool>;} && ...)) {
506+
// (((CPP2_FORWARD(fun).template operator()<Is, Ts>()) && (found = Is, true)) || ...);
507+
// }
508+
// }(std::index_sequence_for<Ts...>());
509+
// return found;
510+
// }
511+
//
512+
// The workaround is not needed in gcc-12.1+, clang-13+, msvc 19.29+
513+
//
514+
// Note2: the internal if constexpr could have else with static_assert.
515+
// Unfortunatelly I cannot make it work on MSVC.
516+
//
517+
//-----------------------------------------------------------------------
518+
//
519+
template <std::size_t Index, typename T>
520+
struct type_it {
521+
using type = T;
522+
inline static const std::size_t index = Index;
523+
};
524+
525+
template <typename... Ts, typename F>
526+
constexpr auto type_find_if(F&& fun)
527+
{
528+
std::size_t found = std::variant_npos;
529+
[&]<std::size_t... Is>(std::index_sequence<Is...>){
530+
if constexpr ((requires { {CPP2_FORWARD(fun)(type_it<Is, Ts>{})} -> boolean_testable;} && ...)) {
531+
((CPP2_FORWARD(fun)(type_it<Is, Ts>{}) && (found = Is, true)) || ...);
532+
}
533+
}(std::index_sequence_for<Ts...>());
534+
return found;
535+
}
536+
537+
template <typename F, template<typename...> class C, typename... Ts>
538+
constexpr auto type_find_if(C<Ts...>, F&& fun)
539+
{
540+
return type_find_if<Ts...>(CPP2_FORWARD(fun));
541+
}
542+
543+
template <typename T, typename... Ts>
544+
constexpr auto variant_contains_type(std::variant<Ts...>)
545+
{
546+
if constexpr (is_any<T, Ts...>) {
547+
return std::true_type{};
548+
} else {
549+
return std::false_type{};
550+
}
551+
}
487552

488553
//-----------------------------------------------------------------------
489554
//
@@ -849,6 +914,26 @@ using in =
849914
>;
850915

851916

917+
template<class T, class U>
918+
[[nodiscard]] constexpr auto&& forward_like(U&& x) noexcept
919+
{
920+
constexpr bool is_adding_const = std::is_const_v<std::remove_reference_t<T>>;
921+
if constexpr (std::is_lvalue_reference_v<T&&>)
922+
{
923+
if constexpr (is_adding_const)
924+
return std::as_const(x);
925+
else
926+
return static_cast<U&>(x);
927+
}
928+
else
929+
{
930+
if constexpr (is_adding_const)
931+
return std::move(std::as_const(x));
932+
else
933+
return std::move(x);
934+
}
935+
}
936+
852937
//-----------------------------------------------------------------------
853938
//
854939
// Initialization: These are closely related...
@@ -1615,104 +1700,79 @@ constexpr auto operator_as( std::variant<Ts...> const& x ) -> decltype(auto) {
16151700
}
16161701
}
16171702

1703+
//-------------------------------------------------------------------------------------------------------------
1704+
// forward declarations needed for recursive calls
1705+
//
16181706

1619-
// is Type
1707+
template<specialization_of_template<std::variant> T, typename C>
1708+
constexpr auto is( T&& x, C&& value );
1709+
1710+
// std::variant variable is Template
16201711
//
1621-
template<typename... Ts>
1622-
constexpr auto operator_is( std::variant<Ts...> const& x ) {
1623-
return x.index();
1712+
1713+
template<template <typename...> class C, specialization_of_template<std::variant> T>
1714+
requires (!specialization_of_template<T, C>)
1715+
constexpr auto is( T&& x ) {
1716+
return type_find_if(x, [&]<typename It>(It const&) -> bool {
1717+
if (x.index() == It::index) { return is<C>(forward_like<T>(std::get<It::index>(x)));}
1718+
return false;
1719+
}) != std::variant_npos;
16241720
}
16251721

1626-
template<typename T, typename... Ts>
1627-
auto is( std::variant<Ts...> const& x );
1722+
template <template <typename...> class C, typename... Ts>
1723+
requires std::same_as<C<Ts...>, std::variant<Ts...>>
1724+
constexpr auto is( std::variant<Ts...> const& ) -> std::true_type {
1725+
return {};
1726+
}
16281727

1728+
template<template <typename, auto...> class C, specialization_of_template<std::variant> T>
1729+
constexpr auto is( T&& x ) {
1730+
return type_find_if(x, [&]<typename It>(It const&) -> bool {
1731+
if (x.index() == It::index) { return is<C>(forward_like<T>(std::get<It::index>(x)));}
1732+
return false;
1733+
}) != std::variant_npos || specialization_of_template_type_and_nttp<T, C>;
1734+
}
16291735

1630-
// is Value
1736+
// std::variant variable is Value
16311737
//
1632-
template<typename... Ts>
1633-
constexpr auto is( std::variant<Ts...> const& x, auto&& value ) -> bool
1634-
{
1635-
// Predicate case
1636-
if constexpr (requires{ bool{ value(operator_as< 0>(x)) }; }) { if (x.index() == 0) return value(operator_as< 0>(x)); }
1637-
else if constexpr (requires{ bool{ value(operator_as< 1>(x)) }; }) { if (x.index() == 1) return value(operator_as< 1>(x)); }
1638-
else if constexpr (requires{ bool{ value(operator_as< 2>(x)) }; }) { if (x.index() == 2) return value(operator_as< 2>(x)); }
1639-
else if constexpr (requires{ bool{ value(operator_as< 3>(x)) }; }) { if (x.index() == 3) return value(operator_as< 3>(x)); }
1640-
else if constexpr (requires{ bool{ value(operator_as< 4>(x)) }; }) { if (x.index() == 4) return value(operator_as< 4>(x)); }
1641-
else if constexpr (requires{ bool{ value(operator_as< 5>(x)) }; }) { if (x.index() == 5) return value(operator_as< 5>(x)); }
1642-
else if constexpr (requires{ bool{ value(operator_as< 6>(x)) }; }) { if (x.index() == 6) return value(operator_as< 6>(x)); }
1643-
else if constexpr (requires{ bool{ value(operator_as< 7>(x)) }; }) { if (x.index() == 7) return value(operator_as< 7>(x)); }
1644-
else if constexpr (requires{ bool{ value(operator_as< 8>(x)) }; }) { if (x.index() == 8) return value(operator_as< 8>(x)); }
1645-
else if constexpr (requires{ bool{ value(operator_as< 9>(x)) }; }) { if (x.index() == 9) return value(operator_as< 9>(x)); }
1646-
else if constexpr (requires{ bool{ value(operator_as<10>(x)) }; }) { if (x.index() == 10) return value(operator_as<10>(x)); }
1647-
else if constexpr (requires{ bool{ value(operator_as<11>(x)) }; }) { if (x.index() == 11) return value(operator_as<11>(x)); }
1648-
else if constexpr (requires{ bool{ value(operator_as<12>(x)) }; }) { if (x.index() == 12) return value(operator_as<12>(x)); }
1649-
else if constexpr (requires{ bool{ value(operator_as<13>(x)) }; }) { if (x.index() == 13) return value(operator_as<13>(x)); }
1650-
else if constexpr (requires{ bool{ value(operator_as<14>(x)) }; }) { if (x.index() == 14) return value(operator_as<14>(x)); }
1651-
else if constexpr (requires{ bool{ value(operator_as<15>(x)) }; }) { if (x.index() == 15) return value(operator_as<15>(x)); }
1652-
else if constexpr (requires{ bool{ value(operator_as<16>(x)) }; }) { if (x.index() == 16) return value(operator_as<16>(x)); }
1653-
else if constexpr (requires{ bool{ value(operator_as<17>(x)) }; }) { if (x.index() == 17) return value(operator_as<17>(x)); }
1654-
else if constexpr (requires{ bool{ value(operator_as<18>(x)) }; }) { if (x.index() == 18) return value(operator_as<18>(x)); }
1655-
else if constexpr (requires{ bool{ value(operator_as<19>(x)) }; }) { if (x.index() == 19) return value(operator_as<19>(x)); }
1656-
else if constexpr (std::is_function_v<decltype(value)> || requires{ &value.operator(); }) {
1657-
return false;
1658-
}
16591738

1660-
// Value case
1661-
else {
1662-
if constexpr (requires{ bool{ operator_as< 0>(x) == value }; }) { if (x.index() == 0) return operator_as< 0>(x) == value; }
1663-
if constexpr (requires{ bool{ operator_as< 1>(x) == value }; }) { if (x.index() == 1) return operator_as< 1>(x) == value; }
1664-
if constexpr (requires{ bool{ operator_as< 2>(x) == value }; }) { if (x.index() == 2) return operator_as< 2>(x) == value; }
1665-
if constexpr (requires{ bool{ operator_as< 3>(x) == value }; }) { if (x.index() == 3) return operator_as< 3>(x) == value; }
1666-
if constexpr (requires{ bool{ operator_as< 4>(x) == value }; }) { if (x.index() == 4) return operator_as< 4>(x) == value; }
1667-
if constexpr (requires{ bool{ operator_as< 5>(x) == value }; }) { if (x.index() == 5) return operator_as< 5>(x) == value; }
1668-
if constexpr (requires{ bool{ operator_as< 6>(x) == value }; }) { if (x.index() == 6) return operator_as< 6>(x) == value; }
1669-
if constexpr (requires{ bool{ operator_as< 7>(x) == value }; }) { if (x.index() == 7) return operator_as< 7>(x) == value; }
1670-
if constexpr (requires{ bool{ operator_as< 8>(x) == value }; }) { if (x.index() == 8) return operator_as< 8>(x) == value; }
1671-
if constexpr (requires{ bool{ operator_as< 9>(x) == value }; }) { if (x.index() == 9) return operator_as< 9>(x) == value; }
1672-
if constexpr (requires{ bool{ operator_as<10>(x) == value }; }) { if (x.index() == 10) return operator_as<10>(x) == value; }
1673-
if constexpr (requires{ bool{ operator_as<11>(x) == value }; }) { if (x.index() == 11) return operator_as<11>(x) == value; }
1674-
if constexpr (requires{ bool{ operator_as<12>(x) == value }; }) { if (x.index() == 12) return operator_as<12>(x) == value; }
1675-
if constexpr (requires{ bool{ operator_as<13>(x) == value }; }) { if (x.index() == 13) return operator_as<13>(x) == value; }
1676-
if constexpr (requires{ bool{ operator_as<14>(x) == value }; }) { if (x.index() == 14) return operator_as<14>(x) == value; }
1677-
if constexpr (requires{ bool{ operator_as<15>(x) == value }; }) { if (x.index() == 15) return operator_as<15>(x) == value; }
1678-
if constexpr (requires{ bool{ operator_as<16>(x) == value }; }) { if (x.index() == 16) return operator_as<16>(x) == value; }
1679-
if constexpr (requires{ bool{ operator_as<17>(x) == value }; }) { if (x.index() == 17) return operator_as<17>(x) == value; }
1680-
if constexpr (requires{ bool{ operator_as<18>(x) == value }; }) { if (x.index() == 18) return operator_as<18>(x) == value; }
1681-
if constexpr (requires{ bool{ operator_as<19>(x) == value }; }) { if (x.index() == 19) return operator_as<19>(x) == value; }
1739+
template<specialization_of_template<std::variant> T, typename C>
1740+
constexpr auto is( T&& x, C&& value ) {
1741+
if constexpr (std::same_as<T,C>) {
1742+
return x == value;
1743+
} else {
1744+
return type_find_if(x, [&]<typename It>(It const&) -> bool {
1745+
if (x.index() == It::index) { return is(forward_like<T>(std::get<It::index>(x)), std::forward<C>(value));}
1746+
return false;
1747+
}) != std::variant_npos;
16821748
}
1683-
return false;
16841749
}
16851750

1686-
1687-
// as
1751+
// std::variant variable is Type
16881752
//
1689-
template<typename T, typename... Ts>
1690-
auto is( std::variant<Ts...> const& x ) {
1691-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 0>(x)), T >) { if (x.index() == 0) return true; }
1692-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 1>(x)), T >) { if (x.index() == 1) return true; }
1693-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 2>(x)), T >) { if (x.index() == 2) return true; }
1694-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 3>(x)), T >) { if (x.index() == 3) return true; }
1695-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 4>(x)), T >) { if (x.index() == 4) return true; }
1696-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 5>(x)), T >) { if (x.index() == 5) return true; }
1697-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 6>(x)), T >) { if (x.index() == 6) return true; }
1698-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 7>(x)), T >) { if (x.index() == 7) return true; }
1699-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 8>(x)), T >) { if (x.index() == 8) return true; }
1700-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 9>(x)), T >) { if (x.index() == 9) return true; }
1701-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<10>(x)), T >) { if (x.index() == 10) return true; }
1702-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<11>(x)), T >) { if (x.index() == 11) return true; }
1703-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<12>(x)), T >) { if (x.index() == 12) return true; }
1704-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<13>(x)), T >) { if (x.index() == 13) return true; }
1705-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<14>(x)), T >) { if (x.index() == 14) return true; }
1706-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<15>(x)), T >) { if (x.index() == 15) return true; }
1707-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<16>(x)), T >) { if (x.index() == 16) return true; }
1708-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<17>(x)), T >) { if (x.index() == 17) return true; }
1709-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<18>(x)), T >) { if (x.index() == 18) return true; }
1710-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<19>(x)), T >) { if (x.index() == 19) return true; }
1711-
if constexpr (std::is_same_v< T, empty > ) {
1712-
if (x.valueless_by_exception()) return true;
1713-
// Need to guard this with is_any otherwise the get_if is illegal
1714-
if constexpr (is_any<std::monostate, Ts...>) return std::get_if<std::monostate>(&x) != nullptr;
1753+
template<specialization_of_template<std::variant> T, specialization_of_template<std::variant> C>
1754+
constexpr auto is( C&& ) {
1755+
if constexpr (std::same_as<std::remove_cvref_t<T>, std::remove_cvref_t<C>>) {
1756+
return std::true_type{};
1757+
} else {
1758+
return std::false_type{};
17151759
}
1760+
}
1761+
1762+
template<typename C, specialization_of_template<std::variant> T>
1763+
auto is( T&& x ) {
1764+
return type_find_if(x, [&]<typename It>(It const&) -> bool {
1765+
if (x.index() == It::index) { return is<C>(std::get<It::index>(x));}
1766+
return false;
1767+
}) != std::variant_npos;
1768+
}
1769+
1770+
template<std::same_as<empty> C, specialization_of_template<std::variant> T>
1771+
auto is( T&& x ) {
1772+
if (x.valueless_by_exception())
1773+
return true;
1774+
if constexpr (requires { {variant_contains_type<std::monostate>(std::declval<T>())} -> std::same_as<std::true_type>; })
1775+
return std::get_if<std::monostate>(&x) != nullptr;
17161776
return false;
17171777
}
17181778

0 commit comments

Comments
 (0)