// // match.hpp // case-matcher // // Created by Sam Jaffe on 9/10/16. // #pragma once #include #include namespace matcher { struct {} any; using any_t = decltype(any); template bool operator==(T const &, any_t) { return true; } } namespace matcher { template struct any_of_t { std::array options; }; template bool operator==(T const & t, any_of_t const & of) { return std::find(of.options.begin(), of.options.end(), t) != of.options.end(); } template any_of_t::type, sizeof...(Args)> any_of(Args &&... args) { return {{args...}}; } } namespace matcher { template struct any_in_t { Container options; }; template bool operator==(T const & t, any_in_t const & of) { return std::find(of.options.begin(), of.options.end(), t) != of.options.end(); } template any_in_t any_in(Container && args) { return {args}; } } namespace matcher { template struct predicate_t { Pred predicate; }; template bool operator==(T const & t, predicate_t const & of) { return of.predicate(t); } template predicate_t matches(Pred && args) { return {args}; } } namespace matcher { template struct matcher { public: matcher(Args &&... args) : value(std::forward(args)...) {} operator bool( ) const { return true; } bool unmatched( ) const { return ! satisfied; } template bool matches(NArgs &&... args) const { bool const matched = value == std::make_tuple(std::forward(args)...); satisfied |= matched; return matched; } private: std::tuple value; mutable bool satisfied = false; }; template matcher make_matcher(Args &&... args) { return matcher(std::forward(args)...); } } #define match( ... ) \ if ( auto const & _matcher_local = \ ::matcher::make_matcher( __VA_ARGS__ ) ) #define with( ... ) \ if ( _matcher_local.unmatched( ) && \ _matcher_local.matches( __VA_ARGS__ ) ) #define else_with( ... ) \ else if ( _matcher_local.matches( __VA_ARGS__ ) ) #define and_with( ... ) \ if ( _matcher_local.matches( __VA_ARGS__ ) ) #define nomatch( ) \ if ( _matcher_local.unmatched( ) )