xref: /freebsd/contrib/llvm-project/compiler-rt/lib/orc/unique_function.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
1*700637cbSDimitry Andric //===----- unique_function.h - moveable type-erasing function ---*- C++ -*-===//
2*700637cbSDimitry Andric //
3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*700637cbSDimitry Andric //
7*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
8*700637cbSDimitry Andric ///
9*700637cbSDimitry Andric /// unique_function works like std::function, but supports move-only callable
10*700637cbSDimitry Andric /// objects.
11*700637cbSDimitry Andric ///
12*700637cbSDimitry Andric /// TODO: Use LLVM's unique_function (llvm/include/llvm/ADT/FunctionExtras.h),
13*700637cbSDimitry Andric ///       which uses some extra inline storage to avoid heap allocations for
14*700637cbSDimitry Andric ///       small objects. Using LLVM's unique_function will require first
15*700637cbSDimitry Andric ///       porting some other utilities like PointerIntPair, PointerUnion, and
16*700637cbSDimitry Andric ///       PointerLikeTypeTraits. (These are likely to be independently useful
17*700637cbSDimitry Andric ///       in the orc runtime, so porting will have additional benefits).
18*700637cbSDimitry Andric ///
19*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
20*700637cbSDimitry Andric 
21*700637cbSDimitry Andric #ifndef ORC_RT_UNIQUE_FUNCTION_H
22*700637cbSDimitry Andric #define ORC_RT_UNIQUE_FUNCTION_H
23*700637cbSDimitry Andric 
24*700637cbSDimitry Andric #include <memory>
25*700637cbSDimitry Andric 
26*700637cbSDimitry Andric namespace orc_rt {
27*700637cbSDimitry Andric 
28*700637cbSDimitry Andric namespace unique_function_detail {
29*700637cbSDimitry Andric 
30*700637cbSDimitry Andric template <typename RetT, typename... ArgTs> class Callable {
31*700637cbSDimitry Andric public:
32*700637cbSDimitry Andric   virtual ~Callable() = default;
33*700637cbSDimitry Andric   virtual RetT call(ArgTs &&...Args) = 0;
34*700637cbSDimitry Andric };
35*700637cbSDimitry Andric 
36*700637cbSDimitry Andric template <typename CallableT, typename RetT, typename... ArgTs>
37*700637cbSDimitry Andric class CallableImpl : public Callable<RetT, ArgTs...> {
38*700637cbSDimitry Andric public:
CallableImpl(CallableT && Callable)39*700637cbSDimitry Andric   CallableImpl(CallableT &&Callable) : Callable(std::move(Callable)) {}
call(ArgTs &&...Args)40*700637cbSDimitry Andric   RetT call(ArgTs &&...Args) override {
41*700637cbSDimitry Andric     return Callable(std::forward<ArgTs>(Args)...);
42*700637cbSDimitry Andric   }
43*700637cbSDimitry Andric 
44*700637cbSDimitry Andric private:
45*700637cbSDimitry Andric   CallableT Callable;
46*700637cbSDimitry Andric };
47*700637cbSDimitry Andric 
48*700637cbSDimitry Andric } // namespace unique_function_detail
49*700637cbSDimitry Andric 
50*700637cbSDimitry Andric template <typename FnT> class unique_function;
51*700637cbSDimitry Andric 
52*700637cbSDimitry Andric template <typename RetT, typename... ArgTs>
53*700637cbSDimitry Andric class unique_function<RetT(ArgTs...)> {
54*700637cbSDimitry Andric public:
55*700637cbSDimitry Andric   unique_function() = default;
unique_function(std::nullptr_t)56*700637cbSDimitry Andric   unique_function(std::nullptr_t) {}
57*700637cbSDimitry Andric   unique_function(unique_function &&) = default;
58*700637cbSDimitry Andric   unique_function(const unique_function &&) = delete;
59*700637cbSDimitry Andric   unique_function &operator=(unique_function &&) = default;
60*700637cbSDimitry Andric   unique_function &operator=(const unique_function &&) = delete;
61*700637cbSDimitry Andric 
62*700637cbSDimitry Andric   template <typename CallableT>
unique_function(CallableT && Callable)63*700637cbSDimitry Andric   unique_function(CallableT &&Callable)
64*700637cbSDimitry Andric       : C(std::make_unique<
65*700637cbSDimitry Andric             unique_function_detail::CallableImpl<CallableT, RetT, ArgTs...>>(
66*700637cbSDimitry Andric                 std::forward<CallableT>(Callable))) {}
67*700637cbSDimitry Andric 
operator()68*700637cbSDimitry Andric   RetT operator()(ArgTs... Params) {
69*700637cbSDimitry Andric     return C->call(std::forward<ArgTs>(Params)...);
70*700637cbSDimitry Andric   }
71*700637cbSDimitry Andric 
72*700637cbSDimitry Andric   explicit operator bool() const { return !!C; }
73*700637cbSDimitry Andric 
74*700637cbSDimitry Andric private:
75*700637cbSDimitry Andric   std::unique_ptr<unique_function_detail::Callable<RetT, ArgTs...>> C;
76*700637cbSDimitry Andric };
77*700637cbSDimitry Andric 
78*700637cbSDimitry Andric } // namespace orc_rt
79*700637cbSDimitry Andric 
80*700637cbSDimitry Andric #endif // ORC_RT_UNIQUE_FUNCTION_H
81