From a9d9e1bb06e5ebe3d078f52eb6baf58fd6995a82 Mon Sep 17 00:00:00 2001 From: Jim Porter Date: Sat, 4 May 2024 19:45:31 -0700 Subject: [PATCH] For easily-capturable objects, just use the original type This is ever-so-slightly more efficient, and also makes looking at symbols a whole lot easier. --- include/mettle/detail/any_capture.hpp | 60 +++++++++++++++----------- include/mettle/matchers/collection.hpp | 10 ++--- include/mettle/matchers/core.hpp | 6 +-- include/mettle/matchers/relational.hpp | 15 ++++--- include/mettle/suite/factory.hpp | 2 +- test/test_any_capture.cpp | 49 +++++++++++---------- 6 files changed, 79 insertions(+), 63 deletions(-) diff --git a/include/mettle/detail/any_capture.hpp b/include/mettle/detail/any_capture.hpp index 5bde0ba5..1cd9c4d2 100644 --- a/include/mettle/detail/any_capture.hpp +++ b/include/mettle/detail/any_capture.hpp @@ -5,29 +5,25 @@ #include #include -namespace mettle::detail { +#include "forward_like.hpp" - template - class any_capture { - public: - using type = T; +namespace mettle::detail { - constexpr any_capture(const T &t) : value(t) {} - constexpr any_capture(T &&t) : value(std::move(t)) {} + struct any_capture_tag {}; - T value; - }; + template + class capture_array; template requires(std::is_trivial_v) - class any_capture { + class capture_array : public any_capture_tag { public: using type = T[N]; - constexpr any_capture(const T (&t)[N]) { + constexpr capture_array(const T (&t)[N]) { for(std::size_t i = 0; i != N; i++) value[i] = t[i]; } - constexpr any_capture(T (&&t)[N]) { + constexpr capture_array(T (&&t)[N]) { for(std::size_t i = 0; i != N; i++) value[i] = std::move(t[i]); } @@ -42,23 +38,23 @@ namespace mettle::detail { #endif template - class any_capture { + class capture_array : public any_capture_tag { public: using type = T[N]; - constexpr any_capture(const T (&t)[N]) - : any_capture(t, std::make_index_sequence()) {} - constexpr any_capture(T (&&t)[N]) - : any_capture(std::move(t), std::make_index_sequence()) {} + constexpr capture_array(const T (&t)[N]) + : capture_array(t, std::make_index_sequence()) {} + constexpr capture_array(T (&&t)[N]) + : capture_array(std::move(t), std::make_index_sequence()) {} T value[N]; private: template - constexpr any_capture(const T (&t)[N], std::index_sequence) + constexpr capture_array(const T (&t)[N], std::index_sequence) : value{t[I]...} {} template - constexpr any_capture(T (&&t)[N], std::index_sequence) + constexpr capture_array(T (&&t)[N], std::index_sequence) : value{std::move(t[I])...} {} }; @@ -66,17 +62,31 @@ namespace mettle::detail { # pragma warning(pop) #endif - template - class any_capture : public any_capture { - using any_capture::any_capture; - }; - template - class any_capture { + class capture_array : public any_capture_tag { static_assert(std::is_same::value, "any_capture can't be used by incomplete array types"); }; + template + struct any_capture_type { using type = T; }; + template requires(std::is_array_v) + struct any_capture_type { using type = capture_array; }; + template + struct any_capture_type { using type = Ret(*)(Args...); }; + + template + using any_capture = typename any_capture_type::type; + + template + inline auto && unwrap_capture(T &&t) { + using V = std::remove_reference_t>; + if constexpr(std::is_base_of_v) + return detail::forward_like(t.value); + else + return std::forward(t); + } + } // namespace mettle::detail #endif diff --git a/include/mettle/matchers/collection.hpp b/include/mettle/matchers/collection.hpp index 3caebd27..b8999995 100644 --- a/include/mettle/matchers/collection.hpp +++ b/include/mettle/matchers/collection.hpp @@ -290,13 +290,13 @@ namespace mettle { using std::begin, std::end; return std::is_permutation( begin(actual), end(actual), - begin(container_.value), end(container_.value) + begin(unwrap_capture(container_)), end(unwrap_capture(container_)) ); } std::string desc() const { std::ostringstream ss; - ss << "permutation of " << to_printable(container_.value); + ss << "permutation of " << to_printable(unwrap_capture(container_)); return ss.str(); } private: @@ -314,15 +314,15 @@ namespace mettle { using std::begin, std::end; return std::is_permutation( begin(actual), end(actual), - begin(container_.value), end(container_.value), + begin(unwrap_capture(container_)), end(unwrap_capture(container_)), predicate_ ); } std::string desc() const { std::ostringstream ss; - ss << "permutation of " << to_printable(container_.value) << " for " - << to_printable(predicate_); + ss << "permutation of " << to_printable(unwrap_capture(container_)) + << " for " << to_printable(predicate_); return ss.str(); } private: diff --git a/include/mettle/matchers/core.hpp b/include/mettle/matchers/core.hpp index 77bc9ab8..c454af13 100644 --- a/include/mettle/matchers/core.hpp +++ b/include/mettle/matchers/core.hpp @@ -44,11 +44,11 @@ namespace mettle { template decltype(auto) operator ()(U &&actual) const { - return f_(std::forward(actual), thing_.value); + return f_(std::forward(actual), detail::unwrap_capture(thing_)); } std::string desc() const { - return desc_.format_desc(to_printable(thing_.value)); + return desc_.format_desc(to_printable(detail::unwrap_capture(thing_))); } private: detail::any_capture thing_; @@ -140,7 +140,7 @@ namespace mettle { } template - inline auto ensure_matcher(T &&t) { + inline decltype(auto) ensure_matcher(T &&t) { if constexpr(any_matcher) { return std::forward(t); } else { diff --git a/include/mettle/matchers/relational.hpp b/include/mettle/matchers/relational.hpp index 5473c12e..61b79a30 100644 --- a/include/mettle/matchers/relational.hpp +++ b/include/mettle/matchers/relational.hpp @@ -50,25 +50,28 @@ namespace mettle { template bool operator ()(U &&actual) const { + using detail::unwrap_capture; if (left_open()) { - if (actual <= low_.value) return false; + if (actual <= unwrap_capture(low_)) return false; } else { - if (actual < low_.value) return false; + if (actual < unwrap_capture(low_)) return false; } if (right_open()) { - if (actual >= high_.value) return false; + if (actual >= unwrap_capture(high_)) return false; } else { - if (actual > high_.value) return false; + if (actual > unwrap_capture(high_)) return false; } return true; } std::string desc() const { + using detail::unwrap_capture; std::ostringstream ss; - ss << "in " << (left_open() ? "(" : "[") << to_printable(low_.value) - << " .. " << to_printable(high_.value) << (right_open() ? ")" : "]"); + ss << "in " << (left_open() ? "(" : "[") + << to_printable(unwrap_capture(low_)) << " .. " + << to_printable(unwrap_capture(high_)) << (right_open() ? ")" : "]"); return ss.str(); } private: diff --git a/include/mettle/suite/factory.hpp b/include/mettle/suite/factory.hpp index d9e07880..7a84d967 100644 --- a/include/mettle/suite/factory.hpp +++ b/include/mettle/suite/factory.hpp @@ -46,7 +46,7 @@ namespace mettle { private: template T make_impl(std::index_sequence) const { - return T(std::get(args_).value...); + return T(detail::unwrap_capture(std::get(args_))...); } tuple_type args_; diff --git a/test/test_any_capture.cpp b/test/test_any_capture.cpp index 528f4e2a..020879db 100644 --- a/test/test_any_capture.cpp +++ b/test/test_any_capture.cpp @@ -6,69 +6,72 @@ using namespace mettle; void func() {} suite<> test_capture("any_capture", [](auto &_) { + using detail::any_capture; + using detail::unwrap_capture; + _.test("capture int", []() { - detail::any_capture capture1(1); - expect(capture1.value, equal_to(1)); + any_capture capture1(1); + expect(unwrap_capture(capture1), equal_to(1)); int i = 2; - detail::any_capture capture2(i); - expect(capture2.value, equal_to(i)); + any_capture capture2(i); + expect(unwrap_capture(capture2), equal_to(i)); }); _.test("capture std::string", []() { - detail::any_capture capture1("foo"); - expect(capture1.value, equal_to("foo")); + any_capture capture1("foo"); + expect(unwrap_capture(capture1), equal_to("foo")); std::string s = "bar"; - detail::any_capture capture2(s); - expect(capture2.value, equal_to(s)); + any_capture capture2(s); + expect(unwrap_capture(capture2), equal_to(s)); }); _.test("capture char[]", []() { char s[] = "foo"; - detail::any_capture capture(s); - expect(capture.value, equal_to(std::string("foo"))); + any_capture capture(s); + expect(unwrap_capture(capture), equal_to(std::string("foo"))); }); _.test("capture function", []() { - detail::any_capture capture(func); + any_capture capture(func); - expect(capture.value, equal_to(func)); - expect(capture.value, equal_to(&func)); + expect(unwrap_capture(capture), equal_to(func)); + expect(unwrap_capture(capture), equal_to(&func)); }); _.test("capture by copy", []() { copyable_type t; - detail::any_capture capture(t); + any_capture capture(t); - expect("number of copies", capture.value.copies, equal_to(1)); + expect("number of copies", unwrap_capture(capture).copies, equal_to(1)); }); _.test("capture by move", []() { moveable_type t; - detail::any_capture capture(std::move(t)); + any_capture capture(std::move(t)); - expect("number of copies", capture.value.copies, equal_to(0)); - expect("number of moves", capture.value.moves, equal_to(1)); + expect("number of copies", unwrap_capture(capture).copies, equal_to(0)); + expect("number of moves", unwrap_capture(capture).moves, equal_to(1)); }); _.test("capture array by copy", []() { copyable_type t[2]; - detail::any_capture capture(t); + any_capture capture(t); - expect("number of copies", capture.value, each( + expect("number of copies", unwrap_capture(capture), each( filter([](auto &&x) { return x.copies; }, equal_to(1)) )); }); _.test("capture array by move", []() { moveable_type t[2]; - detail::any_capture capture(std::move(t)); + any_capture capture(std::move(t)); - expect("number of copies", capture.value, each( + expect("number of copies", unwrap_capture(capture), each( filter([](auto &&x) { return x.copies; }, equal_to(0)) )); - expect("number of moves", capture.value, each( + expect("number of moves", unwrap_capture(capture), each( filter([](auto &&x) { return x.moves; }, equal_to(1)) )); });