Skip to content

Commit 78867f8

Browse files
filipsajdakhsutter
andauthored
is()/as(): refactor of is() and as() for variant to new design (part 2 of n) (#1203)
* is(): Add tests for variant * is(): Add test for is as value with variant * is(): refactor is() for variant * as(): refactor of as() for std::variant No functional changes The implementation still can handle only 20 types in variant. It will be changed in future Pull Requests. * is(): Add tests for variant (other platforms) * is(): Add test for is as value with variant (other platforms) * Fixup: remove the limits of number of types * Fixup: mixed-is-as-variant * Fixup: tests of mixed-is-as-variant when no limits * Minor editorial touchup * Move is() and as() for variant to separate functions * Fix compiler error - cannot use concept inline with auto * Fix tests --------- Co-authored-by: Herb Sutter <[email protected]>
1 parent 2e23597 commit 78867f8

File tree

59 files changed

+2941
-267
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+2941
-267
lines changed

include/cpp2util.h

Lines changed: 141 additions & 197 deletions
Large diffs are not rendered by default.
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
auto in(int min, int max) {
2+
return [=](int x){ return min <= x && x <= max; };
3+
}
4+
5+
test: (forward v) = {
6+
if v is (42) {
7+
std::cout << " 42";
8+
}
9+
if v is (24) {
10+
std::cout << " 24";
11+
}
12+
if v is (100) {
13+
std::cout << " 100";
14+
}
15+
if v is (-100) {
16+
std::cout << " -100";
17+
}
18+
if v is (314) {
19+
std::cout << " 314";
20+
}
21+
if v is (std::optional<int>(100)) {
22+
std::cout << " std::optional<int>(100)";
23+
}
24+
if v is (std::any(-100)) {
25+
std::cout << " std::any(-100)";
26+
}
27+
if v is (new<int>(1000)) {
28+
std::cout << " std::unique_ptr<int>(1000)";
29+
}
30+
i : int = 314;
31+
if v is (i&) {
32+
std::cout << " *int(314)";
33+
}
34+
if v is (in(0,100)) {
35+
std::cout << " in(0,100)";
36+
}
37+
std::cout << "\n---" << std::endl;
38+
}
39+
40+
my_variant: type == std::variant<std::monostate, int, int, std::optional<int>, std::any, *int, std::unique_ptr<int>>;
41+
42+
main: () -> int = {
43+
44+
v: std::variant<std::monostate, int, int, std::optional<int>, std::any, *int, std::unique_ptr<int>, my_variant> = ();
45+
46+
header(1, "std::monostate");
47+
v..emplace<0>();
48+
test(v);
49+
50+
header(1, "int(42)");
51+
v..emplace<1>(42);
52+
test(v);
53+
54+
header(1, "int(24)");
55+
v..emplace<2>(24);
56+
test(v);
57+
58+
header(1, "std::optional<int>(100)");
59+
v..emplace<3>(100);
60+
test(v);
61+
62+
header(1, "std::any(-100)");
63+
v..emplace<4>(-100);
64+
test(v);
65+
66+
i : int = 314;
67+
header(1, "*int(314)");
68+
v..emplace<5>(i&);
69+
test(v);
70+
71+
header(1, "std::unique_ptr<int>(1000)");
72+
v..emplace<6>(new<int>(1000));
73+
test(v);
74+
75+
header(1, "my_variant(std::monostate)");
76+
v..emplace<7>();
77+
test(v);
78+
79+
header(1, "my_variant(int(42))");
80+
v..emplace<7>();
81+
std::get<7>(v)..emplace<1>(42);
82+
test(v);
83+
84+
header(1, "my_variant(int(24))");
85+
v..emplace<7>();
86+
std::get<7>(v)..emplace<2>(24);
87+
test(v);
88+
89+
header(1, "my_variant(std::optional<int>(100))");
90+
v..emplace<7>();
91+
std::get<7>(v)..emplace<3>(100);
92+
test(v);
93+
94+
header(1, "my_variant(std::any(-100))");
95+
v..emplace<7>();
96+
std::get<7>(v)..emplace<4>(-100);
97+
test(v);
98+
99+
header(1, "my_variant(*int(314))");
100+
v..emplace<7>();
101+
std::get<7>(v)..emplace<5>(i&);
102+
test(v);
103+
104+
header(1, "my_variant(std::unique_ptr<int>(1000))");
105+
v..emplace<7>();
106+
std::get<7>(v)..emplace<6>(new<int>(1000));
107+
test(v);
108+
}
109+
110+
header: (lvl : int, msg: std::string) = {
111+
std::cout << std::string(lvl, '#') << " " << msg << std::endl;
112+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
test: (forward v) = {
2+
std::cout << "v is empty = (v is void)$" << std::endl;
3+
std::cout << "v is std::monostate = (v is std::monostate)$" << std::endl;
4+
std::cout << "v is X< 0> = (v is X< 0>)$,\t(v as X< 1>) = " << expect_no_throw(forward v, :(forward v) v as X<0>) << std::endl;
5+
std::cout << "v is X< 1> = (v is X< 1>)$,\t(v as X< 1>).to_string() = (expect_no_throw(forward v, :(forward v) -> std::string = { return (v as X< 1>).to_string();}))$" << std::endl;
6+
std::cout << "v is X<19> = (v is X<19>)$,\t(v as X<19>).to_string() = (expect_no_throw(forward v, :(forward v) -> std::string = { return (v as X<19>).to_string();}))$" << std::endl;
7+
std::cout << "v is X<20> = (v is X<20>)$,\t(v as X<20>) = " << expect_no_throw(forward v, :(forward v) v as X<20>) << std::endl;
8+
std::cout << std::endl;
9+
}
10+
11+
main: () -> int = {
12+
13+
v: std::variant<std::monostate,
14+
X< 1>, X< 2>, X< 3>, X< 4>, X< 5>, X< 6>, X< 7>, X< 8>, X< 9>, X<10>,
15+
X<11>, X<12>, X<13>, X<14>, X<15>, X<16>, X<17>, X<18>, X<19>, X<20> > = ();
16+
17+
header(1, "std::monostate");
18+
v..emplace<0>();
19+
run_tests(v);
20+
21+
header(1, "X<1>");
22+
v..emplace<1>();
23+
run_tests(v);
24+
25+
header(1, "X<19>");
26+
v..emplace<19>();
27+
run_tests(v);
28+
29+
header(1, "X<20>");
30+
v..emplace<20>();
31+
run_tests(v);
32+
33+
header(1, "X<10>(std::exception)");
34+
set_to_valueless_by_exception<10>(v);
35+
run_tests(v);
36+
37+
}
38+
39+
run_tests: (forward v) = {
40+
header(2, "v as lvalue reference");
41+
test(v);
42+
43+
header(2, "v as const lvalue reference");
44+
test(std::as_const(v));
45+
46+
header(2, "v as rvalue reference");
47+
test(move v);
48+
}
49+
50+
header: (lvl : int, msg: std::string) = {
51+
std::cout << std::string(lvl, '#') << " " << msg << "\n" << std::endl;
52+
}
53+
54+
template<int I>
55+
struct X {
56+
operator int() const { return I; }
57+
X() = default;
58+
X(std::exception const& e) { throw e; }
59+
auto to_string() const { return "X<" + std::to_string(I) + ">"; }
60+
};
61+
62+
template <std::size_t I>
63+
void set_to_valueless_by_exception(auto& v) try {
64+
v.template emplace<I>(std::runtime_error("make valueless"));
65+
} catch (...) {}
66+
67+
auto expect_no_throw(auto&& l) -> std::string try {
68+
if constexpr ( requires { { l() } -> std::convertible_to<std::string>; }) {
69+
return l();
70+
} else {
71+
l();
72+
return "works!";
73+
}
74+
} catch (std::exception const& e) {
75+
return e.what();
76+
} catch (...) {
77+
return "unknown exception!";
78+
}
79+
80+
auto expect_no_throw(auto&& v, auto&& l) -> std::string try {
81+
if constexpr ( requires { { l(v) } -> std::convertible_to<std::string>; }) {
82+
return l(v);
83+
} else {
84+
l(v);
85+
return "works!";
86+
}
87+
} catch (std::exception const& e) {
88+
return e.what();
89+
} catch (...) {
90+
return "unknown exception!";
91+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# std::monostate
2+
3+
---
4+
# int(42)
5+
42 in(0,100)
6+
---
7+
# int(24)
8+
24 in(0,100)
9+
---
10+
# std::optional<int>(100)
11+
100 std::optional<int>(100)
12+
---
13+
# std::any(-100)
14+
15+
---
16+
# *int(314)
17+
18+
---
19+
# std::unique_ptr<int>(1000)
20+
21+
---
22+
# my_variant(std::monostate)
23+
24+
---
25+
# my_variant(int(42))
26+
27+
---
28+
# my_variant(int(24))
29+
30+
---
31+
# my_variant(std::optional<int>(100))
32+
33+
---
34+
# my_variant(std::any(-100))
35+
36+
---
37+
# my_variant(*int(314))
38+
39+
---
40+
# my_variant(std::unique_ptr<int>(1000))
41+
42+
---
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
# std::monostate
2+
3+
## v as lvalue reference
4+
5+
v is empty = true
6+
v is std::monostate = true
7+
v is X< 0> = false, (v as X< 1>) = bad_variant_access
8+
v is X< 1> = false, (v as X< 1>).to_string() = bad_variant_access
9+
v is X<19> = false, (v as X<19>).to_string() = bad_variant_access
10+
v is X<20> = false, (v as X<20>) = bad_variant_access
11+
12+
## v as const lvalue reference
13+
14+
v is empty = true
15+
v is std::monostate = true
16+
v is X< 0> = false, (v as X< 1>) = bad_variant_access
17+
v is X< 1> = false, (v as X< 1>).to_string() = bad_variant_access
18+
v is X<19> = false, (v as X<19>).to_string() = bad_variant_access
19+
v is X<20> = false, (v as X<20>) = bad_variant_access
20+
21+
## v as rvalue reference
22+
23+
v is empty = true
24+
v is std::monostate = true
25+
v is X< 0> = false, (v as X< 1>) = bad_variant_access
26+
v is X< 1> = false, (v as X< 1>).to_string() = bad_variant_access
27+
v is X<19> = false, (v as X<19>).to_string() = bad_variant_access
28+
v is X<20> = false, (v as X<20>) = bad_variant_access
29+
30+
# X<1>
31+
32+
## v as lvalue reference
33+
34+
v is empty = false
35+
v is std::monostate = false
36+
v is X< 0> = false, (v as X< 1>) = bad_variant_access
37+
v is X< 1> = true, (v as X< 1>).to_string() = X<1>
38+
v is X<19> = false, (v as X<19>).to_string() = bad_variant_access
39+
v is X<20> = false, (v as X<20>) = bad_variant_access
40+
41+
## v as const lvalue reference
42+
43+
v is empty = false
44+
v is std::monostate = false
45+
v is X< 0> = false, (v as X< 1>) = bad_variant_access
46+
v is X< 1> = true, (v as X< 1>).to_string() = X<1>
47+
v is X<19> = false, (v as X<19>).to_string() = bad_variant_access
48+
v is X<20> = false, (v as X<20>) = bad_variant_access
49+
50+
## v as rvalue reference
51+
52+
v is empty = false
53+
v is std::monostate = false
54+
v is X< 0> = false, (v as X< 1>) = bad_variant_access
55+
v is X< 1> = true, (v as X< 1>).to_string() = X<1>
56+
v is X<19> = false, (v as X<19>).to_string() = bad_variant_access
57+
v is X<20> = false, (v as X<20>) = bad_variant_access
58+
59+
# X<19>
60+
61+
## v as lvalue reference
62+
63+
v is empty = false
64+
v is std::monostate = false
65+
v is X< 0> = false, (v as X< 1>) = bad_variant_access
66+
v is X< 1> = false, (v as X< 1>).to_string() = bad_variant_access
67+
v is X<19> = true, (v as X<19>).to_string() = X<19>
68+
v is X<20> = false, (v as X<20>) = bad_variant_access
69+
70+
## v as const lvalue reference
71+
72+
v is empty = false
73+
v is std::monostate = false
74+
v is X< 0> = false, (v as X< 1>) = bad_variant_access
75+
v is X< 1> = false, (v as X< 1>).to_string() = bad_variant_access
76+
v is X<19> = true, (v as X<19>).to_string() = X<19>
77+
v is X<20> = false, (v as X<20>) = bad_variant_access
78+
79+
## v as rvalue reference
80+
81+
v is empty = false
82+
v is std::monostate = false
83+
v is X< 0> = false, (v as X< 1>) = bad_variant_access
84+
v is X< 1> = false, (v as X< 1>).to_string() = bad_variant_access
85+
v is X<19> = true, (v as X<19>).to_string() = X<19>
86+
v is X<20> = false, (v as X<20>) = bad_variant_access
87+
88+
# X<20>
89+
90+
## v as lvalue reference
91+
92+
v is empty = false
93+
v is std::monostate = false
94+
v is X< 0> = false, (v as X< 1>) = bad_variant_access
95+
v is X< 1> = false, (v as X< 1>).to_string() = bad_variant_access
96+
v is X<19> = false, (v as X<19>).to_string() = bad_variant_access
97+
v is X<20> = true, (v as X<20>) = works!
98+
99+
## v as const lvalue reference
100+
101+
v is empty = false
102+
v is std::monostate = false
103+
v is X< 0> = false, (v as X< 1>) = bad_variant_access
104+
v is X< 1> = false, (v as X< 1>).to_string() = bad_variant_access
105+
v is X<19> = false, (v as X<19>).to_string() = bad_variant_access
106+
v is X<20> = true, (v as X<20>) = works!
107+
108+
## v as rvalue reference
109+
110+
v is empty = false
111+
v is std::monostate = false
112+
v is X< 0> = false, (v as X< 1>) = bad_variant_access
113+
v is X< 1> = false, (v as X< 1>).to_string() = bad_variant_access
114+
v is X<19> = false, (v as X<19>).to_string() = bad_variant_access
115+
v is X<20> = true, (v as X<20>) = works!
116+
117+
# X<10>(std::exception)
118+
119+
## v as lvalue reference
120+
121+
v is empty = true
122+
v is std::monostate = false
123+
v is X< 0> = false, (v as X< 1>) = bad_variant_access
124+
v is X< 1> = false, (v as X< 1>).to_string() = bad_variant_access
125+
v is X<19> = false, (v as X<19>).to_string() = bad_variant_access
126+
v is X<20> = false, (v as X<20>) = bad_variant_access
127+
128+
## v as const lvalue reference
129+
130+
v is empty = true
131+
v is std::monostate = false
132+
v is X< 0> = false, (v as X< 1>) = bad_variant_access
133+
v is X< 1> = false, (v as X< 1>).to_string() = bad_variant_access
134+
v is X<19> = false, (v as X<19>).to_string() = bad_variant_access
135+
v is X<20> = false, (v as X<20>) = bad_variant_access
136+
137+
## v as rvalue reference
138+
139+
v is empty = true
140+
v is std::monostate = false
141+
v is X< 0> = false, (v as X< 1>) = bad_variant_access
142+
v is X< 1> = false, (v as X< 1>).to_string() = bad_variant_access
143+
v is X<19> = false, (v as X<19>).to_string() = bad_variant_access
144+
v is X<20> = false, (v as X<20>) = bad_variant_access
145+
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
../../../include/cpp2util.h(1007) decltype(auto) cpp2::impl::assert_in_bounds(auto &&, std::source_location) [arg = 5, x:auto = std::vector<int>]: Bounds safety violation: out of bounds access attempt detected - attempted access at index 5, [min,max] range is [0,4]
1+
../../../include/cpp2util.h(1103) decltype(auto) cpp2::impl::assert_in_bounds(auto &&, std::source_location) [arg = 5, x:auto = std::vector<int>]: Bounds safety violation: out of bounds access attempt detected - attempted access at index 5, [min,max] range is [0,4]
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
../../../include/cpp2util.h(819) : Bounds safety violation
1+
../../../include/cpp2util.h(915) : Bounds safety violation

0 commit comments

Comments
 (0)