-
Notifications
You must be signed in to change notification settings - Fork 252
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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]>
- Loading branch information
1 parent
2e23597
commit 78867f8
Showing
59 changed files
with
2,941 additions
and
267 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
auto in(int min, int max) { | ||
return [=](int x){ return min <= x && x <= max; }; | ||
} | ||
|
||
test: (forward v) = { | ||
if v is (42) { | ||
std::cout << " 42"; | ||
} | ||
if v is (24) { | ||
std::cout << " 24"; | ||
} | ||
if v is (100) { | ||
std::cout << " 100"; | ||
} | ||
if v is (-100) { | ||
std::cout << " -100"; | ||
} | ||
if v is (314) { | ||
std::cout << " 314"; | ||
} | ||
if v is (std::optional<int>(100)) { | ||
std::cout << " std::optional<int>(100)"; | ||
} | ||
if v is (std::any(-100)) { | ||
std::cout << " std::any(-100)"; | ||
} | ||
if v is (new<int>(1000)) { | ||
std::cout << " std::unique_ptr<int>(1000)"; | ||
} | ||
i : int = 314; | ||
if v is (i&) { | ||
std::cout << " *int(314)"; | ||
} | ||
if v is (in(0,100)) { | ||
std::cout << " in(0,100)"; | ||
} | ||
std::cout << "\n---" << std::endl; | ||
} | ||
|
||
my_variant: type == std::variant<std::monostate, int, int, std::optional<int>, std::any, *int, std::unique_ptr<int>>; | ||
|
||
main: () -> int = { | ||
|
||
v: std::variant<std::monostate, int, int, std::optional<int>, std::any, *int, std::unique_ptr<int>, my_variant> = (); | ||
|
||
header(1, "std::monostate"); | ||
v..emplace<0>(); | ||
test(v); | ||
|
||
header(1, "int(42)"); | ||
v..emplace<1>(42); | ||
test(v); | ||
|
||
header(1, "int(24)"); | ||
v..emplace<2>(24); | ||
test(v); | ||
|
||
header(1, "std::optional<int>(100)"); | ||
v..emplace<3>(100); | ||
test(v); | ||
|
||
header(1, "std::any(-100)"); | ||
v..emplace<4>(-100); | ||
test(v); | ||
|
||
i : int = 314; | ||
header(1, "*int(314)"); | ||
v..emplace<5>(i&); | ||
test(v); | ||
|
||
header(1, "std::unique_ptr<int>(1000)"); | ||
v..emplace<6>(new<int>(1000)); | ||
test(v); | ||
|
||
header(1, "my_variant(std::monostate)"); | ||
v..emplace<7>(); | ||
test(v); | ||
|
||
header(1, "my_variant(int(42))"); | ||
v..emplace<7>(); | ||
std::get<7>(v)..emplace<1>(42); | ||
test(v); | ||
|
||
header(1, "my_variant(int(24))"); | ||
v..emplace<7>(); | ||
std::get<7>(v)..emplace<2>(24); | ||
test(v); | ||
|
||
header(1, "my_variant(std::optional<int>(100))"); | ||
v..emplace<7>(); | ||
std::get<7>(v)..emplace<3>(100); | ||
test(v); | ||
|
||
header(1, "my_variant(std::any(-100))"); | ||
v..emplace<7>(); | ||
std::get<7>(v)..emplace<4>(-100); | ||
test(v); | ||
|
||
header(1, "my_variant(*int(314))"); | ||
v..emplace<7>(); | ||
std::get<7>(v)..emplace<5>(i&); | ||
test(v); | ||
|
||
header(1, "my_variant(std::unique_ptr<int>(1000))"); | ||
v..emplace<7>(); | ||
std::get<7>(v)..emplace<6>(new<int>(1000)); | ||
test(v); | ||
} | ||
|
||
header: (lvl : int, msg: std::string) = { | ||
std::cout << std::string(lvl, '#') << " " << msg << std::endl; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
test: (forward v) = { | ||
std::cout << "v is empty = (v is void)$" << std::endl; | ||
std::cout << "v is std::monostate = (v is std::monostate)$" << std::endl; | ||
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; | ||
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; | ||
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; | ||
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; | ||
std::cout << std::endl; | ||
} | ||
|
||
main: () -> int = { | ||
|
||
v: std::variant<std::monostate, | ||
X< 1>, X< 2>, X< 3>, X< 4>, X< 5>, X< 6>, X< 7>, X< 8>, X< 9>, X<10>, | ||
X<11>, X<12>, X<13>, X<14>, X<15>, X<16>, X<17>, X<18>, X<19>, X<20> > = (); | ||
|
||
header(1, "std::monostate"); | ||
v..emplace<0>(); | ||
run_tests(v); | ||
|
||
header(1, "X<1>"); | ||
v..emplace<1>(); | ||
run_tests(v); | ||
|
||
header(1, "X<19>"); | ||
v..emplace<19>(); | ||
run_tests(v); | ||
|
||
header(1, "X<20>"); | ||
v..emplace<20>(); | ||
run_tests(v); | ||
|
||
header(1, "X<10>(std::exception)"); | ||
set_to_valueless_by_exception<10>(v); | ||
run_tests(v); | ||
|
||
} | ||
|
||
run_tests: (forward v) = { | ||
header(2, "v as lvalue reference"); | ||
test(v); | ||
|
||
header(2, "v as const lvalue reference"); | ||
test(std::as_const(v)); | ||
|
||
header(2, "v as rvalue reference"); | ||
test(move v); | ||
} | ||
|
||
header: (lvl : int, msg: std::string) = { | ||
std::cout << std::string(lvl, '#') << " " << msg << "\n" << std::endl; | ||
} | ||
|
||
template<int I> | ||
struct X { | ||
operator int() const { return I; } | ||
X() = default; | ||
X(std::exception const& e) { throw e; } | ||
auto to_string() const { return "X<" + std::to_string(I) + ">"; } | ||
}; | ||
|
||
template <std::size_t I> | ||
void set_to_valueless_by_exception(auto& v) try { | ||
v.template emplace<I>(std::runtime_error("make valueless")); | ||
} catch (...) {} | ||
|
||
auto expect_no_throw(auto&& l) -> std::string try { | ||
if constexpr ( requires { { l() } -> std::convertible_to<std::string>; }) { | ||
return l(); | ||
} else { | ||
l(); | ||
return "works!"; | ||
} | ||
} catch (std::exception const& e) { | ||
return e.what(); | ||
} catch (...) { | ||
return "unknown exception!"; | ||
} | ||
|
||
auto expect_no_throw(auto&& v, auto&& l) -> std::string try { | ||
if constexpr ( requires { { l(v) } -> std::convertible_to<std::string>; }) { | ||
return l(v); | ||
} else { | ||
l(v); | ||
return "works!"; | ||
} | ||
} catch (std::exception const& e) { | ||
return e.what(); | ||
} catch (...) { | ||
return "unknown exception!"; | ||
} |
42 changes: 42 additions & 0 deletions
42
...sion-tests/test-results/apple-clang-14-c++2b/mixed-is-as-value-with-variant.cpp.execution
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
# std::monostate | ||
|
||
--- | ||
# int(42) | ||
42 in(0,100) | ||
--- | ||
# int(24) | ||
24 in(0,100) | ||
--- | ||
# std::optional<int>(100) | ||
100 std::optional<int>(100) | ||
--- | ||
# std::any(-100) | ||
|
||
--- | ||
# *int(314) | ||
|
||
--- | ||
# std::unique_ptr<int>(1000) | ||
|
||
--- | ||
# my_variant(std::monostate) | ||
|
||
--- | ||
# my_variant(int(42)) | ||
|
||
--- | ||
# my_variant(int(24)) | ||
|
||
--- | ||
# my_variant(std::optional<int>(100)) | ||
|
||
--- | ||
# my_variant(std::any(-100)) | ||
|
||
--- | ||
# my_variant(*int(314)) | ||
|
||
--- | ||
# my_variant(std::unique_ptr<int>(1000)) | ||
|
||
--- |
145 changes: 145 additions & 0 deletions
145
regression-tests/test-results/apple-clang-14-c++2b/mixed-is-as-variant.cpp.execution
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
# std::monostate | ||
|
||
## v as lvalue reference | ||
|
||
v is empty = true | ||
v is std::monostate = true | ||
v is X< 0> = false, (v as X< 1>) = bad_variant_access | ||
v is X< 1> = false, (v as X< 1>).to_string() = bad_variant_access | ||
v is X<19> = false, (v as X<19>).to_string() = bad_variant_access | ||
v is X<20> = false, (v as X<20>) = bad_variant_access | ||
|
||
## v as const lvalue reference | ||
|
||
v is empty = true | ||
v is std::monostate = true | ||
v is X< 0> = false, (v as X< 1>) = bad_variant_access | ||
v is X< 1> = false, (v as X< 1>).to_string() = bad_variant_access | ||
v is X<19> = false, (v as X<19>).to_string() = bad_variant_access | ||
v is X<20> = false, (v as X<20>) = bad_variant_access | ||
|
||
## v as rvalue reference | ||
|
||
v is empty = true | ||
v is std::monostate = true | ||
v is X< 0> = false, (v as X< 1>) = bad_variant_access | ||
v is X< 1> = false, (v as X< 1>).to_string() = bad_variant_access | ||
v is X<19> = false, (v as X<19>).to_string() = bad_variant_access | ||
v is X<20> = false, (v as X<20>) = bad_variant_access | ||
|
||
# X<1> | ||
|
||
## v as lvalue reference | ||
|
||
v is empty = false | ||
v is std::monostate = false | ||
v is X< 0> = false, (v as X< 1>) = bad_variant_access | ||
v is X< 1> = true, (v as X< 1>).to_string() = X<1> | ||
v is X<19> = false, (v as X<19>).to_string() = bad_variant_access | ||
v is X<20> = false, (v as X<20>) = bad_variant_access | ||
|
||
## v as const lvalue reference | ||
|
||
v is empty = false | ||
v is std::monostate = false | ||
v is X< 0> = false, (v as X< 1>) = bad_variant_access | ||
v is X< 1> = true, (v as X< 1>).to_string() = X<1> | ||
v is X<19> = false, (v as X<19>).to_string() = bad_variant_access | ||
v is X<20> = false, (v as X<20>) = bad_variant_access | ||
|
||
## v as rvalue reference | ||
|
||
v is empty = false | ||
v is std::monostate = false | ||
v is X< 0> = false, (v as X< 1>) = bad_variant_access | ||
v is X< 1> = true, (v as X< 1>).to_string() = X<1> | ||
v is X<19> = false, (v as X<19>).to_string() = bad_variant_access | ||
v is X<20> = false, (v as X<20>) = bad_variant_access | ||
|
||
# X<19> | ||
|
||
## v as lvalue reference | ||
|
||
v is empty = false | ||
v is std::monostate = false | ||
v is X< 0> = false, (v as X< 1>) = bad_variant_access | ||
v is X< 1> = false, (v as X< 1>).to_string() = bad_variant_access | ||
v is X<19> = true, (v as X<19>).to_string() = X<19> | ||
v is X<20> = false, (v as X<20>) = bad_variant_access | ||
|
||
## v as const lvalue reference | ||
|
||
v is empty = false | ||
v is std::monostate = false | ||
v is X< 0> = false, (v as X< 1>) = bad_variant_access | ||
v is X< 1> = false, (v as X< 1>).to_string() = bad_variant_access | ||
v is X<19> = true, (v as X<19>).to_string() = X<19> | ||
v is X<20> = false, (v as X<20>) = bad_variant_access | ||
|
||
## v as rvalue reference | ||
|
||
v is empty = false | ||
v is std::monostate = false | ||
v is X< 0> = false, (v as X< 1>) = bad_variant_access | ||
v is X< 1> = false, (v as X< 1>).to_string() = bad_variant_access | ||
v is X<19> = true, (v as X<19>).to_string() = X<19> | ||
v is X<20> = false, (v as X<20>) = bad_variant_access | ||
|
||
# X<20> | ||
|
||
## v as lvalue reference | ||
|
||
v is empty = false | ||
v is std::monostate = false | ||
v is X< 0> = false, (v as X< 1>) = bad_variant_access | ||
v is X< 1> = false, (v as X< 1>).to_string() = bad_variant_access | ||
v is X<19> = false, (v as X<19>).to_string() = bad_variant_access | ||
v is X<20> = true, (v as X<20>) = works! | ||
|
||
## v as const lvalue reference | ||
|
||
v is empty = false | ||
v is std::monostate = false | ||
v is X< 0> = false, (v as X< 1>) = bad_variant_access | ||
v is X< 1> = false, (v as X< 1>).to_string() = bad_variant_access | ||
v is X<19> = false, (v as X<19>).to_string() = bad_variant_access | ||
v is X<20> = true, (v as X<20>) = works! | ||
|
||
## v as rvalue reference | ||
|
||
v is empty = false | ||
v is std::monostate = false | ||
v is X< 0> = false, (v as X< 1>) = bad_variant_access | ||
v is X< 1> = false, (v as X< 1>).to_string() = bad_variant_access | ||
v is X<19> = false, (v as X<19>).to_string() = bad_variant_access | ||
v is X<20> = true, (v as X<20>) = works! | ||
|
||
# X<10>(std::exception) | ||
|
||
## v as lvalue reference | ||
|
||
v is empty = true | ||
v is std::monostate = false | ||
v is X< 0> = false, (v as X< 1>) = bad_variant_access | ||
v is X< 1> = false, (v as X< 1>).to_string() = bad_variant_access | ||
v is X<19> = false, (v as X<19>).to_string() = bad_variant_access | ||
v is X<20> = false, (v as X<20>) = bad_variant_access | ||
|
||
## v as const lvalue reference | ||
|
||
v is empty = true | ||
v is std::monostate = false | ||
v is X< 0> = false, (v as X< 1>) = bad_variant_access | ||
v is X< 1> = false, (v as X< 1>).to_string() = bad_variant_access | ||
v is X<19> = false, (v as X<19>).to_string() = bad_variant_access | ||
v is X<20> = false, (v as X<20>) = bad_variant_access | ||
|
||
## v as rvalue reference | ||
|
||
v is empty = true | ||
v is std::monostate = false | ||
v is X< 0> = false, (v as X< 1>) = bad_variant_access | ||
v is X< 1> = false, (v as X< 1>).to_string() = bad_variant_access | ||
v is X<19> = false, (v as X<19>).to_string() = bad_variant_access | ||
v is X<20> = false, (v as X<20>) = bad_variant_access | ||
|
2 changes: 1 addition & 1 deletion
2
regression-tests/test-results/apple-clang-15-c++2b/mixed-bounds-check.cpp.execution
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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] | ||
../../../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] |
2 changes: 1 addition & 1 deletion
2
...ion-tests/test-results/apple-clang-15-c++2b/mixed-bounds-safety-with-assert.cpp.execution
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
../../../include/cpp2util.h(819) : Bounds safety violation | ||
../../../include/cpp2util.h(915) : Bounds safety violation |
Oops, something went wrong.