Skip to content

Commit 40fce32

Browse files
authored
[orc-rt] Add CallableTraitsHelper, refactor WrapperFunction to use it. (#161761)
CallableTraitsHelper identifies the return type and argument types of a callable type and passes those to an implementation class template to operate on. The CallableArgInfo utility uses CallableTraitsHelper to provide typedefs for the return type and argument types (as a tuple) of a callable type. In WrapperFunction.h, the detail::WFCallableTraits utility is rewritten in terms of CallableTraitsHandler (and renamed to WFHandlerTraits).
1 parent 487cdf1 commit 40fce32

File tree

4 files changed

+176
-45
lines changed

4 files changed

+176
-45
lines changed
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
//===- CallableTraitsHelper.h - Callable arg/ret type extractor -*- 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+
// CallableTraitsHelper API.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef ORC_RT_CALLABLETRAITSHELPER_H
14+
#define ORC_RT_CALLABLETRAITSHELPER_H
15+
16+
#include <tuple>
17+
#include <type_traits>
18+
19+
namespace orc_rt {
20+
21+
/// CallableTraitsHelper takes an implementation class template Impl and some
22+
/// callable type C and passes the return and argument types of C to the Impl
23+
/// class template.
24+
///
25+
/// This can be used to simplify the implementation of classes that need to
26+
/// operate on callable types.
27+
template <template <typename...> typename ImplT, typename C>
28+
struct CallableTraitsHelper
29+
: public CallableTraitsHelper<
30+
ImplT,
31+
decltype(&std::remove_cv_t<std::remove_reference_t<C>>::operator())> {
32+
};
33+
34+
template <template <typename...> typename ImplT, typename RetT,
35+
typename... ArgTs>
36+
struct CallableTraitsHelper<ImplT, RetT(ArgTs...)>
37+
: public ImplT<RetT, ArgTs...> {};
38+
39+
template <template <typename...> typename ImplT, typename RetT,
40+
typename... ArgTs>
41+
struct CallableTraitsHelper<ImplT, RetT (*)(ArgTs...)>
42+
: public CallableTraitsHelper<ImplT, RetT(ArgTs...)> {};
43+
44+
template <template <typename...> typename ImplT, typename RetT,
45+
typename... ArgTs>
46+
struct CallableTraitsHelper<ImplT, RetT (&)(ArgTs...)>
47+
: public CallableTraitsHelper<ImplT, RetT(ArgTs...)> {};
48+
49+
template <template <typename...> typename ImplT, typename ClassT, typename RetT,
50+
typename... ArgTs>
51+
struct CallableTraitsHelper<ImplT, RetT (ClassT::*)(ArgTs...)>
52+
: public CallableTraitsHelper<ImplT, RetT(ArgTs...)> {};
53+
54+
template <template <typename...> typename ImplT, typename ClassT, typename RetT,
55+
typename... ArgTs>
56+
struct CallableTraitsHelper<ImplT, RetT (ClassT::*)(ArgTs...) const>
57+
: public CallableTraitsHelper<ImplT, RetT(ArgTs...)> {};
58+
59+
namespace detail {
60+
template <typename RetT, typename... ArgTs> struct CallableArgInfoImpl {
61+
typedef RetT return_type;
62+
typedef std::tuple<ArgTs...> args_tuple_type;
63+
};
64+
} // namespace detail
65+
66+
/// CallableArgInfo provides typedefs for the return type and argument types
67+
/// (as a tuple) of the given callable type.
68+
template <typename Callable>
69+
struct CallableArgInfo
70+
: public CallableTraitsHelper<detail::CallableArgInfoImpl, Callable> {};
71+
72+
} // namespace orc_rt
73+
74+
#endif // ORC_RT_CALLABLETRAITSHELPER_H

orc-rt/include/orc-rt/WrapperFunction.h

Lines changed: 32 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#define ORC_RT_WRAPPERFUNCTION_H
1515

1616
#include "orc-rt-c/WrapperFunction.h"
17+
#include "orc-rt/CallableTraitsHelper.h"
1718
#include "orc-rt/Error.h"
1819
#include "orc-rt/bind.h"
1920

@@ -105,37 +106,16 @@ class WrapperFunctionBuffer {
105106

106107
namespace detail {
107108

108-
template <typename C>
109-
struct WFCallableTraits
110-
: public WFCallableTraits<
111-
decltype(&std::remove_cv_t<std::remove_reference_t<C>>::operator())> {
112-
};
113-
114-
template <typename RetT> struct WFCallableTraits<RetT()> {
115-
typedef void HeadArgType;
109+
template <typename RetT, typename ReturnT, typename... ArgTs>
110+
struct WFHandlerTraitsImpl {
111+
static_assert(std::is_void_v<RetT>,
112+
"Async wrapper function handler must return void");
113+
typedef ReturnT YieldType;
114+
typedef std::tuple<ArgTs...> ArgTupleType;
116115
};
117116

118-
template <typename RetT, typename ArgT, typename... ArgTs>
119-
struct WFCallableTraits<RetT(ArgT, ArgTs...)> {
120-
typedef ArgT HeadArgType;
121-
typedef std::tuple<ArgTs...> TailArgTuple;
122-
};
123-
124-
template <typename RetT, typename... ArgTs>
125-
struct WFCallableTraits<RetT (*)(ArgTs...)>
126-
: public WFCallableTraits<RetT(ArgTs...)> {};
127-
128-
template <typename RetT, typename... ArgTs>
129-
struct WFCallableTraits<RetT (&)(ArgTs...)>
130-
: public WFCallableTraits<RetT(ArgTs...)> {};
131-
132-
template <typename ClassT, typename RetT, typename... ArgTs>
133-
struct WFCallableTraits<RetT (ClassT::*)(ArgTs...)>
134-
: public WFCallableTraits<RetT(ArgTs...)> {};
135-
136-
template <typename ClassT, typename RetT, typename... ArgTs>
137-
struct WFCallableTraits<RetT (ClassT::*)(ArgTs...) const>
138-
: public WFCallableTraits<RetT(ArgTs...)> {};
117+
template <typename C>
118+
using WFHandlerTraits = CallableTraitsHelper<WFHandlerTraitsImpl, C>;
139119

140120
template <typename Serializer> class StructuredYieldBase {
141121
public:
@@ -151,8 +131,11 @@ template <typename Serializer> class StructuredYieldBase {
151131
std::decay_t<Serializer> S;
152132
};
153133

134+
template <typename RetT, typename Serializer> class StructuredYield;
135+
154136
template <typename RetT, typename Serializer>
155-
class StructuredYield : public StructuredYieldBase<Serializer> {
137+
class StructuredYield<std::tuple<RetT>, Serializer>
138+
: public StructuredYieldBase<Serializer> {
156139
public:
157140
using StructuredYieldBase<Serializer>::StructuredYieldBase;
158141
void operator()(RetT &&R) {
@@ -167,7 +150,7 @@ class StructuredYield : public StructuredYieldBase<Serializer> {
167150
};
168151

169152
template <typename Serializer>
170-
class StructuredYield<void, Serializer>
153+
class StructuredYield<std::tuple<>, Serializer>
171154
: public StructuredYieldBase<Serializer> {
172155
public:
173156
using StructuredYieldBase<Serializer>::StructuredYieldBase;
@@ -180,7 +163,7 @@ class StructuredYield<void, Serializer>
180163
template <typename T, typename Serializer> struct ResultDeserializer;
181164

182165
template <typename T, typename Serializer>
183-
struct ResultDeserializer<Expected<T>, Serializer> {
166+
struct ResultDeserializer<std::tuple<Expected<T>>, Serializer> {
184167
static Expected<T> deserialize(WrapperFunctionBuffer ResultBytes,
185168
Serializer &S) {
186169
T Val;
@@ -191,7 +174,8 @@ struct ResultDeserializer<Expected<T>, Serializer> {
191174
}
192175
};
193176

194-
template <typename Serializer> struct ResultDeserializer<Error, Serializer> {
177+
template <typename Serializer>
178+
struct ResultDeserializer<std::tuple<Error>, Serializer> {
195179
static Error deserialize(WrapperFunctionBuffer ResultBytes, Serializer &S) {
196180
assert(ResultBytes.empty());
197181
return Error::success();
@@ -213,11 +197,13 @@ struct WrapperFunction {
213197
typename... ArgTs>
214198
static void call(Caller &&C, Serializer &&S, ResultHandler &&RH,
215199
ArgTs &&...Args) {
216-
typedef detail::WFCallableTraits<ResultHandler> ResultHandlerTraits;
200+
typedef CallableArgInfo<ResultHandler> ResultHandlerTraits;
201+
static_assert(std::is_void_v<typename ResultHandlerTraits::return_type>,
202+
"Result handler should return void");
217203
static_assert(
218-
std::tuple_size_v<typename ResultHandlerTraits::TailArgTuple> == 0,
219-
"Expected one argument to result-handler");
220-
typedef typename ResultHandlerTraits::HeadArgType ResultType;
204+
std::tuple_size_v<typename ResultHandlerTraits::args_tuple_type> == 1,
205+
"Result-handler should have exactly one argument");
206+
typedef typename ResultHandlerTraits::args_tuple_type ResultTupleType;
221207

222208
if (auto ArgBytes = S.argumentSerializer()(std::forward<ArgTs>(Args)...)) {
223209
C(
@@ -227,9 +213,8 @@ struct WrapperFunction {
227213
if (const char *ErrMsg = ResultBytes.getOutOfBandError())
228214
RH(make_error<StringError>(ErrMsg));
229215
else
230-
RH(detail::ResultDeserializer<
231-
ResultType, Serializer>::deserialize(std::move(ResultBytes),
232-
S));
216+
RH(detail::ResultDeserializer<ResultTupleType, Serializer>::
217+
deserialize(std::move(ResultBytes), S));
233218
},
234219
std::move(*ArgBytes));
235220
} else
@@ -246,10 +231,12 @@ struct WrapperFunction {
246231
orc_rt_WrapperFunctionReturn Return,
247232
WrapperFunctionBuffer ArgBytes, Serializer &&S,
248233
Handler &&H) {
249-
typedef detail::WFCallableTraits<Handler> HandlerTraits;
250-
typedef typename HandlerTraits::HeadArgType Yield;
251-
typedef typename HandlerTraits::TailArgTuple ArgTuple;
252-
typedef typename detail::WFCallableTraits<Yield>::HeadArgType RetType;
234+
typedef detail::WFHandlerTraits<Handler> HandlerTraits;
235+
typedef typename HandlerTraits::ArgTupleType ArgTuple;
236+
typedef typename HandlerTraits::YieldType Yield;
237+
static_assert(std::is_void_v<typename CallableArgInfo<Yield>::return_type>,
238+
"Return callback must return void");
239+
typedef typename CallableArgInfo<Yield>::args_tuple_type RetTupleType;
253240

254241
if (ArgBytes.getOutOfBandError())
255242
return Return(Session, CallCtx, ArgBytes.release());
@@ -258,7 +245,7 @@ struct WrapperFunction {
258245
if (std::apply(bind_front(S.argumentDeserializer(), std::move(ArgBytes)),
259246
Args))
260247
std::apply(bind_front(std::forward<Handler>(H),
261-
detail::StructuredYield<RetType, Serializer>(
248+
detail::StructuredYield<RetTupleType, Serializer>(
262249
Session, CallCtx, Return, std::move(S))),
263250
std::move(Args));
264251
else

orc-rt/unittests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ endfunction()
1414
add_orc_rt_unittest(CoreTests
1515
AllocActionTest.cpp
1616
BitmaskEnumTest.cpp
17+
CallableTraitsHelperTest.cpp
1718
CommonTestUtils.cpp
1819
ErrorTest.cpp
1920
ExecutorAddressTest.cpp
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
//===- CallableTraitsHelperTest.cpp ---------------------------------------===//
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+
// Tests for orc-rt's CallableTraitsHelper.h APIs.
10+
//
11+
// NOTE: All tests in this file are testing compile-time functionality, so the
12+
// tests at runtime all end up being noops. That's fine -- those are
13+
// cheap.
14+
//===----------------------------------------------------------------------===//
15+
16+
#include "orc-rt/CallableTraitsHelper.h"
17+
#include "gtest/gtest.h"
18+
19+
using namespace orc_rt;
20+
21+
static void freeVoidVoid() {}
22+
23+
TEST(CallableTraitsHelperTest, FreeVoidVoid) {
24+
(void)freeVoidVoid;
25+
typedef CallableArgInfo<decltype(freeVoidVoid)> CAI;
26+
static_assert(std::is_void_v<CAI::return_type>);
27+
static_assert(std::is_same_v<CAI::args_tuple_type, std::tuple<>>);
28+
}
29+
30+
static int freeBinaryOp(int, float) { return 0; }
31+
32+
TEST(CallableTraitsHelperTest, FreeBinaryOp) {
33+
(void)freeBinaryOp;
34+
typedef CallableArgInfo<decltype(freeBinaryOp)> CAI;
35+
static_assert(std::is_same_v<CAI::return_type, int>);
36+
static_assert(std::is_same_v<CAI::args_tuple_type, std::tuple<int, float>>);
37+
}
38+
39+
TEST(CallableTraitsHelperTest, VoidVoidObj) {
40+
auto VoidVoid = []() {};
41+
typedef CallableArgInfo<decltype(VoidVoid)> CAI;
42+
static_assert(std::is_void_v<CAI::return_type>);
43+
static_assert(std::is_same_v<CAI::args_tuple_type, std::tuple<>>);
44+
}
45+
46+
TEST(CallableTraitsHelperTest, BinaryOpObj) {
47+
auto BinaryOp = [](int X, float Y) -> int { return X + Y; };
48+
typedef CallableArgInfo<decltype(BinaryOp)> CAI;
49+
static_assert(std::is_same_v<CAI::return_type, int>);
50+
static_assert(std::is_same_v<CAI::args_tuple_type, std::tuple<int, float>>);
51+
}
52+
53+
TEST(CallableTraitsHelperTest, PreservesLValueRef) {
54+
auto RefOp = [](int &) {};
55+
typedef CallableArgInfo<decltype(RefOp)> CAI;
56+
static_assert(std::is_same_v<CAI::args_tuple_type, std::tuple<int &>>);
57+
}
58+
59+
TEST(CallableTraitsHelperTest, PreservesLValueRefConstness) {
60+
auto RefOp = [](const int &) {};
61+
typedef CallableArgInfo<decltype(RefOp)> CAI;
62+
static_assert(std::is_same_v<CAI::args_tuple_type, std::tuple<const int &>>);
63+
}
64+
65+
TEST(CallableTraitsHelperTest, PreservesRValueRef) {
66+
auto RefOp = [](int &&) {};
67+
typedef CallableArgInfo<decltype(RefOp)> CAI;
68+
static_assert(std::is_same_v<CAI::args_tuple_type, std::tuple<int &&>>);
69+
}

0 commit comments

Comments
 (0)