Skip to content

Commit 98f6dd4

Browse files
committed
Added generic "is empty" support via is void or synonym is empty
1 parent e119ada commit 98f6dd4

5 files changed

+124
-1
lines changed

include/cpp2util.h

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,10 @@ class out {
481481
// when customizing is/as for std::variant
482482
static std::nullptr_t nonesuch = nullptr;
483483

484+
// For designating "holds no value" -- used only with is, not as
485+
// TODO: Does this really warrant a new synonym? Perhaps "is void" is enough
486+
using empty = void;
487+
484488
template< typename C, typename X >
485489
auto is( X const& ) -> bool {
486490
return false;
@@ -510,6 +514,12 @@ auto is( X const* x ) -> bool {
510514
return dynamic_cast<C const&>(x) != nullptr;
511515
}
512516

517+
template< typename C, typename X >
518+
requires (requires (X x) { *x; X(); } && std::is_same_v<C, empty>)
519+
auto is( X const& x ) -> bool {
520+
return x == X();
521+
}
522+
513523

514524
//-------------------------------------------------------------------------------------------------------------
515525
// Built-in as (partial)
@@ -570,6 +580,7 @@ template<typename... Ts>
570580
constexpr auto operator_is( std::variant<Ts...> const& x ) {
571581
return x.index();
572582
}
583+
573584
template<size_t I, typename... Ts>
574585
constexpr auto operator_as( std::variant<Ts...> const& x ) -> auto&& {
575586
if constexpr (I < std::variant_size_v<std::variant<Ts...>>) {
@@ -580,6 +591,10 @@ constexpr auto operator_as( std::variant<Ts...> const& x ) -> auto&& {
580591
}
581592
}
582593

594+
// A helper for is...
595+
template <class T, class... Ts>
596+
inline constexpr auto is_any = std::disjunction_v<std::is_same<T, Ts>...> {};
597+
583598
template<typename T, typename... Ts>
584599
auto is( std::variant<Ts...> const& x ) {
585600
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<0>(x)), T >) if (x.index() == 0) return true;
@@ -592,6 +607,11 @@ auto is( std::variant<Ts...> const& x ) {
592607
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<7>(x)), T >) if (x.index() == 7) return true;
593608
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<8>(x)), T >) if (x.index() == 8) return true;
594609
if constexpr (std::is_same_v< CPP2_TYPEOF(operator_as<9>(x)), T >) if (x.index() == 9) return true;
610+
if constexpr (std::is_same_v< T, empty > ) {
611+
if (x.valueless_by_exception()) return true;
612+
// Need to guard this with is_any otherwise the get_if is illegal
613+
if constexpr (is_any<std::monostate, Ts...>) return std::get_if<std::monostate>(&x) != nullptr;
614+
}
595615
return false;
596616
}
597617

@@ -615,10 +635,15 @@ auto as( std::variant<Ts...> const& x ) {
615635
// std::any is and as
616636
//
617637
template<typename T, typename X>
618-
requires (std::is_same_v<X,std::any> && !std::is_same_v<T,std::any>)
638+
requires (std::is_same_v<X,std::any> && !std::is_same_v<T,std::any> && !std::is_same_v<T,empty>)
619639
constexpr auto is( X const& x ) -> bool
620640
{ return x.type() == typeid(T); }
621641

642+
template<typename T, typename X>
643+
requires (std::is_same_v<X,std::any> && std::is_same_v<T,empty>)
644+
constexpr auto is( X const& x ) -> bool
645+
{ return !x.has_value(); }
646+
622647
template<typename T, typename X>
623648
requires (!std::is_reference_v<T> && std::is_same_v<X,std::any> && !std::is_same_v<T,std::any>)
624649
constexpr auto as( X const& x ) -> T
@@ -633,6 +658,11 @@ template<typename T, typename X>
633658
constexpr auto is( X const& x ) -> bool
634659
{ return x.has_value(); }
635660

661+
template<typename T, typename U>
662+
requires std::is_same_v<T,empty>
663+
constexpr auto is( std::optional<U> const& x ) -> bool
664+
{ return !x.has_value(); }
665+
636666
template<typename T, typename X>
637667
requires std::is_same_v<X,std::optional<T>>
638668
constexpr auto as( X const& x ) -> auto&&
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
2+
main: () -> int = {
3+
p: std::unique_ptr<int> = ();
4+
i: std::vector<int>::iterator = ();
5+
v: std::variant<std::monostate, int, std::string> = ();
6+
a: std::any = ();
7+
o: std::optional<std::string> = ();
8+
9+
std::cout << "\nAll these cases satisfy \"VOYDE AND EMPTIE\"\n";
10+
11+
test_generic(p);
12+
test_generic(i);
13+
test_generic(v);
14+
test_generic(a);
15+
test_generic(o);
16+
}
17+
18+
test_generic: ( x: _ ) = {
19+
std::cout
20+
<< "\n" << typeid(x).name() << "\n ..."
21+
<< inspect x -> std::string {
22+
is void = " VOYDE AND EMPTIE";
23+
is _ = " no match";
24+
}
25+
<< "\n";
26+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// ----- Cpp2 support -----
2+
#define CPP2_USE_MODULES Yes
3+
#include "cpp2util.h"
4+
5+
6+
#line 2 "pure2-inspect-generic-void-empty-with-variant-any-optional.cpp2"
7+
[[nodiscard]] auto main() -> int;
8+
#line 18 "pure2-inspect-generic-void-empty-with-variant-any-optional.cpp2"
9+
auto test_generic(auto const& x) -> void;
10+
11+
//=== Cpp2 definitions ==========================================================
12+
13+
#line 1 "pure2-inspect-generic-void-empty-with-variant-any-optional.cpp2"
14+
15+
[[nodiscard]] auto main() -> int{
16+
std::unique_ptr<int> p { };
17+
std::vector<int>::iterator i { };
18+
std::variant<std::monostate,int,std::string> v { };
19+
std::any a { };
20+
std::optional<std::string> o { };
21+
22+
std::cout << "\nAll these cases satisfy \"VOYDE AND EMPTIE\"\n";
23+
24+
test_generic(p);
25+
test_generic(i);
26+
test_generic(v);
27+
test_generic(a);
28+
test_generic(o);
29+
}
30+
31+
auto test_generic(auto const& x) -> void{
32+
std::cout
33+
<< "\n" << typeid(x).name() << "\n ..."
34+
<< [&] () -> std::string { auto&& __expr = x;
35+
if (cpp2::is<void>(__expr)) { if constexpr( requires{" VOYDE AND EMPTIE";} ) if constexpr( std::is_convertible_v<CPP2_TYPEOF(" VOYDE AND EMPTIE"),std::string> ) return " VOYDE AND EMPTIE"; else return std::string{}; else return std::string{}; }
36+
else return " no match"; }
37+
()
38+
<< "\n";
39+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
2+
main: () -> int = {
3+
p: std::unique_ptr<int> = ();
4+
i: std::vector<int>::iterator = ();
5+
v: std::variant<std::monostate, int, std::string> = ();
6+
a: std::any = ();
7+
o: std::optional<std::string> = ();
8+
9+
std::cout << "\nAll these cases satisfy \"VOYDE AND EMPTIE\"\n";
10+
11+
test_generic(p);
12+
test_generic(i);
13+
test_generic(v);
14+
test_generic(a);
15+
test_generic(o);
16+
}
17+
18+
test_generic: ( x: _ ) = {
19+
std::cout
20+
<< "\n" << typeid(x).name() << "\n ..."
21+
<< inspect x -> std::string {
22+
is void = " VOYDE AND EMPTIE";
23+
is _ = " no match";
24+
}
25+
<< "\n";
26+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pure2-inspect-generic-void-empty-with-variant-any-optional.cpp2... ok (all Cpp2, passes safety checks)
2+

0 commit comments

Comments
 (0)