Line data Source code
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 WEBRTC_BASE_FUNCTION_VIEW_H_
12 : #define WEBRTC_BASE_FUNCTION_VIEW_H_
13 :
14 : #include <type_traits>
15 : #include <utility>
16 :
17 : #include "webrtc/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>
66 0 : FunctionView(F&& f)
67 0 : : call_(CallVoidPtr<typename std::remove_reference<F>::type>) {
68 0 : f_.void_ptr = &f;
69 0 : }
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>
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>
88 : FunctionView(F&& f) : call_(nullptr) {}
89 :
90 : // Default constructor. Creates an empty FunctionView.
91 : FunctionView() : call_(nullptr) {}
92 :
93 0 : RetT operator()(ArgT... args) const {
94 0 : RTC_DCHECK(call_);
95 0 : 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>
108 0 : static RetT CallVoidPtr(VoidUnion vu, ArgT... args) {
109 0 : return (*static_cast<F*>(vu.void_ptr))(std::forward<ArgT>(args)...);
110 : }
111 : template <typename F>
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 // WEBRTC_BASE_FUNCTION_VIEW_H_
|