Skip to content

Commit

Permalink
For easily-capturable objects, just use the original type
Browse files Browse the repository at this point in the history
This is ever-so-slightly more efficient, and also makes looking at symbols a
whole lot easier.
  • Loading branch information
jimporter committed May 5, 2024
1 parent 23d31b6 commit 6cbc5fe
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 63 deletions.
66 changes: 41 additions & 25 deletions include/mettle/detail/any_capture.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,22 @@

namespace mettle::detail {

template<typename T, typename Enable = void>
class any_capture {
public:
using type = T;
struct any_capture_tag {};

constexpr any_capture(const T &t) : value(t) {}
constexpr any_capture(T &&t) : value(std::move(t)) {}

T value;
};
template<typename T, typename Enable = void>
class capture_array;

template<typename T, std::size_t N>
class any_capture<T[N], std::enable_if_t<std::is_trivial_v<T>>> {
class capture_array<T[N], std::enable_if_t<std::is_trivial_v<T>>>
: 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]);
}
Expand All @@ -42,41 +37,62 @@ namespace mettle::detail {
#endif

template<typename T, std::size_t N>
class any_capture<T[N], std::enable_if_t<!std::is_trivial_v<T>>> {
class capture_array<T[N], std::enable_if_t<!std::is_trivial_v<T>>>
: public any_capture_tag {
public:
using type = T[N];

constexpr any_capture(const T (&t)[N])
: any_capture(t, std::make_index_sequence<N>()) {}
constexpr any_capture(T (&&t)[N])
: any_capture(std::move(t), std::make_index_sequence<N>()) {}
constexpr capture_array(const T (&t)[N])
: capture_array(t, std::make_index_sequence<N>()) {}
constexpr capture_array(T (&&t)[N])
: capture_array(std::move(t), std::make_index_sequence<N>()) {}

T value[N];
private:
template<std::size_t ...I>
constexpr any_capture(const T (&t)[N], std::index_sequence<I...>)
constexpr capture_array(const T (&t)[N], std::index_sequence<I...>)
: value{t[I]...} {}

template<std::size_t ...I>
constexpr any_capture(T (&&t)[N], std::index_sequence<I...>)
constexpr capture_array(T (&&t)[N], std::index_sequence<I...>)
: value{std::move(t[I])...} {}
};

#if defined(_MSC_VER) && !defined(__clang__)
# pragma warning(pop)
#endif

template<typename Ret, typename ...Args>
class any_capture<Ret(Args...)> : public any_capture<Ret(*)(Args...)> {
using any_capture<Ret(*)(Args...)>::any_capture;
};

template<typename T>
class any_capture<T[]> {
class capture_array<T[]> : public any_capture_tag {
static_assert(std::is_same<T, void>::value,
"any_capture can't be used by incomplete array types");
};

template<typename T, typename = void>
struct any_capture_type {
using type = T;
};
template<typename T>
struct any_capture_type<T, std::void_t<typename capture_array<T>::type>> {
using type = capture_array<T>;
};
template<typename Ret, typename ...Args>
struct any_capture_type<Ret(Args...)> {
using type = Ret(*)(Args...);
};

template<typename T>
using any_capture = typename any_capture_type<T>::type;

template<typename T>
decltype(auto) unwrap_capture(T &&t) {
using V = std::remove_reference_t<std::remove_cv_t<T>>;
if constexpr(std::is_base_of_v<any_capture_tag, V>)
return (t.value);
else
return std::forward<T>(t);
}

} // namespace mettle::detail

#endif
10 changes: 5 additions & 5 deletions include/mettle/matchers/collection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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:
Expand Down
7 changes: 4 additions & 3 deletions include/mettle/matchers/core.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,13 @@ namespace mettle {

template<typename U>
decltype(auto) operator ()(U &&actual) const {
return f_(std::forward<U>(actual), thing_.value);
return f_(std::forward<U>(actual), detail::unwrap_capture(thing_));
}

std::string desc() const {
std::ostringstream ss;
ss << prefix_ << detail::matcher_desc(thing_.value) << suffix_;
ss << prefix_ << detail::matcher_desc(detail::unwrap_capture(thing_))
<< suffix_;
return ss.str();
}
private:
Expand Down Expand Up @@ -95,7 +96,7 @@ namespace mettle {
}

template<typename T>
inline auto ensure_matcher(T &&t) {
inline decltype(auto) ensure_matcher(T &&t) {
if constexpr(is_matcher_v<T>) {
return std::forward<T>(t);
} else {
Expand Down
15 changes: 9 additions & 6 deletions include/mettle/matchers/relational.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,25 +50,28 @@ namespace mettle {

template<typename U>
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:
Expand Down
2 changes: 1 addition & 1 deletion include/mettle/suite/factory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ namespace mettle {
private:
template<typename T, std::size_t ...I>
T make_impl(std::index_sequence<I...>) const {
return T(std::get<I>(args_).value...);
return T(detail::unwrap_capture(std::get<I>(args_))...);
}

tuple_type args_;
Expand Down
49 changes: 26 additions & 23 deletions test/test_any_capture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,57 +6,60 @@ 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<int> capture1(1);
expect(capture1.value, equal_to(1));
any_capture<int> capture1(1);
expect(unwrap_capture(capture1), equal_to(1));

int i = 2;
detail::any_capture<int> capture2(i);
expect(capture2.value, equal_to(i));
any_capture<int> capture2(i);
expect(unwrap_capture(capture2), equal_to(i));
});

_.test("capture std::string", []() {
detail::any_capture<std::string> capture1("foo");
expect(capture1.value, equal_to("foo"));
any_capture<std::string> capture1("foo");
expect(unwrap_capture(capture1), equal_to("foo"));

std::string s = "bar";
detail::any_capture<std::string> capture2(s);
expect(capture2.value, equal_to(s));
any_capture<std::string> capture2(s);
expect(unwrap_capture(capture2), equal_to(s));
});

_.test("capture char[]", []() {
char s[] = "foo";
detail::any_capture<char[4]> capture(s);
expect(capture.value, equal_to(std::string("foo")));
any_capture<char[4]> capture(s);
expect(unwrap_capture(capture), equal_to(std::string("foo")));
});

_.test("capture function", []() {
detail::any_capture<void()> capture(func);
any_capture<void()> 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<copyable_type> capture(t);
any_capture<copyable_type> 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<moveable_type> capture(std::move(t));
any_capture<moveable_type> 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<copyable_type[2]> capture(t);
any_capture<copyable_type[2]> 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))
));
});
Expand All @@ -68,12 +71,12 @@ suite<> test_capture("any_capture", [](auto &_) {

_.test("capture array by move", move_arr_attrs, []() {
moveable_type t[2];
detail::any_capture<moveable_type[2]> capture(std::move(t));
any_capture<moveable_type[2]> 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))
));
});
Expand Down

0 comments on commit 6cbc5fe

Please sign in to comment.