Last active
August 29, 2015 14:17
-
-
Save jbandela/c82b649ef4f31aed229d to your computer and use it in GitHub Desktop.
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
#include <tuple> | |
#include <utility> | |
#include <cstdint> | |
#include <stdexcept> | |
using std::size_t; | |
template<typename F, typename Tuple, size_t... I> | |
auto | |
apply_(F&& f, Tuple&& args, std::integer_sequence<size_t,I...>) | |
{ | |
return std::forward<F>(f)(std::get<I>(std::forward<Tuple>(args))...); | |
} | |
template<typename F, typename Tuple> | |
auto | |
apply(F&& f, Tuple&& args) | |
{ | |
return apply_(std::forward<F>(f), std::forward<Tuple>(args), std::make_index_sequence<std::tuple_size<typename std::remove_reference<Tuple>::type>::value >()); | |
} | |
template<class T, class U> | |
struct matcher; | |
template<class T, class U> | |
bool match_check(T&& t, U&& u) { | |
using m = matcher<std::decay_t<T>, std::decay_t<U>>; | |
return m::check(std::forward<T>(t), std::forward<U>(u)); | |
} | |
template<class T, class U> | |
auto match_get(T&& t, U&& u) { | |
using m = matcher<std::decay_t<T>, std::decay_t<U>>; | |
return m::get(std::forward<T>(t), std::forward<U>(u)); | |
} | |
template<class T, class A1, class F1,class A2, class F2, class... Args> | |
auto match(T&& t, A1&& a, F1&& f, A2&& a2,F2&& f2, Args&&... args) { | |
if (match_check(t, a)) { | |
return apply(f, match_get(std::forward<T>(t), std::forward<A1>(a))); | |
} | |
else { | |
return match(t,std::forward<A2>(a2),std::forward<F2>(f2),std::forward<Args>(args)...); | |
} | |
} | |
template<class T, class A1, class F1> | |
auto match(T&& t, A1&& a, F1&& f) { | |
if (match_check(std::forward<T>(t), std::forward<A1>(a))) { | |
return apply(f, match_get(std::forward<T>(t), std::forward<A1>(a))); | |
} | |
else { | |
throw std::logic_error("No match"); | |
} | |
} | |
// Match same type | |
template<class T> | |
struct matcher<T, T> { | |
static bool check(const T& t, const T& v) { | |
return t == v; | |
} | |
static auto get(const T&, const T&) { | |
return std::tie(); | |
} | |
}; | |
struct otherwise_t {}; | |
const otherwise_t otherwise {}; | |
const otherwise_t _ {}; | |
// Match otherwise | |
template<class Type> | |
struct matcher<Type, otherwise_t> { | |
template<class T> | |
static bool check(T&&, otherwise_t) { | |
return true; | |
} | |
template<class T> | |
static auto get(T&&, otherwise_t) { | |
return std::tie(); | |
} | |
}; | |
template<class F> | |
struct matcher_predicate { | |
F f_; | |
}; | |
template<class Type, class F> | |
struct matcher<Type, matcher_predicate<F>> { | |
template<class T, class U> | |
static bool check(T&& t, U&& u) { | |
return u.f_(std::forward<T>(t)); | |
} | |
template<class T, class U> | |
static auto get(T&& t, U&&) { | |
return std::tie(std::forward<T>(t)); | |
} | |
}; | |
template<class F> | |
matcher_predicate<F> make_matcher_predicate(F&& f) { | |
return matcher_predicate<F>{std::forward<F>(f)}; | |
} | |
const auto _x = make_matcher_predicate([](auto&&) {return true; }); | |
// relational operators | |
template<class F, class T> | |
auto operator==(const matcher_predicate<F>& m, const T& t) { | |
return make_matcher_predicate([m, &t](const auto& x) {return m.f_(x) && x == t; }); | |
} | |
template<class F, class T> | |
auto operator!=(const matcher_predicate<F>& m, const T& t) { | |
return make_matcher_predicate([m, &t](const auto& x) {return m.f_(x) && x != t; }); | |
} | |
template<class F, class T> | |
auto operator<=(const matcher_predicate<F>& m, const T& t) { | |
return make_matcher_predicate([m, &t](const auto& x) {return m.f_(x) && x <= t; }); | |
} | |
template<class F, class T> | |
auto operator>=(const matcher_predicate<F>& m, const T& t) { | |
return make_matcher_predicate([m, &t](const auto& x) {return m.f_(x) && x >= t; }); | |
} | |
template<class F, class T> | |
auto operator<(const matcher_predicate<F>& m, const T& t) { | |
return make_matcher_predicate([m, &t](const auto& x) {return m.f_(x) && x < t; }); | |
} | |
template<class F, class T> | |
auto operator>(const matcher_predicate<F>& m, const T& t) { | |
return make_matcher_predicate([m, &t](const auto& x) {return m.f_(x) && x > t; }); | |
} | |
template<class F> | |
auto operator!(const matcher_predicate<F>& m) { | |
return make_matcher_predicate([m](const auto& x) {return !m.f_(x); }); | |
} | |
template<class F, class F2> | |
auto operator&&(const matcher_predicate<F>& m, const matcher_predicate<F2>& m2) { | |
return make_matcher_predicate([m,m2](const auto& x) {return m.f_(x) && m2.f_(x); }); | |
} | |
template<class F, class F2> | |
auto operator||(const matcher_predicate<F>& m, const matcher_predicate<F2>& m2) { | |
return make_matcher_predicate([m, m2](const auto& x) {return m.f_(x) || m2.f_(x); }); | |
} | |
// relational operators | |
template<class F, class T> | |
auto operator==(const T& t, const matcher_predicate<F>& m) { | |
return make_matcher_predicate([m, &t](const auto& x) {return m.f_(x) && t == x; }); | |
} | |
template<class F, class T> | |
auto operator!=(const T& t, const matcher_predicate<F>& m) { | |
return make_matcher_predicate([m, &t](const auto& x) {return m.f_(x) && t != x; }); | |
} | |
template<class F, class T> | |
auto operator<=(const T& t, const matcher_predicate<F>& m) { | |
return make_matcher_predicate([m, &t](const auto& x) {return m.f_(x) && t <= x; }); | |
} | |
template<class F, class T> | |
auto operator>=(const T& t, const matcher_predicate<F>& m) { | |
return make_matcher_predicate([m, &t](const auto& x) {return m.f_(x) && t >= x; }); | |
} | |
template<class F, class T> | |
auto operator<(const T& t, const matcher_predicate<F>& m) { | |
return make_matcher_predicate([m, &t](const auto& x) {return m.f_(x) && t < x; }); | |
} | |
template<class F, class T> | |
auto operator>(const T& t, const matcher_predicate<F>& m) { | |
return make_matcher_predicate([m, &t](const auto& x) {return m.f_(x) && t > x; }); | |
} | |
template<class Type, class... Args> | |
struct matcher<Type, std::tuple<Args...>> { | |
enum { tuple_len = sizeof...(Args) }; | |
template<size_t pos, size_t last> | |
struct helper { | |
template<class T, class A> | |
static bool check(T&& t, A&& a) { | |
return match_check(std::get<pos>(std::forward<T>(t)), std::get<pos>(std::forward<A>(a))) | |
&& helper<pos + 1, last>::check(std::forward<T>(t), std::forward<A>(a)); | |
} | |
template<class T, class A> | |
static auto get(T&& t, A&& a) { | |
return std::tuple_cat(match_get(std::get<pos>(std::forward<T>(t)), std::get<pos>(std::forward<A>(a))), | |
helper<pos + 1, last>::get(std::forward<T>(t), std::forward<A>(a))); | |
} | |
}; | |
template<size_t pos> | |
struct helper<pos, pos> { | |
template<class T, class A> | |
static bool check(T&& t, A&& a) { | |
return match_check(std::get<pos>(std::forward<T>(t)), std::get<pos>(std::forward<A>(a))); | |
} | |
template<class T, class A> | |
static auto get(T&& t, A&& a) { | |
return match_get(std::get<pos>(std::forward<T>(t)), std::get<pos>(std::forward<A>(a))); | |
} | |
}; | |
template<class T, class A> | |
static bool check(T&& t, A&& a) { | |
return helper<0, tuple_len - 1>::check(std::forward<T>(t), std::forward<A>(a)); | |
} | |
template<class T, class A> | |
static auto get(T&& t, A&& a) { | |
return helper<0, tuple_len - 1>::get(std::forward<T>(t), std::forward<A>(a)); | |
} | |
}; | |
template<class... A> | |
decltype(auto) tup(A&& ... a) { | |
return std::forward_as_tuple(std::forward<A>(a)...); | |
} | |
#include <iostream> | |
int main() { | |
std::tuple<int, int> t{1, 2}; | |
int x = 0; | |
int y = 0; | |
using std::tie; | |
using std::forward_as_tuple; | |
while (true) { | |
std::cin >> x; | |
std::cin >> y; | |
match(tie(x,y), | |
tup(1,1), []() {std::cout << "The answer is one\n"; }, | |
tup(2,2), []() {std::cout << "The answer is two\n"; }, | |
tup(_x > 10, _x < 10), [](auto&& a, auto && b) {std::cout << "The answer " << a << " " << b << " is less than 10\n"; }, | |
tup(10 < _x < 20,10 < _x < 20), [](auto&& a, auto&& b) {std::cout << "The answer " << a << " " << b << " is between 10 and 20 exclusive\n"; }, | |
tup(_ ,100 <= _x && _x <= 200), [](auto&& a) {std::cout << "The answer " << a << " is between 100 and 200 inclusive\n"; }, | |
otherwise, []() {std::cout << "Did not match\n"; } | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment