1 //===- llvm/ADT/STLFunctionalExtras.h - Extras for <functional> -*- 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 // This file contains some extension to <functional>.
10 //
11 // No library is required when using these functions.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #ifndef LLVM_ADT_STLFUNCTIONALEXTRAS_H
16 #define LLVM_ADT_STLFUNCTIONALEXTRAS_H
17 
18 #include "llvm/ADT/STLForwardCompat.h"
19 
20 #include <type_traits>
21 #include <utility>
22 #include <cstdint>
23 
24 namespace llvm {
25 
26 //===----------------------------------------------------------------------===//
27 //     Extra additions to <functional>
28 //===----------------------------------------------------------------------===//
29 
30 /// An efficient, type-erasing, non-owning reference to a callable. This is
31 /// intended for use as the type of a function parameter that is not used
32 /// after the function in question returns.
33 ///
34 /// This class does not own the callable, so it is not in general safe to store
35 /// a function_ref.
36 template<typename Fn> class function_ref;
37 
38 template<typename Ret, typename ...Params>
39 class function_ref<Ret(Params...)> {
40   Ret (*callback)(intptr_t callable, Params ...params) = nullptr;
41   intptr_t callable;
42 
43   template<typename Callable>
44   static Ret callback_fn(intptr_t callable, Params ...params) {
45     return (*reinterpret_cast<Callable*>(callable))(
46         std::forward<Params>(params)...);
47   }
48 
49 public:
50   function_ref() = default;
51   function_ref(std::nullptr_t) {}
52 
53   template <typename Callable>
54   function_ref(
55       Callable &&callable,
56       // This is not the copy-constructor.
57       std::enable_if_t<!std::is_same<remove_cvref_t<Callable>,
58                                      function_ref>::value> * = nullptr,
59       // Functor must be callable and return a suitable type.
60       std::enable_if_t<std::is_void<Ret>::value ||
61                        std::is_convertible<decltype(std::declval<Callable>()(
62                                                std::declval<Params>()...)),
63                                            Ret>::value> * = nullptr)
64       : callback(callback_fn<typename std::remove_reference<Callable>::type>),
65         callable(reinterpret_cast<intptr_t>(&callable)) {}
66 
67   Ret operator()(Params ...params) const {
68     return callback(callable, std::forward<Params>(params)...);
69   }
70 
71   explicit operator bool() const { return callback; }
72 };
73 
74 } // end namespace llvm
75 
76 #endif // LLVM_ADT_STLFUNCTIONALEXTRAS_H
77