diff --git a/From-Pattern-Matching-Proposal-to-matchit.md b/From-Pattern-Matching-Proposal-to-matchit.md index 802044d..28f3cf2 100644 --- a/From-Pattern-Matching-Proposal-to-matchit.md +++ b/From-Pattern-Matching-Proposal-to-matchit.md @@ -169,18 +169,27 @@ int eval(const Expr& expr) { In `match(it)`: ```C++ -int eval(const Expr& expr){ - Id e, l, r; - return match (expr) ( - pattern | as(i) = i, - pattern | as(ds(some(e))) = [&]{ return -eval(*e); }, - pattern | as(ds(some(l), some(r))) = [&]{ return eval(*l) + eval(*r); }, - // Optimize multiplication by 0. - pattern | as(ds(some(as(0), _))) = expr(0), - pattern | as(ds(_, some(as(0)))) = expr(0), - pattern | as(ds(some(l), some(r))) = [&]{ return eval(*l) * eval(*r); } - ); +const auto asNegDs = asDsVia(&Neg::expr); +const auto asAddDs = asDsVia(&Add::lhs, &Add::rhs); +const auto asMulDs = asDsVia(&Mul::lhs, &Mul::rhs); + +int eval(const Expr &ex) +{ + using namespace matchit; + Id i; + Id e, l, r; + return match(ex)( + pattern | as(i) = expr(i), + pattern | asNegDs(some(e)) = [&]{ return -eval(*e); }, + pattern | asAddDs(some(l), some(r)) = [&]{ return eval(*l) + eval(*r); }, + // Optimize multiplication by 0. + pattern | asMulDs(some(as(0)), _) = expr(0), + pattern | asMulDs(_, some(as(0))) = expr(0), + pattern | asMulDs(some(l), some(r)) = [&]{ return eval(*l) * eval(*r); }, + pattern | _ = expr(-1) + ); } + ``` ### Terminate from Inspect @@ -402,17 +411,18 @@ In `match(it)`: ```C++ struct Player { std::string name; int hitpoints; int coins; }; void get_hint(const Player& p){ + using P = Player; Id n; match (p) ( - pattern | app(&Player::hitpoints, 1) = + pattern | app(&P::hitpoints, 1) = [&]{ std::cout << "You're almost destroyed. Give up!\n"; }, - pattern | and_(app(&Player::hitpoints, 10), app(&Player::coins, 10)) = + pattern | and_(app(&P::hitpoints, 10), app(&P::coins, 10)) = [&]{ std::cout << "I need the hints from you!\n"; }, - pattern | app(&Player::coins, 10) = + pattern | app(&P::coins, 10) = [&]{ std::cout << "Get more hitpoints!\n"; }, - pattern | app(&Player::hitpoints, 10) = + pattern | app(&P::hitpoints, 10) = [&]{ std::cout << "Get more ammo!\n"; }, - pattern | app(&Player::name, n) = + pattern | app(&P::name, n) = [&]{ if (*n != "The Bruce Dickenson") { std::cout << "Get more hitpoints and ammo!\n"; diff --git a/From-Rust-to-matchit.md b/From-Rust-to-matchit.md index 5f4dbc6..6218875 100644 --- a/From-Rust-to-matchit.md +++ b/From-Rust-to-matchit.md @@ -1124,17 +1124,18 @@ using Message = std::variant; int32_t main() { Message const msg = Hello{5}; + auto const asHelloDs = asDsVia(&Hello::id); Id id_variable; match(msg)( - pattern | as(app(&Hello::id, id_variable.at(3 <= _ && _ <= 7)) = [&] { + pattern | asHelloDs(id_variable.at(3 <= _ && _ <= 7)) = [&] { std::cout << "Found an id in range: " << *id_variable << std::endl; }, - pattern | as(app(&Hello::id, 10 <= _ && _ <= 12) = [&] { + pattern | asHelloDs(10 <= _ && _ <= 12) = [&] { std::cout << "Found an id in another range" << std::endl; }, - pattern | as(app(&Hello::id, id_variable) = [&] { + pattern | asHelloDs(id_variable) = [&] { std::cout << "Found some other id: " << *id_variable << std::endl; } - ) + ); } ``` diff --git a/develop/matchit/utility.h b/develop/matchit/utility.h index 7e9acfa..91d438f 100644 --- a/develop/matchit/utility.h +++ b/develop/matchit/utility.h @@ -83,11 +83,29 @@ namespace matchit { return false; }); } + constexpr auto dsVia = [](auto&&... members) + { + return [members...](auto&&... pats) + { + return and_(app(members, pats)...); + }; + }; + + template + constexpr auto asDsVia = [](auto&&... members) + { + return [members...](auto&&... pats) + { + return as(and_(app(members, pats)...)); + }; + }; + } // namespace impl using impl::as; using impl::matched; using impl::none; using impl::some; + using impl::asDsVia; } // namespace matchit #endif // MATCHIT_UTILITY_H diff --git a/include/matchit.h b/include/matchit.h index 4c8a4d3..b84ca9d 100644 --- a/include/matchit.h +++ b/include/matchit.h @@ -1956,11 +1956,29 @@ namespace matchit { return false; }); } + constexpr auto dsVia = [](auto&&... members) + { + return [members...](auto&&... pats) + { + return and_(app(members, pats)...); + }; + }; + + template + constexpr auto asDsVia = [](auto&&... members) + { + return [members...](auto&&... pats) + { + return as(and_(app(members, pats)...)); + }; + }; + } // namespace impl using impl::as; using impl::matched; using impl::none; using impl::some; + using impl::asDsVia; } // namespace matchit #endif // MATCHIT_UTILITY_H diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index 6442ecb..835500a 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -41,6 +41,9 @@ Matching-Variants Matching-Polymorphic-Types Evaluating-Expression-Trees Terminate +Structured-Binding-Pattern +Dereference-Pattern +Extractor-Pattern ) foreach(sample ${MATCHIT_SAMPLES}) diff --git a/samples/Dereference-Pattern.cpp b/samples/Dereference-Pattern.cpp new file mode 100644 index 0000000..511b8a7 --- /dev/null +++ b/samples/Dereference-Pattern.cpp @@ -0,0 +1,36 @@ +#include "matchit.h" +#include +#include + +struct Node { + int value; + std::unique_ptr lhs, rhs; +}; + +bool operator==(Node const& lhs, Node const& rhs) +{ + return lhs.value == rhs.value && lhs.lhs == rhs.lhs && lhs.rhs == rhs.rhs; +} + +void print_leftmost(const Node& node) { + auto deref = [](auto&& e) -> decltype(auto) { return *e; }; + using namespace matchit; + Id v; + Id l; + + using N = Node; + match(node) ( + pattern | and_(app(&N::value, v), app(&N::lhs, nullptr)) = [&]{ std::cout << *v << '\n'; }, + pattern | app(&N::lhs, app(deref, l)) = [&]{ print_leftmost(*l); } +// ˆˆˆˆˆˆˆˆˆˆˆˆˆ dereference pattern + ); +} + + +int32_t main() +{ + const auto n = Node{4, {}, {}}; + print_leftmost(n); + + return 0; +} diff --git a/samples/Evaluating-Expression-Trees.cpp b/samples/Evaluating-Expression-Trees.cpp index 25407ae..3ae0e2a 100644 --- a/samples/Evaluating-Expression-Trees.cpp +++ b/samples/Evaluating-Expression-Trees.cpp @@ -2,6 +2,7 @@ #include #include #include +using namespace matchit; struct Expr; struct Neg { std::shared_ptr expr; }; @@ -9,11 +10,6 @@ struct Add { std::shared_ptr lhs, rhs; }; struct Mul { std::shared_ptr lhs, rhs; }; struct Expr : std::variant { using variant::variant; }; -bool operator==(Expr const& l, Expr const& r) -{ - return static_cast const&>(l) == static_cast const&>(r); -} - namespace std { template <> struct variant_size : variant_size {}; @@ -21,38 +17,30 @@ template struct variant_alternative : variant_alternative {}; } -constexpr auto dsNeg = [](auto&& expr) -{ - return app(&Neg::expr, expr); -}; - -constexpr auto dsAdd = [](auto &&lhs, auto &&rhs) +bool operator==(Expr const& l, Expr const& r) { - return and_(app(&Add::lhs, lhs), - app(&Add::rhs, rhs)); -}; + return static_cast const&>(l) == static_cast const&>(r); +} -constexpr auto dsMul = [](auto &&lhs, auto &&rhs) -{ - return and_(app(&Mul::lhs, lhs), - app(&Mul::rhs, rhs)); -}; +const auto asNegDs = asDsVia(&Neg::expr); +const auto asAddDs = asDsVia(&Add::lhs, &Add::rhs); +const auto asMulDs = asDsVia(&Mul::lhs, &Mul::rhs); int eval(const Expr &ex) { - using namespace matchit; Id i; Id e, l, r; return match(ex)( // clang-format off - pattern | as(i) = expr(i), - pattern | as(dsNeg(some(e))) = [&]{ return -eval(*e); }, - pattern | as(dsAdd(some(l), some(r))) = [&]{ return eval(*l) + eval(*r); }, + // FIXME: Expr{5} won't match the following line. + pattern | as(i) = expr(i), + pattern | asNegDs(some(e)) = [&]{ return -eval(*e); }, + pattern | asAddDs(some(l), some(r)) = [&]{ return eval(*l) + eval(*r); }, // Optimize multiplication by 0. - pattern | as(dsMul(some(as(0)), _)) = expr(0), - pattern | as(dsMul(_, some(as(0)))) = expr(0), - pattern | as(dsMul(some(l), some(r))) = [&]{ return eval(*l) * eval(*r); }, - pattern | _ = expr(-1) + pattern | asMulDs(some(as(0)), _) = expr(0), + pattern | asMulDs(_, some(as(0))) = expr(0), + pattern | asMulDs(some(l), some(r)) = [&]{ return eval(*l) * eval(*r); }, + pattern | _ = expr(-1) // clang-format on ); } diff --git a/samples/Extractor-Pattern.cpp b/samples/Extractor-Pattern.cpp new file mode 100644 index 0000000..bfe9fd6 --- /dev/null +++ b/samples/Extractor-Pattern.cpp @@ -0,0 +1,77 @@ +#include "matchit.h" +#include +#include +#include + +template +struct Is { + template + Arg&& operator()(Arg&& arg) const { + static_assert(std::is_same_v>); + return std::forward(arg); + } +}; + +template +inline constexpr Is is; + +auto sample1() +{ + const auto x = std::make_tuple(std::string("str"), 123); + using namespace matchit; + Id s; + Id i; + match(x)( + pattern | ds(app(is, s), app(is, i)) = [&] { std::cout << "first " << *s << " second " << *i; } + ); + std::cout << std::endl; +} + +struct Email { + constexpr std::optional> + operator()(std::string_view sv) const + { + auto const d = sv.find("@"); + if (d == std::string_view::npos) + { + return {}; + } + return std::array{sv.substr(0, d), sv.substr(d+1)}; + } +}; + +inline constexpr Email email; + +struct PhoneNumber { + std::optional> + operator()(std::string_view sv) const + { + return std::array{sv.substr(0, 3), sv.substr(3, 3), sv.substr(6)}; + } +}; + +inline constexpr PhoneNumber phone_number; + +void sample2() +{ + using namespace matchit; + + using namespace std::literals; + // auto const s = "match@it"sv; + auto const s = "415123456"sv; + Id address, domain; + match(s)( + pattern | app(email, some(ds(address, domain))) = [&] { std::cout << "got an email"; }, + pattern | app(phone_number, some(ds("415", _, _))) = [&] { std::cout << "got a San Francisco phone number"; } + // ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ extractor pattern + ); + std::cout << std::endl; +} + +int32_t main() +{ + sample1(); + sample2(); + + return 0; +} diff --git a/samples/Matching-Polymorphic-Types.cpp b/samples/Matching-Polymorphic-Types.cpp index 3f3de2a..e82722b 100644 --- a/samples/Matching-Polymorphic-Types.cpp +++ b/samples/Matching-Polymorphic-Types.cpp @@ -56,7 +56,7 @@ int32_t main() { auto c = Circle{}; c.radius = 5; - std::cout << get_area((c)) << std::endl; + std::cout << get_area(c) << std::endl; return 0; } diff --git a/samples/Structured-Binding-Pattern.cpp b/samples/Structured-Binding-Pattern.cpp new file mode 100644 index 0000000..71f621d --- /dev/null +++ b/samples/Structured-Binding-Pattern.cpp @@ -0,0 +1,37 @@ +#include "matchit.h" +#include +#include + +struct Player { std::string name; int hitpoints; int coins; }; + +void get_hint(const Player& p){ + using namespace matchit; + using P = Player; + Id n; + match (p) ( + pattern | app(&P::hitpoints, 1) = + [&]{ std::cout << "You're almost destroyed. Give up!\n"; }, + pattern | and_(app(&P::hitpoints, 10), app(&P::coins, 10)) = + [&]{ std::cout << "I need the hints from you!\n"; }, + pattern | app(&P::coins, 10) = + [&]{ std::cout << "Get more hitpoints!\n"; }, + pattern | app(&P::hitpoints, 10) = + [&]{ std::cout << "Get more ammo!\n"; }, + pattern | app(&P::name, n) = + [&]{ + if (*n != "The Bruce Dickenson") { + std::cout << "Get more hitpoints and ammo!\n"; + } else { + std::cout << "More cowbell!\n"; + } + } + ); +} + +int32_t main() +{ + const auto p = Player{"Bob", 4, 6}; + get_hint(p); + + return 0; +} diff --git a/samples/at-Bindings.cpp b/samples/at-Bindings.cpp index d7c1306..aa096d0 100644 --- a/samples/at-Bindings.cpp +++ b/samples/at-Bindings.cpp @@ -10,15 +10,16 @@ int32_t main() Message const msg = Hello{5}; using namespace matchit; + auto const asHelloDs = asDsVia(&Hello::id); Id id_variable; match(msg)( - pattern | as(app(&Hello::id, id_variable.at(3 <= _ && _ <= 7))) = [&] { + pattern | asHelloDs(id_variable.at(3 <= _ && _ <= 7)) = [&] { std::cout << "Found an id in range: " << *id_variable << std::endl; }, - pattern | as(app(&Hello::id, 10 <= _ && _ <= 12)) = [&] { + pattern | asHelloDs(10 <= _ && _ <= 12) = [&] { std::cout << "Found an id in another range" << std::endl; }, - pattern | as(app(&Hello::id, id_variable)) = [&] { + pattern | asHelloDs(id_variable) = [&] { std::cout << "Found some other id: " << *id_variable << std::endl; } );