Skip to content

Commit 5023264

Browse files
committed
[libc] add invoke / invoke_result type traits
1 parent a685715 commit 5023264

File tree

6 files changed

+177
-0
lines changed

6 files changed

+177
-0
lines changed

libc/src/__support/CPP/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ add_header_library(
104104
type_traits/enable_if.h
105105
type_traits/false_type.h
106106
type_traits/integral_constant.h
107+
type_traits/invoke.h
108+
type_traits/invoke_result.h
107109
type_traits/is_arithmetic.h
108110
type_traits/is_array.h
109111
type_traits/is_base_of.h

libc/src/__support/CPP/type_traits.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
#include "src/__support/CPP/type_traits/enable_if.h"
1919
#include "src/__support/CPP/type_traits/false_type.h"
2020
#include "src/__support/CPP/type_traits/integral_constant.h"
21+
#include "src/__support/CPP/type_traits/invoke.h"
22+
#include "src/__support/CPP/type_traits/invoke_result.h"
2123
#include "src/__support/CPP/type_traits/is_arithmetic.h"
2224
#include "src/__support/CPP/type_traits/is_array.h"
2325
#include "src/__support/CPP/type_traits/is_base_of.h"
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//===-- invoke type_traits --------------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_LIBC_SRC_SUPPORT_CPP_TYPE_TRAITS_INVOKE_H
10+
#define LLVM_LIBC_SRC_SUPPORT_CPP_TYPE_TRAITS_INVOKE_H
11+
12+
#include "src/__support/CPP/type_traits/decay.h"
13+
#include "src/__support/CPP/type_traits/is_base_of.h"
14+
#include "src/__support/CPP/utility/forward.h"
15+
16+
// BEWARE : this implementation is not fully conformant as it doesn't take
17+
// `cpp::reference_wrapper` into account.
18+
19+
namespace __llvm_libc::cpp {
20+
21+
namespace detail {
22+
23+
// Catch all function types.
24+
template <class FunctionPtrType> struct invoke_dispatcher {
25+
template <class... Args>
26+
static auto call(FunctionPtrType &&fun, Args &&...args) {
27+
return cpp::forward<FunctionPtrType>(fun)(cpp::forward<Args>(args)...);
28+
}
29+
};
30+
31+
// Catch pointer to member function types.
32+
template <class Class, class FunctionReturnType>
33+
struct invoke_dispatcher<FunctionReturnType Class::*> {
34+
using FunctionPtrType = FunctionReturnType Class::*;
35+
36+
template <class T, class... Args, class DecayT = cpp::decay_t<T>>
37+
static auto call(FunctionPtrType fun, T &&t1, Args &&...args) {
38+
if constexpr (cpp::is_base_of_v<Class, DecayT>) {
39+
// T is a (possibly cv ref) type.
40+
return (cpp::forward<T>(t1).*fun)(cpp::forward<Args>(args)...);
41+
} else {
42+
// T is assumed to be a pointer type.
43+
return (*cpp::forward<T>(t1).*fun)(cpp::forward<Args>(args)...);
44+
}
45+
}
46+
};
47+
48+
} // namespace detail
49+
50+
template <class Function, class... Args>
51+
auto invoke(Function &&fun, Args &&...args) {
52+
return detail::invoke_dispatcher<cpp::decay_t<Function>>::call(
53+
cpp::forward<Function>(fun), cpp::forward<Args>(args)...);
54+
}
55+
56+
} // namespace __llvm_libc::cpp
57+
58+
#endif // LLVM_LIBC_SRC_SUPPORT_CPP_TYPE_TRAITS_INVOKE_H
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//===-- invoke_result type_traits -------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
#ifndef LLVM_LIBC_SRC_SUPPORT_CPP_TYPE_TRAITS_INVOKE_RESULT_H
9+
#define LLVM_LIBC_SRC_SUPPORT_CPP_TYPE_TRAITS_INVOKE_RESULT_H
10+
11+
#include "src/__support/CPP/type_traits/invoke.h"
12+
#include "src/__support/CPP/utility/declval.h"
13+
14+
namespace __llvm_libc::cpp {
15+
16+
template <class F, class... Args> struct invoke_result {
17+
using type =
18+
decltype(cpp::invoke(cpp::declval<F>(), cpp::declval<Args>()...));
19+
};
20+
21+
template <class F, class... Args>
22+
using invoke_result_t = typename invoke_result<F, Args...>::type;
23+
24+
} // namespace __llvm_libc::cpp
25+
26+
#endif // LLVM_LIBC_SRC_SUPPORT_CPP_TYPE_TRAITS_INVOKE_RESULT_H

libc/test/src/__support/CPP/type_traits_test.cpp

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,92 @@ TEST(LlvmLibcTypeTraitsTest, integral_constant) {
145145
EXPECT_EQ((integral_constant<int, 4>::value), 4);
146146
}
147147

148+
namespace invoke_detail {
149+
150+
enum State { INIT = 0, A_APPLY_CALLED, B_APPLY_CALLED };
151+
152+
struct A {
153+
State state = INIT;
154+
virtual ~A() {}
155+
virtual void apply() { state = A_APPLY_CALLED; }
156+
};
157+
158+
struct B : public A {
159+
virtual ~B() {}
160+
virtual void apply() { state = B_APPLY_CALLED; }
161+
};
162+
163+
void free_function() {}
164+
int free_function_return_5() { return 5; }
165+
int free_function_passtrough(int value) { return value; }
166+
167+
struct Delegate {
168+
int (*ptr)(int) = &free_function_passtrough;
169+
};
170+
171+
} // namespace invoke_detail
172+
173+
TEST(LlvmLibcTypeTraitsTest, invoke) {
174+
using namespace invoke_detail;
175+
{ // member function call
176+
A a;
177+
EXPECT_EQ(a.state, INIT);
178+
cpp::invoke(&A::apply, a);
179+
EXPECT_EQ(a.state, A_APPLY_CALLED);
180+
}
181+
{ // overriden member function call
182+
B b;
183+
EXPECT_EQ(b.state, INIT);
184+
cpp::invoke(&A::apply, b);
185+
EXPECT_EQ(b.state, B_APPLY_CALLED);
186+
}
187+
{ // free function
188+
cpp::invoke(&free_function);
189+
EXPECT_EQ(cpp::invoke(&free_function_return_5), 5);
190+
EXPECT_EQ(cpp::invoke(&free_function_passtrough, 1), 1);
191+
}
192+
{ // pointer member function call
193+
Delegate d;
194+
EXPECT_EQ(cpp::invoke(&Delegate::ptr, d, 2), 2);
195+
}
196+
{ // lambda
197+
EXPECT_EQ(cpp::invoke([]() -> int { return 2; }), 2);
198+
EXPECT_EQ(cpp::invoke([](int value) -> int { return value; }, 1), 1);
199+
}
200+
}
201+
202+
TEST(LlvmLibcTypeTraitsTest, invoke_result) {
203+
using namespace invoke_detail;
204+
EXPECT_TRUE(
205+
(cpp::is_same_v<cpp::invoke_result_t<decltype(&A::apply), A>, void>));
206+
EXPECT_TRUE(
207+
(cpp::is_same_v<cpp::invoke_result_t<decltype(&A::apply), B>, void>));
208+
EXPECT_TRUE(
209+
(cpp::is_same_v<cpp::invoke_result_t<decltype(&free_function)>, void>));
210+
EXPECT_TRUE(
211+
(cpp::is_same_v<cpp::invoke_result_t<decltype(&free_function_return_5)>,
212+
int>));
213+
EXPECT_TRUE((cpp::is_same_v<
214+
cpp::invoke_result_t<decltype(&free_function_passtrough), int>,
215+
int>));
216+
EXPECT_TRUE(
217+
(cpp::is_same_v<
218+
cpp::invoke_result_t<decltype(&Delegate::ptr), Delegate, int>, int>));
219+
{
220+
auto lambda = []() {};
221+
EXPECT_TRUE((cpp::is_same_v<cpp::invoke_result_t<decltype(lambda)>, void>));
222+
}
223+
{
224+
auto lambda = []() { return 0; };
225+
EXPECT_TRUE((cpp::is_same_v<cpp::invoke_result_t<decltype(lambda)>, int>));
226+
}
227+
{
228+
auto lambda = [](int) -> double { return 0; };
229+
EXPECT_TRUE(
230+
(cpp::is_same_v<cpp::invoke_result_t<decltype(lambda), int>, double>));
231+
}
232+
}
233+
148234
using IntegralAndFloatingTypes =
149235
testing::TypeList<bool, char, short, int, long, long long, unsigned char,
150236
unsigned short, unsigned int, unsigned long,

utils/bazel/llvm-project-overlay/libc/BUILD.bazel

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,8 @@ libc_support_library(
295295
"src/__support/CPP/type_traits/enable_if.h",
296296
"src/__support/CPP/type_traits/false_type.h",
297297
"src/__support/CPP/type_traits/integral_constant.h",
298+
"src/__support/CPP/type_traits/invoke.h",
299+
"src/__support/CPP/type_traits/invoke_result.h",
298300
"src/__support/CPP/type_traits/is_arithmetic.h",
299301
"src/__support/CPP/type_traits/is_array.h",
300302
"src/__support/CPP/type_traits/is_base_of.h",
@@ -333,6 +335,7 @@ libc_support_library(
333335
"src/__support/CPP/type_traits/type_identity.h",
334336
"src/__support/CPP/type_traits/void_t.h",
335337
"src/__support/CPP/utility/declval.h",
338+
"src/__support/CPP/utility/forward.h",
336339
],
337340
deps = [
338341
":__support_macros_attributes",

0 commit comments

Comments
 (0)