diff --git a/include/utils/match.hxx b/include/utils/match.hxx index fefad20..f060daf 100644 --- a/include/utils/match.hxx +++ b/include/utils/match.hxx @@ -13,7 +13,7 @@ /// /// License: MIT /// -/// Copyright: Copyright (c) 2022 +/// Copyright: Copyright (c) 2022-23 /// \file match.hxx #ifndef CORTEX_MATCH @@ -26,111 +26,109 @@ # include #endif /// __cpp_concepts >= 201907L -namespace cxl +namespace cxl::utils { - namespace utils + + /// \brief match structure + /// + /// \details Inherits the properties + /// of the variadic template of + /// invocables and interfaces the + /// invocables `()` operators. + /// + /// \tparam ...Fs + template + struct match : Fs... { - /// \brief match structure - /// - /// \details Inherits the properties - /// of the variadic template of - /// invocables and interfaces the - /// invocables `()` operators. - /// - /// \tparam ...Fs concept: std::invocable - template - struct match : Fs... - { - - /// \brief Forward Constructor - /// - /// \details Consumes all function types - /// and forwards them to the variadic constructor - /// of the invocables. - /// - /// \tparam ...Ts - /// - /// \param ...ts - template - explicit match(Ts&&... ts) - : Fs { std::forward(ts) }... { } - - /// \brief Invocation declaration - /// - /// \details Declares `match` to be using - /// the invocation operators `()`. - using Fs::operator()...; - }; - - /// \brief Template Deduction Guide - template - match(Fs&&...) -> match...>; - - /// \brief Match Expression Notation + + /// \brief Forward Constructor /// - /// \details Overloads `>>` to reverse the argument - /// order of a match expression for a cleaner syntax - /// with existing match types. + /// \details Consumes all function types + /// and forwards them to the variadic constructor + /// of the invocables. /// /// \tparam ...Ts - /// \tparam ...Fs concept: std::invocable - /// \param var type: std::variant - /// \param m type match&& - /// \return decltype(auto) - template - constexpr auto - operator| (const std::variant& var, - const match& m) -> void { - std::visit(m, var); - } - - /// \brief Match Expression Assignment Overload /// - /// \details Overloads the `>>=` operator to - /// reverse the argument order of a match - /// expression for a cleaner syntax with existing - /// match types and to denote an explicit syntax - /// for match expressions that return a value. + /// \param ...ts + template + explicit match(Ts&&... ts) + : Fs { std::forward(ts) }... { } + + /// \brief Invocation declaration /// - /// \tparam R - /// \tparam ...Ts - /// \tparam ...Fs concept: std::invocable - /// \param var type: const std::variant& - /// \param m type: match&& - /// \return R - template - constexpr auto - operator|= (const std::variant& var, - const match& m) -> decltype(auto) { - return std::visit(m, var); - } + /// \details Declares `match` to be using + /// the invocation operators `()`. + using Fs::operator()...; + }; + + /// \brief Template Deduction Guide + template + match(Fs&&...) -> match...>; - } // namespace utils + /// \brief Match Expression Notation + /// + /// \details Overloads `>>` to reverse the argument + /// order of a match expression for a cleaner syntax + /// with existing match types. + /// + /// \tparam ...Ts + /// \tparam ...Fs + /// \param var type: const std::variant& + /// \param m type const match& + /// \return auto + template + constexpr auto + operator>> ( + const std::variant& var, + const match& m + ) -> void + { std::visit(m, var); } + + /// \brief Match Expression Assignment Overload + /// + /// \details Overloads the `>>=` operator to + /// reverse the argument order of a match + /// expression for a cleaner syntax with existing + /// match types and to denote an explicit syntax + /// for match expressions that return a value. + /// + /// \tparam ...Ts + /// \tparam ...Fs + /// \param var type: const std::variant& + /// \param m type: const match& + /// \return decltype(auto) + template + constexpr auto + operator<< ( + const std::variant& var, + const match& m + ) -> decltype(auto) + { return std::visit(m, var); } /// \brief Wildcard Empty Placeholder /// /// \details Names a placeholder type /// that can match to anything in a match /// expression. The value is un-retrievable - /// from `_`, use `auto&& ` to have a + /// from `bottom`, use `auto&& ` to have a /// retrievable value. - struct _ + struct match_any { template - explicit constexpr _([[maybe_unused]] T&& t) noexcept { } + explicit constexpr match_any([[maybe_unused]] T&& t) noexcept { } - explicit constexpr _(const _&) noexcept = delete; - explicit constexpr _(_&&) noexcept = delete; + explicit constexpr match_any(const match_any&) noexcept = delete; + explicit constexpr match_any(match_any&&) noexcept = delete; constexpr auto - operator= (const _&) noexcept -> _& = delete; + operator= (const match_any&) noexcept -> match_any& = delete; constexpr auto - operator= (_&&) noexcept -> _& = delete; + operator= (match_any&&) noexcept -> match_any& = delete; - constexpr ~_() noexcept = delete; + constexpr ~match_any() noexcept = delete; }; -} // namespace cxl +} // namespace cxl::utils #endif /// CORTEX_MATCH diff --git a/src/utils/match.test.cxx b/src/utils/match.test.cxx index ae838ea..aca6037 100644 --- a/src/utils/match.test.cxx +++ b/src/utils/match.test.cxx @@ -8,7 +8,8 @@ #include #include -TEST_CASE("match test") { +TEST_CASE("match test") +{ using namespace std::literals; using var_t = std::variant; @@ -16,35 +17,39 @@ TEST_CASE("match test") { auto varstr { var_t { "Hello"s } }; auto varf { var_t { 6.78f } }; - SECTION("match with std::visit") { - std::visit(cxl::utils::match { - [](std::string& s) { - fmt::print("s: std::string = {}\n", s); - }, - [](int& i) { fmt::print("i: int = {}\n", i); }, - [](float& f) { fmt::print("s: float = {}\n", f); }, - [](cxl::_) { fmt::print("Other\n"); } }, - var7); + SECTION("match with std::visit") + { + std::visit( + cxl::utils::match { + [](std::string& s) { fmt::print("s: std::string = {}\n", s); }, + [](int& i) { fmt::print("i: int = {}\n", i); }, + [](float& f) { fmt::print("s: float = {}\n", f); }, + [](cxl::utils::match_any) { fmt::print("Other\n"); } + }, + var7 + ); auto r = std::visit( cxl::utils::match { []([[maybe_unused]] std::string& s) { return "String"s; }, []([[maybe_unused]] int& i) { return "Int"s; }, []([[maybe_unused]] float& f) { return "Float"s; }, - [](cxl::_) { return "Other"s; } }, - varf); + [](cxl::utils::match_any) { return "Other"s; } }, + varf + ); REQUIRE(r == "Float"s); fmt::print("r = {}\n", r); } - SECTION("match expression syntax sugar") { + SECTION("match expression syntax sugar") + { auto print_match = cxl::utils::match { [](std::string s) { fmt::print("s: std::string = {}\n", s); }, [](int i) { fmt::print("i: int = {}\n", i); }, [](float f) { fmt::print("s: float = {}\n", f); }, - [](cxl::_) { fmt::print("Other\n"); } + [](cxl::utils::match_any) { fmt::print("Other\n"); } }; using namespace cxl; @@ -53,37 +58,38 @@ TEST_CASE("match test") { []([[maybe_unused]] std::string s) { return "String"s; }, []([[maybe_unused]] int i) { return "Int"s; }, []([[maybe_unused]] float f) { return "Float"s; }, - [](_) { return "Other"s; } + [](utils::match_any) { return "Other"s; } }; - SECTION("Regular match expression") { - varstr | - cxl::utils::match { - [](std::string s) { - fmt::print("s: std::string = {}\n", s); - }, - [](int i) { fmt::print("i: int = {}\n", i); }, - [](float f) { fmt::print("s: float = {}\n", f); }, - [](cxl::_) { fmt::print("Other\n"); } - }; + SECTION("Regular match expression") + { + varstr >> cxl::utils::match { + [](std::string s) { fmt::print("s: std::string = {}\n", s); }, + [](int i) { fmt::print("i: int = {}\n", i); }, + [](float f) { fmt::print("s: float = {}\n", f); }, + [](cxl::utils::match_any) { fmt::print("Other\n"); } + }; - varf | print_match; + varf >> print_match; - REQUIRE(std::is_void_v == true); + REQUIRE(std::is_void_v> name_match)> == true); } - SECTION("Returning match expression") { - auto r = varstr |= cxl::utils::match { + SECTION("Returning match expression") + { + auto r = varstr << cxl::utils::match { []([[maybe_unused]] std::string s) { return "String"s; }, []([[maybe_unused]] int i) { return "Int"s; }, []([[maybe_unused]] float f) { return "Float"s; }, - [](cxl::_) { return "Other"s; } + [](cxl::utils::match_any) { return "Other"s; } }; fmt::print("r = {}\n", r); + REQUIRE(r == "String"); - auto name = var7 |= name_match; + auto name = var7 << name_match; fmt::print("name = {}\n", name); + REQUIRE(name == "Int"); } } } \ No newline at end of file