diff --git a/develop/matchit.h b/develop/matchit.h new file mode 100644 index 0000000..e785ebe --- /dev/null +++ b/develop/matchit.h @@ -0,0 +1,6 @@ +// Replace include/matchit.h with this file when developing. + +#include "../develop/matchit/core.h" +#include "../develop/matchit/expression.h" +#include "../develop/matchit/patterns.h" +#include "../develop/matchit/utility.h" diff --git a/develop/matchit/patterns.h b/develop/matchit/patterns.h index 597504e..9e87e0a 100644 --- a/develop/matchit/patterns.h +++ b/develop/matchit/patterns.h @@ -214,6 +214,22 @@ namespace matchit static_assert(std::is_same_v, int32_t const *>); static_assert(std::is_same_v, int32_t const &>); + template + struct AddConstToPointer + { + using type = std::conditional_t< + !std::is_pointer_v, T, + std::add_pointer_t>>>; + }; + template + using AddConstToPointerT = typename AddConstToPointer::type; + + static_assert(std::is_same_v, void const *>); + static_assert(std::is_same_v, int32_t>); + + template + using EscapeArrayT = AddConstToPointerT>; + template class PatternTraits; @@ -310,7 +326,7 @@ namespace matchit private: Pattern const mPattern; - Func const mHandler; + std::conditional_t, Func const &, Func const> mHandler; }; template @@ -439,7 +455,7 @@ namespace matchit constexpr auto const &patterns() const { return mPatterns; } private: - std::tuple mPatterns; + std::tuple...> mPatterns; }; template @@ -530,7 +546,7 @@ namespace matchit private: Unary const mUnary; - Pattern const mPattern; + EscapeArrayT const mPattern; }; template @@ -602,7 +618,7 @@ namespace matchit constexpr auto const &patterns() const { return mPatterns; } private: - std::tuple mPatterns; + std::tuple...> mPatterns; }; template @@ -681,7 +697,7 @@ namespace matchit auto const &pattern() const { return mPattern; } private: - Pattern mPattern; + EscapeArrayT mPattern; }; template @@ -944,22 +960,7 @@ namespace matchit constexpr explicit Ds(Patterns const &...patterns) : mPatterns{patterns...} {} constexpr auto const &patterns() const { return mPatterns; } - private: - template - struct AddConstToPointer - { - using type = std::conditional_t< - !std::is_pointer_v, T, - std::add_pointer_t>>>; - }; - template - using AddConstToPointerT = typename AddConstToPointer::type; - - static_assert(std::is_same_v, void const *>); - static_assert(std::is_same_v, int32_t>); - - public: - using Type = std::tuple>...>; + using Type = std::tuple...>; private: Type mPatterns; diff --git a/develop/matchit/utility.h b/develop/matchit/utility.h index 497c42e..9133ef6 100644 --- a/develop/matchit/utility.h +++ b/develop/matchit/utility.h @@ -93,16 +93,16 @@ namespace matchit constexpr auto dsVia = [](auto &&...members) { - return [members...](auto &&...pats) + return [members...](auto ...pats) { return and_(app(members, pats)...); }; }; template constexpr auto asDsVia = [](auto &&...members) { - return [members...](auto &&...pats) + return [members...](auto ...pats) { - return as(and_(app(members, pats)...)); + return as(dsVia(members...)(pats...)); }; }; diff --git a/include/matchit.h b/include/matchit.h index a096394..e785ebe 100644 --- a/include/matchit.h +++ b/include/matchit.h @@ -1,2052 +1,6 @@ -/* - * Copyright (c) 2021 Bowen Fu - * Distributed Under The Apache-2.0 License - */ +// Replace include/matchit.h with this file when developing. -#ifndef MATCHIT_H -#define MATCHIT_H - -#ifndef MATCHIT_CORE_H -#define MATCHIT_CORE_H - -#include -#include -#include - -namespace matchit -{ - namespace impl - { - template - class ValueType - { - public: - using ValueT = Value; - }; - - template - class ValueType - { - public: - using ValueT = Value &&; - }; - - template - constexpr auto matchPatterns(Value &&value, Patterns const &...patterns); - - template - class MatchHelper - { - private: - using ValueT = typename ValueType::ValueT; - ValueT mValue; - using ValueRefT = ValueT &&; - - public: - template - constexpr explicit MatchHelper(V &&value) : mValue{std::forward(value)} {} - template - constexpr auto operator()(PatternPair const &...patterns) - { - return matchPatterns(std::forward(mValue), patterns...); - } - }; - - template - constexpr auto match(Value &&value) - { - return MatchHelper{std::forward(value)}; - } - - template - constexpr auto match(First &&first, Values &&...values) - { - auto result = std::forward_as_tuple(std::forward(first), - std::forward(values)...); - return MatchHelper{ - std::forward(result)}; - } - } // namespace impl - - // export symbols - using impl::match; - -} // namespace matchit -#endif // MATCHIT_CORE_H -#ifndef MATCHIT_EXPRESSION_H -#define MATCHIT_EXPRESSION_H - -#include - -namespace matchit -{ - namespace impl - { - template - class Nullary : public T - { - public: - using T::operator(); - }; - - template - constexpr auto nullary(T const &t) - { - return Nullary{t}; - } - - template - class Id; - template - constexpr auto expr(Id &id) - { - return nullary([&] - { return *id; }); - } - - template - constexpr auto expr(T const &v) - { - return nullary([&] - { return v; }); - } - - // for constant - template - class EvalTraits - { - public: - template - constexpr static decltype(auto) evalImpl(T const &v, Args const &...) - { - return v; - } - }; - - template - class EvalTraits> - { - public: - constexpr static decltype(auto) evalImpl(Nullary const &e) { return e(); } - }; - - // Only allowed in nullary - template - class EvalTraits> - { - public: - constexpr static decltype(auto) evalImpl(Id const &id) - { - return *const_cast &>(id); - } - }; - - template - class Meet; - - // Unary is an alias of Meet. - template - using Unary = Meet; - - template - class EvalTraits> - { - public: - template - constexpr static decltype(auto) evalImpl(Unary const &e, Arg const &arg) - { - return e(arg); - } - }; - - class Wildcard; - template <> - class EvalTraits - { - public: - template - constexpr static decltype(auto) evalImpl(Wildcard const &, Arg const &arg) - { - return arg; - } - }; - - template - constexpr decltype(auto) evaluate_(T const &t, Args const &...args) - { - return EvalTraits::evalImpl(t, args...); - } - - template - class IsNullaryOrId : public std::false_type - { - }; - - template - class IsNullaryOrId> : public std::true_type - { - }; - - template - class IsNullaryOrId> : public std::true_type - { - }; - - template - constexpr auto isNullaryOrIdV = IsNullaryOrId>::value; - -#define UN_OP_FOR_NULLARY(op) \ - template , bool> = true> \ - constexpr auto operator op(T const &t) \ - { \ - return nullary([&] { return op evaluate_(t); }); \ - } - -#define BIN_OP_FOR_NULLARY(op) \ - template || isNullaryOrIdV, bool> = \ - true> \ - constexpr auto operator op(T const &t, U const &u) \ - { \ - return nullary([&] { return evaluate_(t) op evaluate_(u); }); \ - } - - // ADL will find these operators. - UN_OP_FOR_NULLARY(!) - UN_OP_FOR_NULLARY(-) - -#undef UN_OP_FOR_NULLARY - - BIN_OP_FOR_NULLARY(+) - BIN_OP_FOR_NULLARY(-) - BIN_OP_FOR_NULLARY(*) - BIN_OP_FOR_NULLARY(/) - BIN_OP_FOR_NULLARY(%) - BIN_OP_FOR_NULLARY(<) - BIN_OP_FOR_NULLARY(<=) - BIN_OP_FOR_NULLARY(==) - BIN_OP_FOR_NULLARY(!=) - BIN_OP_FOR_NULLARY(>=) - BIN_OP_FOR_NULLARY(>) - BIN_OP_FOR_NULLARY(||) - BIN_OP_FOR_NULLARY(&&) - BIN_OP_FOR_NULLARY(^) - -#undef BIN_OP_FOR_NULLARY - - // Unary - template - class IsUnaryOrWildcard : public std::false_type - { - }; - - template <> - class IsUnaryOrWildcard : public std::true_type - { - }; - - template - class IsUnaryOrWildcard> : public std::true_type - { - }; - - template - constexpr auto isUnaryOrWildcardV = IsUnaryOrWildcard>::value; - - // unary is an alias of meet. - template - constexpr auto unary(T &&t) - { - return meet(std::forward(t)); - } - -#define UN_OP_FOR_UNARY(op) \ - template , bool> = true> \ - constexpr auto operator op(T const &t) \ - { \ - return unary([&](auto &&arg) constexpr { return op evaluate_(t, arg); }); \ - } - -#define BIN_OP_FOR_UNARY(op) \ - template || isUnaryOrWildcardV, \ - bool> = true> \ - constexpr auto operator op(T const &t, U const &u) \ - { \ - return unary([&](auto &&arg) constexpr { \ - return evaluate_(t, arg) op evaluate_(u, arg); \ - }); \ - } - - UN_OP_FOR_UNARY(!) - UN_OP_FOR_UNARY(-) - -#undef UN_OP_FOR_UNARY - - BIN_OP_FOR_UNARY(+) - BIN_OP_FOR_UNARY(-) - BIN_OP_FOR_UNARY(*) - BIN_OP_FOR_UNARY(/) - BIN_OP_FOR_UNARY(%) - BIN_OP_FOR_UNARY(<) - BIN_OP_FOR_UNARY(<=) - BIN_OP_FOR_UNARY(==) - BIN_OP_FOR_UNARY(!=) - BIN_OP_FOR_UNARY(>=) - BIN_OP_FOR_UNARY(>) - BIN_OP_FOR_UNARY(||) - BIN_OP_FOR_UNARY(&&) - BIN_OP_FOR_UNARY(^) - -#undef BIN_OP_FOR_UNARY - - } // namespace impl - using impl::expr; -} // namespace matchit - -#endif // MATCHIT_EXPRESSION_H -#ifndef MATCHIT_PATTERNS_H -#define MATCHIT_PATTERNS_H - -#include -#include -#include -#include -#include -#include -#include - -namespace matchit -{ - namespace impl - { - template - class Subrange - { - I mBegin; - S mEnd; - - public: - constexpr Subrange(I const begin, S const end) : mBegin{begin}, mEnd{end} {} - - constexpr Subrange(Subrange const &other) - : mBegin{other.begin()}, mEnd{other.end()} {} - - Subrange &operator=(Subrange const &other) - { - mBegin = other.begin(); - mEnd = other.end(); - return *this; - } - - size_t size() const - { - return static_cast(std::distance(mBegin, mEnd)); - } - auto begin() const { return mBegin; } - auto end() const { return mEnd; } - }; - - template - constexpr auto makeSubrange(I begin, S end) - { - return Subrange{begin, end}; - } - - template - class IterUnderlyingType - { - public: - using beginT = decltype(std::begin(std::declval())); - using endT = decltype(std::end(std::declval())); - }; - - // force array iterators fallback to pointers. - template - class IterUnderlyingType> - { - public: - using beginT = - decltype(&*std::begin(std::declval &>())); - using endT = beginT; - }; - - // force array iterators fallback to pointers. - template - class IterUnderlyingType const> - { - public: - using beginT = - decltype(&*std::begin(std::declval const &>())); - using endT = beginT; - }; - - template - using SubrangeT = Subrange::beginT, - typename IterUnderlyingType::endT>; - - template - bool operator==(Subrange const &lhs, Subrange const &rhs) - { - using std::operator==; - return lhs.size() == rhs.size() && - std::equal(lhs.begin(), lhs.end(), rhs.begin()); - } - - template - auto operator==(std::pair const &t, std::pair const &u) - { - return t.first == u.first && t.second == u.second; - } - - template - class WithinTypes - { - public: - constexpr static auto value = (std::is_same_v || ...); - }; - - template - class PrependUnique; - - template - class PrependUnique> - { - constexpr static auto unique = !WithinTypes::value; - - public: - using type = - std::conditional_t, std::tuple>; - }; - - template - using PrependUniqueT = typename PrependUnique::type; - - template - class Unique; - - template - using UniqueT = typename Unique::type; - - template <> - class Unique> - { - public: - using type = std::tuple<>; - }; - - template - class Unique> - { - public: - using type = PrependUniqueT>>; - }; - - static_assert( - std::is_same_v, UniqueT>>); - static_assert( - std::is_same_v, int32_t>, - UniqueT, int32_t>>>); - - using std::get; - - namespace detail - { - template - constexpr decltype(auto) subtupleImpl(Tuple &&t, std::index_sequence) - { - return std::forward_as_tuple(get(std::forward(t))...); - } - } // namespace detail - - // [start, end) - template - constexpr decltype(auto) subtuple(Tuple &&t) - { - constexpr auto tupleSize = std::tuple_size_v>; - static_assert(start <= end); - static_assert(end <= tupleSize); - return detail::subtupleImpl(std::forward(t), - std::make_index_sequence{}); - } - - template - constexpr decltype(auto) drop(Tuple &&t) - { - constexpr auto tupleSize = std::tuple_size_v>; - static_assert(start <= tupleSize); - return subtuple(std::forward(t)); - } - - template - constexpr decltype(auto) take(Tuple &&t) - { - constexpr auto tupleSize = std::tuple_size_v>; - static_assert(len <= tupleSize); - return subtuple<0, len>(std::forward(t)); - } - - template - constexpr decltype(auto) apply_(F &&f, Tuple &&t) - { - return std::apply(std::forward(f), drop<0>(std::forward(t))); - } - - // as constexpr - template - constexpr std::invoke_result_t - invoke_(F &&f, - Args &&...args) noexcept(std::is_nothrow_invocable_v) - { - return std::apply(std::forward(f), - std::forward_as_tuple(std::forward(args)...)); - } - - template - struct decayArray - { - private: - typedef typename std::remove_reference::type U; - - public: - using type = - typename std::conditional_t::value, - typename std::remove_extent::type *, T>; - }; - - template - using decayArrayT = typename decayArray::type; - - static_assert(std::is_same_v, int32_t *>); - static_assert(std::is_same_v, int32_t const *>); - static_assert(std::is_same_v, int32_t const &>); - - template - class PatternTraits; - - template - class PatternPairsRetType - { - public: - using RetType = std::common_type_t; - }; - - enum class IdProcess : int32_t - { - kCANCEL, - kCONFIRM - }; - - template - constexpr void processId(Pattern const &pattern, int32_t depth, - IdProcess idProcess) - { - PatternTraits::processIdImpl(pattern, depth, idProcess); - } - - template - class Variant; - - template - class Variant> - { - public: - using type = std::variant; - }; - - template - class Context - { - using ElementT = typename Variant>>::type; - using ContainerT = std::array; - ContainerT mMemHolder; - size_t mSize = 0; - - public: - template - constexpr void emplace_back(T &&t) - { - mMemHolder[mSize] = std::forward(t); - ++mSize; - } - constexpr auto back() -> ElementT & { return mMemHolder[mSize - 1]; } - }; - - template <> - class Context<> - { - }; - - template - class ContextTrait; - - template - class ContextTrait> - { - public: - using ContextT = Context; - }; - - template - constexpr auto matchPattern(Value &&value, Pattern const &pattern, - int32_t depth, ConctextT &context) - { - auto const result = PatternTraits::matchPatternImpl( - std::forward(value), pattern, depth, context); - auto const process = result ? IdProcess::kCONFIRM : IdProcess::kCANCEL; - processId(pattern, depth, process); - return result; - } - - template - class PatternPair - { - public: - using RetType = std::invoke_result_t; - using PatternT = Pattern; - - constexpr PatternPair(Pattern const &pattern, Func const &func) - : mPattern{pattern}, mHandler{func} {} - template - constexpr bool matchValue(Value &&value, ContextT &context) const - { - return matchPattern(std::forward(value), mPattern, /*depth*/ 0, - context); - } - constexpr auto execute() const { return mHandler(); } - - private: - Pattern const mPattern; - std::conditional_t, Func const&, Func const> mHandler; - }; - - template - class PostCheck; - - template - class When - { - public: - Pred mPred; - }; - - template - constexpr auto when(Pred const &pred) - { - return When{pred}; - } - - template - class PatternHelper - { - public: - constexpr explicit PatternHelper(Pattern const &pattern) - : mPattern{pattern} {} - template - constexpr auto operator=(Func const &func) - { - return PatternPair{mPattern, func}; - } - template - constexpr auto operator|(When const &w) - { - return PatternHelper>( - PostCheck(mPattern, w.mPred)); - } - - private: - Pattern const mPattern; - }; - - template - class Ds; - - template - constexpr auto ds(Patterns const &...patterns) -> Ds; - - template - class OooBinder; - - class PatternPipable - { - public: - template - constexpr auto operator|(Pattern const &p) const - { - return PatternHelper{p}; - } - - template - constexpr auto operator|(T const *p) const - { - return PatternHelper{p}; - } - - template - constexpr auto operator|(OooBinder const &p) const - { - return operator|(ds(p)); - } - }; - - constexpr PatternPipable pattern{}; - - template - class PatternTraits - { - public: - template - using AppResultTuple = std::tuple<>; - - constexpr static auto nbIdV = 0; - - template - constexpr static auto matchPatternImpl(Value &&value, Pattern const &pattern, - int32_t /* depth */, - ContextT & /*context*/) - { - return pattern == std::forward(value); - } - constexpr static void processIdImpl(Pattern const &, int32_t /*depth*/, - IdProcess) {} - }; - - class Wildcard - { - }; - - constexpr Wildcard _; - - template <> - class PatternTraits - { - using Pattern = Wildcard; - - public: - template - using AppResultTuple = std::tuple<>; - - constexpr static auto nbIdV = 0; - - template - constexpr static bool matchPatternImpl(Value &&, Pattern const &, int32_t, - ContextT &) - { - return true; - } - constexpr static void processIdImpl(Pattern const &, int32_t /*depth*/, - IdProcess) {} - }; - - template - class Or - { - public: - constexpr explicit Or(Patterns const &...patterns) : mPatterns{patterns...} {} - constexpr auto const &patterns() const { return mPatterns; } - - private: - std::tuple mPatterns; - }; - - template - constexpr auto or_(Patterns const &...patterns) - { - return Or{patterns...}; - } - - template - class PatternTraits> - { - public: - template - using AppResultTuple = decltype(std::tuple_cat( - typename PatternTraits::template AppResultTuple{}...)); - - constexpr static auto nbIdV = (PatternTraits::nbIdV + ... + 0); - - template - constexpr static auto matchPatternImpl(Value &&value, - Or const &orPat, - int32_t depth, ContextT &context) - { - constexpr auto patSize = sizeof...(Patterns); - return std::apply( - [&value, depth, &context](auto const &...patterns) - { - return (matchPattern(value, patterns, depth + 1, context) || - ...); - }, - take(orPat.patterns())) || - matchPattern(std::forward(value), - get(orPat.patterns()), depth + 1, context); - } - constexpr static void processIdImpl(Or const &orPat, - int32_t depth, IdProcess idProcess) - { - return std::apply( - [depth, idProcess](Patterns const &...patterns) - { - return (processId(patterns, depth, idProcess), ...); - }, - orPat.patterns()); - } - }; - - template - class Meet : public Pred - { - public: - using Pred::operator(); - }; - - template - constexpr auto meet(Pred const &pred) - { - return Meet{pred}; - } - - template - class PatternTraits> - { - public: - template - using AppResultTuple = std::tuple<>; - - constexpr static auto nbIdV = 0; - - template - constexpr static auto matchPatternImpl(Value &&value, - Meet const &meetPat, - int32_t /* depth */, ContextT &) - { - return meetPat(std::forward(value)); - } - constexpr static void processIdImpl(Meet const &, int32_t /*depth*/, - IdProcess) {} - }; - - template - class App - { - public: - constexpr App(Unary &&unary, Pattern const &pattern) - : mUnary{std::forward(unary)}, mPattern{pattern} {} - constexpr auto const &unary() const { return mUnary; } - constexpr auto const &pattern() const { return mPattern; } - - private: - Unary const mUnary; - Pattern const mPattern; - }; - - template - constexpr auto app(Unary &&unary, Pattern const &pattern) - { - return App{std::forward(unary), pattern}; - } - - constexpr auto y = 1; - static_assert(std::holds_alternative( - std::variant{&y})); - - template - class PatternTraits> - { - public: - template - using AppResult = std::invoke_result_t; - // We store value for scalar types in Id and they can not be moved. So to - // support constexpr. - template - using AppResultCurTuple = - std::conditional_t> || - std::is_scalar_v>, - std::tuple<>, - std::tuple>>>; - - template - using AppResultTuple = decltype(std::tuple_cat( - std::declval>(), - std::declval::template AppResultTuple< - AppResult>>())); - - constexpr static auto nbIdV = PatternTraits::nbIdV; - - template - constexpr static auto matchPatternImpl(Value &&value, - App const &appPat, - int32_t depth, ContextT &context) - { - if constexpr (std::is_same_v, std::tuple<>>) - { - return matchPattern( - std::forward>(invoke_(appPat.unary(), value)), - appPat.pattern(), depth + 1, context); - } - else - { - context.emplace_back(invoke_(appPat.unary(), value)); - decltype(auto) result = - get>>(context.back()); - return matchPattern(std::forward>(result), - appPat.pattern(), depth + 1, context); - } - } - constexpr static void processIdImpl(App const &appPat, - int32_t depth, IdProcess idProcess) - { - return processId(appPat.pattern(), depth, idProcess); - } - }; - - template - class And - { - public: - constexpr explicit And(Patterns const &...patterns) - : mPatterns{patterns...} {} - constexpr auto const &patterns() const { return mPatterns; } - - private: - std::tuple mPatterns; - }; - - template - constexpr auto and_(Patterns const &...patterns) - { - return And{patterns...}; - } - - template - class NbIdInTuple; - - template - class NbIdInTuple> - { - public: - constexpr static auto nbIdV = - (PatternTraits>::nbIdV + ... + 0); - }; - - template - class PatternTraits> - { - public: - template - using AppResultTuple = decltype(std::tuple_cat( - std::declval::template AppResultTuple< - Value>>()...)); - - constexpr static auto nbIdV = (PatternTraits::nbIdV + ... + 0); - - template - constexpr static auto matchPatternImpl(Value &&value, - And const &andPat, - int32_t depth, ContextT &context) - { - constexpr auto patSize = sizeof...(Patterns); - auto const exceptLast = std::apply( - [&value, depth, &context](auto const &...patterns) - { - return (matchPattern(value, patterns, depth + 1, context) && ...); - }, - take(andPat.patterns())); - - // No Id in patterns except the last one. - if constexpr (NbIdInTuple( - andPat.patterns()))>>::nbIdV == 0) - { - return exceptLast && matchPattern(std::forward(value), - get(andPat.patterns()), - depth + 1, context); - } - else - { - return exceptLast && - matchPattern(value, get(andPat.patterns()), depth + 1, - context); - } - } - constexpr static void processIdImpl(And const &andPat, - int32_t depth, IdProcess idProcess) - { - return std::apply( - [depth, idProcess](Patterns const &...patterns) - { - return (processId(patterns, depth, idProcess), ...); - }, - andPat.patterns()); - } - }; - - template - class Not - { - public: - explicit Not(Pattern const &pattern) : mPattern{pattern} {} - auto const &pattern() const { return mPattern; } - - private: - Pattern mPattern; - }; - - template - constexpr auto not_(Pattern const &pattern) - { - return Not{pattern}; - } - - template - class PatternTraits> - { - public: - template - using AppResultTuple = - typename PatternTraits::template AppResultTuple; - - constexpr static auto nbIdV = PatternTraits::nbIdV; - - template - constexpr static auto matchPatternImpl(Value &&value, - Not const ¬Pat, - int32_t depth, ContextT &context) - { - return !matchPattern(std::forward(value), notPat.pattern(), - depth + 1, context); - } - constexpr static void processIdImpl(Not const ¬Pat, int32_t depth, - IdProcess idProcess) - { - processId(notPat.pattern(), depth, idProcess); - } - }; - - template > - struct StorePointer : std::false_type - { - }; - - template - using ValueVariant = - std::conditional_t, - std::variant, - std::variant>; - - template - struct StorePointer &>() = - &std::declval())>> - : std::conjunction, - std::negation>> - { - }; - - static_assert(StorePointer::value); - static_assert(StorePointer::value); - static_assert(StorePointer::value); - static_assert(StorePointer const, - std::tuple const &>::value); - - template - class Overload : public Ts... - { - public: - using Ts::operator()...; - }; - - template - constexpr auto overload(Ts &&...ts) - { - return Overload{ts...}; - } - - template - class OooBinder; - - class Ooo; - - template - class IdTraits - { - public: - constexpr static auto -#if defined(__has_feature) -#if __has_feature(address_sanitizer) - __attribute__((no_sanitize_address)) -#endif -#endif - equal(Type const &lhs, Type const &rhs) - { - return lhs == rhs; - } - }; - - template - class Id - { - private: - class Block - { - public: - ValueVariant mVariant; - int32_t mDepth; - - constexpr auto &variant() { return mVariant; } - constexpr auto hasValue() const - { - return std::visit(overload([](Type const &) - { return true; }, - [](Type const *) - { return true; }, - [](std::monostate const &) - { return false; }), - mVariant); - } - constexpr decltype(auto) value() const - { - return std::visit( - overload([](Type const &v) -> Type const & { return v; }, - [](Type const *p) -> Type const & { return *p; }, - [](std::monostate const &) -> Type const & { - throw std::logic_error("invalid state!"); - }), - mVariant); - } - - constexpr decltype(auto) mutableValue() - { - return std::visit( - overload([](Type &v) -> Type & { return v; }, - [](Type const *) -> Type & { - throw std::logic_error( - "Cannot get mutableValue for pointer type!"); - }, - [](std::monostate &) -> Type & { - throw std::logic_error("Invalid state!"); - }), - mVariant); - } - constexpr void reset(int32_t depth) - { - if (mDepth - depth >= 0) - { - mVariant = {}; - mDepth = depth; - } - } - constexpr void confirm(int32_t depth) - { - if (mDepth > depth || mDepth == 0) - { - assert(depth == mDepth - 1 || depth == mDepth || mDepth == 0); - mDepth = depth; - } - } - }; - class IdUtil - { - public: - template - constexpr static auto bindValue(ValueVariant &v, Value &&value, - std::false_type /* StorePointer */) - { - // for constexpr - v = ValueVariant{std::forward(value)}; - } - template - constexpr static auto bindValue(ValueVariant &v, Value &&value, - std::true_type /* StorePointer */) - { - v = ValueVariant{&value}; - } - }; - - using BlockVT = std::variant; - BlockVT mBlock = Block{}; - - constexpr Type const &internalValue() const { return block().value(); } - - public: - constexpr Id() = default; - - constexpr Id(Id const &id) { mBlock = BlockVT{&id.block()}; } - - // non-const to inform users not to mark Id as const. - template - constexpr auto at(Pattern &&pattern) - { - return and_(pattern, *this); - } - - // non-const to inform users not to mark Id as const. - constexpr auto at(Ooo const &) { return OooBinder{*this}; } - - constexpr Block &block() const - { - return std::visit(overload([](Block &v) -> Block & { return v; }, - [](Block *p) -> Block & { return *p; }), - // constexpr does not allow mutable, we use const_cast - // instead. Never declare Id as const. - const_cast(mBlock)); - } - - template - constexpr auto - matchValue(Value &&v) const - { - if (hasValue()) - { - return IdTraits::equal(internalValue(), v); - } - IdUtil::bindValue(block().variant(), std::forward(v), - StorePointer{}); - return true; - } - constexpr void reset(int32_t depth) const { return block().reset(depth); } - constexpr void confirm(int32_t depth) const { return block().confirm(depth); } - constexpr bool hasValue() const { return block().hasValue(); } - // non-const to inform users not to mark Id as const. - constexpr Type const &value() { return block().value(); } - // non-const to inform users not to mark Id as const. - constexpr Type const &operator*() { return value(); } - constexpr Type &&move() { return std::move(block().mutableValue()); } - }; - - template - class PatternTraits> - { - public: - template - using AppResultTuple = std::tuple<>; - - constexpr static auto nbIdV = true; - - template - constexpr static auto matchPatternImpl(Value &&value, Id const &idPat, - int32_t /* depth */, ContextT &) - { - return idPat.matchValue(std::forward(value)); - } - constexpr static void processIdImpl(Id const &idPat, int32_t depth, - IdProcess idProcess) - { - switch (idProcess) - { - case IdProcess::kCANCEL: - idPat.reset(depth); - break; - - case IdProcess::kCONFIRM: - idPat.confirm(depth); - break; - } - } - }; - - template - class Ds - { - public: - constexpr explicit Ds(Patterns const &...patterns) : mPatterns{patterns...} {} - constexpr auto const &patterns() const { return mPatterns; } - - private: - template - struct AddConstToPointer - { - using type = std::conditional_t< - !std::is_pointer_v, T, - std::add_pointer_t>>>; - }; - template - using AddConstToPointerT = typename AddConstToPointer::type; - - static_assert(std::is_same_v, void const *>); - static_assert(std::is_same_v, int32_t>); - - public: - using Type = std::tuple>...>; - - private: - Type mPatterns; - }; - - template - constexpr auto ds(Patterns const &...patterns) -> Ds - { - return Ds{patterns...}; - } - - template - class OooBinder - { - Id mId; - - public: - OooBinder(Id const &id) : mId{id} {} - decltype(auto) binder() const { return mId; } - }; - - class Ooo - { - public: - template - constexpr auto operator()(Id id) const - { - return OooBinder{id}; - } - }; - - constexpr Ooo ooo; - - template <> - class PatternTraits - { - public: - template - using AppResultTuple = std::tuple<>; - - constexpr static auto nbIdV = false; - - template - constexpr static auto matchPatternImpl(Value &&, Ooo, int32_t /*depth*/, - ContextT &) - { - return true; - } - constexpr static void processIdImpl(Ooo, int32_t /*depth*/, IdProcess) {} - }; - - template - class PatternTraits> - { - public: - template - using AppResultTuple = - typename PatternTraits::template AppResultTuple; - - constexpr static auto nbIdV = PatternTraits::nbIdV; - - template - constexpr static auto matchPatternImpl(Value &&value, - OooBinder const &oooBinderPat, - int32_t depth, ContextT &context) - { - return matchPattern(std::forward(value), oooBinderPat.binder(), - depth + 1, context); - } - constexpr static void processIdImpl(OooBinder const &oooBinderPat, - int32_t depth, IdProcess idProcess) - { - processId(oooBinderPat.binder(), depth, idProcess); - } - }; - - template - class IsOoo : public std::false_type - { - }; - - template <> - class IsOoo : public std::true_type - { - }; - - template - class IsOooBinder : public std::false_type - { - }; - - template - class IsOooBinder> : public std::true_type - { - }; - - template - constexpr auto isOooBinderV = IsOooBinder>::value; - - template - constexpr auto isOooOrBinderV = - IsOoo>::value || isOooBinderV; - - template - constexpr auto nbOooOrBinderV = ((isOooOrBinderV ? 1 : 0) + ... + 0); - - static_assert( - nbOooOrBinderV == - 2); - - template - constexpr size_t findOooIdxImpl(std::index_sequence) - { - return ((isOooOrBinderV(std::declval()))> ? I : 0) + - ...); - } - - template - constexpr size_t findOooIdx() - { - return findOooIdxImpl( - std::make_index_sequence< - std::tuple_size_v>>{}); - } - - static_assert(isOooOrBinderV); - static_assert(isOooOrBinderV>); - static_assert( - findOooIdx, const char *>>() == 1); - static_assert(findOooIdx>() == 1); - - using std::get; - template - constexpr decltype(auto) - matchPatternMultipleImpl(ValueTuple &&valueTuple, PatternTuple &&patternTuple, - int32_t depth, ContextT &context, - std::index_sequence) - { - auto const func = [&](auto &&value, auto &&pattern) - { - return matchPattern(std::forward(value), pattern, - depth + 1, context); - }; - static_cast(func); - return (func(get(std::forward(valueTuple)), - std::get(patternTuple)) && - ...); - } - - template - constexpr decltype(auto) - matchPatternMultiple(ValueTuple &&valueTuple, PatternTuple &&patternTuple, - int32_t depth, ContextT &context) - { - return matchPatternMultipleImpl( - std::forward(valueTuple), patternTuple, depth, context, - std::make_index_sequence{}); - } - - template - constexpr decltype(auto) matchPatternRangeImpl(RangeBegin &&rangeBegin, - PatternTuple &&patternTuple, - int32_t depth, ContextT &context, - std::index_sequence) - { - auto const func = [&](auto &&value, auto &&pattern) - { - return matchPattern(std::forward(value), pattern, - depth + 1, context); - }; - static_cast(func); - // Fix Me, avoid call next from begin every time. - return (func(*std::next(rangeBegin, static_cast(I)), - std::get(patternTuple)) && - ...); - } - - template - constexpr decltype(auto) matchPatternRange(ValueRangeBegin &&valueRangeBegin, - PatternTuple &&patternTuple, - int32_t depth, ContextT &context) - { - return matchPatternRangeImpl( - valueRangeBegin, patternTuple, depth, context, - std::make_index_sequence{}); - } - - template - class IndexedTypes; - - template - class IndexedTypes, Tuple> - { - public: - using type = std::tuple< - std::decay_t(std::declval()))>...>; - }; - - template - class SubTypes - { - constexpr static auto tupleSize = - std::tuple_size_v>; - static_assert(start <= end); - static_assert(end <= tupleSize); - - using Indices = std::make_index_sequence; - - public: - using type = typename IndexedTypes::type; - }; - - template - using SubTypesT = typename SubTypes::type; - - static_assert( - std::is_same_v< - std::tuple, - SubTypesT<3, 4, std::tuple>>); - static_assert( - std::is_same_v< - std::tuple, - SubTypesT<0, 1, std::tuple>>); - static_assert( - std::is_same_v< - std::tuple<>, - SubTypesT<1, 1, std::tuple>>); - static_assert( - std::is_same_v< - std::tuple, - SubTypesT<2, 4, std::tuple>>); - - template - class IsArray : public std::false_type - { - }; - - template - class IsArray> : public std::true_type - { - }; - - template - constexpr auto isArrayV = IsArray>::value; - - template > - struct IsTupleLike : std::false_type - { - }; - - template - struct IsTupleLike::value)>> - : std::true_type - { - }; - - template - constexpr auto isTupleLikeV = IsTupleLike>::value; - - static_assert(isTupleLikeV>); - static_assert(!isTupleLikeV); - - template > - struct IsRange : std::false_type - { - }; - - template - struct IsRange())), - decltype(std::end(std::declval()))>> - : std::true_type - { - }; - - template - constexpr auto isRangeV = IsRange>::value; - - static_assert(!isRangeV>); - static_assert(isRangeV>); - - template - class PatternTraits> - { - constexpr static auto nbOooOrBinder = nbOooOrBinderV; - static_assert(nbOooOrBinder == 0 || nbOooOrBinder == 1); - - public: - template - class PairPV; - - template - class PairPV, std::tuple> - { - public: - using type = decltype(std::tuple_cat( - std::declval< - typename PatternTraits::template AppResultTuple>()...)); - }; - - template - class AppResultForTupleHelper; - - template - class AppResultForTupleHelper<0, std::tuple> - { - public: - using type = decltype(std::tuple_cat( - std::declval::template AppResultTuple< - Values>>()...)); - }; - - template - class AppResultForTupleHelper<1, std::tuple> - { - constexpr static auto idxOoo = findOooIdx::Type>(); - using Ps0 = SubTypesT<0, idxOoo, std::tuple>; - using Vs0 = SubTypesT<0, idxOoo, std::tuple>; - constexpr static auto isBinder = - isOooBinderV>>; - // <0, ...int32_t> to workaround compile failure for std::tuple<>. - using ElemT = std::tuple_element_t< - 0, std::tuple..., int32_t>>; - constexpr static int64_t diff = - static_cast(sizeof...(Values) - sizeof...(Patterns)); - constexpr static size_t clippedDiff = - static_cast(diff > 0 ? diff : 0); - using OooResultTuple = typename std::conditional< - isBinder, std::tuple>>, - std::tuple<>>::type; - using FirstHalfTuple = typename PairPV::type; - using Ps1 = - SubTypesT>; - constexpr static auto vs1Start = - static_cast(static_cast(idxOoo) + 1 + diff); - using Vs1 = SubTypesT>; - using SecondHalfTuple = typename PairPV::type; - - public: - using type = decltype(std::tuple_cat(std::declval(), - std::declval(), - std::declval())); - }; - - template - using AppResultForTuple = typename AppResultForTupleHelper< - nbOooOrBinder, decltype(drop<0>(std::declval()))>::type; - - template - using RangeTuple = - std::conditional_t>, - std::tuple<>>; - - template - using AppResultForRangeType = decltype(std::tuple_cat( - std::declval>(), - std::declval::template AppResultTuple< - decltype(*std::begin(std::declval()))>>()...)); - - template > - class AppResultHelper; - - template - class AppResultHelper>> - { - public: - using type = AppResultForTuple; - }; - - template - class AppResultHelper && - isRangeV>> - { - public: - using type = AppResultForRangeType; - }; - - template - using AppResultTuple = typename AppResultHelper::type; - - constexpr static auto nbIdV = (PatternTraits::nbIdV + ... + 0); - - template - constexpr static auto matchPatternImpl(ValueTuple &&valueTuple, - Ds const &dsPat, - int32_t depth, ContextT &context) - -> std::enable_if_t, bool> - { - if constexpr (nbOooOrBinder == 0) - { - return std::apply( - [&valueTuple, depth, &context](auto const &...patterns) - { - return apply_( - [ depth, &context, &patterns... ](auto &&...values) constexpr - { - static_assert(sizeof...(patterns) == sizeof...(values)); - return (matchPattern(std::forward(values), - patterns, depth + 1, context) && - ...); - }, - valueTuple); - }, - dsPat.patterns()); - } - else if constexpr (nbOooOrBinder == 1) - { - constexpr auto idxOoo = findOooIdx::Type>(); - constexpr auto isBinder = - isOooBinderV>>; - constexpr auto isArray = isArrayV; - auto result = matchPatternMultiple<0, 0, idxOoo>( - std::forward(valueTuple), dsPat.patterns(), depth, - context); - constexpr auto valLen = std::tuple_size_v>; - constexpr auto patLen = sizeof...(Patterns); - if constexpr (isArray) - { - if constexpr (isBinder) - { - auto const rangeSize = static_cast(valLen - (patLen - 1)); - context.emplace_back(makeSubrange(&valueTuple[idxOoo], - &valueTuple[idxOoo] + rangeSize)); - using type = decltype(makeSubrange(&valueTuple[idxOoo], - &valueTuple[idxOoo] + rangeSize)); - result = result && matchPattern(std::get(context.back()), - std::get(dsPat.patterns()), - depth, context); - } - } - else - { - static_assert(!isBinder); - } - return result && matchPatternMultiple( - std::forward(valueTuple), - dsPat.patterns(), depth, context); - } - } - - template - constexpr static auto matchPatternImpl(ValueRange &&valueRange, - Ds const &dsPat, - int32_t depth, ContextT &context) - -> std::enable_if_t && isRangeV, - bool> - { - static_assert(nbOooOrBinder == 0 || nbOooOrBinder == 1); - constexpr auto nbPat = sizeof...(Patterns); - - if constexpr (nbOooOrBinder == 0) - { - // size mismatch for dynamic array is not an error; - if (valueRange.size() != nbPat) - { - return false; - } - return matchPatternRange<0, nbPat>(std::begin(valueRange), - dsPat.patterns(), depth, context); - } - else if constexpr (nbOooOrBinder == 1) - { - if (valueRange.size() < nbPat - 1) - { - return false; - } - constexpr auto idxOoo = findOooIdx::Type>(); - constexpr auto isBinder = - isOooBinderV>>; - auto result = matchPatternRange<0, idxOoo>( - std::begin(valueRange), dsPat.patterns(), depth, context); - auto const valLen = valueRange.size(); - constexpr auto patLen = sizeof...(Patterns); - auto const beginOoo = std::next(std::begin(valueRange), idxOoo); - if constexpr (isBinder) - { - auto const rangeSize = static_cast(valLen - (patLen - 1)); - auto const end = std::next(beginOoo, rangeSize); - context.emplace_back(makeSubrange(beginOoo, end)); - using type = decltype(makeSubrange(beginOoo, end)); - result = result && matchPattern(std::get(context.back()), - std::get(dsPat.patterns()), - depth, context); - } - auto const beginAfterOoo = - std::next(beginOoo, static_cast(valLen - patLen + 1)); - return result && matchPatternRange( - beginAfterOoo, dsPat.patterns(), depth, context); - } - } - - constexpr static void processIdImpl(Ds const &dsPat, - int32_t depth, IdProcess idProcess) - { - return std::apply( - [depth, idProcess](auto &&...patterns) - { - return (processId(patterns, depth, idProcess), ...); - }, - dsPat.patterns()); - } - }; - - static_assert( - std::is_same_v< - typename PatternTraits< - Ds>>>>:: - AppResultTuple>, - std::tuple>>); - - static_assert( - std::is_same_v< - typename PatternTraits>, - matchit::impl::Id>>:: - AppResultTuple>, - std::tuple>>); - - static_assert( - std::is_same_v< - typename PatternTraits>, - matchit::impl::Id>>:: - AppResultTuple>, - std::tuple>>); - - template - class PostCheck - { - public: - constexpr explicit PostCheck(Pattern const &pattern, Pred const &pred) - : mPattern{pattern}, mPred{pred} {} - constexpr bool check() const { return mPred(); } - constexpr auto const &pattern() const { return mPattern; } - - private: - Pattern const mPattern; - Pred const mPred; - }; - - template - class PatternTraits> - { - public: - template - using AppResultTuple = - typename PatternTraits::template AppResultTuple; - - template - constexpr static auto - matchPatternImpl(Value &&value, PostCheck const &postCheck, - int32_t depth, ContextT &context) - { - return matchPattern(std::forward(value), postCheck.pattern(), - depth + 1, context) && - postCheck.check(); - } - constexpr static void processIdImpl(PostCheck const &postCheck, - int32_t depth, IdProcess idProcess) - { - processId(postCheck.pattern(), depth, idProcess); - } - }; - - static_assert( - std::is_same_v::template AppResultTuple, - std::tuple<>>); - static_assert( - std::is_same_v::template AppResultTuple, - std::tuple<>>); - constexpr auto x = [](auto &&t) - { return t; }; - static_assert(std::is_same_v>:: - template AppResultTuple, - std::tuple<>>); - static_assert( - std::is_same_v>:: - template AppResultTuple>, - std::tuple>>); - static_assert(std::is_same_v>>:: - template AppResultTuple, - std::tuple<>>); - - static_assert(PatternTraits>>::nbIdV == 0); - static_assert(PatternTraits>>>::nbIdV == 1); - static_assert(PatternTraits, Id>>::nbIdV == 2); - static_assert(PatternTraits, Id>>::nbIdV == 2); - static_assert(PatternTraits>::nbIdV == 0); - - template - constexpr auto matchPatterns(Value &&value, PatternPairs const &...patterns) - { - using RetType = typename PatternPairsRetType::RetType; - using TypeTuple = decltype(std::tuple_cat( - std::declval:: - template AppResultTuple>()...)); - - // expression, has return value. - if constexpr (!std::is_same_v) - { - constexpr auto const func = - [](auto const &pattern, auto &&value, RetType &result) constexpr->bool - { - auto context = typename ContextTrait::ContextT{}; - if (pattern.matchValue(std::forward(value), context)) - { - result = pattern.execute(); - processId(pattern, 0, IdProcess::kCANCEL); - return true; - } - return false; - }; - RetType result{}; - bool const matched = (func(patterns, value, result) || ...); - if (!matched) - { - throw std::logic_error{"Error: no patterns got matched!"}; - } - static_cast(matched); - return result; - } - else - // statement, no return value, mismatching all patterns is not an error. - { - auto const func = [](auto const &pattern, auto &&value) -> bool - { - auto context = typename ContextTrait::ContextT{}; - if (pattern.matchValue(std::forward(value), context)) - { - pattern.execute(); - processId(pattern, 0, IdProcess::kCANCEL); - return true; - } - return false; - }; - bool const matched = (func(patterns, value) || ...); - static_cast(matched); - } - } - - } // namespace impl - - // export symbols - using impl::_; - using impl::and_; - using impl::app; - using impl::ds; - using impl::Id; - using impl::meet; - using impl::not_; - using impl::ooo; - using impl::or_; - using impl::pattern; - using impl::Subrange; - using impl::SubrangeT; - using impl::when; -} // namespace matchit - -#endif // MATCHIT_PATTERNS_H -#ifndef MATCHIT_UTILITY_H -#define MATCHIT_UTILITY_H - -#include -#include - -namespace matchit -{ - namespace impl - { - - template - constexpr auto cast = [](auto &&input) - { return static_cast(input); }; - - constexpr auto deref = [](auto &&x) -> decltype(*x) & { return *x; }; - constexpr auto some = [](auto const pat) - { - return and_(app(cast, true), app(deref, pat)); - }; - - constexpr auto none = app(cast, false); - - template > - struct ViaGetIf : std::false_type - { - }; - - using std::get_if; - - template - struct ViaGetIf< - T, Variant, - std::void_t(std::declval()))>> - : std::true_type - { - }; - - template - constexpr auto viaGetIfV = ViaGetIf::value; - - static_assert(viaGetIfV>); - - template - class AsPointer - { - public: - template >::type * = nullptr> - constexpr auto operator()(Variant const &v) const - { - return get_if(std::addressof(v)); - } - - // template to disable implicit cast to std::any - template ::value>::type * = nullptr> - constexpr auto operator()(A const &a) const - { - return std::any_cast(std::addressof(a)); - } - - template && std::is_base_of_v>::type * = nullptr> - constexpr auto operator()(D const &d) const - -> decltype(static_cast(std::addressof(d))) - { - return static_cast(std::addressof(d)); - } - - template && std::is_base_of_v>::type * = nullptr> - constexpr auto operator()(B const &b) const - -> decltype(dynamic_cast(std::addressof(b))) - { - return dynamic_cast(std::addressof(b)); - } - }; - - template - constexpr AsPointer asPointer; - - template - constexpr auto as = [](auto const pat) - { return app(asPointer, some(pat)); }; - - template - constexpr auto matched(Value &&v, Pattern &&p) - { - return match(std::forward(v))( - pattern | std::forward(p) = [] - { return true; }, - pattern | _ = [] - { 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::asDsVia; - using impl::dsVia; - using impl::matched; - using impl::none; - using impl::some; -} // namespace matchit - -#endif // MATCHIT_UTILITY_H - -#endif // MATCHIT_H +#include "../develop/matchit/core.h" +#include "../develop/matchit/expression.h" +#include "../develop/matchit/patterns.h" +#include "../develop/matchit/utility.h" diff --git a/sample/CMakeLists.txt b/sample/CMakeLists.txt index 2ed2e75..3200e13 100644 --- a/sample/CMakeLists.txt +++ b/sample/CMakeLists.txt @@ -49,6 +49,7 @@ Predicate-based-Discriminator Closed-Class-Hierarchy Matcher-within visit +graph ) foreach(sample ${MATCHIT_SAMPLES}) diff --git a/sample/graph.cpp b/sample/graph.cpp new file mode 100644 index 0000000..3dedf24 --- /dev/null +++ b/sample/graph.cpp @@ -0,0 +1,54 @@ +#include "matchit.h" +#include +#include +#include +#include + +template +struct Node +{ + T value; + std::vector parents; +}; + +// A +// | +// B +// | \ +// | C +// | / +// D + +bool matchGraph() +{ + using StrNode = Node; + auto A = std::make_unique(StrNode{"A", {}}); + auto B = std::make_unique(StrNode{"B", {A.get()}}); + auto C = std::make_unique(StrNode{"C", {B.get()}}); + auto D = std::make_unique(StrNode{"D", {B.get(), C.get()}}); + + using namespace matchit; + constexpr auto someDsN = [](auto... pats) + { + constexpr auto dsN = dsVia(&StrNode::value, &StrNode::parents); + return some(dsN(pats...)); + }; + Id b; + return match(D)( + pattern | someDsN("D", + ds( + b.at( + someDsN("B", + ds(someDsN("A", ds())))), + someDsN("C", ds(b)))) = [] + { + std::cout << "Matched!" << std::endl; + return true; + }); +} + +int main() +{ + assert(matchGraph()); + return 0; +} \ No newline at end of file