1 /*
2  *  Copyright 2016 The WebRTC Project Authors. All rights reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #ifndef API_FUNCTION_VIEW_H_
12 #define API_FUNCTION_VIEW_H_
13 
14 #include <type_traits>
15 #include <utility>
16 
17 #include "rtc_base/checks.h"
18 
19 // Just like std::function, FunctionView will wrap any callable and hide its
20 // actual type, exposing only its signature. But unlike std::function,
21 // FunctionView doesn't own its callable---it just points to it. Thus, it's a
22 // good choice mainly as a function argument when the callable argument will
23 // not be called again once the function has returned.
24 //
25 // Its constructors are implicit, so that callers won't have to convert lambdas
26 // and other callables to FunctionView<Blah(Blah, Blah)> explicitly. This is
27 // safe because FunctionView is only a reference to the real callable.
28 //
29 // Example use:
30 //
31 //   void SomeFunction(rtc::FunctionView<int(int)> index_transform);
32 //   ...
33 //   SomeFunction([](int i) { return 2 * i + 1; });
34 //
35 // Note: FunctionView is tiny (essentially just two pointers) and trivially
36 // copyable, so it's probably cheaper to pass it by value than by const
37 // reference.
38 
39 namespace rtc {
40 
41 template <typename T>
42 class FunctionView;  // Undefined.
43 
44 template <typename RetT, typename... ArgT>
45 class FunctionView<RetT(ArgT...)> final {
46  public:
47   // Constructor for lambdas and other callables; it accepts every type of
48   // argument except those noted in its enable_if call.
49   template <
50       typename F,
51       typename std::enable_if<
52           // Not for function pointers; we have another constructor for that
53           // below.
54           !std::is_function<typename std::remove_pointer<
55               typename std::remove_reference<F>::type>::type>::value &&
56 
57           // Not for nullptr; we have another constructor for that below.
58           !std::is_same<std::nullptr_t,
59                         typename std::remove_cv<F>::type>::value &&
60 
61           // Not for FunctionView objects; we have another constructor for that
62           // (the implicitly declared copy constructor).
63           !std::is_same<FunctionView,
64                         typename std::remove_cv<typename std::remove_reference<
65                             F>::type>::type>::value>::type* = nullptr>
FunctionView(F && f)66   FunctionView(F&& f)
67       : call_(CallVoidPtr<typename std::remove_reference<F>::type>) {
68     f_.void_ptr = &f;
69   }
70 
71   // Constructor that accepts function pointers. If the argument is null, the
72   // result is an empty FunctionView.
73   template <
74       typename F,
75       typename std::enable_if<std::is_function<typename std::remove_pointer<
76           typename std::remove_reference<F>::type>::type>::value>::type* =
77           nullptr>
FunctionView(F && f)78   FunctionView(F&& f)
79       : call_(f ? CallFunPtr<typename std::remove_pointer<F>::type> : nullptr) {
80     f_.fun_ptr = reinterpret_cast<void (*)()>(f);
81   }
82 
83   // Constructor that accepts nullptr. It creates an empty FunctionView.
84   template <typename F,
85             typename std::enable_if<std::is_same<
86                 std::nullptr_t,
87                 typename std::remove_cv<F>::type>::value>::type* = nullptr>
FunctionView(F && f)88   FunctionView(F&& f) : call_(nullptr) {}
89 
90   // Default constructor. Creates an empty FunctionView.
FunctionView()91   FunctionView() : call_(nullptr) {}
92 
operator()93   RetT operator()(ArgT... args) const {
94     RTC_DCHECK(call_);
95     return call_(f_, std::forward<ArgT>(args)...);
96   }
97 
98   // Returns true if we have a function, false if we don't (i.e., we're null).
99   explicit operator bool() const { return !!call_; }
100 
101  private:
102   union VoidUnion {
103     void* void_ptr;
104     void (*fun_ptr)();
105   };
106 
107   template <typename F>
CallVoidPtr(VoidUnion vu,ArgT...args)108   static RetT CallVoidPtr(VoidUnion vu, ArgT... args) {
109     return (*static_cast<F*>(vu.void_ptr))(std::forward<ArgT>(args)...);
110   }
111   template <typename F>
CallFunPtr(VoidUnion vu,ArgT...args)112   static RetT CallFunPtr(VoidUnion vu, ArgT... args) {
113     return (reinterpret_cast<typename std::add_pointer<F>::type>(vu.fun_ptr))(
114         std::forward<ArgT>(args)...);
115   }
116 
117   // A pointer to the callable thing, with type information erased. It's a
118   // union because we have to use separate types depending on if the callable
119   // thing is a function pointer or something else.
120   VoidUnion f_;
121 
122   // Pointer to a dispatch function that knows the type of the callable thing
123   // that's stored in f_, and how to call it. A FunctionView object is empty
124   // (null) iff call_ is null.
125   RetT (*call_)(VoidUnion, ArgT...);
126 };
127 
128 }  // namespace rtc
129 
130 #endif  // API_FUNCTION_VIEW_H_
131