summaryrefslogtreecommitdiff
path: root/asl
diff options
context:
space:
mode:
authorSteven Le Rouzic <steven.lerouzic@gmail.com>2024-11-02 19:54:50 +0100
committerSteven Le Rouzic <steven.lerouzic@gmail.com>2024-12-20 15:35:58 +0100
commitc09323804c6c6d42c052b1c60061134261e515fc (patch)
tree1c5dd6962e82ee35bc1ae662e6f268826511ada9 /asl
parentbe34f768e093cb6752ab81fde3ab529861a8a6a8 (diff)
Add function with invoke and result_of_t
Diffstat (limited to 'asl')
-rw-r--r--asl/BUILD.bazel2
-rw-r--r--asl/functional.hpp65
-rw-r--r--asl/meta.hpp6
-rw-r--r--asl/tests/functional_tests.cpp73
-rw-r--r--asl/tests/meta_tests.cpp10
5 files changed, 156 insertions, 0 deletions
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<typename... Args, typename C>
+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<typename... Args, typename C>
+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<typename... Args, typename C>
+constexpr auto invoke(is_object auto C::* m, auto&& self, Args&&...)
+ requires (
+ sizeof...(Args) == 0 &&
+ requires { self.*m; }
+ )
+{
+ return ASL_FWD(self).*m;
+}
+
+template<typename... Args, typename C>
+constexpr auto invoke(is_object auto C::* m, auto* self, Args&&...)
+ requires (
+ sizeof...(Args) == 0 &&
+ requires { self->*m; }
+ )
+{
+ return self->*m;
+}
+
+template<typename... Args>
+constexpr auto invoke(auto&& f, Args&&... args)
+ requires requires {
+ f(ASL_FWD(args)...);
+ }
+{
+ return ASL_FWD(f)(ASL_FWD(args)...);
+}
+
+template<typename F> struct _result_of_helper;
+
+template<typename R, typename... Args>
+struct _result_of_helper<R(Args...)>
+{
+ using type = decltype(invoke(declval<R>(), declval<Args>()...));
+};
+
+template<typename F> using result_of_t = _result_of_helper<F>::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<typename T> auto _as_rref_helper(...) -> id<T>;
template<typename T> using as_lref_t = decltype(_as_lref_helper<T>(0))::type;
template<typename T> using as_rref_t = decltype(_as_rref_helper<T>(0))::type;
+template<typename T> consteval as_rref_t<T> declval() {}
+
template<typename T> struct _un_ref_t { using type = T; };
template<typename T> struct _un_ref_t<T&> { using type = T; };
template<typename T> struct _un_ref_t<T&&> { using type = T; };
@@ -67,9 +69,13 @@ template<typename T> concept trivially_destructible = __is_trivially_destructibl
template<typename T> concept trivially_copyable = __is_trivially_copyable(T);
+// @Todo Rename concepts (_from)
template<typename From, typename To>
concept convertible = __is_convertible(From, To);
+template<typename Derived, class Base>
+concept derived_from = __is_class(Derived) && __is_class(Base) && convertible<const volatile Derived*, const volatile Base*>;
+
using nullptr_t = decltype(nullptr);
template<typename T> 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<asl::result_of_t<Functor()>, int64_t>);
+static_assert(asl::is_same<asl::result_of_t<Functor(int)>, int>);
+static_assert(asl::is_same<asl::result_of_t<decltype(static_cast<float(*)(float)>(some_func1))(float)>, float>);
+static_assert(asl::is_same<asl::result_of_t<decltype(&HasFunction::do_something)(HasFunction, int, float)>, void>);
+static_assert(asl::is_same<asl::result_of_t<decltype(&HasMember::member)(HasMember)>, 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<int(*)(int)>(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<int(*)(int)>(&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<Base*, Derived*>);
static_assert(asl::convertible<D, C>);
static_assert(!asl::convertible<Derived*, C*>);
static_assert(asl::convertible<Base, E>);
+
+static_assert(asl::derived_from<Derived, Base>);
+static_assert(!asl::derived_from<Base, Derived>);
+static_assert(!asl::derived_from<D, C>);
+static_assert(!asl::derived_from<C, D>);
+static_assert(!asl::derived_from<uint8_t, uint16_t>);
+static_assert(!asl::derived_from<uint16_t, uint8_t>);
+static_assert(!asl::derived_from<int, int>);
+