Skip to content

Commit

Permalink
More samples. (#49)
Browse files Browse the repository at this point in the history
* More samples.
  • Loading branch information
BowenFu authored Jun 26, 2021
1 parent 4bc4ee5 commit 132449d
Show file tree
Hide file tree
Showing 11 changed files with 240 additions and 51 deletions.
42 changes: 26 additions & 16 deletions From-Pattern-Matching-Proposal-to-matchit.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,18 +169,27 @@ int eval(const Expr& expr) {
In `match(it)`:
```C++
int eval(const Expr& expr){
Id<Expr> e, l, r;
return match (expr) (
pattern | as<int>(i) = i,
pattern | as<Neg>(ds(some(e))) = [&]{ return -eval(*e); },
pattern | as<Add>(ds(some(l), some(r))) = [&]{ return eval(*l) + eval(*r); },
// Optimize multiplication by 0.
pattern | as<Mul>(ds(some(as<int>(0), _))) = expr(0),
pattern | as<Mul>(ds(_, some(as<int>(0)))) = expr(0),
pattern | as<Mul>(ds(some(l), some(r))) = [&]{ return eval(*l) * eval(*r); }
);
const auto asNegDs = asDsVia<Neg>(&Neg::expr);
const auto asAddDs = asDsVia<Add>(&Add::lhs, &Add::rhs);
const auto asMulDs = asDsVia<Mul>(&Mul::lhs, &Mul::rhs);
int eval(const Expr &ex)
{
using namespace matchit;
Id<int> i;
Id<Expr> e, l, r;
return match(ex)(
pattern | as<int>(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<int>(0)), _) = expr(0),
pattern | asMulDs(_, some(as<int>(0))) = expr(0),
pattern | asMulDs(some(l), some(r)) = [&]{ return eval(*l) * eval(*r); },
pattern | _ = expr(-1)
);
}
```

### Terminate from Inspect
Expand Down Expand Up @@ -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<std::string> 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";
Expand Down
9 changes: 5 additions & 4 deletions From-Rust-to-matchit.md
Original file line number Diff line number Diff line change
Expand Up @@ -1124,17 +1124,18 @@ using Message = std::variant<Hello>;
int32_t main() {
Message const msg = Hello{5};

auto const asHelloDs = asDsVia<Hello>(&Hello::id);
Id<int32_t> id_variable;
match(msg)(
pattern | as<Hello>(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<Hello>(app(&Hello::id, 10 <= _ && _ <= 12) = [&] {
pattern | asHelloDs(10 <= _ && _ <= 12) = [&] {
std::cout << "Found an id in another range" << std::endl;
},
pattern | as<Hello>(app(&Hello::id, id_variable) = [&] {
pattern | asHelloDs(id_variable) = [&] {
std::cout << "Found some other id: " << *id_variable << std::endl;
}
)
);
}
```
18 changes: 18 additions & 0 deletions develop/matchit/utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,29 @@ namespace matchit
{ return false; });
}

constexpr auto dsVia = [](auto&&... members)
{
return [members...](auto&&... pats)
{
return and_(app(members, pats)...);
};
};

template <typename T>
constexpr auto asDsVia = [](auto&&... members)
{
return [members...](auto&&... pats)
{
return as<T>(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
18 changes: 18 additions & 0 deletions include/matchit.h
Original file line number Diff line number Diff line change
Expand Up @@ -1956,11 +1956,29 @@ namespace matchit
{ return false; });
}

constexpr auto dsVia = [](auto&&... members)
{
return [members...](auto&&... pats)
{
return and_(app(members, pats)...);
};
};

template <typename T>
constexpr auto asDsVia = [](auto&&... members)
{
return [members...](auto&&... pats)
{
return as<T>(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
Expand Down
3 changes: 3 additions & 0 deletions samples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ Matching-Variants
Matching-Polymorphic-Types
Evaluating-Expression-Trees
Terminate
Structured-Binding-Pattern
Dereference-Pattern
Extractor-Pattern
)

foreach(sample ${MATCHIT_SAMPLES})
Expand Down
36 changes: 36 additions & 0 deletions samples/Dereference-Pattern.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#include "matchit.h"
#include <iostream>
#include <memory>

struct Node {
int value;
std::unique_ptr<Node> 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<int> v;
Id<Node> 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;
}
42 changes: 15 additions & 27 deletions samples/Evaluating-Expression-Trees.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,57 +2,45 @@
#include <iostream>
#include <tuple>
#include <memory>
using namespace matchit;

struct Expr;
struct Neg { std::shared_ptr<Expr> expr; };
struct Add { std::shared_ptr<Expr> lhs, rhs; };
struct Mul { std::shared_ptr<Expr> lhs, rhs; };
struct Expr : std::variant<int, Neg, Add, Mul> { using variant::variant; };

bool operator==(Expr const& l, Expr const& r)
{
return static_cast<std::variant<int, Neg, Add, Mul> const&>(l) == static_cast<std::variant<int, Neg, Add, Mul> const&>(r);
}

namespace std {
template <>
struct variant_size<Expr> : variant_size<Expr::variant> {};
template <std::size_t I>
struct variant_alternative<I, Expr> : variant_alternative<I, Expr::variant> {};
}

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<std::variant<int, Neg, Add, Mul> const&>(l) == static_cast<std::variant<int, Neg, Add, Mul> const&>(r);
}

constexpr auto dsMul = [](auto &&lhs, auto &&rhs)
{
return and_(app(&Mul::lhs, lhs),
app(&Mul::rhs, rhs));
};
const auto asNegDs = asDsVia<Neg>(&Neg::expr);
const auto asAddDs = asDsVia<Add>(&Add::lhs, &Add::rhs);
const auto asMulDs = asDsVia<Mul>(&Mul::lhs, &Mul::rhs);

int eval(const Expr &ex)
{
using namespace matchit;
Id<int> i;
Id<Expr> e, l, r;
return match(ex)(
// clang-format off
pattern | as<int>(i) = expr(i),
pattern | as<Neg>(dsNeg(some(e))) = [&]{ return -eval(*e); },
pattern | as<Add>(dsAdd(some(l), some(r))) = [&]{ return eval(*l) + eval(*r); },
// FIXME: Expr{5} won't match the following line.
pattern | as<int>(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<Mul>(dsMul(some(as<int>(0)), _)) = expr(0),
pattern | as<Mul>(dsMul(_, some(as<int>(0)))) = expr(0),
pattern | as<Mul>(dsMul(some(l), some(r))) = [&]{ return eval(*l) * eval(*r); },
pattern | _ = expr(-1)
pattern | asMulDs(some(as<int>(0)), _) = expr(0),
pattern | asMulDs(_, some(as<int>(0))) = expr(0),
pattern | asMulDs(some(l), some(r)) = [&]{ return eval(*l) * eval(*r); },
pattern | _ = expr(-1)
// clang-format on
);
}
Expand Down
77 changes: 77 additions & 0 deletions samples/Extractor-Pattern.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#include "matchit.h"
#include <optional>
#include <string_view>
#include <iostream>

template <typename T>
struct Is {
template <typename Arg>
Arg&& operator()(Arg&& arg) const {
static_assert(std::is_same_v<T, std::decay_t<Arg>>);
return std::forward<Arg>(arg);
}
};

template <typename T>
inline constexpr Is<T> is;

auto sample1()
{
const auto x = std::make_tuple(std::string("str"), 123);
using namespace matchit;
Id<std::string> s;
Id<int> i;
match(x)(
pattern | ds(app(is<std::string>, s), app(is<int>, i)) = [&] { std::cout << "first " << *s << " second " << *i; }
);
std::cout << std::endl;
}

struct Email {
constexpr std::optional<std::array<std::string_view, 2>>
operator()(std::string_view sv) const
{
auto const d = sv.find("@");
if (d == std::string_view::npos)
{
return {};
}
return std::array<std::string_view, 2>{sv.substr(0, d), sv.substr(d+1)};
}
};

inline constexpr Email email;

struct PhoneNumber {
std::optional<std::array<std::string_view, 3>>
operator()(std::string_view sv) const
{
return std::array<std::string_view, 3>{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<std::string_view> 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;
}
2 changes: 1 addition & 1 deletion samples/Matching-Polymorphic-Types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
37 changes: 37 additions & 0 deletions samples/Structured-Binding-Pattern.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#include "matchit.h"
#include <iostream>
#include <tuple>

struct Player { std::string name; int hitpoints; int coins; };

void get_hint(const Player& p){
using namespace matchit;
using P = Player;
Id<std::string> 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;
}
Loading

0 comments on commit 132449d

Please sign in to comment.