Skip to content

Commit c664b07

Browse files
committed
is(): refactor is() for variant
1 parent aa8f29c commit c664b07

File tree

1 file changed

+102
-100
lines changed

1 file changed

+102
-100
lines changed

include/cpp2util.h

Lines changed: 102 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,11 @@ concept specialization_of_template_type_and_nttp = requires (X x) {
655655
{ specialization_of_template_helper<C>(std::forward<X>(x)) } -> std::same_as<std::true_type>;
656656
};
657657

658+
template<typename X>
659+
concept boolean_testable = std::convertible_to<X, bool> && requires(X&& x) {
660+
{ !std::forward<X>(x) } -> std::convertible_to<bool>;
661+
};
662+
658663
template <typename X>
659664
concept dereferencable = requires (X x) { *x; };
660665

@@ -738,6 +743,67 @@ auto pointer_eq(T const* a, T const* b) {
738743
return std::compare_three_way{}(a, b) == std::strong_ordering::equal;
739744
}
740745

746+
//-----------------------------------------------------------------------
747+
//
748+
// A type_find_if for iterating over types in parameter packs
749+
//
750+
// Note: the current implementation is a workaround for clang-12 internal error.
751+
// Original implementation does not need type_it and is implemented
752+
// using lambda with explicit parameter type list in the following way:
753+
//
754+
// template <typename... Ts, typename F>
755+
// constexpr auto type_find_if(F&& fun)
756+
// {
757+
// std::size_t found = std::variant_npos;
758+
// [&]<std::size_t... Is>(std::index_sequence<Is...>){
759+
// if constexpr ((requires { {CPP2_FORWARD(fun).template operator()<Is, Ts>()} -> std::convertible_to<bool>;} && ...)) {
760+
// (((CPP2_FORWARD(fun).template operator()<Is, Ts>()) && (found = Is, true)) || ...);
761+
// }
762+
// }(std::index_sequence_for<Ts...>());
763+
// return found;
764+
// }
765+
//
766+
// The workaround is not needed in gcc-12.1+, clang-13+, msvc 19.29+
767+
//
768+
// Note2: the internal if constexpr could have else with static_assert.
769+
// Unfortunatelly I cannot make it work on MSVC.
770+
//
771+
//-----------------------------------------------------------------------
772+
//
773+
template <std::size_t Index, typename T>
774+
struct type_it {
775+
using type = T;
776+
inline static const std::size_t index = Index;
777+
};
778+
779+
template <typename... Ts, typename F>
780+
constexpr auto type_find_if(F&& fun)
781+
{
782+
std::size_t found = std::variant_npos;
783+
[&]<std::size_t... Is>(std::index_sequence<Is...>){
784+
if constexpr ((requires { {CPP2_FORWARD(fun)(type_it<Is, Ts>{})} -> boolean_testable;} && ...)) {
785+
((CPP2_FORWARD(fun)(type_it<Is, Ts>{}) && (found = Is, true)) || ...);
786+
}
787+
}(std::index_sequence_for<Ts...>());
788+
return found;
789+
}
790+
791+
template <typename F, template<typename...> class C, typename... Ts>
792+
constexpr auto type_find_if(C<Ts...> const&, F&& fun)
793+
{
794+
return type_find_if<Ts...>(CPP2_FORWARD(fun));
795+
}
796+
797+
template <typename T, typename... Ts>
798+
constexpr auto variant_contains_type(std::variant<Ts...>)
799+
{
800+
if constexpr (is_any<T, Ts...>) {
801+
return std::true_type{};
802+
} else {
803+
return std::false_type{};
804+
}
805+
}
806+
741807

742808
//-----------------------------------------------------------------------
743809
//
@@ -1650,6 +1716,28 @@ constexpr auto is( X const& x ) -> auto {
16501716
{
16511717
return Dynamic_cast<C const*>(&x) != nullptr;
16521718
}
1719+
else if constexpr (
1720+
specialization_of_template<X, std::variant>
1721+
)
1722+
{
1723+
if (x.valueless_by_exception()) {
1724+
return std::is_same_v<C, empty>;
1725+
}
1726+
if constexpr (
1727+
std::is_same_v<C, empty>
1728+
)
1729+
{
1730+
if constexpr (requires { {variant_contains_type<std::monostate>(std::declval<X>())} -> std::same_as<std::true_type>; }) {
1731+
return std::get_if<std::monostate>(&x) != nullptr;
1732+
}
1733+
}
1734+
return type_find_if(x, [&]<typename It>(It const&) -> bool {
1735+
if constexpr (It::index < 20) {
1736+
if (x.index() == It::index) { return std::is_same_v<C, std::variant_alternative_t<It::index, X>>;}
1737+
}
1738+
return false;
1739+
}) != std::variant_npos;
1740+
}
16531741
else if constexpr (
16541742
(
16551743
std::is_same_v<X, std::nullptr_t>
@@ -1700,6 +1788,20 @@ inline constexpr auto is( auto const& x, auto&& value ) -> bool
17001788
else if constexpr (requires{ bool{x == value}; }) {
17011789
return x == value;
17021790
}
1791+
else if constexpr (specialization_of_template<decltype(x), std::variant> ) {
1792+
return type_find_if(x, [&]<typename It>(It const&) -> bool {
1793+
if constexpr (It::index < 20) { // TODO: remove after refactor
1794+
if (x.index() == It::index) {
1795+
if constexpr (valid_predicate<decltype(value), decltype(std::get<It::index>(x))>) {
1796+
return value(std::get<It::index>(x));
1797+
} else if constexpr ( requires { bool{std::get<It::index>(x) == value}; } ) {
1798+
return std::get<It::index>(x) == value;
1799+
}
1800+
}
1801+
}
1802+
return false;
1803+
}) != std::variant_npos;
1804+
}
17031805
return false;
17041806
}
17051807

@@ -1919,106 +2021,6 @@ constexpr auto operator_as( std::variant<Ts...> const& x ) -> decltype(auto) {
19192021
}
19202022

19212023

1922-
// is Type
1923-
//
1924-
template<typename... Ts>
1925-
constexpr auto operator_is( std::variant<Ts...> const& x ) {
1926-
return x.index();
1927-
}
1928-
1929-
template<typename T, typename... Ts>
1930-
auto is( std::variant<Ts...> const& x );
1931-
1932-
1933-
// is Value
1934-
//
1935-
template<typename... Ts>
1936-
constexpr auto is( std::variant<Ts...> const& x, auto&& value ) -> bool
1937-
{
1938-
// Predicate case
1939-
if constexpr (requires{ bool{ value(operator_as< 0>(x)) }; }) { if (x.index() == 0) return value(operator_as< 0>(x)); }
1940-
else if constexpr (requires{ bool{ value(operator_as< 1>(x)) }; }) { if (x.index() == 1) return value(operator_as< 1>(x)); }
1941-
else if constexpr (requires{ bool{ value(operator_as< 2>(x)) }; }) { if (x.index() == 2) return value(operator_as< 2>(x)); }
1942-
else if constexpr (requires{ bool{ value(operator_as< 3>(x)) }; }) { if (x.index() == 3) return value(operator_as< 3>(x)); }
1943-
else if constexpr (requires{ bool{ value(operator_as< 4>(x)) }; }) { if (x.index() == 4) return value(operator_as< 4>(x)); }
1944-
else if constexpr (requires{ bool{ value(operator_as< 5>(x)) }; }) { if (x.index() == 5) return value(operator_as< 5>(x)); }
1945-
else if constexpr (requires{ bool{ value(operator_as< 6>(x)) }; }) { if (x.index() == 6) return value(operator_as< 6>(x)); }
1946-
else if constexpr (requires{ bool{ value(operator_as< 7>(x)) }; }) { if (x.index() == 7) return value(operator_as< 7>(x)); }
1947-
else if constexpr (requires{ bool{ value(operator_as< 8>(x)) }; }) { if (x.index() == 8) return value(operator_as< 8>(x)); }
1948-
else if constexpr (requires{ bool{ value(operator_as< 9>(x)) }; }) { if (x.index() == 9) return value(operator_as< 9>(x)); }
1949-
else if constexpr (requires{ bool{ value(operator_as<10>(x)) }; }) { if (x.index() == 10) return value(operator_as<10>(x)); }
1950-
else if constexpr (requires{ bool{ value(operator_as<11>(x)) }; }) { if (x.index() == 11) return value(operator_as<11>(x)); }
1951-
else if constexpr (requires{ bool{ value(operator_as<12>(x)) }; }) { if (x.index() == 12) return value(operator_as<12>(x)); }
1952-
else if constexpr (requires{ bool{ value(operator_as<13>(x)) }; }) { if (x.index() == 13) return value(operator_as<13>(x)); }
1953-
else if constexpr (requires{ bool{ value(operator_as<14>(x)) }; }) { if (x.index() == 14) return value(operator_as<14>(x)); }
1954-
else if constexpr (requires{ bool{ value(operator_as<15>(x)) }; }) { if (x.index() == 15) return value(operator_as<15>(x)); }
1955-
else if constexpr (requires{ bool{ value(operator_as<16>(x)) }; }) { if (x.index() == 16) return value(operator_as<16>(x)); }
1956-
else if constexpr (requires{ bool{ value(operator_as<17>(x)) }; }) { if (x.index() == 17) return value(operator_as<17>(x)); }
1957-
else if constexpr (requires{ bool{ value(operator_as<18>(x)) }; }) { if (x.index() == 18) return value(operator_as<18>(x)); }
1958-
else if constexpr (requires{ bool{ value(operator_as<19>(x)) }; }) { if (x.index() == 19) return value(operator_as<19>(x)); }
1959-
else if constexpr (std::is_function_v<decltype(value)> || requires{ &value.operator(); }) {
1960-
return false;
1961-
}
1962-
1963-
// Value case
1964-
else {
1965-
if constexpr (requires{ bool{ operator_as< 0>(x) == value }; }) { if (x.index() == 0) return operator_as< 0>(x) == value; }
1966-
if constexpr (requires{ bool{ operator_as< 1>(x) == value }; }) { if (x.index() == 1) return operator_as< 1>(x) == value; }
1967-
if constexpr (requires{ bool{ operator_as< 2>(x) == value }; }) { if (x.index() == 2) return operator_as< 2>(x) == value; }
1968-
if constexpr (requires{ bool{ operator_as< 3>(x) == value }; }) { if (x.index() == 3) return operator_as< 3>(x) == value; }
1969-
if constexpr (requires{ bool{ operator_as< 4>(x) == value }; }) { if (x.index() == 4) return operator_as< 4>(x) == value; }
1970-
if constexpr (requires{ bool{ operator_as< 5>(x) == value }; }) { if (x.index() == 5) return operator_as< 5>(x) == value; }
1971-
if constexpr (requires{ bool{ operator_as< 6>(x) == value }; }) { if (x.index() == 6) return operator_as< 6>(x) == value; }
1972-
if constexpr (requires{ bool{ operator_as< 7>(x) == value }; }) { if (x.index() == 7) return operator_as< 7>(x) == value; }
1973-
if constexpr (requires{ bool{ operator_as< 8>(x) == value }; }) { if (x.index() == 8) return operator_as< 8>(x) == value; }
1974-
if constexpr (requires{ bool{ operator_as< 9>(x) == value }; }) { if (x.index() == 9) return operator_as< 9>(x) == value; }
1975-
if constexpr (requires{ bool{ operator_as<10>(x) == value }; }) { if (x.index() == 10) return operator_as<10>(x) == value; }
1976-
if constexpr (requires{ bool{ operator_as<11>(x) == value }; }) { if (x.index() == 11) return operator_as<11>(x) == value; }
1977-
if constexpr (requires{ bool{ operator_as<12>(x) == value }; }) { if (x.index() == 12) return operator_as<12>(x) == value; }
1978-
if constexpr (requires{ bool{ operator_as<13>(x) == value }; }) { if (x.index() == 13) return operator_as<13>(x) == value; }
1979-
if constexpr (requires{ bool{ operator_as<14>(x) == value }; }) { if (x.index() == 14) return operator_as<14>(x) == value; }
1980-
if constexpr (requires{ bool{ operator_as<15>(x) == value }; }) { if (x.index() == 15) return operator_as<15>(x) == value; }
1981-
if constexpr (requires{ bool{ operator_as<16>(x) == value }; }) { if (x.index() == 16) return operator_as<16>(x) == value; }
1982-
if constexpr (requires{ bool{ operator_as<17>(x) == value }; }) { if (x.index() == 17) return operator_as<17>(x) == value; }
1983-
if constexpr (requires{ bool{ operator_as<18>(x) == value }; }) { if (x.index() == 18) return operator_as<18>(x) == value; }
1984-
if constexpr (requires{ bool{ operator_as<19>(x) == value }; }) { if (x.index() == 19) return operator_as<19>(x) == value; }
1985-
}
1986-
return false;
1987-
}
1988-
1989-
1990-
// as
1991-
//
1992-
template<typename T, typename... Ts>
1993-
auto is( std::variant<Ts...> const& x ) {
1994-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 0>(x)), T >) { if (x.index() == 0) return true; }
1995-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 1>(x)), T >) { if (x.index() == 1) return true; }
1996-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 2>(x)), T >) { if (x.index() == 2) return true; }
1997-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 3>(x)), T >) { if (x.index() == 3) return true; }
1998-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 4>(x)), T >) { if (x.index() == 4) return true; }
1999-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 5>(x)), T >) { if (x.index() == 5) return true; }
2000-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 6>(x)), T >) { if (x.index() == 6) return true; }
2001-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 7>(x)), T >) { if (x.index() == 7) return true; }
2002-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 8>(x)), T >) { if (x.index() == 8) return true; }
2003-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 9>(x)), T >) { if (x.index() == 9) return true; }
2004-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<10>(x)), T >) { if (x.index() == 10) return true; }
2005-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<11>(x)), T >) { if (x.index() == 11) return true; }
2006-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<12>(x)), T >) { if (x.index() == 12) return true; }
2007-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<13>(x)), T >) { if (x.index() == 13) return true; }
2008-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<14>(x)), T >) { if (x.index() == 14) return true; }
2009-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<15>(x)), T >) { if (x.index() == 15) return true; }
2010-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<16>(x)), T >) { if (x.index() == 16) return true; }
2011-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<17>(x)), T >) { if (x.index() == 17) return true; }
2012-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<18>(x)), T >) { if (x.index() == 18) return true; }
2013-
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<19>(x)), T >) { if (x.index() == 19) return true; }
2014-
if constexpr (std::is_same_v< T, empty > ) {
2015-
if (x.valueless_by_exception()) return true;
2016-
// Need to guard this with is_any otherwise the get_if is illegal
2017-
if constexpr (is_any<std::monostate, Ts...>) return std::get_if<std::monostate>(&x) != nullptr;
2018-
}
2019-
return false;
2020-
}
2021-
20222024
template<typename T, typename... Ts>
20232025
auto as( std::variant<Ts...> && x ) -> decltype(auto) {
20242026
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as< 0>(x)), T >) { if (x.index() == 0) return operator_as<0>(x); }

0 commit comments

Comments
 (0)