From 56dc9cd60cce8e51f8b87d6874b5e23d606b3580 Mon Sep 17 00:00:00 2001 From: Bowen Fu Date: Sat, 27 Aug 2022 10:49:23 +0800 Subject: [PATCH 01/15] Update readme. (#79) * Update readme. * Update readme. Co-authored-by: Bowen Fu --- .github/ISSUE_TEMPLATE/bug_report.md | 19 +++------- README.md | 52 ++++++++++++++++++++++++++-- 2 files changed, 54 insertions(+), 17 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index dd84ea7..8b35928 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -11,11 +11,7 @@ assignees: '' A clear and concise description of what the bug is. **To Reproduce** -Steps to reproduce the behavior: -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error +Steps to reproduce the behavior. **Expected behavior** A clear and concise description of what you expected to happen. @@ -23,16 +19,9 @@ A clear and concise description of what you expected to happen. **Screenshots** If applicable, add screenshots to help explain your problem. -**Desktop (please complete the following information):** - - OS: [e.g. iOS] - - Browser [e.g. chrome, safari] - - Version [e.g. 22] - -**Smartphone (please complete the following information):** - - Device: [e.g. iPhone6] - - OS: [e.g. iOS8.1] - - Browser [e.g. stock browser, safari] - - Version [e.g. 22] +**Environment (please complete the following information):** + - OS + - Compiler **Additional context** Add any other context about the problem here. diff --git a/README.md b/README.md index 29cc124..178a3c7 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,14 @@ make install Then use find_package in your CMakeLists.txt. +### Option 4. Manage with vcpkg + +(Thanks to @[daljit97](https://github.com/daljit97) for adding the support.) + +``` +vcpkg install matchit +``` + ## Syntax Design @@ -459,7 +467,7 @@ Some and none patterns are not atomic patterns in `match(it)`, they are composed template constexpr auto cast = [](auto && input) { return static_cast(input); -}; +}; constexpr auto deref = [](auto &&x) { return *x; }; @@ -587,6 +595,44 @@ There is additional **Customziation Point**. Users can specialize `PatternTraits` if they want to add a brand new pattern. +### Hello Black Hole! + +One thing to note is that `Id` is not a plain type. Any copies of it are just references to it. +So do not try to return it from where it is defined. + +A bad case would be + +```c++ +auto badId() +{ + Id x; + return x; +} +``` + +Returning a composed pattern including a local `Id` is also incorrect. + +```c++ +auto badPattern() +{ + Id x; + return composeSomePattern(x); +} +``` + +Good practice is to define the `Id` close to its usage in pattern matching. +```c++ +auto badPattern() +{ + Id x; + auto somePattern = composeSomePattern(x); + return match(...) + ( + pattern | somePattern = ... + ); +} +``` + ## Real world use case [`mathiu`](https://github.com/BowenFu/mathiu.cpp) is a simple computer algebra system built upon `match(it)`. @@ -603,7 +649,9 @@ std::cout << toString(d) << std::endl; ## Contact -If you have questions regarding the library, I would like to invite you to [open an issue at GitHub](https://github.com/bowenfu/matchit.cpp/issues/new/choose). +If you have any questions or ideas regarding the library, I would like to invite you to [open an issue at GitHub](https://github.com/bowenfu/matchit.cpp/issues/new/choose). + +Discussions / issues / PRs are welcome. ## Related Work From 149e9188416c8d50b8bda802d7faa9396acbb10b Mon Sep 17 00:00:00 2001 From: Bowen Fu Date: Sat, 27 Aug 2022 10:52:35 +0800 Subject: [PATCH 02/15] Fix typo. (#80) Co-authored-by: Bowen Fu --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 178a3c7..2e4c3dd 100644 --- a/README.md +++ b/README.md @@ -622,7 +622,7 @@ auto badPattern() Good practice is to define the `Id` close to its usage in pattern matching. ```c++ -auto badPattern() +auto goodPattern() { Id x; auto somePattern = composeSomePattern(x); From 8c5dd3220e0dc2384d07fac71259716c0d09f3ff Mon Sep 17 00:00:00 2001 From: Bowen Fu Date: Tue, 30 Aug 2022 23:00:33 +0800 Subject: [PATCH 03/15] Debugging tips. (#81) * Fix typo. * Debugging tips. * Debugging tips. Co-authored-by: Bowen Fu --- README.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/README.md b/README.md index 2e4c3dd..5309e5f 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,28 @@ Then use find_package in your CMakeLists.txt. vcpkg install matchit ``` +## Tips for Debugging + +To make your debugging easier, try to write your lambda function body in separate lines so that you can set break points in it. + +```c++ +pattern | xyz = [&] +{ + // Separate lines for function body <- set break points here +} +``` + +is much more debugging-friendly compared to + +```c++ +pattern | xyz = [&] { /* some codes here */ }, // <- Set break points here, you will debug into the library. +``` + +Do not debug into this library unless you really decide to root cause / fix some bugs in this library, just like you won't debug into STL variant or ranges. + +Please try to create a minimal sample to reproduce the issues you've met. You can root cause the issue more quickly in that way. + +You can also create an issue in this repo and attach the minimal sample codes and I'll try to response as soon as possible (sometimes please expect one or two days delay). ## Syntax Design From f1a6af4edee88e60b50b8b0c556dbff15124b706 Mon Sep 17 00:00:00 2001 From: Bowen Fu Date: Thu, 1 Sep 2022 23:04:37 +0800 Subject: [PATCH 04/15] Add sample mutation and utility pattern asPtr (#84) * Add sample mutation and utility pattern asPtr * Add more sections to readme. * update to latest version. * Add missing file. Co-authored-by: Bowen Fu --- CMakeLists.txt | 2 +- README.md | 15 +++++++++-- develop/matchit/utility.h | 37 ++++++++++++++++++++++----- include/matchit.h | 37 ++++++++++++++++++++++----- sample/CMakeLists.txt | 1 + sample/mutation.cpp | 53 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 130 insertions(+), 15 deletions(-) create mode 100644 sample/mutation.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index f311fe4..2a9c0a6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.15...3.19) project( "matchit" - VERSION 1.0.0 + VERSION 1.0.1 LANGUAGES CXX DESCRIPTION "match(it): A lightweight single-header pattern-matching library for C++17 with macro-free APIs." diff --git a/README.md b/README.md index 5309e5f..a504c80 100644 --- a/README.md +++ b/README.md @@ -669,11 +669,22 @@ auto const d = diff(e, x); std::cout << toString(d) << std::endl; ``` +## Support this library + +Please star the repo, share the repo, or sponsor one dollar to let me know this library matters. + +## Projects using this library + +[opennask](https://github.com/HobbyOSs/opennask) : An 80x86 assembler like MASM/NASM for the tiny OS. + + +If you are aware of other projects using this library, please let me know by submitting an issue or an PR. + ## Contact -If you have any questions or ideas regarding the library, I would like to invite you to [open an issue at GitHub](https://github.com/bowenfu/matchit.cpp/issues/new/choose). +If you have any questions or ideas regarding the library, please [open an issue](https://github.com/bowenfu/matchit.cpp/issues/new/choose). -Discussions / issues / PRs are welcome. +Discussions / issues / PRs are all welcome. ## Related Work diff --git a/develop/matchit/utility.h b/develop/matchit/utility.h index ce98ad6..cc24108 100644 --- a/develop/matchit/utility.h +++ b/develop/matchit/utility.h @@ -44,34 +44,54 @@ namespace matchit template class AsPointer { + static_assert(!std::is_reference_v); public: template >::type * = nullptr> - constexpr auto operator()(Variant const &v) const + typename std::enable_if>>::type * = nullptr> + constexpr auto operator()(Variant&& 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 + template , std::any>::value>::type * = nullptr> + constexpr auto operator()(A&& a) const { return std::any_cast(std::addressof(a)); } + // cast to base class template && std::is_base_of_v>::type * = nullptr> - constexpr auto operator()(D const &d) const + constexpr auto operator()(D const& d) const -> decltype(static_cast(std::addressof(d))) { return static_cast(std::addressof(d)); } + // No way to handle rvalue to save copy in this class. Need to define some in another way to handle this. + // cast to base class + template && std::is_base_of_v>::type * = nullptr> + constexpr auto operator()(D& d) const + -> decltype(static_cast(std::addressof(d))) + { + return static_cast(std::addressof(d)); + } + + // cast to derived class template && std::is_base_of_v>::type * = nullptr> - constexpr auto operator()(B const &b) const + constexpr auto operator()(B const& b) const -> decltype(dynamic_cast(std::addressof(b))) { return dynamic_cast(std::addressof(b)); } + + // cast to derived class + template && std::is_base_of_v>::type * = nullptr> + constexpr auto operator()(B& b) const + -> decltype(dynamic_cast(std::addressof(b))) + { + return dynamic_cast(std::addressof(b)); + } }; template @@ -81,6 +101,10 @@ namespace matchit constexpr auto as = [](auto const pat) { return app(asPointer, some(pat)); }; + template + constexpr auto asPtr = [](auto const pat) + { return app(asPointer, and_(pat, _ != nullptr)); }; + template constexpr auto matched(Value &&v, Pattern &&p) { @@ -110,6 +134,7 @@ namespace matchit } // namespace impl using impl::as; + using impl::asPtr; using impl::asDsVia; using impl::dsVia; using impl::matched; diff --git a/include/matchit.h b/include/matchit.h index 29bcebb..1e3f1dc 100644 --- a/include/matchit.h +++ b/include/matchit.h @@ -1977,34 +1977,54 @@ namespace matchit template class AsPointer { + static_assert(!std::is_reference_v); public: template >::type * = nullptr> - constexpr auto operator()(Variant const &v) const + typename std::enable_if>>::type * = nullptr> + constexpr auto operator()(Variant&& 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 + template , std::any>::value>::type * = nullptr> + constexpr auto operator()(A&& a) const { return std::any_cast(std::addressof(a)); } + // cast to base class template && std::is_base_of_v>::type * = nullptr> - constexpr auto operator()(D const &d) const + constexpr auto operator()(D const& d) const -> decltype(static_cast(std::addressof(d))) { return static_cast(std::addressof(d)); } + // No way to handle rvalue to save copy in this class. Need to define some in another way to handle this. + // cast to base class + template && std::is_base_of_v>::type * = nullptr> + constexpr auto operator()(D& d) const + -> decltype(static_cast(std::addressof(d))) + { + return static_cast(std::addressof(d)); + } + + // cast to derived class template && std::is_base_of_v>::type * = nullptr> - constexpr auto operator()(B const &b) const + constexpr auto operator()(B const& b) const -> decltype(dynamic_cast(std::addressof(b))) { return dynamic_cast(std::addressof(b)); } + + // cast to derived class + template && std::is_base_of_v>::type * = nullptr> + constexpr auto operator()(B& b) const + -> decltype(dynamic_cast(std::addressof(b))) + { + return dynamic_cast(std::addressof(b)); + } }; template @@ -2014,6 +2034,10 @@ namespace matchit constexpr auto as = [](auto const pat) { return app(asPointer, some(pat)); }; + template + constexpr auto asPtr = [](auto const pat) + { return app(asPointer, and_(pat, _ != nullptr)); }; + template constexpr auto matched(Value &&v, Pattern &&p) { @@ -2043,6 +2067,7 @@ namespace matchit } // namespace impl using impl::as; + using impl::asPtr; using impl::asDsVia; using impl::dsVia; using impl::matched; diff --git a/sample/CMakeLists.txt b/sample/CMakeLists.txt index 3200e13..94587d0 100644 --- a/sample/CMakeLists.txt +++ b/sample/CMakeLists.txt @@ -50,6 +50,7 @@ Closed-Class-Hierarchy Matcher-within visit graph +mutation ) foreach(sample ${MATCHIT_SAMPLES}) diff --git a/sample/mutation.cpp b/sample/mutation.cpp new file mode 100644 index 0000000..26cb672 --- /dev/null +++ b/sample/mutation.cpp @@ -0,0 +1,53 @@ +#include "matchit.h" +#include +#include + +class Circle { +public: + void setLineWidth(float w) + { + std::cout << "Calling Circle::setLineWidth with w = " << w << std::endl; + }; + // other stuff +}; + +class Square { +public: + void setLineWidth(float) + { + // set line width + }; + // other stuff +}; + +class Image { + // other stuff +}; + +using Visual = std::variant; + +using namespace matchit; + +void setLineWidth(Visual &visual, float width) { + Id sq; + Id cir; + match(visual) + ( + pattern | as(_) = []{}, + pattern | asPtr(sq) = [&] + { + (*sq)->setLineWidth(width); + }, + pattern | asPtr(cir) = [&] + { + (*cir)->setLineWidth(width); + } + ); +} + +int main() +{ + Visual v = Circle{}; + setLineWidth(v, 1); + return 0; +} From 5b6a79ee4ea6658b6b287c55fcfa23bbb969c20d Mon Sep 17 00:00:00 2001 From: Bowen Fu Date: Sat, 3 Sep 2022 00:54:53 +0800 Subject: [PATCH 05/15] Add a flag NO_SCALAR_REFERENCE_USED_IN_PATTERNS to control behavior. (#85) * scalarPtr * typo * single header Co-authored-by: Bowen Fu --- develop/matchit/patterns.h | 23 +++++++++++++++-------- develop/matchit/utility.h | 13 +++++++++++++ include/matchit.h | 36 ++++++++++++++++++++++++++++-------- sample/isLarge.cpp | 2 ++ sample/quotientRemainder.cpp | 2 ++ sample/someNone.cpp | 2 ++ sample/variantAny.cpp | 2 ++ test/matchit/app.cpp | 11 +++++++++++ 8 files changed, 75 insertions(+), 16 deletions(-) diff --git a/develop/matchit/patterns.h b/develop/matchit/patterns.h index 4a4029c..3c3cff4 100644 --- a/develop/matchit/patterns.h +++ b/develop/matchit/patterns.h @@ -9,6 +9,10 @@ #include #include +#if !defined(NO_SCALAR_REFERENCES_USED_IN_PATTERNS) +#define NO_SCALAR_REFERENCES_USED_IN_PATTERNS 0 +#endif // !defined(NO_SCALAR_REFERENCES_USED_IN_PATTERNS) + namespace matchit { namespace impl @@ -569,8 +573,11 @@ namespace matchit // support constexpr. template using AppResultCurTuple = - std::conditional_t> || - std::is_scalar_v>, + std::conditional_t> +#if NO_SCALAR_REFERENCES_USED_IN_PATTERNS + || std::is_scalar_v> +#endif // NO_SCALAR_REFERENCES_USED_IN_PATTERNS + , std::tuple<>, std::tuple>>>; @@ -1537,16 +1544,16 @@ namespace matchit 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(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); diff --git a/develop/matchit/utility.h b/develop/matchit/utility.h index cc24108..ca8cb63 100644 --- a/develop/matchit/utility.h +++ b/develop/matchit/utility.h @@ -92,8 +92,21 @@ namespace matchit { return dynamic_cast(std::addressof(b)); } + + constexpr auto operator()(T const& b) const + { + return std::addressof(b); + } + + constexpr auto operator()(T& b) const + { + return std::addressof(b); + } }; + static_assert(std::is_invocable_v, int>); + static_assert(std::is_invocable_v>, std::tuple>); + template constexpr AsPointer asPointer; diff --git a/include/matchit.h b/include/matchit.h index 1e3f1dc..168aa40 100644 --- a/include/matchit.h +++ b/include/matchit.h @@ -316,6 +316,10 @@ namespace matchit #include #include +#if !defined(NO_SCALAR_REFERENCES_USED_IN_PATTERNS) +#define NO_SCALAR_REFERENCES_USED_IN_PATTERNS 0 +#endif // !defined(NO_SCALAR_REFERENCES_USED_IN_PATTERNS) + namespace matchit { namespace impl @@ -876,8 +880,11 @@ namespace matchit // support constexpr. template using AppResultCurTuple = - std::conditional_t> || - std::is_scalar_v>, + std::conditional_t> +#if NO_SCALAR_REFERENCES_USED_IN_PATTERNS + || std::is_scalar_v> +#endif // NO_SCALAR_REFERENCES_USED_IN_PATTERNS + , std::tuple<>, std::tuple>>>; @@ -1844,16 +1851,16 @@ namespace matchit 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(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); @@ -2025,8 +2032,21 @@ namespace matchit { return dynamic_cast(std::addressof(b)); } + + constexpr auto operator()(T const& b) const + { + return std::addressof(b); + } + + constexpr auto operator()(T& b) const + { + return std::addressof(b); + } }; + static_assert(std::is_invocable_v, int>); + static_assert(std::is_invocable_v>, std::tuple>); + template constexpr AsPointer asPointer; diff --git a/sample/isLarge.cpp b/sample/isLarge.cpp index 740a569..32f15d2 100644 --- a/sample/isLarge.cpp +++ b/sample/isLarge.cpp @@ -1,3 +1,5 @@ +#define NO_SCALAR_REFERENCES_USED_IN_PATTERNS 1 + #include "matchit.h" #include diff --git a/sample/quotientRemainder.cpp b/sample/quotientRemainder.cpp index 8663a37..e9bcfe1 100644 --- a/sample/quotientRemainder.cpp +++ b/sample/quotientRemainder.cpp @@ -1,3 +1,5 @@ +#define NO_SCALAR_REFERENCES_USED_IN_PATTERNS 1 + #include "matchit.h" #include diff --git a/sample/someNone.cpp b/sample/someNone.cpp index 845909f..52e0a02 100644 --- a/sample/someNone.cpp +++ b/sample/someNone.cpp @@ -1,3 +1,5 @@ +#define NO_SCALAR_REFERENCES_USED_IN_PATTERNS 1 + #include "matchit.h" #include #include diff --git a/sample/variantAny.cpp b/sample/variantAny.cpp index cf0c0e6..c7cb5b9 100644 --- a/sample/variantAny.cpp +++ b/sample/variantAny.cpp @@ -1,3 +1,5 @@ +#define NO_SCALAR_REFERENCES_USED_IN_PATTERNS 1 + #include "matchit.h" #include diff --git a/test/matchit/app.cpp b/test/matchit/app.cpp index 6a9bfe5..b81b073 100644 --- a/test/matchit/app.cpp +++ b/test/matchit/app.cpp @@ -31,3 +31,14 @@ TEST(App, someAs) auto const x = std::unique_ptr{new Derived}; EXPECT_TRUE(matched(x, some(as(_)))); } + +TEST(App, scalarPtr) +{ + auto const x = std::make_unique(10); + Id xPtr; + match(x) + ( + pattern | some(as(asPtr(xPtr))) = [&] { *(*xPtr) = 20 ; } + ); + EXPECT_EQ(*x, 20); +} From 5edc0428c8d1a8ebab94287b780920a1517c2828 Mon Sep 17 00:00:00 2001 From: Bowen Fu Date: Sat, 3 Sep 2022 12:34:52 +0800 Subject: [PATCH 06/15] More lightweight Id. (#86) * More lightweight Id. * Clean up * Clean up Co-authored-by: Bowen Fu --- develop/matchit/patterns.h | 92 ++++++++++++++----- include/matchit.h | 92 ++++++++++++++----- ...Destructuring-Nested-Structs-and-Enums.cpp | 1 - sample/quotientRemainder.cpp | 1 + test/matchit/id.cpp | 20 ++-- test/matchit/legacy.cpp | 2 +- 6 files changed, 153 insertions(+), 55 deletions(-) diff --git a/develop/matchit/patterns.h b/develop/matchit/patterns.h index 3c3cff4..dd7b03e 100644 --- a/develop/matchit/patterns.h +++ b/develop/matchit/patterns.h @@ -122,8 +122,8 @@ namespace matchit template class Unique; - template - using UniqueT = typename Unique::type; + template + using UniqueT = typename Unique>::type; template <> class Unique> @@ -136,14 +136,14 @@ namespace matchit class Unique> { public: - using type = PrependUniqueT>>; + using type = PrependUniqueT>; }; static_assert( - std::is_same_v, UniqueT>>); + std::is_same_v, UniqueT>); static_assert( std::is_same_v, int32_t>, - UniqueT, int32_t>>>); + UniqueT, int32_t>>); using std::get; @@ -267,10 +267,13 @@ namespace matchit using type = std::variant; }; + template + using UniqVariant = typename Variant>::type; + template class Context { - using ElementT = typename Variant>>::type; + using ElementT = UniqVariant; using ContainerT = std::array; ContainerT mMemHolder; size_t mSize = 0; @@ -745,22 +748,23 @@ namespace matchit template using ValueVariant = - std::conditional_t, - std::variant, - std::variant>; + std::conditional_t, + UniqVariant, + UniqVariant>; template struct StorePointer &>() = &std::declval())>> - : std::conjunction, - std::negation>> + : std::is_reference // need to double check this condition. to loosen it. { }; + static_assert(!StorePointer::value); + // static_assert(StorePointer, std::tuple>::value); static_assert(StorePointer::value); - static_assert(StorePointer::value); static_assert(StorePointer::value); + static_assert(StorePointer::value); static_assert(StorePointer const, std::tuple const &>::value); @@ -824,6 +828,7 @@ namespace matchit return std::visit( overload([](Type const &v) -> Type const & { return v; }, [](Type const *p) -> Type const & { return *p; }, + [](Type *p) -> Type const & { return *p; }, [](std::monostate const &) -> Type const & { throw std::logic_error("invalid state!"); }), @@ -833,14 +838,58 @@ namespace matchit 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!"); - }), + overload( + [](Type &) -> Type & + { + throw std::logic_error( + "Cannot get mutableValue for value type!"); + }, + [](Type * v) -> Type & + { + if (v == nullptr) + { + throw std::logic_error( + "Trying to dereference a nullptr!"); + } + 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 decltype(auto) movableValue() + { + return std::visit( + overload( + [](Type &v) -> Type && + { + return std::move(v); + }, + [](Type * v) -> Type && + { + if (v == nullptr) + { + throw std::logic_error( + "Trying to dereference a nullptr!"); + } + return std::move(*v); + }, + [](Type const *) -> Type && + { + throw std::logic_error( + "Cannot get movableValue from const pointer type!"); + }, + [](std::monostate &) -> Type && + { + throw std::logic_error("Invalid state!"); + }), mVariant); } constexpr void reset(int32_t depth) @@ -924,9 +973,10 @@ namespace matchit 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(); } + constexpr Type & mutableValue() { return block().mutableValue(); } // 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()); } + constexpr Type &&move() { return std::move(block().movableValue()); } }; template diff --git a/include/matchit.h b/include/matchit.h index 168aa40..8463ad3 100644 --- a/include/matchit.h +++ b/include/matchit.h @@ -429,8 +429,8 @@ namespace matchit template class Unique; - template - using UniqueT = typename Unique::type; + template + using UniqueT = typename Unique>::type; template <> class Unique> @@ -443,14 +443,14 @@ namespace matchit class Unique> { public: - using type = PrependUniqueT>>; + using type = PrependUniqueT>; }; static_assert( - std::is_same_v, UniqueT>>); + std::is_same_v, UniqueT>); static_assert( std::is_same_v, int32_t>, - UniqueT, int32_t>>>); + UniqueT, int32_t>>); using std::get; @@ -574,10 +574,13 @@ namespace matchit using type = std::variant; }; + template + using UniqVariant = typename Variant>::type; + template class Context { - using ElementT = typename Variant>>::type; + using ElementT = UniqVariant; using ContainerT = std::array; ContainerT mMemHolder; size_t mSize = 0; @@ -1052,22 +1055,23 @@ namespace matchit template using ValueVariant = - std::conditional_t, - std::variant, - std::variant>; + std::conditional_t, + UniqVariant, + UniqVariant>; template struct StorePointer &>() = &std::declval())>> - : std::conjunction, - std::negation>> + : std::is_reference // need to double check this condition. to loosen it. { }; + static_assert(!StorePointer::value); + // static_assert(StorePointer, std::tuple>::value); static_assert(StorePointer::value); - static_assert(StorePointer::value); static_assert(StorePointer::value); + static_assert(StorePointer::value); static_assert(StorePointer const, std::tuple const &>::value); @@ -1131,6 +1135,7 @@ namespace matchit return std::visit( overload([](Type const &v) -> Type const & { return v; }, [](Type const *p) -> Type const & { return *p; }, + [](Type *p) -> Type const & { return *p; }, [](std::monostate const &) -> Type const & { throw std::logic_error("invalid state!"); }), @@ -1140,14 +1145,58 @@ namespace matchit 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!"); - }), + overload( + [](Type &) -> Type & + { + throw std::logic_error( + "Cannot get mutableValue for value type!"); + }, + [](Type * v) -> Type & + { + if (v == nullptr) + { + throw std::logic_error( + "Trying to dereference a nullptr!"); + } + 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 decltype(auto) movableValue() + { + return std::visit( + overload( + [](Type &v) -> Type && + { + return std::move(v); + }, + [](Type * v) -> Type && + { + if (v == nullptr) + { + throw std::logic_error( + "Trying to dereference a nullptr!"); + } + return std::move(*v); + }, + [](Type const *) -> Type && + { + throw std::logic_error( + "Cannot get movableValue from const pointer type!"); + }, + [](std::monostate &) -> Type && + { + throw std::logic_error("Invalid state!"); + }), mVariant); } constexpr void reset(int32_t depth) @@ -1231,9 +1280,10 @@ namespace matchit 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(); } + constexpr Type & mutableValue() { return block().mutableValue(); } // 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()); } + constexpr Type &&move() { return std::move(block().movableValue()); } }; template diff --git a/sample/Destructuring-Nested-Structs-and-Enums.cpp b/sample/Destructuring-Nested-Structs-and-Enums.cpp index f1543f6..92f5c71 100644 --- a/sample/Destructuring-Nested-Structs-and-Enums.cpp +++ b/sample/Destructuring-Nested-Structs-and-Enums.cpp @@ -26,7 +26,6 @@ int32_t main() using namespace matchit; Id r, g, b; Id h, s, v; - Id text; match(msg)( pattern | as(as(ds(r, g, b))) = [&] diff --git a/sample/quotientRemainder.cpp b/sample/quotientRemainder.cpp index e9bcfe1..d06575b 100644 --- a/sample/quotientRemainder.cpp +++ b/sample/quotientRemainder.cpp @@ -25,6 +25,7 @@ constexpr std::array quoRem(int32_t dividend, int32_t divisor) ); } +// todo: make Id variants for Id Id Id Id constexpr auto qrResult1 = quoRem(12, 6); static_assert(qrResult1[0] == 2); static_assert(qrResult1[1] == 0); diff --git a/test/matchit/id.cpp b/test/matchit/id.cpp index e9b67d6..63f9f50 100644 --- a/test/matchit/id.cpp +++ b/test/matchit/id.cpp @@ -234,16 +234,13 @@ TEST(Id, AppToId5PlusPro) EXPECT_EQ(*result, 11); } -TEST(Id, AppToId5PlusProNegative) +TEST(Id, AppToId5PlusPro2) { - auto const invalidMove = [] - { - Id> ii, jj; - match(std::make_unique(11))( - pattern | and_(ii, jj) = [&] - { return jj.move(); }); - }; - EXPECT_THROW(invalidMove(), std::logic_error); + Id> ii, jj; + auto const result = match(std::make_unique(11))( + pattern | and_(ii, jj) = [&] + { return jj.move(); }); + EXPECT_EQ(*result, 11); } TEST(Id, AppToId6) @@ -301,11 +298,12 @@ TEST(Id, invalidValue) EXPECT_THROW(*x, std::logic_error); } -TEST(Id, invalidMove) +TEST(Id, move) { Id x; EXPECT_THROW(x.move(), std::logic_error); std::string str = "12345"; x.matchValue(str); - EXPECT_THROW(x.move(), std::logic_error); + auto y = x.move(); + EXPECT_TRUE((*x).empty()); } diff --git a/test/matchit/legacy.cpp b/test/matchit/legacy.cpp index 6d59c8e..33548f4 100644 --- a/test/matchit/legacy.cpp +++ b/test/matchit/legacy.cpp @@ -13,7 +13,7 @@ using namespace matchit; static_assert(impl::StorePointer const, std::unique_ptr const &>::value); static_assert(!impl::StorePointer, - std::unique_ptr &&>::value); + std::unique_ptr>::value); std::tuple<> xxx(); From 4fbe206701b808bf9c40b8ea13802b805d09ed92 Mon Sep 17 00:00:00 2001 From: Bowen Fu Date: Sat, 3 Sep 2022 13:46:56 +0800 Subject: [PATCH 07/15] Clean up asPtr (#87) Co-authored-by: Bowen Fu --- README.md | 2 ++ develop/matchit/patterns.h | 24 +++++++++++++----------- develop/matchit/utility.h | 5 ----- include/matchit.h | 29 +++++++++++++---------------- sample/mutation.cpp | 22 ++++++++++++++++------ test/matchit/app.cpp | 6 +++--- 6 files changed, 47 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index a504c80..64d5d4e 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,8 @@ message(STATUS "Matchit header are present at ${matchit_SOURCE_DIR}") And add `${matchit_SOURCE_DIR}/include` to your include path. +Replace `main` with latest release tag to avoid API compatibility breaking. + ### Option 3. Manage with cmake find_package Clone the repo via diff --git a/develop/matchit/patterns.h b/develop/matchit/patterns.h index dd7b03e..04b9bdf 100644 --- a/develop/matchit/patterns.h +++ b/develop/matchit/patterns.h @@ -816,6 +816,8 @@ namespace matchit constexpr auto hasValue() const { return std::visit(overload([](Type const &) + { return true; }, + [](Type *) { return true; }, [](Type const *) { return true; }, @@ -823,7 +825,7 @@ namespace matchit { return false; }), mVariant); } - constexpr decltype(auto) value() const + constexpr decltype(auto) get() const { return std::visit( overload([](Type const &v) -> Type const & { return v; }, @@ -835,14 +837,14 @@ namespace matchit mVariant); } - constexpr decltype(auto) mutableValue() + constexpr decltype(auto) getMut() { return std::visit( overload( [](Type &) -> Type & { throw std::logic_error( - "Cannot get mutableValue for value type!"); + "Cannot get getMut for value type!"); }, [](Type * v) -> Type & { @@ -856,7 +858,7 @@ namespace matchit [](Type const *) -> Type & { throw std::logic_error( - "Cannot get mutableValue for pointer type!"); + "Cannot get getMut for pointer type!"); }, [](std::monostate &) -> Type & { @@ -864,7 +866,7 @@ namespace matchit }), mVariant); } - constexpr decltype(auto) movableValue() + constexpr decltype(auto) getMovable() { return std::visit( overload( @@ -884,7 +886,7 @@ namespace matchit [](Type const *) -> Type && { throw std::logic_error( - "Cannot get movableValue from const pointer type!"); + "Cannot get getMovable from const pointer type!"); }, [](std::monostate &) -> Type && { @@ -930,7 +932,7 @@ namespace matchit using BlockVT = std::variant; BlockVT mBlock = Block{}; - constexpr Type const &internalValue() const { return block().value(); } + constexpr Type const &internalValue() const { return block().get(); } public: constexpr Id() = default; @@ -972,11 +974,11 @@ namespace matchit 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(); } - constexpr Type & mutableValue() { return block().mutableValue(); } + constexpr Type const &get() { return block().get(); } + constexpr Type & getMut() { return block().getMut(); } // non-const to inform users not to mark Id as const. - constexpr Type const &operator*() { return value(); } - constexpr Type &&move() { return std::move(block().movableValue()); } + constexpr Type const &operator*() { return get(); } + constexpr Type &&move() { return std::move(block().getMovable()); } }; template diff --git a/develop/matchit/utility.h b/develop/matchit/utility.h index ca8cb63..a6a2670 100644 --- a/develop/matchit/utility.h +++ b/develop/matchit/utility.h @@ -114,10 +114,6 @@ namespace matchit constexpr auto as = [](auto const pat) { return app(asPointer, some(pat)); }; - template - constexpr auto asPtr = [](auto const pat) - { return app(asPointer, and_(pat, _ != nullptr)); }; - template constexpr auto matched(Value &&v, Pattern &&p) { @@ -147,7 +143,6 @@ namespace matchit } // namespace impl using impl::as; - using impl::asPtr; using impl::asDsVia; using impl::dsVia; using impl::matched; diff --git a/include/matchit.h b/include/matchit.h index 8463ad3..d14f17e 100644 --- a/include/matchit.h +++ b/include/matchit.h @@ -1123,6 +1123,8 @@ namespace matchit constexpr auto hasValue() const { return std::visit(overload([](Type const &) + { return true; }, + [](Type *) { return true; }, [](Type const *) { return true; }, @@ -1130,7 +1132,7 @@ namespace matchit { return false; }), mVariant); } - constexpr decltype(auto) value() const + constexpr decltype(auto) get() const { return std::visit( overload([](Type const &v) -> Type const & { return v; }, @@ -1142,14 +1144,14 @@ namespace matchit mVariant); } - constexpr decltype(auto) mutableValue() + constexpr decltype(auto) getMut() { return std::visit( overload( [](Type &) -> Type & { throw std::logic_error( - "Cannot get mutableValue for value type!"); + "Cannot get getMut for value type!"); }, [](Type * v) -> Type & { @@ -1163,7 +1165,7 @@ namespace matchit [](Type const *) -> Type & { throw std::logic_error( - "Cannot get mutableValue for pointer type!"); + "Cannot get getMut for pointer type!"); }, [](std::monostate &) -> Type & { @@ -1171,7 +1173,7 @@ namespace matchit }), mVariant); } - constexpr decltype(auto) movableValue() + constexpr decltype(auto) getMovable() { return std::visit( overload( @@ -1191,7 +1193,7 @@ namespace matchit [](Type const *) -> Type && { throw std::logic_error( - "Cannot get movableValue from const pointer type!"); + "Cannot get getMovable from const pointer type!"); }, [](std::monostate &) -> Type && { @@ -1237,7 +1239,7 @@ namespace matchit using BlockVT = std::variant; BlockVT mBlock = Block{}; - constexpr Type const &internalValue() const { return block().value(); } + constexpr Type const &internalValue() const { return block().get(); } public: constexpr Id() = default; @@ -1279,11 +1281,11 @@ namespace matchit 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(); } - constexpr Type & mutableValue() { return block().mutableValue(); } + constexpr Type const &get() { return block().get(); } + constexpr Type & getMut() { return block().getMut(); } // non-const to inform users not to mark Id as const. - constexpr Type const &operator*() { return value(); } - constexpr Type &&move() { return std::move(block().movableValue()); } + constexpr Type const &operator*() { return get(); } + constexpr Type &&move() { return std::move(block().getMovable()); } }; template @@ -2104,10 +2106,6 @@ namespace matchit constexpr auto as = [](auto const pat) { return app(asPointer, some(pat)); }; - template - constexpr auto asPtr = [](auto const pat) - { return app(asPointer, and_(pat, _ != nullptr)); }; - template constexpr auto matched(Value &&v, Pattern &&p) { @@ -2137,7 +2135,6 @@ namespace matchit } // namespace impl using impl::as; - using impl::asPtr; using impl::asDsVia; using impl::dsVia; using impl::matched; diff --git a/sample/mutation.cpp b/sample/mutation.cpp index 26cb672..f838b5d 100644 --- a/sample/mutation.cpp +++ b/sample/mutation.cpp @@ -24,23 +24,33 @@ class Image { // other stuff }; +auto operator==(Circle const&, Circle const&) +{ + return true; +} + +auto operator==(Square const&, Square const&) +{ + return true; +} + using Visual = std::variant; using namespace matchit; void setLineWidth(Visual &visual, float width) { - Id sq; - Id cir; + Id sq; + Id cir; match(visual) ( pattern | as(_) = []{}, - pattern | asPtr(sq) = [&] + pattern | as(sq) = [&] { - (*sq)->setLineWidth(width); + sq.getMut().setLineWidth(width); }, - pattern | asPtr(cir) = [&] + pattern | as(cir) = [&] { - (*cir)->setLineWidth(width); + cir.getMut().setLineWidth(width); } ); } diff --git a/test/matchit/app.cpp b/test/matchit/app.cpp index b81b073..36e008d 100644 --- a/test/matchit/app.cpp +++ b/test/matchit/app.cpp @@ -32,13 +32,13 @@ TEST(App, someAs) EXPECT_TRUE(matched(x, some(as(_)))); } -TEST(App, scalarPtr) +TEST(App, scalarMut) { auto const x = std::make_unique(10); - Id xPtr; + Id ii; match(x) ( - pattern | some(as(asPtr(xPtr))) = [&] { *(*xPtr) = 20 ; } + pattern | some(as(as(ii))) = [&] { ii.getMut() = 20 ; } ); EXPECT_EQ(*x, 20); } From bc15dfd53aa7583e77c1242ac0dd3e4f53b95637 Mon Sep 17 00:00:00 2001 From: Bowen Fu Date: Sat, 3 Sep 2022 22:59:39 +0800 Subject: [PATCH 08/15] Id Id (#89) Co-authored-by: Bowen Fu --- develop/matchit/patterns.h | 302 +++++++++++++++++++++---------------- include/matchit.h | 302 +++++++++++++++++++++---------------- sample/mutation.cpp | 8 +- test/matchit/app.cpp | 4 +- test/matchit/id.cpp | 38 ++--- 5 files changed, 373 insertions(+), 281 deletions(-) diff --git a/develop/matchit/patterns.h b/develop/matchit/patterns.h index 04b9bdf..2324f1b 100644 --- a/develop/matchit/patterns.h +++ b/develop/matchit/patterns.h @@ -748,9 +748,15 @@ namespace matchit template using ValueVariant = - std::conditional_t, - UniqVariant, - UniqVariant>; + std::conditional_t, + UniqVariant*>, + std::conditional_t, + UniqVariant, std::remove_reference_t *>, + std::conditional_t>, + UniqVariant*, std::remove_reference_t const *>, + UniqVariant, std::remove_reference_t*, std::remove_reference_t const *> + > + >>; template struct StorePointer - class Id + class IdBlockBase { - private: - class Block - { - public: - ValueVariant mVariant; - int32_t mDepth; + int32_t mDepth; + protected: + ValueVariant mVariant; - constexpr auto &variant() { return mVariant; } - constexpr auto hasValue() const + public: + constexpr IdBlockBase() + : mDepth{} + , mVariant{} + {} + + constexpr auto &variant() { return mVariant; } + constexpr void reset(int32_t depth) + { + if (mDepth - depth >= 0) { - return std::visit(overload([](Type const &) - { return true; }, - [](Type *) - { return true; }, - [](Type const *) - { return true; }, - [](std::monostate const &) - { return false; }), - mVariant); + mVariant = {}; + mDepth = depth; } - constexpr decltype(auto) get() const + } + constexpr void confirm(int32_t depth) + { + if (mDepth > depth || mDepth == 0) { - return std::visit( - overload([](Type const &v) -> Type const & { return v; }, - [](Type const *p) -> Type const & { return *p; }, - [](Type *p) -> Type const & { return *p; }, - [](std::monostate const &) -> Type const & { - throw std::logic_error("invalid state!"); - }), - mVariant); + assert(depth == mDepth - 1 || depth == mDepth || mDepth == 0); + mDepth = depth; } + } + }; - constexpr decltype(auto) getMut() - { - return std::visit( - overload( - [](Type &) -> Type & - { - throw std::logic_error( - "Cannot get getMut for value type!"); - }, - [](Type * v) -> Type & - { - if (v == nullptr) - { - throw std::logic_error( - "Trying to dereference a nullptr!"); - } - return *v; - }, - [](Type const *) -> Type & + constexpr IdBlockBase dummy; + + template + class IdBlock : public IdBlockBase + { + public: + constexpr auto hasValue() const + { + return std::visit(overload([](Type const &) + { return true; }, + [](Type const *) + { return true; }, + // [](Type *) + // { return true; }, + [](std::monostate const &) + { return false; }), + IdBlockBase::mVariant); + } + constexpr decltype(auto) get() const + { + return std::visit( + overload([](Type const &v) -> Type const & { return v; }, + [](Type const *p) -> Type const & { return *p; }, + [](Type *p) -> Type const & { return *p; }, + [](std::monostate const &) -> Type const & { + throw std::logic_error("invalid state!"); + }), + IdBlockBase::mVariant); + } + }; + + template + class IdBlock : public IdBlock + {}; + + template + class IdBlock : public IdBlockBase + { + public: + constexpr auto hasValue() const + { + return std::visit(overload([](Type *) + { return true; }, + [](std::monostate const &) + { return false; }), + IdBlockBase::mVariant); + } + + constexpr decltype(auto) get() + { + return std::visit( + overload( + [](Type * v) -> Type & + { + if (v == nullptr) { throw std::logic_error( - "Cannot get getMut for pointer type!"); - }, - [](std::monostate &) -> Type & - { - throw std::logic_error("Invalid state!"); - }), - mVariant); - } - constexpr decltype(auto) getMovable() - { - return std::visit( - overload( - [](Type &v) -> Type && - { - return std::move(v); - }, - [](Type * v) -> Type && - { - if (v == nullptr) - { - throw std::logic_error( - "Trying to dereference a nullptr!"); - } - return std::move(*v); - }, - [](Type const *) -> Type && + "Trying to dereference a nullptr!"); + } + return *v; + }, + [](std::monostate &) -> Type & + { + throw std::logic_error("Invalid state!"); + }), + IdBlockBase::mVariant); + } + }; + + template + class IdBlock : public IdBlockBase + { + public: + constexpr auto hasValue() const + { + return std::visit(overload([](Type const &) + { return true; }, + [](Type *) + { return true; }, + [](std::monostate const &) + { return false; }), + IdBlockBase::mVariant); + } + + constexpr decltype(auto) get() + { + return std::visit( + overload( + [](Type &v) -> Type && + { + return std::move(v); + }, + [](Type * v) -> Type && + { + if (v == nullptr) { throw std::logic_error( - "Cannot get getMovable from const 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 + "Trying to dereference a nullptr!"); + } + return std::move(*v); + }, + [](std::monostate &) -> Type && + { + throw std::logic_error("Invalid state!"); + }), + IdBlockBase::mVariant); + } + }; + + template + class IdUtil + { + public: + template + constexpr static auto bindValue(ValueVariant &v, Value &&value, + std::false_type /* StorePointer */) { - 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}; - } - }; + // 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{}; + template + class Id + { + private: + using BlockT = IdBlock; + using BlockVT = std::variant; + BlockVT mBlock = BlockT{}; - constexpr Type const &internalValue() const { return block().get(); } + constexpr decltype(auto) internalValue() const { return block().get(); } public: constexpr Id() = default; @@ -949,10 +993,10 @@ namespace matchit // non-const to inform users not to mark Id as const. constexpr auto at(Ooo const &) { return OooBinder{*this}; } - constexpr Block &block() const + constexpr BlockT &block() const { - return std::visit(overload([](Block &v) -> Block & { return v; }, - [](Block *p) -> Block & { return *p; }), + return std::visit(overload([](BlockT &v) -> BlockT & { return v; }, + [](BlockT *p) -> BlockT & { return *p; }), // constexpr does not allow mutable, we use const_cast // instead. Never declare Id as const. const_cast(mBlock)); @@ -964,9 +1008,9 @@ namespace matchit { if (hasValue()) { - return IdTraits::equal(internalValue(), v); + return IdTraits>::equal(internalValue(), v); } - IdUtil::bindValue(block().variant(), std::forward(v), + IdUtil::bindValue(block().variant(), std::forward(v), StorePointer{}); return true; } @@ -974,11 +1018,13 @@ namespace matchit 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 &get() { return block().get(); } - constexpr Type & getMut() { return block().getMut(); } + constexpr decltype(auto) get() { return block().get(); } // non-const to inform users not to mark Id as const. - constexpr Type const &operator*() { return get(); } - constexpr Type &&move() { return std::move(block().getMovable()); } + constexpr decltype(auto) operator*() { return get(); } + // constexpr auto move() -> std::enable_if_t, Type &&> + // { + // return std::move(block().getMovable()); + // } }; template diff --git a/include/matchit.h b/include/matchit.h index d14f17e..1bb2463 100644 --- a/include/matchit.h +++ b/include/matchit.h @@ -1055,9 +1055,15 @@ namespace matchit template using ValueVariant = - std::conditional_t, - UniqVariant, - UniqVariant>; + std::conditional_t, + UniqVariant*>, + std::conditional_t, + UniqVariant, std::remove_reference_t *>, + std::conditional_t>, + UniqVariant*, std::remove_reference_t const *>, + UniqVariant, std::remove_reference_t*, std::remove_reference_t const *> + > + >>; template struct StorePointer - class Id + class IdBlockBase { - private: - class Block - { - public: - ValueVariant mVariant; - int32_t mDepth; + int32_t mDepth; + protected: + ValueVariant mVariant; - constexpr auto &variant() { return mVariant; } - constexpr auto hasValue() const + public: + constexpr IdBlockBase() + : mDepth{} + , mVariant{} + {} + + constexpr auto &variant() { return mVariant; } + constexpr void reset(int32_t depth) + { + if (mDepth - depth >= 0) { - return std::visit(overload([](Type const &) - { return true; }, - [](Type *) - { return true; }, - [](Type const *) - { return true; }, - [](std::monostate const &) - { return false; }), - mVariant); + mVariant = {}; + mDepth = depth; } - constexpr decltype(auto) get() const + } + constexpr void confirm(int32_t depth) + { + if (mDepth > depth || mDepth == 0) { - return std::visit( - overload([](Type const &v) -> Type const & { return v; }, - [](Type const *p) -> Type const & { return *p; }, - [](Type *p) -> Type const & { return *p; }, - [](std::monostate const &) -> Type const & { - throw std::logic_error("invalid state!"); - }), - mVariant); + assert(depth == mDepth - 1 || depth == mDepth || mDepth == 0); + mDepth = depth; } + } + }; - constexpr decltype(auto) getMut() - { - return std::visit( - overload( - [](Type &) -> Type & - { - throw std::logic_error( - "Cannot get getMut for value type!"); - }, - [](Type * v) -> Type & - { - if (v == nullptr) - { - throw std::logic_error( - "Trying to dereference a nullptr!"); - } - return *v; - }, - [](Type const *) -> Type & + constexpr IdBlockBase dummy; + + template + class IdBlock : public IdBlockBase + { + public: + constexpr auto hasValue() const + { + return std::visit(overload([](Type const &) + { return true; }, + [](Type const *) + { return true; }, + // [](Type *) + // { return true; }, + [](std::monostate const &) + { return false; }), + IdBlockBase::mVariant); + } + constexpr decltype(auto) get() const + { + return std::visit( + overload([](Type const &v) -> Type const & { return v; }, + [](Type const *p) -> Type const & { return *p; }, + [](Type *p) -> Type const & { return *p; }, + [](std::monostate const &) -> Type const & { + throw std::logic_error("invalid state!"); + }), + IdBlockBase::mVariant); + } + }; + + template + class IdBlock : public IdBlock + {}; + + template + class IdBlock : public IdBlockBase + { + public: + constexpr auto hasValue() const + { + return std::visit(overload([](Type *) + { return true; }, + [](std::monostate const &) + { return false; }), + IdBlockBase::mVariant); + } + + constexpr decltype(auto) get() + { + return std::visit( + overload( + [](Type * v) -> Type & + { + if (v == nullptr) { throw std::logic_error( - "Cannot get getMut for pointer type!"); - }, - [](std::monostate &) -> Type & - { - throw std::logic_error("Invalid state!"); - }), - mVariant); - } - constexpr decltype(auto) getMovable() - { - return std::visit( - overload( - [](Type &v) -> Type && - { - return std::move(v); - }, - [](Type * v) -> Type && - { - if (v == nullptr) - { - throw std::logic_error( - "Trying to dereference a nullptr!"); - } - return std::move(*v); - }, - [](Type const *) -> Type && + "Trying to dereference a nullptr!"); + } + return *v; + }, + [](std::monostate &) -> Type & + { + throw std::logic_error("Invalid state!"); + }), + IdBlockBase::mVariant); + } + }; + + template + class IdBlock : public IdBlockBase + { + public: + constexpr auto hasValue() const + { + return std::visit(overload([](Type const &) + { return true; }, + [](Type *) + { return true; }, + [](std::monostate const &) + { return false; }), + IdBlockBase::mVariant); + } + + constexpr decltype(auto) get() + { + return std::visit( + overload( + [](Type &v) -> Type && + { + return std::move(v); + }, + [](Type * v) -> Type && + { + if (v == nullptr) { throw std::logic_error( - "Cannot get getMovable from const 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 + "Trying to dereference a nullptr!"); + } + return std::move(*v); + }, + [](std::monostate &) -> Type && + { + throw std::logic_error("Invalid state!"); + }), + IdBlockBase::mVariant); + } + }; + + template + class IdUtil + { + public: + template + constexpr static auto bindValue(ValueVariant &v, Value &&value, + std::false_type /* StorePointer */) { - 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}; - } - }; + // 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{}; + template + class Id + { + private: + using BlockT = IdBlock; + using BlockVT = std::variant; + BlockVT mBlock = BlockT{}; - constexpr Type const &internalValue() const { return block().get(); } + constexpr decltype(auto) internalValue() const { return block().get(); } public: constexpr Id() = default; @@ -1256,10 +1300,10 @@ namespace matchit // non-const to inform users not to mark Id as const. constexpr auto at(Ooo const &) { return OooBinder{*this}; } - constexpr Block &block() const + constexpr BlockT &block() const { - return std::visit(overload([](Block &v) -> Block & { return v; }, - [](Block *p) -> Block & { return *p; }), + return std::visit(overload([](BlockT &v) -> BlockT & { return v; }, + [](BlockT *p) -> BlockT & { return *p; }), // constexpr does not allow mutable, we use const_cast // instead. Never declare Id as const. const_cast(mBlock)); @@ -1271,9 +1315,9 @@ namespace matchit { if (hasValue()) { - return IdTraits::equal(internalValue(), v); + return IdTraits>::equal(internalValue(), v); } - IdUtil::bindValue(block().variant(), std::forward(v), + IdUtil::bindValue(block().variant(), std::forward(v), StorePointer{}); return true; } @@ -1281,11 +1325,13 @@ namespace matchit 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 &get() { return block().get(); } - constexpr Type & getMut() { return block().getMut(); } + constexpr decltype(auto) get() { return block().get(); } // non-const to inform users not to mark Id as const. - constexpr Type const &operator*() { return get(); } - constexpr Type &&move() { return std::move(block().getMovable()); } + constexpr decltype(auto) operator*() { return get(); } + // constexpr auto move() -> std::enable_if_t, Type &&> + // { + // return std::move(block().getMovable()); + // } }; template diff --git a/sample/mutation.cpp b/sample/mutation.cpp index f838b5d..6c33efc 100644 --- a/sample/mutation.cpp +++ b/sample/mutation.cpp @@ -39,18 +39,18 @@ using Visual = std::variant; using namespace matchit; void setLineWidth(Visual &visual, float width) { - Id sq; - Id cir; + Id sq; + Id cir; match(visual) ( pattern | as(_) = []{}, pattern | as(sq) = [&] { - sq.getMut().setLineWidth(width); + (*sq).setLineWidth(width); }, pattern | as(cir) = [&] { - cir.getMut().setLineWidth(width); + (*cir).setLineWidth(width); } ); } diff --git a/test/matchit/app.cpp b/test/matchit/app.cpp index 36e008d..95612f6 100644 --- a/test/matchit/app.cpp +++ b/test/matchit/app.cpp @@ -35,10 +35,10 @@ TEST(App, someAs) TEST(App, scalarMut) { auto const x = std::make_unique(10); - Id ii; + Id ii; match(x) ( - pattern | some(as(as(ii))) = [&] { ii.getMut() = 20 ; } + pattern | some(as(as(ii))) = [&] { *ii = 20 ; } ); EXPECT_EQ(*x, 20); } diff --git a/test/matchit/id.cpp b/test/matchit/id.cpp index 63f9f50..4fc2afd 100644 --- a/test/matchit/id.cpp +++ b/test/matchit/id.cpp @@ -183,27 +183,27 @@ TEST(Id, AppToId3) Id> ii; auto const result = match(std::make_shared(11))( pattern | ii = [&] - { return ii.move(); }); + { return *ii; }); EXPECT_EQ(*result, 11); } TEST(Id, AppToId4) { - Id> ii; + Id&&> ii; auto const result = match(11)( pattern | app([](auto &&x) { return std::make_shared(x); }, ii) = [&] - { return ii.move(); }); + { return *ii; }); EXPECT_EQ(*result, 11); } TEST(Id, AppToId5) { - Id> ii; + Id&&> ii; auto const result = match(std::make_unique(11))( pattern | ii = [&] - { return ii.move(); }); + { return *ii; }); EXPECT_EQ(*result, 11); } @@ -227,30 +227,30 @@ TEST(Id, AppToId5Plus2) TEST(Id, AppToId5PlusPro) { - Id> jj; + Id&&> jj; auto const result = match(std::make_unique(11))( pattern | and_(_, jj) = [&] - { return jj.move(); }); + { return *jj; }); EXPECT_EQ(*result, 11); } TEST(Id, AppToId5PlusPro2) { - Id> ii, jj; + Id&&> ii, jj; auto const result = match(std::make_unique(11))( pattern | and_(ii, jj) = [&] - { return jj.move(); }); + { return *jj; }); EXPECT_EQ(*result, 11); } TEST(Id, AppToId6) { - Id> ii; + Id&&> ii; auto const result = match(11)( pattern | app([](auto &&x) { return std::make_unique(x); }, ii) = [&] - { return ii.move(); }); + { return *ii; }); EXPECT_EQ(*result, 11); } @@ -259,18 +259,18 @@ TEST(Id, AppToId7) Id> ii; auto const result = match(std::make_optional(11))(pattern | ii = [&] - { return ii.move(); }); + { return *ii; }); EXPECT_EQ(*result, 11); } TEST(Id, AppToId8) { - Id> ii; + Id&&> ii; auto const result = match(11)(pattern | app([](auto &&x) { return std::make_optional(x); }, ii) = [&] - { return ii.move(); }); + { return *ii; }); EXPECT_EQ(*result, 11); } @@ -283,12 +283,12 @@ TEST(Id, IdAtInt) TEST(Id, IdAtUnique) { - Id> ii; + Id&&> ii; auto const result = match(11)( pattern | app([](auto &&x) { return std::make_unique(x * x); }, ii.at(some(_))) = [&] - { return ii.move(); }); + { return *ii; }); EXPECT_EQ(*result, 121); } @@ -300,10 +300,10 @@ TEST(Id, invalidValue) TEST(Id, move) { - Id x; - EXPECT_THROW(x.move(), std::logic_error); + Id x; + EXPECT_THROW(*x, std::logic_error); std::string str = "12345"; x.matchValue(str); - auto y = x.move(); + auto y = *x; EXPECT_TRUE((*x).empty()); } From 5b727be2d86e71ae4b37e33d51ef4b201dc7453f Mon Sep 17 00:00:00 2001 From: Bowen Fu Date: Sat, 3 Sep 2022 23:12:17 +0800 Subject: [PATCH 09/15] Update README. (#90) Co-authored-by: Bowen Fu --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 64d5d4e..041eb09 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,15 @@ Then use find_package in your CMakeLists.txt. vcpkg install matchit ``` +### Option 5. Manage with conan + +Now the library has been submitted to [Conan Center Index](https://github.com/conan-io/conan-center-index). + +You can now install the library via conan. + +(Thanks to @[sanblch](https://github.com/sanblch) for adding the support.) + + ## Tips for Debugging To make your debugging easier, try to write your lambda function body in separate lines so that you can set break points in it. From 5b5ffd8c6332f73577797d74e258f400332ba7b3 Mon Sep 17 00:00:00 2001 From: Bowen Fu Date: Tue, 6 Sep 2022 20:56:31 +0800 Subject: [PATCH 10/15] Update readme. (#91) Co-authored-by: Bowen Fu --- LICENSE | 2 +- README.md | 4 ++++ develop/header.txt | 2 +- include/matchit.h | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/LICENSE b/LICENSE index c9ab656..1cbca2f 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright [2021] [Bowen Fu] + Copyright [2021-2022] [Bowen Fu] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index 041eb09..dde66fb 100644 --- a/README.md +++ b/README.md @@ -711,3 +711,7 @@ Discussions / issues / PRs are all welcome. ## Other Work If you are interested in `match(it)`, you may also be interested in [hspp](https://github.com/BowenFu/hspp) which brings Haskell style programming to C++. + +## Sponsor(s) + +Thanks to @[e-dant](https://github.com/e-dant) for sponsoring this project. diff --git a/develop/header.txt b/develop/header.txt index caff298..b2a1dce 100644 --- a/develop/header.txt +++ b/develop/header.txt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Bowen Fu + * Copyright (c) 2021-2022 Bowen Fu * Distributed Under The Apache-2.0 License */ diff --git a/include/matchit.h b/include/matchit.h index 1bb2463..99750b5 100644 --- a/include/matchit.h +++ b/include/matchit.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Bowen Fu + * Copyright (c) 2021-2022 Bowen Fu * Distributed Under The Apache-2.0 License */ From a6c34895db9e2c0b01a98c04664c637d5683b176 Mon Sep 17 00:00:00 2001 From: Bowen Fu Date: Thu, 22 Sep 2022 20:45:08 +0800 Subject: [PATCH 11/15] Update Id to require users to use std::move explicitly. (#92) * Update Id to require users to use std::move explicitly. * Add star history. * Fix tests. Co-authored-by: Bowen Fu --- README.md | 12 ++++++++---- develop/matchit/patterns.h | 16 ++++++---------- include/matchit.h | 16 ++++++---------- test/matchit/id.cpp | 12 ++++++------ 4 files changed, 26 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index dde66fb..625ba29 100644 --- a/README.md +++ b/README.md @@ -680,10 +680,6 @@ auto const d = diff(e, x); std::cout << toString(d) << std::endl; ``` -## Support this library - -Please star the repo, share the repo, or sponsor one dollar to let me know this library matters. - ## Projects using this library [opennask](https://github.com/HobbyOSs/opennask) : An 80x86 assembler like MASM/NASM for the tiny OS. @@ -712,6 +708,14 @@ Discussions / issues / PRs are all welcome. If you are interested in `match(it)`, you may also be interested in [hspp](https://github.com/BowenFu/hspp) which brings Haskell style programming to C++. +## Support this library + +Please star the repo, share the repo, or sponsor one dollar to let me know this library matters. + ## Sponsor(s) Thanks to @[e-dant](https://github.com/e-dant) for sponsoring this project. + +## Star History + +[![Star History Chart](https://api.star-history.com/svg?repos=bowenfu/matchit.cpp&type=Date)](https://star-history.com/#bowenfu/matchit.cpp&Date) diff --git a/develop/matchit/patterns.h b/develop/matchit/patterns.h index 2324f1b..6c272b2 100644 --- a/develop/matchit/patterns.h +++ b/develop/matchit/patterns.h @@ -820,7 +820,7 @@ namespace matchit : mDepth{} , mVariant{} {} - + constexpr auto &variant() { return mVariant; } constexpr void reset(int32_t depth) { @@ -928,20 +928,20 @@ namespace matchit { return std::visit( overload( - [](Type &v) -> Type && + [](Type &v) -> Type & { - return std::move(v); + return v; }, - [](Type * v) -> Type && + [](Type * v) -> Type & { if (v == nullptr) { throw std::logic_error( "Trying to dereference a nullptr!"); } - return std::move(*v); + return *v; }, - [](std::monostate &) -> Type && + [](std::monostate &) -> Type & { throw std::logic_error("Invalid state!"); }), @@ -1021,10 +1021,6 @@ namespace matchit constexpr decltype(auto) get() { return block().get(); } // non-const to inform users not to mark Id as const. constexpr decltype(auto) operator*() { return get(); } - // constexpr auto move() -> std::enable_if_t, Type &&> - // { - // return std::move(block().getMovable()); - // } }; template diff --git a/include/matchit.h b/include/matchit.h index 99750b5..3b0eb7b 100644 --- a/include/matchit.h +++ b/include/matchit.h @@ -1127,7 +1127,7 @@ namespace matchit : mDepth{} , mVariant{} {} - + constexpr auto &variant() { return mVariant; } constexpr void reset(int32_t depth) { @@ -1235,20 +1235,20 @@ namespace matchit { return std::visit( overload( - [](Type &v) -> Type && + [](Type &v) -> Type & { - return std::move(v); + return v; }, - [](Type * v) -> Type && + [](Type * v) -> Type & { if (v == nullptr) { throw std::logic_error( "Trying to dereference a nullptr!"); } - return std::move(*v); + return *v; }, - [](std::monostate &) -> Type && + [](std::monostate &) -> Type & { throw std::logic_error("Invalid state!"); }), @@ -1328,10 +1328,6 @@ namespace matchit constexpr decltype(auto) get() { return block().get(); } // non-const to inform users not to mark Id as const. constexpr decltype(auto) operator*() { return get(); } - // constexpr auto move() -> std::enable_if_t, Type &&> - // { - // return std::move(block().getMovable()); - // } }; template diff --git a/test/matchit/id.cpp b/test/matchit/id.cpp index 4fc2afd..52fcea2 100644 --- a/test/matchit/id.cpp +++ b/test/matchit/id.cpp @@ -203,7 +203,7 @@ TEST(Id, AppToId5) Id&&> ii; auto const result = match(std::make_unique(11))( pattern | ii = [&] - { return *ii; }); + { return std::move(*ii); }); EXPECT_EQ(*result, 11); } @@ -230,7 +230,7 @@ TEST(Id, AppToId5PlusPro) Id&&> jj; auto const result = match(std::make_unique(11))( pattern | and_(_, jj) = [&] - { return *jj; }); + { return std::move(*jj); }); EXPECT_EQ(*result, 11); } @@ -239,7 +239,7 @@ TEST(Id, AppToId5PlusPro2) Id&&> ii, jj; auto const result = match(std::make_unique(11))( pattern | and_(ii, jj) = [&] - { return *jj; }); + { return std::move(*jj); }); EXPECT_EQ(*result, 11); } @@ -250,7 +250,7 @@ TEST(Id, AppToId6) pattern | app([](auto &&x) { return std::make_unique(x); }, ii) = [&] - { return *ii; }); + { return std::move(*ii); }); EXPECT_EQ(*result, 11); } @@ -288,7 +288,7 @@ TEST(Id, IdAtUnique) pattern | app([](auto &&x) { return std::make_unique(x * x); }, ii.at(some(_))) = [&] - { return *ii; }); + { return std::move(*ii); }); EXPECT_EQ(*result, 121); } @@ -304,6 +304,6 @@ TEST(Id, move) EXPECT_THROW(*x, std::logic_error); std::string str = "12345"; x.matchValue(str); - auto y = *x; + auto y = std::move(*x); EXPECT_TRUE((*x).empty()); } From fe255659f1643f42095e85c5d5b8d0d31df7dc8e Mon Sep 17 00:00:00 2001 From: Hugo Etchegoyen Date: Thu, 17 Nov 2022 11:24:05 -0300 Subject: [PATCH 12/15] Uniform and optional use of expr() (#95) * Use of expr() made uniform and optional * Added optExpr test * Added optExpr test * Update develop/matchit/expression.h Co-authored-by: Bowen Fu Signed-off-by: Hugo Etchegoyen * Update test/matchit/optexpr.cpp Co-authored-by: Bowen Fu Signed-off-by: Hugo Etchegoyen * Update test/matchit/optexpr.cpp Co-authored-by: Bowen Fu Signed-off-by: Hugo Etchegoyen * No expr() for Nullary * Removed unnecessary toNullary() overload Signed-off-by: Hugo Etchegoyen Co-authored-by: Bowen Fu --- develop/matchit/expression.h | 13 +++++++++ develop/matchit/patterns.h | 12 ++++---- include/matchit.h | 25 ++++++++++++---- test/matchit/CMakeLists.txt | 4 +-- test/matchit/optexpr.cpp | 55 ++++++++++++++++++++++++++++++++++++ 5 files changed, 97 insertions(+), 12 deletions(-) create mode 100644 test/matchit/optexpr.cpp diff --git a/develop/matchit/expression.h b/develop/matchit/expression.h index 7b19c83..2e30084 100644 --- a/develop/matchit/expression.h +++ b/develop/matchit/expression.h @@ -36,6 +36,19 @@ namespace matchit { return v; }); } + template + constexpr auto toNullary(T &&v) + { + if constexpr (std::is_invocable_v>) + { + return v; + } + else + { + return expr(v); + } + } + // for constant template class EvalTraits diff --git a/develop/matchit/patterns.h b/develop/matchit/patterns.h index 6c272b2..7e3fc53 100644 --- a/develop/matchit/patterns.h +++ b/develop/matchit/patterns.h @@ -347,11 +347,12 @@ namespace matchit }; template - constexpr auto when(Pred const &pred) + constexpr auto when(Pred &&pred) { - return When{pred}; + auto p = toNullary(pred); + return When{p}; } - + template class PatternHelper { @@ -359,9 +360,10 @@ namespace matchit constexpr explicit PatternHelper(Pattern const &pattern) : mPattern{pattern} {} template - constexpr auto operator=(Func const &func) + constexpr auto operator=(Func &&func) { - return PatternPair{mPattern, func}; + auto f = toNullary(func); + return PatternPair{mPattern, f}; } template constexpr auto operator|(When const &w) diff --git a/include/matchit.h b/include/matchit.h index 3b0eb7b..f3df93b 100644 --- a/include/matchit.h +++ b/include/matchit.h @@ -111,6 +111,19 @@ namespace matchit { return v; }); } + template + constexpr auto toNullary(T &&v) + { + if constexpr (std::is_invocable_v>) + { + return v; + } + else + { + return expr(v); + } + } + // for constant template class EvalTraits @@ -654,11 +667,12 @@ namespace matchit }; template - constexpr auto when(Pred const &pred) + constexpr auto when(Pred &&pred) { - return When{pred}; + auto p = toNullary(pred); + return When{p}; } - + template class PatternHelper { @@ -666,9 +680,10 @@ namespace matchit constexpr explicit PatternHelper(Pattern const &pattern) : mPattern{pattern} {} template - constexpr auto operator=(Func const &func) + constexpr auto operator=(Func &&func) { - return PatternPair{mPattern, func}; + auto f = toNullary(func); + return PatternPair{mPattern, f}; } template constexpr auto operator|(When const &w) diff --git a/test/matchit/CMakeLists.txt b/test/matchit/CMakeLists.txt index 4751f42..809aae7 100644 --- a/test/matchit/CMakeLists.txt +++ b/test/matchit/CMakeLists.txt @@ -1,5 +1,5 @@ -add_executable(unittests app.cpp constexpr.cpp expr.cpp legacy.cpp noRet.cpp id.cpp ds.cpp) +add_executable(unittests app.cpp constexpr.cpp expr.cpp legacy.cpp noRet.cpp id.cpp ds.cpp optexpr.cpp) target_compile_options(unittests PRIVATE ${BASE_COMPILE_FLAGS}) target_link_libraries(unittests PRIVATE matchit gtest_main) set_target_properties(unittests PROPERTIES CXX_EXTENSIONS OFF) -gtest_discover_tests(unittests) \ No newline at end of file +gtest_discover_tests(unittests) diff --git a/test/matchit/optexpr.cpp b/test/matchit/optexpr.cpp new file mode 100644 index 0000000..3679458 --- /dev/null +++ b/test/matchit/optexpr.cpp @@ -0,0 +1,55 @@ +#include +#include + +#include "matchit.h" +using namespace matchit; + +template +constexpr auto eval1(std::tuple const& exp) +{ + using namespace matchit; + Id i; + Id j; + return match(exp) // no expr() + ( + pattern | ds('+', i, j) | when((i + j) > 0) = i + j, + pattern | ds('-', i, j) | when(true) = i - j, + pattern | ds('*', i, j) | when(i) = i, + pattern | ds('/', i, j) = 12345, + pattern | _ = [] { return -1; } + ); +} + +template +constexpr auto eval2(std::tuple const& exp) +{ + using namespace matchit; + Id i; + Id j; + return match(exp) // unnecessary expr() + ( + pattern | ds('+', i, j) | when((i + j) > 0) = i + j, + pattern | ds('-', i, j) | when(expr(true)) = i - j, + pattern | ds('*', i, j) | when(expr(i)) = expr(i), + pattern | ds('/', i, j) = expr(12345), + pattern | _ = [] { return -1; } + ); +} + +TEST(OptExpr, no_expr) +{ + EXPECT_EQ(eval1(std::tuple{'+', 20, 3}), 23); + EXPECT_EQ(eval1(std::tuple{'-', 20, 3}), 17); + EXPECT_EQ(eval1(std::tuple{'*', 20, 3}), 20); + EXPECT_EQ(eval1(std::tuple{'/', 20, 3}), 12345); + EXPECT_EQ(eval1(std::tuple{' ', 20, 3}), -1); +} + +TEST(OptExpr, unnecessary_expr) +{ + EXPECT_EQ(eval2(std::tuple{'+', 20, 3}), 23); + EXPECT_EQ(eval2(std::tuple{'-', 20, 3}), 17); + EXPECT_EQ(eval2(std::tuple{'*', 20, 3}), 20); + EXPECT_EQ(eval2(std::tuple{'/', 20, 3}), 12345); + EXPECT_EQ(eval2(std::tuple{' ', 20, 3}), -1); +} From 10f6320074a2dba3599c7880efe7853a13cd55cb Mon Sep 17 00:00:00 2001 From: Bowen Fu Date: Sun, 20 Nov 2022 20:31:38 +0800 Subject: [PATCH 13/15] Update README. (#97) * Update README. * Update godbolt link. Co-authored-by: Bowen Fu --- README.md | 74 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 42 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 625ba29..7b170b0 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ [![codecov](https://codecov.io/gh/BowenFu/matchit.cpp/branch/main/graph/badge.svg?token=G5B0RE6THD)](https://codecov.io/gh/BowenFu/matchit.cpp) [badge.godbolt]: https://img.shields.io/badge/try-godbolt-blue -[godbolt]: https://godbolt.org/z/8YMr8Kz8j +[godbolt]: https://godbolt.org/z/Psf3qrxW4 ## Features @@ -165,7 +165,7 @@ constexpr int32_t factorial(int32_t n) using namespace matchit; assert(n >= 0); return match(n)( - pattern | 0 = expr(1), + pattern | 0 = 1, pattern | _ = [n] { return n * factorial(n - 1); } ); } @@ -186,7 +186,7 @@ This is a function call and will return some value returned by handlers. The ret When handlers return values, the patterns must be exhaustive. A runtime error will happen if all patterns do not get matched. It is not an error if handlers' return types are all void. -`expr` in the above sample is a helper function that can be used to generate a nullary function that returns a value. `expr(1)` is equivalent to `[]{return 1;}`. It can be useful for short functions. +The handler can also be a value or an Id variable. `1` is equivalent to `[]{return 1;}`. The wildcard `_` will match any values. It is a common practice to always use it as the last pattern, playing the same role in our library as `default case` does for `switch` statements, to avoid case escaping. @@ -220,8 +220,8 @@ constexpr bool contains(Map const& map, Key const& key) { using namespace matchit; return match(map.find(key))( - pattern | map.end() = expr(false), - pattern | _ = expr(true) + pattern | map.end() = false, + pattern | _ = true ); } ``` @@ -234,8 +234,9 @@ We can use **Predicate Pattern** to put some restrictions on the value to be mat constexpr double relu(double value) { return match(value)( - pattern | (_ >= 0) = expr(value), - pattern | _ = expr(0)); + pattern | (_ >= 0) = value, + pattern | _ = 0 + ); } static_assert(relu(5) == 5); @@ -253,8 +254,8 @@ constexpr bool isValid(int32_t n) { using namespace matchit; return match(n)( - pattern | or_(1, 3, 5) = expr(true), - pattern | _ = expr(false) + pattern | or_(1, 3, 5) = true, + pattern | _ = false ); } @@ -280,8 +281,8 @@ constexpr bool isLarge(double value) { using namespace matchit; return match(value)( - pattern | app(_ * _, _ > 1000) = expr(true), - pattern | _ = expr(false) + pattern | app(_ * _, _ > 1000) = true, + pattern | _ = false ); } @@ -307,7 +308,7 @@ bool checkAndlogLarge(double value) pattern | app(_ * _, s.at(_ > 1000)) = [&] { std::cout << value << "^2 = " << *s << " > 1000!" << std::endl; return true; }, - pattern | _ = expr(false)); + pattern | _ = false); } ``` @@ -330,8 +331,8 @@ constexpr bool symmetric(std::array const& arr) using namespace matchit; Id i, j; return match(arr)( - pattern | ds(i, j, _, j, i) = expr(true), - pattern | _ = expr(false) + pattern | ds(i, j, _, j, i) = true, + pattern | _ = false ); } @@ -383,8 +384,8 @@ constexpr auto dsByMember(DummyStruct const&v) constexpr auto dsA = dsVia(&DummyStruct::size, &DummyStruct::name); Id name; return match(v)( - pattern | dsA(2, name) = expr(name), - pattern | _ = expr("not matched") + pattern | dsA(2, name) = name, + pattern | _ = "not matched" ); }; @@ -411,8 +412,8 @@ constexpr bool sumIs(std::array const& arr, int32_t s) using namespace matchit; Id i, j; return match(arr)( - pattern | ds(i, j) | when(i + j == s) = expr(true), - pattern | _ = expr(false)); + pattern | ds(i, j) | when(i + j == s) = true, + pattern | _ = false); } static_assert(sumIs(std::array{5, 6}, 11)); @@ -435,10 +436,10 @@ constexpr int32_t detectTuplePattern(Tuple const& tuple) using namespace matchit; return match(tuple) ( - pattern | ds(2, ooo, 2) = expr(4), - pattern | ds(2, ooo ) = expr(3), - pattern | ds(ooo, 2 ) = expr(2), - pattern | ds(ooo ) = expr(1) + pattern | ds(2, ooo, 2) = 4, + pattern | ds(2, ooo ) = 3, + pattern | ds(ooo, 2 ) = 2, + pattern | ds(ooo ) = 1 ); } @@ -457,8 +458,8 @@ constexpr bool recursiveSymmetric(Range const &range) Id> subrange; return match(range)( pattern | ds(i, subrange.at(ooo), i) = [&] { return recursiveSymmetric(*subrange); }, - pattern | ds(_, ooo, _) = expr(false), - pattern | _ = expr(true) + pattern | ds(_, ooo, _) = false, + pattern | _ = true ); ``` @@ -485,7 +486,7 @@ constexpr auto square(std::optional const& t) Id id; return match(t)( pattern | some(id) = id * id, - pattern | none = expr(0)); + pattern | none = 0); } constexpr auto x = std::make_optional(5); static_assert(square(x) == 25); @@ -524,8 +525,8 @@ constexpr auto getClassName(T const& v) { using namespace matchit; return match(v)( - pattern | as(_) = expr("chars"), - pattern | as(_) = expr("int32_t") + pattern | as(_) = "chars", + pattern | as(_) = "int32_t" ); } @@ -546,8 +547,8 @@ struct Square : Shape {}; auto getClassName(Shape const &s) { return match(s)( - pattern | as(_) = expr("Circle"), - pattern | as(_) = expr("Square") + pattern | as(_) = "Circle", + pattern | as(_) = "Square" ); } ``` @@ -610,9 +611,9 @@ int32_t staticCastAs(Num const& input) { using namespace matchit; return match(input)( - pattern | as(_) = expr(1), - pattern | kind = expr(2), - pattern | _ = expr(3)); + pattern | as(_) = 1, + pattern | kind = 2, + pattern | _ = 3); } int32_t main() @@ -712,6 +713,15 @@ If you are interested in `match(it)`, you may also be interested in [hspp](https Please star the repo, share the repo, or sponsor one dollar to let me know this library matters. +## Contributor(s) + +Thanks to all for contributing code and sending in bugs. + +In particular, thanks to the following contributors: + +Hugo Etchegoyen (@[hugoetchegoyen](https://github.com/hugoetchegoyen)) + + ## Sponsor(s) Thanks to @[e-dant](https://github.com/e-dant) for sponsoring this project. From 87c6cbad6b108b2658deba8a43b820732ac18e79 Mon Sep 17 00:00:00 2001 From: Bowen Fu Date: Tue, 22 Nov 2022 20:33:37 +0800 Subject: [PATCH 14/15] Clean up unnecessary expr. (#98) * formatting. * clean up. Co-authored-by: Bowen Fu --- From-Pattern-Matching-Proposal-to-matchit.md | 26 ++--- From-Rust-to-matchit.md | 85 ++++++++------- README.md | 14 ++- REFERENCE.md | 98 +++++++++-------- sample/Conditional-if-let-Expressions.cpp | 8 +- sample/Evaluating-Expression-Trees.cpp | 8 +- .../Extra-Conditionals-with-Match-Guards.cpp | 4 +- sample/Literal-pattern.cpp | 8 +- sample/Predicate-based-Discriminator.cpp | 5 +- sample/Range-pattern.cpp | 28 ++--- sample/Red-black-Tree-Rebalancing.cpp | 4 +- sample/Reference-pattern.cpp | 12 +- sample/Slice-pattern.cpp | 6 +- sample/Terminate.cpp | 4 +- sample/While-conditional-let-Loops.cpp | 2 +- sample/checkAndlogLarge.cpp | 3 +- sample/clip.cpp | 6 +- sample/contains.cpp | 4 +- sample/customAsPointer.cpp | 6 +- sample/customDs.cpp | 8 +- sample/detectTuplePattern.cpp | 8 +- sample/getClassName.cpp | 6 +- sample/isLarge.cpp | 4 +- sample/isValid.cpp | 4 +- sample/optionalLift.cpp | 2 +- sample/relu.cpp | 4 +- sample/someNone.cpp | 2 +- sample/sumIs.cpp | 4 +- sample/symmetric.cpp | 8 +- sample/variantAny.cpp | 4 +- test/matchit/constexpr.cpp | 10 +- test/matchit/ds.cpp | 9 +- test/matchit/id.cpp | 28 ++--- test/matchit/legacy.cpp | 103 ++++++++++-------- test/matchit/noRet.cpp | 2 +- test/matchit/optexpr.cpp | 6 +- 36 files changed, 289 insertions(+), 254 deletions(-) diff --git a/From-Pattern-Matching-Proposal-to-matchit.md b/From-Pattern-Matching-Proposal-to-matchit.md index 09bce21..2a91ef7 100644 --- a/From-Pattern-Matching-Proposal-to-matchit.md +++ b/From-Pattern-Matching-Proposal-to-matchit.md @@ -182,14 +182,14 @@ int eval(const Expr &ex) Id i; Id e, l, r; return match(ex)( - pattern | as(i) = expr(i), + pattern | as(i) = 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(as(0)), _) = 0, + pattern | asMulDs(_, some(as(0))) = 0, pattern | asMulDs(some(l), some(r)) = [&]{ return eval(*l) * eval(*r); }, - pattern | _ = expr(-1) + pattern | _ = -1 ); } @@ -219,11 +219,11 @@ Op parseOp(Parser& parser) { enum class Op { Add, Sub, Mul, Div }; Op parseOp(Parser& parser) { Id token; - return match(parser.consumeToken()) ( - pattern | '+' = expr(Op::Add), - pattern | '-' = expr(Op::Sub), - pattern | '*' = expr(Op::Mul), - pattern | '/' = expr(Op::Div), + return match(parser.consumeToken())( + pattern | '+' = Op::Add, + pattern | '-' = Op::Sub, + pattern | '*' = Op::Mul, + pattern | '/' = Op::Div, pattern | token = [&]{ std::cerr << "Unexpected: " << *token; std::terminate(); @@ -754,7 +754,7 @@ char* String::data() { Id l; Id> r; return match(*this) ( - pattern | asEnum(l) = expr(l), + pattern | asEnum(l) = l, pattern | asEnum(r) = [&]{ return (*r).ptr; } ); } @@ -850,8 +850,8 @@ In `match(it)`: int fib(int n) { Id x; return match (n) ( - pattern | (_ < 0) = expr(0), - pattern | or_(1,2) = expr(n), //1|2 + pattern | (_ < 0) = 0, + pattern | or_(1,2) = n, //1|2 pattern | x = [&] { return fib(*x - 1) + fib(*x - 2); } ); } @@ -1028,7 +1028,7 @@ void Node::balance() { = [&] { return Node{Red, std::make_shared(Black, *a, *x, *b), *y, std::make_shared(Black, *c, *z, *d)}; }, - pattern | self = expr(self) // do nothing + pattern | self = self // do nothing ); } ``` diff --git a/From-Rust-to-matchit.md b/From-Rust-to-matchit.md index 9bba895..9bd5a57 100644 --- a/From-Rust-to-matchit.md +++ b/From-Rust-to-matchit.md @@ -30,10 +30,10 @@ for (auto i = -2; i <= 5; ++i) { std::cout << match(i)( - pattern | -1 = expr("It's minus one"), - pattern | 1 = expr("It's a one"), - pattern | or_(2,4) = expr("It's either a two or a four"), - pattern | _ = expr("Matched none of the arms") + pattern | -1 = "It's minus one", + pattern | 1 = "It's a one", + pattern | or_(2,4) = "It's either a two or a four", + pattern | _ = "Matched none of the arms" ) << std::endl; } @@ -364,17 +364,17 @@ In C++ with `match(it)`: ```C++ constexpr auto c = 'f'; constexpr auto valid_variable = match(c)( - pattern | ('a' <= _ && _ <= 'z') = expr(true), - pattern | ('A' <= _ && _ <= 'Z') = expr(true), - // pattern | ('α' <= _ && _ <= 'ω') = expr(true), - pattern | _ = expr(false) + pattern | ('a' <= _ && _ <= 'z') = true, + pattern | ('A' <= _ && _ <= 'Z') = true, + // pattern | ('α' <= _ && _ <= 'ω') = true, + pattern | _ = false ); constexpr auto ph = 10; -std::cout << match(ph)( - pattern | (0 <= _ && _ <= 6 ) = expr("acid"), - pattern | (7 ) = expr("neutral"), - pattern | (8 <= _ && _ <= 14) = expr("base"), +std::cout << match(ph)( + pattern | (0 <= _ && _ <= 6 ) = "acid", + pattern | (7 ) = "neutral", + pattern | (8 <= _ && _ <= 14) = "base", pattern | _ = [] { assert(false && "unreachable"); } ) << std::endl; @@ -390,11 +390,11 @@ constexpr uint8_t MESOSPHERE_MAX = 85; constexpr auto altitude = 70; -std::cout << match(altitude)( - pattern | (TROPOSPHERE_MIN <= _ && _ <= TROPOSPHERE_MAX ) = expr("troposphere"), - pattern | (STRATOSPHERE_MIN <= _ && _ <= STRATOSPHERE_MAX) = expr("stratosphere"), - pattern | (MESOSPHERE_MIN <= _ && _ <= MESOSPHERE_MAX ) = expr("mesosphere"), - pattern | _ = expr("outer space, maybe") +std::cout << match(altitude)( + pattern | (TROPOSPHERE_MIN <= _ && _ <= TROPOSPHERE_MAX ) = "troposphere", + pattern | (STRATOSPHERE_MIN <= _ && _ <= STRATOSPHERE_MAX) = "stratosphere", + pattern | (MESOSPHERE_MIN <= _ && _ <= MESOSPHERE_MAX ) = "mesosphere", + pattern | _ = "outer space, maybe" ) << std::endl; namespace binary @@ -415,11 +415,11 @@ match(n_items * bytes_per_item) ); // using qualified paths: -std::cout << match(static_cast(0xfacade))( - pattern | (0U <= _ && _ <= numeric_limits::max()) = expr("fits in a u8", - pattern | (0U <= _ && _ <= numeric_limits::max()) = expr("fits in a u16", - pattern | (0U <= _ && _ <= numeric_limits::max()) = expr("fits in a u32", - pattern | _ = expr("too big") +std::cout << match(static_cast(0xfacade))( + pattern | (0U <= _ && _ <= numeric_limits::max()) = "fits in a u8", + pattern | (0U <= _ && _ <= numeric_limits::max()) = "fits in a u16", + pattern | (0U <= _ && _ <= numeric_limits::max()) = "fits in a u32", + pattern | _ = "too big" ) << std::endl; ``` @@ -427,9 +427,9 @@ Tips: feel free to use variables in `match(it)`. You can write codes like ```C++ // using variables: -std::cout << match(0xfacade)( - pattern | (min(a, b) <= _ && _ <= max(a, b)) = expr("fits in the range"), - pattern | _ = expr("out of the range") +std::cout << match(0xfacade)( + pattern | (min(a, b) <= _ && _ <= max(a, b)) = "fits in the range", + pattern | _ = "out of the range" ) << std::endl; ``` @@ -455,12 +455,14 @@ int32_t const *int_reference = &value; int32_t const zero = 0; auto const a = match(*int_reference)( - pattern | zero = expr("zero"), - pattern | _ = expr("some")); + pattern | zero = "zero", + pattern | _ = "some" +); auto const b = match(int_reference)( - pattern | &zero = expr("zero"), - pattern | _ = expr("some")); + pattern | &zero = "zero", + pattern | _ = "some" +); assert(a == b); ``` @@ -589,9 +591,9 @@ In C++ with `match(it)`: // Fixed size constexpr auto arr = std::array{1, 2, 3}; Id a, b, c; -match(arr)( - pattern | ds(1, _, _) = expr("starts with one"), - pattern | ds(a, b, c) = expr("starts with something else") +match(arr)( + pattern | ds(1, _, _) = "starts with one", + pattern | ds(a, b, c) = "starts with something else" ); ``` @@ -678,14 +680,15 @@ int32_t main() Id color; match(favorite_color)( pattern | some(color) = [&] { return "Using your favorite color, " + *color + ", as the background"; }, - pattern | _ | when(expr(is_tuesday)) = expr("Tuesday is green day!"), + pattern | _ | when(is_tuesday) = "Tuesday is green day!", pattern | _ = [&] { Id age_; return match(age)( - pattern | as(age_) | when(age_ > 30) = expr("Using purple as the background color"), - pattern | as(age_) = expr("Using orange as the background color"), - pattern | _ = expr("Using blue as the background color")); + pattern | as(age_) | when(age_ > 30) = "Using purple as the background color", + pattern | as(age_) = "Using orange as the background color", + pattern | _ = "Using blue as the background color" + ); }); return 0; @@ -740,7 +743,6 @@ int32_t main() { return std::optional(); } - }; using namespace matchit; @@ -752,7 +754,8 @@ int32_t main() std::cout << *top << std::endl; return true; }, - pattern | _ = expr(false))) + pattern | _ = false) + ) { }; } @@ -1085,9 +1088,9 @@ int32_t main() { auto const y = false; std::cout << - match(x)( - pattern | or_(4, 5, 6) | when(expr(y)) = expr("yes"), - pattern | _ = expr("no") + match(x)( + pattern | or_(4, 5, 6) | when(y) = "yes", + pattern | _ = "no" ) << std::endl; } ``` diff --git a/README.md b/README.md index 7b170b0..93a486b 100644 --- a/README.md +++ b/README.md @@ -308,7 +308,8 @@ bool checkAndlogLarge(double value) pattern | app(_ * _, s.at(_ > 1000)) = [&] { std::cout << value << "^2 = " << *s << " > 1000!" << std::endl; return true; }, - pattern | _ = false); + pattern | _ = false + ); } ``` @@ -393,7 +394,7 @@ static_assert(dsByMember(DummyStruct{1, "123"}) == std::string_view{"not matched static_assert(dsByMember(DummyStruct{2, "123"}) == std::string_view{"123"}); ``` -Let's continue the journey. +Let's continue the journey. Sometimes you have multiple identifiers and you want exert a restriction on the relationship of them. Is that possible? Sure! Here comes the **Match Guard**. Its syntax is @@ -413,7 +414,8 @@ constexpr bool sumIs(std::array const& arr, int32_t s) Id i, j; return match(arr)( pattern | ds(i, j) | when(i + j == s) = true, - pattern | _ = false); + pattern | _ = false + ); } static_assert(sumIs(std::array{5, 6}, 11)); @@ -486,7 +488,8 @@ constexpr auto square(std::optional const& t) Id id; return match(t)( pattern | some(id) = id * id, - pattern | none = 0); + pattern | none = 0 + ); } constexpr auto x = std::make_optional(5); static_assert(square(x) == 25); @@ -613,7 +616,8 @@ int32_t staticCastAs(Num const& input) return match(input)( pattern | as(_) = 1, pattern | kind = 2, - pattern | _ = 3); + pattern | _ = 3 + ); } int32_t main() diff --git a/REFERENCE.md b/REFERENCE.md index 740d6d5..d30024d 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -21,9 +21,8 @@ The operator `=` between the pattern and handler can be any binary operators. It ### Handler Handlers should always be nullary functions. This is different from `mpark/patterns` and `jbandela/simple_match`. -`expr` can be called to return simple functions returning a single value. -`expr(value)` syntax is inspired by `Boost/Lambda` library. -`pattern | xxx = expr(zzz)` or `pattern | xxx = [&]{zzzzzz}` syntaxes can be aligned and it is easy to find out the pattern parts and handler parts. +Expressions can be used as handlers as well, which are equivalent to nullary functions that return the same values. +Id instances used as handlers are equivalent to nullary functions that return the bound values. ## Pattern Primitives @@ -34,8 +33,8 @@ You can even use a function call as Expression Pattern, the result of the functi ```C++ match(map.find(key))( - pattern | map.end() = expr(false), - pattern | _ = expr(true) + pattern | map.end() = false, + pattern | _ = true ) ``` @@ -53,8 +52,9 @@ Predicate Pattern corresponds to `(? expr)`. ```C++ match(value)( - pattern | meet([](auto &&v { return v >= 0; })) = expr(value), - pattern | _ = expr(0)) + pattern | meet([](auto &&v { return v >= 0; })) = value, + pattern | _ = 0 +) ``` Predicate Pattern syntax is `meet(predicate function)`. @@ -62,8 +62,9 @@ Predicate Pattern syntax is `meet(predicate function)`. ```C++ match(value)( - pattern | (_ >= 0) = expr(value), - pattern | _ = expr(0)) + pattern | (_ >= 0) = value, + pattern | _ = 0 +) ``` The short syntax is inspired by `jbandela/simple_match`. @@ -80,14 +81,14 @@ This means that handlers in `match(it)` are always nullary, but can be unary or ```C++ Id s; match(value)( - pattern | app(_ * _, s) = expr(s), - pattern | _ = expr(0)); + pattern | app(_ * _, s) = s, + pattern | _ = 0 +); ``` You have to define / declare the identifiers first then bind them inside patterns and access them in handlers. -`expr(s)` is a short for `[&]{ return *s; }`, i.e., a function returning the value bound to the identifier. -Identifier Pattern supports binding non-constructable (via reference), non-copyable (via reference or moving) types. +Identifier Pattern supports binding non-constructable (via reference), non-copyable (via reference or moving) types. This can be similar to "Ref pattern" or "Mut Ref pattern" in Rust. Identifier Pattern requires `operator==` for the binding types. @@ -105,13 +106,14 @@ A simple sample can be ```C++ bool flag = true; return match(v)( - pattern | 0 | when(expr(flag)) = expr(true), - pattern | _ = expr(false)); + pattern | 0 | when(flag) = true, + pattern | _ = false +); ``` ### Ooo Pattern -Ooo Pattern can match arbitrary number of items. +Ooo Pattern can match arbitrary number of items. Similar patterns exist in most related works. The current one is mostly influenced by `..` pattern in Rust. (Also inspired by Racket's `...`). It can only be used inside Destructure Patterns and at most one Ooo pattern can appear inside one Destructure Pattern. @@ -120,10 +122,10 @@ Refer to [Pattern Cominators / Destructure Pattern](#destructure-pattern). ```C++ match(tuple) ( - pattern | ds(2, ooo, 2) = expr(4), - pattern | ds(2, ooo ) = expr(3), - pattern | ds(ooo, 2 ) = expr(2), - pattern | ds(ooo ) = expr(1) + pattern | ds(2, ooo, 2) = 4, + pattern | ds(2, ooo ) = 3, + pattern | ds(ooo, 2 ) = 2, + pattern | ds(ooo ) = 1 ) ``` @@ -136,8 +138,8 @@ The Racket syntax is `(or pat ...)`, and the corresponding C++ syntax is `or_(pa ```C++ match(n)( - pattern | or_(1, 3, 5) = expr(true), - pattern | _ = expr(false)) + pattern | or_(1, 3, 5) = true, + pattern | _ = false) ``` Note subpatterns of `or_` pattern can be any patterns, not just expression patterns. @@ -145,8 +147,9 @@ Say Predicate Patterns ```C++ match(n)( - pattern | or_(_ < 3, 5) = expr(true), - pattern | _ = expr(false)) + pattern | or_(_ < 3, 5) = true, + pattern | _ = false +) ``` In Rust and some other related work, there exists a similar `anyof` pattern. But only literal patterns can be used as subpatterns. @@ -158,18 +161,20 @@ The Racket syntax is `(and pat ...)`, and the corresponding C++ syntax is `and_( ```C++ match(value)( - pattern | and_(_ >= min, _ <= max)) = expr(value), - pattern | (_ > max) = expr(max), - pattern | _ = expr(min)) + pattern | and_(_ >= min, _ <= max)) = value, + pattern | (_ > max) = max, + pattern | _ = min +) ``` Note this can also be written as ```C++ match(value)( - pattern | (min <= _ && _ <= max) = expr(value), - pattern | (_ > max) = expr(max), - pattern | _ = expr(min)) + pattern | (min <= _ && _ <= max) = value, + pattern | (_ > max) = max, + pattern | _ = min +) ``` But `&&` can only be used between Predicate patterns, while `and_` can be used for all kinds of patterns (except Ooo Pattern). @@ -189,8 +194,9 @@ That is to say, Predicate Pattern can be expressed with App Pattern, `meet(unary ```C++ match(value)( - pattern | app(_ * _, _ > 1000) = expr(true), - pattern | _ = expr(false)) + pattern | app(_ * _, _ > 1000) = true, + pattern | _ = false +) ``` ### Destructure Pattern @@ -205,7 +211,8 @@ match(expr)( pattern | ds('-', i, j) = i - j, pattern | ds('*', i, j) = i * j, pattern | ds('/', i, j) = i / j, - pattern | _ = expr(-1)) + pattern | _ = -1 +) ``` Note the outermost `ds` inside pattern can be saved. That is to say, when pattern receives multiple parameters, they are treated as subpatterns of a ds pattern. @@ -218,10 +225,11 @@ match(expr)( pattern | ds('-', i, j) = i - j, pattern | ds('*', i, j) = i * j, pattern | ds('/', i, j) = i / j, - pattern | _ = expr(-1)) + pattern | _ = -1 +) ``` -We support Destructure Pattern for `std::tuple`, `std::pair`, `std::array`, and containers / ranges that can be called with `std::begin` and `std::end`. +We support Destructure Pattern for `std::tuple`, `std::pair`, `std::array`, and containers / ranges that can be called with `std::begin` and `std::end`. Mismatch of element numbers is a compile error for fixed-size containers. Mismatch of element numbers is just a mismatch for dynamic containers, neither a compile error, nor a runtime error. @@ -240,8 +248,8 @@ constexpr auto dsViaMember(DummyStruct const&v) const auto dsA = dsVia(&DummyStruct::size, &DummyStruct::name); Id name; return match(v)( - pattern | dsA(2, name) = expr(name), - pattern | _ = expr("not matched") + pattern | dsA(2, name) = name, + pattern | _ = "not matched" ); }; @@ -256,8 +264,9 @@ At Pattern is similar to the `@` pattern in Rust. It can have one subpattern. Th ```C++ Id s; match(value)( - pattern | app(_ * _, s.at(_ > 1000)) = expr(s), - pattern | _ = expr(0)); + pattern | app(_ * _, s.at(_ > 1000)) = s, + pattern | _ = 0 +); ``` ### At Pattern for Ooo Pattern @@ -269,8 +278,8 @@ Id i; Id> subrange; return match(range)( pattern | ds(i, subrange.at(ooo), i) = [&] { return recursiveSymmetric(*subrange); }, - pattern | ds(i, subrange.at(ooo), _) = expr(false), - pattern | _ = expr(true) + pattern | ds(i, subrange.at(ooo), _) = false, + pattern | _ = true ); ``` @@ -284,7 +293,8 @@ Their usage can be ```C++ match(t)( pattern | some(id) = id * id, - pattern | none = expr(0)); + pattern | none = 0 +); ``` ### As Pattern @@ -294,8 +304,8 @@ It can be used to handle sum type, including class hierarchies, std::variant, an ```C++ match(v)( - pattern | as(_) = expr("chars"), - pattern | as(_) = expr("int32_t") + pattern | as(_) = "chars", + pattern | as(_) = "int32_t" ); ``` diff --git a/sample/Conditional-if-let-Expressions.cpp b/sample/Conditional-if-let-Expressions.cpp index 7635983..433b948 100644 --- a/sample/Conditional-if-let-Expressions.cpp +++ b/sample/Conditional-if-let-Expressions.cpp @@ -23,17 +23,17 @@ int32_t main() return "Using your favorite color, " + *color + ", as the background"; }, - pattern | _ | when(expr(is_tuesday)) = expr("Tuesday is green day!"), + pattern | _ | when(is_tuesday) = "Tuesday is green day!", pattern | _ = [&] { Id age_; return match(age)(pattern | as(age_) | when(age_ > 30) = - expr("Using purple as the background color"), + "Using purple as the background color", pattern | as(age_) = - expr("Using orange as the background color"), + "Using orange as the background color", pattern | _ = - expr("Using blue as the background color")); + "Using blue as the background color"); }); return 0; diff --git a/sample/Evaluating-Expression-Trees.cpp b/sample/Evaluating-Expression-Trees.cpp index 457ad9f..d9d7cde 100644 --- a/sample/Evaluating-Expression-Trees.cpp +++ b/sample/Evaluating-Expression-Trees.cpp @@ -51,14 +51,14 @@ int eval(const Expr &ex) return match(ex)( // clang-format off // FIXME: Expr{5} won't match the following line. - pattern | as(i) = expr(i), + pattern | as(i) = 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(as(0)), _) = 0, + pattern | asMulDs(_, some(as(0))) = 0, pattern | asMulDs(some(l), some(r)) = [&]{ return eval(*l) * eval(*r); }, - pattern | _ = expr(-1) + pattern | _ = -1 // clang-format on ); } diff --git a/sample/Extra-Conditionals-with-Match-Guards.cpp b/sample/Extra-Conditionals-with-Match-Guards.cpp index f8e03be..59376c1 100644 --- a/sample/Extra-Conditionals-with-Match-Guards.cpp +++ b/sample/Extra-Conditionals-with-Match-Guards.cpp @@ -56,8 +56,8 @@ void sample3() std::cout << match(x)( // clang-format off - pattern | or_(4, 5, 6) | when(expr(y)) = expr("yes"), - pattern | _ = expr("no") + pattern | or_(4, 5, 6) | when(y) = "yes", + pattern | _ = "no" // clang-format on ) << std::endl; diff --git a/sample/Literal-pattern.cpp b/sample/Literal-pattern.cpp index b8f1049..1023a22 100644 --- a/sample/Literal-pattern.cpp +++ b/sample/Literal-pattern.cpp @@ -8,10 +8,10 @@ int32_t main() using namespace matchit; std::cout << match(i)( // clang-format off - pattern | -1 = expr("It's minus one"), - pattern | 1 = expr("It's a one"), - pattern | or_(2, 4) = expr("It's either a two or a four"), - pattern | _ = expr("Matched none of the arms") + pattern | -1 = "It's minus one", + pattern | 1 = "It's a one", + pattern | or_(2, 4) = "It's either a two or a four", + pattern | _ = "Matched none of the arms" // clang-format off ) << std::endl; diff --git a/sample/Predicate-based-Discriminator.cpp b/sample/Predicate-based-Discriminator.cpp index 488bbbb..d6e6b75 100644 --- a/sample/Predicate-based-Discriminator.cpp +++ b/sample/Predicate-based-Discriminator.cpp @@ -63,9 +63,10 @@ char *String::data() Id l; Id> r; return match(*this)( - pattern | asEnum(l) = expr(l), + pattern | asEnum(l) = l, pattern | asEnum(r) = [&] - { return (*r).ptr; }); + { return (*r).ptr; } + ); } int32_t main() diff --git a/sample/Range-pattern.cpp b/sample/Range-pattern.cpp index 88c00ce..4e5cf99 100644 --- a/sample/Range-pattern.cpp +++ b/sample/Range-pattern.cpp @@ -14,9 +14,9 @@ void sample() constexpr auto c = 'f'; constexpr auto valid_variable = match(c)( // clang-format off - pattern | ('a' <= _ && _ <= 'z') = expr(true), - pattern | ('A' <= _ && _ <= 'Z') = expr(true), - pattern | _ = expr(false) + pattern | ('a' <= _ && _ <= 'z') = true, + pattern | ('A' <= _ && _ <= 'Z') = true, + pattern | _ = false // clang-format on ); static_cast(valid_variable); @@ -24,9 +24,9 @@ void sample() constexpr auto ph = 10; std::cout << match(ph)( // clang-format off - pattern | (0 <= _ && _ <= 6 ) = expr("acid"), - pattern | (7 ) = expr("neutral"), - pattern | (8 <= _ && _ <= 14) = expr("base"), + pattern | (0 <= _ && _ <= 6 ) = "acid", + pattern | (7 ) = "neutral", + pattern | (8 <= _ && _ <= 14) = "base", pattern | (_ ) = [] { assert(false && "unreachable"); return ""; }) // clang-format on << std::endl; @@ -45,10 +45,10 @@ void sample() std::cout << match(altitude)( // clang-format off - pattern | (TROPOSPHERE_MIN <= _ && _ <= TROPOSPHERE_MAX ) = expr("troposphere"), - pattern | (STRATOSPHERE_MIN <= _ && _ <= STRATOSPHERE_MAX) = expr("stratosphere"), - pattern | (MESOSPHERE_MIN <= _ && _ <= MESOSPHERE_MAX ) = expr("mesosphere"), - pattern | (_ ) = expr("outer space, maybe")) + pattern | (TROPOSPHERE_MIN <= _ && _ <= TROPOSPHERE_MAX ) = "troposphere", + pattern | (STRATOSPHERE_MIN <= _ && _ <= STRATOSPHERE_MAX) = "stratosphere", + pattern | (MESOSPHERE_MIN <= _ && _ <= MESOSPHERE_MAX ) = "mesosphere", + pattern | (_ ) = "outer space, maybe") // clang-format on << std::endl; @@ -66,10 +66,10 @@ void sample() std::cout << match(static_cast(0xfacade))( // clang-format off - pattern | (0U <= _ && _ <= std::numeric_limits::max()) = expr("fits in a u8"), - pattern | (0U <= _ && _ <= std::numeric_limits::max()) = expr("fits in a u16"), - pattern | (0U <= _ && _ <= std::numeric_limits::max()) = expr("fits in a u32"), - pattern | _ = expr("too big")) + pattern | (0U <= _ && _ <= std::numeric_limits::max()) = "fits in a u8", + pattern | (0U <= _ && _ <= std::numeric_limits::max()) = "fits in a u16", + pattern | (0U <= _ && _ <= std::numeric_limits::max()) = "fits in a u32", + pattern | _ = "too big") // clang-format on << std::endl; } diff --git a/sample/Red-black-Tree-Rebalancing.cpp b/sample/Red-black-Tree-Rebalancing.cpp index c376c9b..62fcbdd 100644 --- a/sample/Red-black-Tree-Rebalancing.cpp +++ b/sample/Red-black-Tree-Rebalancing.cpp @@ -78,7 +78,7 @@ void Node::balance() return Node{Red, std::make_shared(Black, *a, *x, *b), *y, std::make_shared(Black, *c, *z, *d)}; }, - pattern | self = expr(self) // do nothing + pattern | self = self // do nothing ); } @@ -125,7 +125,7 @@ void Node::balance() = [&] { return Node{Red, std::make_shared(Black, *a, *x, *b), *y, std::make_shared(Black, *c, *z, *d)}; }, - pattern | self = expr(self) // do nothing + pattern | self = self // do nothing ); } diff --git a/sample/Reference-pattern.cpp b/sample/Reference-pattern.cpp index 38b655d..954cc9a 100644 --- a/sample/Reference-pattern.cpp +++ b/sample/Reference-pattern.cpp @@ -9,11 +9,15 @@ void sample() int32_t const zero = 0; - auto const a = match(*int_reference)(pattern | zero = expr("zero"), - pattern | _ = expr("some")); + auto const a = match(*int_reference)( + pattern | zero = "zero", + pattern | _ = "some" + ); - auto const b = match(int_reference)(pattern | &zero = expr("zero"), - pattern | _ = expr("some")); + auto const b = match(int_reference)( + pattern | &zero = "zero", + pattern | _ = "some" + ); static_cast(a); static_cast(b); diff --git a/sample/Slice-pattern.cpp b/sample/Slice-pattern.cpp index db1ff3f..d28053c 100644 --- a/sample/Slice-pattern.cpp +++ b/sample/Slice-pattern.cpp @@ -8,8 +8,10 @@ void sample1() // Fixed size constexpr auto arr = std::array{1, 2, 3}; Id a, b, c; - match(arr)(pattern | ds(1, _, _) = expr("starts with one"), - pattern | ds(a, b, c) = expr("starts with something else")); + match(arr)( + pattern | ds(1, _, _) = "starts with one", + pattern | ds(a, b, c) = "starts with something else" + ); } void sample2() diff --git a/sample/Terminate.cpp b/sample/Terminate.cpp index b7d7cbc..b90234e 100644 --- a/sample/Terminate.cpp +++ b/sample/Terminate.cpp @@ -14,8 +14,8 @@ Op parseOp(char t) using namespace matchit; Id token; return match(t)( - pattern | '+' = expr(Op::Add), pattern | '-' = expr(Op::Sub), - pattern | '*' = expr(Op::Mul), pattern | '/' = expr(Op::Div), + pattern | '+' = Op::Add, pattern | '-' = Op::Sub, + pattern | '*' = Op::Mul, pattern | '/' = Op::Div, pattern | token = [&] { std::cerr << "Unexpected: " << *token; diff --git a/sample/While-conditional-let-Loops.cpp b/sample/While-conditional-let-Loops.cpp index f1ba61a..979834e 100644 --- a/sample/While-conditional-let-Loops.cpp +++ b/sample/While-conditional-let-Loops.cpp @@ -39,7 +39,7 @@ int32_t main() std::cout << *top << std::endl; return true; }, - pattern | _ = expr(false))) + pattern | _ = false)) { }; } \ No newline at end of file diff --git a/sample/checkAndlogLarge.cpp b/sample/checkAndlogLarge.cpp index 9e7fc12..cc9160d 100644 --- a/sample/checkAndlogLarge.cpp +++ b/sample/checkAndlogLarge.cpp @@ -15,7 +15,8 @@ constexpr bool checkAndlogLarge(double value) std::cout << value << "^2 = " << *s << " > 1000!" << std::endl; return true; }, - pattern | _ = expr(false)); + pattern | _ = false + ); } // comment out std::cout then uncomment this. diff --git a/sample/clip.cpp b/sample/clip.cpp index 9d97d15..dc20473 100644 --- a/sample/clip.cpp +++ b/sample/clip.cpp @@ -6,9 +6,9 @@ constexpr double clip(double value, double min, double max) using namespace matchit; return match(value)( // clang-format off - pattern | and_(_ >= min, _ <= max) = expr(value), - pattern | (_ > max) = expr(max), - pattern | _ = expr(min) + pattern | and_(_ >= min, _ <= max) = value, + pattern | (_ > max) = max, + pattern | _ = min // clang-format on ); } diff --git a/sample/contains.cpp b/sample/contains.cpp index 98f4b0d..e104b14 100644 --- a/sample/contains.cpp +++ b/sample/contains.cpp @@ -8,8 +8,8 @@ constexpr bool contains(Map const &map, Key const &key) using namespace matchit; return match(map.find(key))( // clang-format off - pattern | map.end() = expr(false), - pattern | _ = expr(true) + pattern | map.end() = false, + pattern | _ = true // clang-format on ); } diff --git a/sample/customAsPointer.cpp b/sample/customAsPointer.cpp index 7733a4d..ce7ea5b 100644 --- a/sample/customAsPointer.cpp +++ b/sample/customAsPointer.cpp @@ -51,9 +51,9 @@ constexpr int32_t staticCastAs(Num const &input) using namespace matchit; return match(input)( // clang-format off - pattern | as(_) = expr(1), - pattern | kind = expr(2), - pattern | _ = expr(3) + pattern | as(_) = 1, + pattern | kind = 2, + pattern | _ = 3 // clang-format on ); } diff --git a/sample/customDs.cpp b/sample/customDs.cpp index 330fe65..2865477 100644 --- a/sample/customDs.cpp +++ b/sample/customDs.cpp @@ -38,8 +38,8 @@ constexpr auto getSecond(DummyStruct const &d) Id i; return match(d)( // clang-format off - pattern | ds(2, i) = expr(i), - pattern | _ = expr("not matched") + pattern | ds(2, i) = i, + pattern | _ = "not matched" // clang-format on ); } @@ -59,8 +59,8 @@ constexpr auto dsByMember(DummyStruct const &v) Id i; return match(v)( // clang-format off - pattern | dsA(2, i) = expr(i), - pattern | _ = expr("not matched") + pattern | dsA(2, i) = i, + pattern | _ = "not matched" // clang-format on ); } diff --git a/sample/detectTuplePattern.cpp b/sample/detectTuplePattern.cpp index d46c08c..0dfec1a 100644 --- a/sample/detectTuplePattern.cpp +++ b/sample/detectTuplePattern.cpp @@ -8,10 +8,10 @@ constexpr int32_t detectTuplePattern(Tuple const &tuple) using namespace matchit; return match(tuple)( // clang-format off - pattern | ds(2, ooo, 2) = expr(4), - pattern | ds(2, ooo ) = expr(3), - pattern | ds(ooo, 2 ) = expr(2), - pattern | ds(ooo ) = expr(1) + pattern | ds(2, ooo, 2) = 4, + pattern | ds(2, ooo ) = 3, + pattern | ds(ooo, 2 ) = 2, + pattern | ds(ooo ) = 1 // clang-format on ); } diff --git a/sample/getClassName.cpp b/sample/getClassName.cpp index 623e86e..c48b6e6 100644 --- a/sample/getClassName.cpp +++ b/sample/getClassName.cpp @@ -15,8 +15,10 @@ struct Square : Shape constexpr auto getClassName(Shape const &s) { using namespace matchit; - return match(s)(pattern | as(_) = expr("Circle"), - pattern | as(_) = expr("Square")); + return match(s)( + pattern | as(_) = "Circle", + pattern | as(_) = "Square" + ); } int32_t main() diff --git a/sample/isLarge.cpp b/sample/isLarge.cpp index 32f15d2..688f3f9 100644 --- a/sample/isLarge.cpp +++ b/sample/isLarge.cpp @@ -8,8 +8,8 @@ constexpr bool isLarge(double value) using namespace matchit; return match(value)( // clang-format off - pattern | app(_ * _, _ > 1000) = expr(true), - pattern | _ = expr(false) + pattern | app(_ * _, _ > 1000) = true, + pattern | _ = false // clang-format on ); } diff --git a/sample/isValid.cpp b/sample/isValid.cpp index b345ce9..28b6646 100644 --- a/sample/isValid.cpp +++ b/sample/isValid.cpp @@ -6,8 +6,8 @@ constexpr bool isValid(int32_t n) using namespace matchit; return match(n)( // clang-format off - pattern | or_(1, 3, 5) = expr(true), - pattern | _ = expr(false) + pattern | or_(1, 3, 5) = true, + pattern | _ = false // clang-format on ); } diff --git a/sample/optionalLift.cpp b/sample/optionalLift.cpp index 8a273ea..7a9597c 100644 --- a/sample/optionalLift.cpp +++ b/sample/optionalLift.cpp @@ -14,7 +14,7 @@ auto optionalLift(Func func) return match(v)( // clang-format off pattern | some(x) = [&] { return std::make_optional(func(*x)); }, - pattern | none = expr(RetType{}) + pattern | none = RetType{} // clang-format on ); }; diff --git a/sample/relu.cpp b/sample/relu.cpp index 3afdbce..6aaa189 100644 --- a/sample/relu.cpp +++ b/sample/relu.cpp @@ -6,8 +6,8 @@ constexpr double relu(double value) using namespace matchit; return match(value)( // clang-format off - pattern | (_ >= 0) = expr(value), - pattern | _ = expr(0) + pattern | (_ >= 0) = value, + pattern | _ = 0 // clang-format on ); } diff --git a/sample/someNone.cpp b/sample/someNone.cpp index 52e0a02..95b20bc 100644 --- a/sample/someNone.cpp +++ b/sample/someNone.cpp @@ -12,7 +12,7 @@ constexpr auto square(std::optional const &t) return match(t)( // clang-format off pattern | some(id) = id * id, - pattern | none = expr(0) + pattern | none = 0 // clang-format on ); } diff --git a/sample/sumIs.cpp b/sample/sumIs.cpp index 4d93b48..f90fbb0 100644 --- a/sample/sumIs.cpp +++ b/sample/sumIs.cpp @@ -8,8 +8,8 @@ constexpr bool sumIs(std::array const &arr, int32_t s) Id i, j; return match(arr)( // clang-format off - pattern | ds(i, j) | when(i + j == s) = expr(true), - pattern | _ = expr(false) + pattern | ds(i, j) | when(i + j == s) = true, + pattern | _ = false // clang-format on ); } diff --git a/sample/symmetric.cpp b/sample/symmetric.cpp index 70378b0..08bceb2 100644 --- a/sample/symmetric.cpp +++ b/sample/symmetric.cpp @@ -10,8 +10,8 @@ constexpr bool recursiveSymmetric(Range const &range) return match(range)( // clang-format off pattern | ds(i, subrange.at(ooo), i) = [&] { return recursiveSymmetric(*subrange); }, - pattern | ds(_, ooo, _) = expr(false), - pattern | _ = expr(true) + pattern | ds(_, ooo, _) = false, + pattern | _ = true // clang-format on ); } @@ -22,8 +22,8 @@ constexpr bool symmetricArray(std::array const &arr) Id i, j; return match(arr)( // clang-format off - pattern | ds(i, j, _, j, i) = expr(true), - pattern | _ = expr(false) + pattern | ds(i, j, _, j, i) = true, + pattern | _ = false // clang-format on ); } diff --git a/sample/variantAny.cpp b/sample/variantAny.cpp index c7cb5b9..f23a426 100644 --- a/sample/variantAny.cpp +++ b/sample/variantAny.cpp @@ -9,8 +9,8 @@ constexpr auto getClassName(T const &v) using namespace matchit; return match(v)( // clang-format off - pattern | as(_) = expr("chars"), - pattern | as(_) = expr("int32_t") + pattern | as(_) = "chars", + pattern | as(_) = "int32_t" // clang-format on ); } diff --git a/test/matchit/constexpr.cpp b/test/matchit/constexpr.cpp index 0f318cc..e0d42f1 100644 --- a/test/matchit/constexpr.cpp +++ b/test/matchit/constexpr.cpp @@ -6,8 +6,8 @@ constexpr int32_t fib(int32_t n) assert(n >= 1); return match(n)( // clang-format off - pattern | 1 = expr(1), - pattern | 2 = expr(1), + pattern | 1 = 1, + pattern | 2 = 1, pattern | _ = [n] { return fib(n - 1) + fib(n - 2); } // clang-format on ); @@ -24,9 +24,9 @@ constexpr auto eval(Value &&input) { return match(input)( // clang-format off - pattern | ds('/', 1, 1) = expr(1), - pattern | ds('/', 0, _) = expr(0), - pattern | _ = expr(-1)); + pattern | ds('/', 1, 1) = 1, + pattern | ds('/', 0, _) = 0, + pattern | _ = -1); // clang-format on } diff --git a/test/matchit/ds.cpp b/test/matchit/ds.cpp index 51fc75c..e52e4c6 100644 --- a/test/matchit/ds.cpp +++ b/test/matchit/ds.cpp @@ -97,7 +97,8 @@ TEST(Ds, vecOooBinder1) expectRange(*subrange, expected); return true; }, - pattern | _ = expr(false)); + pattern | _ = false + ); EXPECT_TRUE(matched); } @@ -168,7 +169,7 @@ TEST(Ds, arrayOooBinder1) expectRange(*subrange, expected); return true; }, - pattern | _ = expr(false)); + pattern | _ = false); EXPECT_TRUE(matched); } @@ -240,8 +241,8 @@ constexpr bool recursiveSymmetric(Range const &range) return match(range)( // clang-format off pattern | ds(i, subrange.at(ooo), i) = [&] { return recursiveSymmetric(*subrange); }, - pattern | ds(i, subrange.at(ooo), _) = expr(false), - pattern | _ = expr(true) + pattern | ds(i, subrange.at(ooo), _) = false, + pattern | _ = true // clang-format on ); } diff --git a/test/matchit/id.cpp b/test/matchit/id.cpp index 52fcea2..287f691 100644 --- a/test/matchit/id.cpp +++ b/test/matchit/id.cpp @@ -27,7 +27,7 @@ TEST(Id, resetAfterFailure) match(10)(pattern | x = [&] { EXPECT_EQ(*x, 10); }); auto const matched = - match(10)(pattern | not_(x) = expr(true), pattern | _ = expr(false)); + match(10)(pattern | not_(x) = true, pattern | _ = false); EXPECT_FALSE(matched); } @@ -36,16 +36,16 @@ TEST(Id, resetAfterFailure2) Id x; match(10)(pattern | x = [&] { EXPECT_EQ(*x, 10); }); - auto const matched = match(10)(pattern | and_(x, not_(x)) = expr(true), - pattern | _ = expr(false)); + auto const matched = match(10)(pattern | and_(x, not_(x)) = true, + pattern | _ = false); EXPECT_FALSE(matched); } TEST(Id, resetAfterFailure3) { Id x; - auto result = match(10)(pattern | and_(x, app(_ / 2, x)) = expr(true), - pattern | _ = expr(false)); + auto result = match(10)(pattern | and_(x, app(_ / 2, x)) = true, + pattern | _ = false); EXPECT_FALSE(result); result = match(10)( pattern | and_(x, app(_ / 2, not_(x))) = @@ -54,7 +54,7 @@ TEST(Id, resetAfterFailure3) EXPECT_EQ(*x, 10); return true; }, - pattern | _ = expr(false)); + pattern | _ = false); EXPECT_TRUE(result); } @@ -68,7 +68,7 @@ TEST(Id, resetAfterFailure33) EXPECT_EQ(*x, 5); return true; }, - pattern | _ = expr(false)); + pattern | _ = false); EXPECT_TRUE(result); result = match(10)( @@ -78,7 +78,7 @@ TEST(Id, resetAfterFailure33) EXPECT_EQ(*x, 5); return true; }, - pattern | _ = expr(false)); + pattern | _ = false); EXPECT_TRUE(result); result = match(10)( @@ -88,7 +88,7 @@ TEST(Id, resetAfterFailure33) EXPECT_EQ(*x, 5); return true; }, - pattern | _ = expr(false)); + pattern | _ = false); EXPECT_TRUE(result); } @@ -106,7 +106,7 @@ TEST(Id, resetAfterFailure4) EXPECT_EQ(*x, 5); return true; }, - pattern | _ = expr(false)); + pattern | _ = false); EXPECT_TRUE(matched); } @@ -120,7 +120,7 @@ TEST(Id, resetAfterFailure5) EXPECT_EQ(*x, 10); return true; }, - pattern | _ = expr(false)); + pattern | _ = false); EXPECT_TRUE(result); result = match(10)( @@ -130,7 +130,7 @@ TEST(Id, resetAfterFailure5) EXPECT_EQ(*x, 10); return true; }, - pattern | _ = expr(false)); + pattern | _ = false); EXPECT_FALSE(result); } @@ -163,7 +163,7 @@ TEST(Id, matchMultipleTimes3) TEST(Id, AppToId) { Id ii; - auto const result = match(11)(pattern | app(_ * _, ii) = expr(ii)); + auto const result = match(11)(pattern | app(_ * _, ii) = ii); EXPECT_EQ(result, 121); } @@ -277,7 +277,7 @@ TEST(Id, AppToId8) TEST(Id, IdAtInt) { Id ii; - auto const result = match(11)(pattern | app(_ * _, ii.at(121)) = expr(ii)); + auto const result = match(11)(pattern | app(_ * _, ii.at(121)) = ii); EXPECT_EQ(result, 121); } diff --git a/test/matchit/legacy.cpp b/test/matchit/legacy.cpp index 33548f4..5c03b72 100644 --- a/test/matchit/legacy.cpp +++ b/test/matchit/legacy.cpp @@ -27,12 +27,19 @@ TEST(Match, test1) { Id ii; return match(input)( - pattern | 1 = func1, pattern | 2 = func2, pattern | or_(56, 59) = func2, - pattern | (_ < 0) = expr(-1), pattern | (_ < 10) = expr(-10), - pattern | and_(_<17, _> 15) = expr(16), - pattern | app(_ * _, _ > 1000) = expr(1000), - pattern | app(_ * _, ii) = expr(ii), pattern | ii = -ii, - pattern | _ = expr(111)); + // clang-format off + pattern | 1 = func1, + pattern | 2 = func2, + pattern | or_(56, 59) = func2, + pattern | (_ < 0) = -1, + pattern | (_ < 10) = -10, + pattern | and_(_<17, _> 15) = 16, + pattern | app(_ * _, _ > 1000) = 1000, + pattern | app(_ * _, ii) = ii, + pattern | ii = -ii, + pattern | _ = 111 + // clang-format on + ); }; EXPECT_EQ(matchFunc(1), 1); EXPECT_EQ(matchFunc(2), 12); @@ -52,9 +59,9 @@ TEST(Match, test2) Id i; Id j; return match(input)( - pattern | ds('/', 1, 1) = expr(1), pattern | ds('/', 0, _) = expr(0), + pattern | ds('/', 1, 1) = 1, pattern | ds('/', 0, _) = 0, pattern | ds('*', i, j) = i * j, pattern | ds('+', i, j) = i + j, - pattern | _ = expr(-1)); + pattern | _ = -1); }; EXPECT_EQ(matchFunc(std::make_tuple('/', 1, 1)), 1); EXPECT_EQ(matchFunc(std::make_tuple('+', 2, 1)), 3); @@ -81,7 +88,7 @@ TEST(Match, test3) Id i; // compose patterns for destructuring struct A. auto const dsA = dsVia(&A::a, &A::b); - return match(input)(pattern | dsA(i, 1) = expr(i), pattern | _ = expr(-1)); + return match(input)(pattern | dsA(i, 1) = i, pattern | _ = -1); }; EXPECT_EQ(matchFunc(A{3, 1}), 3); EXPECT_EQ(matchFunc(A{2, 2}), -1); @@ -127,9 +134,9 @@ TEST(Match, test4) { auto const matchFunc = [](Num const &input) { - return match(input)(pattern | as(_) = expr(1), - pattern | kind = expr(2), - pattern | _ = expr(3)); + return match(input)(pattern | as(_) = 1, + pattern | kind = 2, + pattern | _ = 3); }; matchit::impl::AsPointer()(std::variant{}); EXPECT_EQ(matchFunc(One{}), 1); @@ -141,8 +148,8 @@ TEST(Match, test5) auto const matchFunc = [](std::pair ij) { return match(ij.first % 3, ij.second % 5)( - pattern | ds(0, 0) = expr(1), pattern | ds(0, _ > 2) = expr(2), - pattern | ds(_, _ > 2) = expr(3), pattern | _ = expr(4)); + pattern | ds(0, 0) = 1, pattern | ds(0, _ > 2) = 2, + pattern | ds(_, _ > 2) = 3, pattern | _ = 4); }; EXPECT_EQ(matchFunc(std::make_pair(3, 5)), 1); EXPECT_EQ(matchFunc(std::make_pair(3, 4)), 2); @@ -154,7 +161,7 @@ int32_t fib(int32_t n) { EXPECT_TRUE(n > 0); return match(n)( - pattern | 1 = expr(1), pattern | 2 = expr(1), + pattern | 1 = 1, pattern | 2 = 1, pattern | _ = [n] { return fib(n - 1) + fib(n - 2); }); } @@ -177,7 +184,7 @@ TEST(Match, test7) auto const at = [](auto &&id, auto &&pattern) { return and_(pattern, id); }; return match(ij.first % 3, ij.second % 5)( - pattern | ds(0, _ > 2) = expr(2), pattern | ds(1, _ > 2) = expr(3), + pattern | ds(0, _ > 2) = 2, pattern | ds(1, _ > 2) = 3, pattern | at(id, ds(_, 2)) = [&id] { @@ -185,7 +192,7 @@ TEST(Match, test7) static_cast(id); return 4; }, - pattern | _ = expr(5)); + pattern | _ = 5); }; EXPECT_EQ(matchFunc(std::make_pair(4, 2)), 4); } @@ -195,8 +202,8 @@ TEST(Match, test8) auto const equal = [](std::pair> ijk) { Id x; - return match(ijk)(pattern | ds(x, ds(_, x)) = expr(true), - pattern | _ = expr(false)); + return match(ijk)(pattern | ds(x, ds(_, x)) = true, + pattern | _ = false); }; EXPECT_TRUE(equal(std::make_pair(2, std::make_pair(1, 2)))); EXPECT_FALSE(equal(std::make_pair(2, std::make_pair(1, 3)))); @@ -208,8 +215,8 @@ TEST(Match, test9) auto const optional = [](auto const &i) { Id x; - return match(i)(pattern | some(x) = expr(true), - pattern | none = expr(false)); + return match(i)(pattern | some(x) = true, + pattern | none = false); }; EXPECT_EQ(optional(std::make_unique(2)), true); EXPECT_EQ(optional(std::make_shared(2)), true); @@ -245,9 +252,9 @@ TEST(Match, test10) auto const dynCast = [](auto const &i) { - return match(i)(pattern | some(as(_)) = expr("Circle"), - pattern | some(as(_)) = expr("Square"), - pattern | none = expr("None")); + return match(i)(pattern | some(as(_)) = "Circle", + pattern | some(as(_)) = "Square", + pattern | none = "None"); }; EXPECT_EQ(dynCast(std::unique_ptr(new Square{})), "Square"); @@ -259,8 +266,8 @@ TEST(Match, test10_) { auto const dToBCast = [](auto const &i) { - return match(i)(pattern | some(as(_)) = expr("Shape"), - pattern | none = expr("None")); + return match(i)(pattern | some(as(_)) = "Shape", + pattern | none = "None"); }; EXPECT_EQ(dToBCast(std::make_unique()), "Shape"); @@ -270,8 +277,8 @@ TEST(Match, test11) { auto const getIf = [](auto const &i) { - return match(i)(pattern | as(_) = expr("Square"), - pattern | as(_) = expr("Circle")); + return match(i)(pattern | as(_) = "Square", + pattern | as(_) = "Circle"); }; std::variant sc = Square{}; @@ -313,7 +320,7 @@ TEST(Match, test13) auto const dsAgg = [](auto const &v) { Id i; - return match(v)(pattern | ds(1, i) = expr(i), pattern | ds(_, i) = expr(i)); + return match(v)(pattern | ds(1, i) = i, pattern | ds(_, i) = i); }; EXPECT_EQ(dsAgg(A{1, 2}), 2); @@ -326,8 +333,8 @@ TEST(Match, test14) { auto const anyCast = [](auto const &i) { - return match(i)(pattern | as(_) = expr("Square"), - pattern | as(_) = expr("Circle")); + return match(i)(pattern | as(_) = "Square", + pattern | as(_) = "Circle"); }; std::any sc; @@ -350,8 +357,8 @@ TEST(Match, test15) auto const optional = [](auto const &i) { Id c; - return match(i)(pattern | none = expr(1), pattern | some(none) = expr(2), - pattern | some(some(c)) = expr(c)); + return match(i)(pattern | none = 1, pattern | some(none) = 2, + pattern | some(some(c)) = c); }; char const **x = nullptr; char const *y_ = nullptr; @@ -368,8 +375,8 @@ TEST(Match, test16) { auto const notX = [](auto const &i) { - return match(i)(pattern | not_(or_(1, 2)) = expr(3), pattern | 2 = expr(2), - pattern | _ = expr(1)); + return match(i)(pattern | not_(or_(1, 2)) = 3, pattern | 2 = 2, + pattern | _ = 1); }; EXPECT_EQ(notX(1), 1); EXPECT_EQ(notX(2), 2); @@ -382,8 +389,8 @@ TEST(Match, test17) auto const whenX = [](auto const &x) { Id i, j; - return match(x)(pattern | ds(i, j) | when(i + j == 10) = expr(3), - pattern | ds(_ < 5, _) = expr(5), pattern | _ = expr(1)); + return match(x)(pattern | ds(i, j) | when(i + j == 10) = 3, + pattern | ds(_ < 5, _) = 5, pattern | _ = 1); }; EXPECT_EQ(whenX(std::make_pair(1, 9)), 3); EXPECT_EQ(whenX(std::make_pair(1, 7)), 5); @@ -395,8 +402,8 @@ TEST(Match, test18) auto const idNotOwn = [](auto const &x) { Id i; - return match(x)(pattern | i | when(i == 5) = expr(1), - pattern | _ = expr(2)); + return match(x)(pattern | i | when(i == 5) = 1, + pattern | _ = 2); }; EXPECT_EQ(idNotOwn(1), 2); EXPECT_EQ(idNotOwn(5), 1); @@ -409,25 +416,25 @@ TEST(Match, test19) Id j; return match(input)( // `... / 2 3` - pattern | ds(ooo, '/', 2, 3) = expr(1), + pattern | ds(ooo, '/', 2, 3) = 1, // `... 3` - pattern | ds(ooo, 3) = expr(3), + pattern | ds(ooo, 3) = 3, // `/ ...` - pattern | ds('/', ooo) = expr(4), + pattern | ds('/', ooo) = 4, - pattern | ooo = expr(222), + pattern | ooo = 222, // `3 3 3 3 ..` all 3 - pattern | ooo = expr(333), + pattern | ooo = 333, // `... int32_t 3` - pattern | ds(ooo, j, 3) = expr(7), + pattern | ds(ooo, j, 3) = 7, // `... int32_t 3` - pattern | ds(ooo, or_(j), 3) = expr(8), + pattern | ds(ooo, or_(j), 3) = 8, // `...` - pattern | ooo = expr(12), + pattern | ooo = 12, - pattern | _ = expr(-1)); + pattern | _ = -1); }; EXPECT_EQ(matchFunc(std::make_tuple('/', 2, 3)), 1); EXPECT_EQ(matchFunc(std::make_tuple(3, 3, 3, 3, 3)), 3); diff --git a/test/matchit/noRet.cpp b/test/matchit/noRet.cpp index a2edcf7..7bfed24 100644 --- a/test/matchit/noRet.cpp +++ b/test/matchit/noRet.cpp @@ -19,5 +19,5 @@ TEST(MatchStatement, test) TEST(MatchExpreesion, Nomatch) { - EXPECT_THROW(match(4)(pattern | 1 = expr(true)), std::logic_error); + EXPECT_THROW(match(4)(pattern | 1 = true), std::logic_error); } \ No newline at end of file diff --git a/test/matchit/optexpr.cpp b/test/matchit/optexpr.cpp index 3679458..c62c6a3 100644 --- a/test/matchit/optexpr.cpp +++ b/test/matchit/optexpr.cpp @@ -29,9 +29,9 @@ constexpr auto eval2(std::tuple const& exp) return match(exp) // unnecessary expr() ( pattern | ds('+', i, j) | when((i + j) > 0) = i + j, - pattern | ds('-', i, j) | when(expr(true)) = i - j, - pattern | ds('*', i, j) | when(expr(i)) = expr(i), - pattern | ds('/', i, j) = expr(12345), + pattern | ds('-', i, j) | when(true) = i - j, + pattern | ds('*', i, j) | when(i) = i, + pattern | ds('/', i, j) = 12345, pattern | _ = [] { return -1; } ); } From 62c85a91413c61880ededee1a265ecfc87eb8ecd Mon Sep 17 00:00:00 2001 From: Bowen Fu Date: Tue, 22 Nov 2022 23:06:47 +0800 Subject: [PATCH 15/15] Recover optexpr.cpp. (#99) Co-authored-by: Bowen Fu --- test/matchit/optexpr.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/matchit/optexpr.cpp b/test/matchit/optexpr.cpp index c62c6a3..3679458 100644 --- a/test/matchit/optexpr.cpp +++ b/test/matchit/optexpr.cpp @@ -29,9 +29,9 @@ constexpr auto eval2(std::tuple const& exp) return match(exp) // unnecessary expr() ( pattern | ds('+', i, j) | when((i + j) > 0) = i + j, - pattern | ds('-', i, j) | when(true) = i - j, - pattern | ds('*', i, j) | when(i) = i, - pattern | ds('/', i, j) = 12345, + pattern | ds('-', i, j) | when(expr(true)) = i - j, + pattern | ds('*', i, j) | when(expr(i)) = expr(i), + pattern | ds('/', i, j) = expr(12345), pattern | _ = [] { return -1; } ); }