From c09323804c6c6d42c052b1c60061134261e515fc Mon Sep 17 00:00:00 2001 From: Steven Le Rouzic Date: Sat, 2 Nov 2024 19:54:50 +0100 Subject: Add function with invoke and result_of_t --- asl/BUILD.bazel | 2 ++ asl/functional.hpp | 65 +++++++++++++++++++++++++++++++++++++ asl/meta.hpp | 6 ++++ asl/tests/functional_tests.cpp | 73 ++++++++++++++++++++++++++++++++++++++++++ asl/tests/meta_tests.cpp | 10 ++++++ 5 files changed, 156 insertions(+) create mode 100644 asl/functional.hpp create mode 100644 asl/tests/functional_tests.cpp (limited to 'asl') diff --git a/asl/BUILD.bazel b/asl/BUILD.bazel index ed26459..f0a9c38 100644 --- a/asl/BUILD.bazel +++ b/asl/BUILD.bazel @@ -5,6 +5,7 @@ cc_library( "assert.hpp", "config.hpp", "format.hpp", + "functional.hpp", "integers.hpp", "io.hpp", "layout.hpp", @@ -34,6 +35,7 @@ cc_library( ], ) for name in [ "format", + "functional", "integers", "maybe_uninit", "meta", diff --git a/asl/functional.hpp b/asl/functional.hpp new file mode 100644 index 0000000..967a2a2 --- /dev/null +++ b/asl/functional.hpp @@ -0,0 +1,65 @@ +#pragma once + +#include "asl/meta.hpp" +#include "asl/utility.hpp" + +namespace asl { + +template +constexpr auto invoke(is_func auto C::* f, auto&& self, Args&&... args) + requires requires { + (self.*f)(ASL_FWD(args)...); + } +{ + return (ASL_FWD(self).*f)(ASL_FWD(args)...); +} + +template +constexpr auto invoke(is_func auto C::* f, auto* self, Args&&... args) + requires requires { + (self->*f)(ASL_FWD(args)...); + } +{ + return (self->*f)(ASL_FWD(args)...); +} + +template +constexpr auto invoke(is_object auto C::* m, auto&& self, Args&&...) + requires ( + sizeof...(Args) == 0 && + requires { self.*m; } + ) +{ + return ASL_FWD(self).*m; +} + +template +constexpr auto invoke(is_object auto C::* m, auto* self, Args&&...) + requires ( + sizeof...(Args) == 0 && + requires { self->*m; } + ) +{ + return self->*m; +} + +template +constexpr auto invoke(auto&& f, Args&&... args) + requires requires { + f(ASL_FWD(args)...); + } +{ + return ASL_FWD(f)(ASL_FWD(args)...); +} + +template struct _result_of_helper; + +template +struct _result_of_helper +{ + using type = decltype(invoke(declval(), declval()...)); +}; + +template using result_of_t = _result_of_helper::type; + +} // namespace asl diff --git a/asl/meta.hpp b/asl/meta.hpp index d253dda..2085118 100644 --- a/asl/meta.hpp +++ b/asl/meta.hpp @@ -35,6 +35,8 @@ template auto _as_rref_helper(...) -> id; template using as_lref_t = decltype(_as_lref_helper(0))::type; template using as_rref_t = decltype(_as_rref_helper(0))::type; +template consteval as_rref_t declval() {} + template struct _un_ref_t { using type = T; }; template struct _un_ref_t { using type = T; }; template struct _un_ref_t { using type = T; }; @@ -67,9 +69,13 @@ template concept trivially_destructible = __is_trivially_destructibl template concept trivially_copyable = __is_trivially_copyable(T); +// @Todo Rename concepts (_from) template concept convertible = __is_convertible(From, To); +template +concept derived_from = __is_class(Derived) && __is_class(Base) && convertible; + using nullptr_t = decltype(nullptr); template struct _un_const_helper { using type = T; }; diff --git a/asl/tests/functional_tests.cpp b/asl/tests/functional_tests.cpp new file mode 100644 index 0000000..9aa15c7 --- /dev/null +++ b/asl/tests/functional_tests.cpp @@ -0,0 +1,73 @@ +#include "asl/functional.hpp" +#include "asl/testing/testing.hpp" + +struct HasFunction +{ + void do_something(int, float) {} +}; + +struct HasMember +{ + int member{}; + int member_array[4]{}; + void (*member_fn)(){}; +}; + +struct Functor +{ + int64_t operator()() { return 35; } + int operator()(int x) { return x; } +}; + +static int some_func0() { return 1; } +static int some_func1(int x) { return x + 1; } +static float some_func1(float x) { return x + 1; } +static int some_func2(int x, int b) { return x + b; } + +static_assert(asl::is_same, int64_t>); +static_assert(asl::is_same, int>); +static_assert(asl::is_same(some_func1))(float)>, float>); +static_assert(asl::is_same, void>); +static_assert(asl::is_same, int>); + +ASL_TEST(invoke_member_function) +{ + HasFunction c; + asl::invoke(&HasFunction::do_something, c, 5, 5.0F); + asl::invoke(&HasFunction::do_something, &c, 5, 5.0F); +} + +ASL_TEST(invoke_member_data) +{ + HasMember c; + + asl::invoke(&HasMember::member, c); + asl::invoke(&HasMember::member_array, c); + asl::invoke(&HasMember::member_fn, c); + asl::invoke(&HasMember::member, &c); + asl::invoke(&HasMember::member_array, &c); + asl::invoke(&HasMember::member_fn, &c); +} + +ASL_TEST(invoke_fn) +{ + ASL_TEST_EXPECT(asl::invoke(some_func0) == 1); + ASL_TEST_EXPECT(asl::invoke(static_cast(some_func1), 8) == 9); + ASL_TEST_EXPECT(asl::invoke(some_func2, 4, 8) == 12); + ASL_TEST_EXPECT(asl::invoke(&some_func0) == 1); + ASL_TEST_EXPECT(asl::invoke(static_cast(&some_func1), 8) == 9); + ASL_TEST_EXPECT(asl::invoke(&some_func2, 4, 8) == 12); +} + +ASL_TEST(invoke_operator_call) +{ + Functor f; + ASL_TEST_EXPECT(asl::invoke(f) == 35); + ASL_TEST_EXPECT(asl::invoke(f, 8) == 8); +} + +ASL_TEST(invoke_lambda) +{ + ASL_TEST_EXPECT(asl::invoke([](){ return 35; }) == 35); + ASL_TEST_EXPECT(asl::invoke([](int x){ return x + 2; }, 6) == 8); +} diff --git a/asl/tests/meta_tests.cpp b/asl/tests/meta_tests.cpp index 4397763..0f5aa63 100644 --- a/asl/tests/meta_tests.cpp +++ b/asl/tests/meta_tests.cpp @@ -1,5 +1,6 @@ #include "asl/meta.hpp" #include "asl/tests/test_types.hpp" +#include "asl/testing/testing.hpp" struct Struct {}; union Union {}; @@ -180,3 +181,12 @@ static_assert(!asl::convertible); static_assert(asl::convertible); static_assert(!asl::convertible); static_assert(asl::convertible); + +static_assert(asl::derived_from); +static_assert(!asl::derived_from); +static_assert(!asl::derived_from); +static_assert(!asl::derived_from); +static_assert(!asl::derived_from); +static_assert(!asl::derived_from); +static_assert(!asl::derived_from); + -- cgit