@@ -24,10 +24,14 @@ namespace webrtc_function_impl {
24
24
25
25
using FunVoid = void ();
26
26
27
+ // Inline storage size is this many machine words.
28
+ enum : size_t { kInlineStorageWords = 4 };
29
+
27
30
union VoidUnion {
28
31
void * void_ptr;
29
32
FunVoid* fun_ptr;
30
- typename std::aligned_storage<4 * sizeof (uintptr_t )>::type inline_storage;
33
+ typename std::aligned_storage<kInlineStorageWords * sizeof (uintptr_t )>::type
34
+ inline_storage;
31
35
};
32
36
33
37
// Returns the number of elements of the `inline_storage` array required to
@@ -74,6 +78,16 @@ struct CallHelpers<RetT(ArgT...)> {
74
78
// size.
75
79
class UntypedFunction final {
76
80
public:
81
+ // Callables of at most this size can be stored inline, if they are trivial.
82
+ // (Useful in tests and benchmarks; avoid using this in production code.)
83
+ enum : size_t {
84
+ kInlineStorageSize = sizeof (webrtc_function_impl::VoidUnion::inline_storage)
85
+ };
86
+ static_assert (kInlineStorageSize ==
87
+ webrtc_function_impl::kInlineStorageWords *
88
+ sizeof (uintptr_t ),
89
+ " " );
90
+
77
91
// The *UntypedFunctionArgs structs are used to transfer arguments from
78
92
// PrepareArgs() to Create(). They are trivial, but may own heap allocations,
79
93
// so make sure to pass them to Create() exactly once!
@@ -85,6 +99,8 @@ class UntypedFunction final {
85
99
// other.
86
100
template <size_t N>
87
101
struct TrivialUntypedFunctionArgs {
102
+ static_assert (N >= 1 , " " );
103
+ static_assert (N <= webrtc_function_impl::kInlineStorageWords , " " );
88
104
// We use an uintptr_t array here instead of std::aligned_storage, because
89
105
// the former can be efficiently passed in registers when using
90
106
// TrivialUntypedFunctionArgs as a function argument. (We can't do the same
@@ -125,13 +141,10 @@ class UntypedFunction final {
125
141
!std::is_same<UntypedFunction,
126
142
typename std::remove_cv<F_deref>::type>::value &&
127
143
128
- // Only for trivial callables that will fit in
129
- // VoidUnion::inline_storage.
144
+ // Only for trivial callables that will fit in inline storage.
130
145
std::is_trivially_move_constructible<F_deref>::value &&
131
146
std::is_trivially_destructible<F_deref>::value &&
132
- sizeof (F_deref) <=
133
- sizeof (webrtc_function_impl::VoidUnion::inline_storage)>::type* =
134
- nullptr ,
147
+ sizeof (F_deref) <= kInlineStorageSize >::type* = nullptr ,
135
148
size_t InlineSize = webrtc_function_impl::InlineStorageSize<F_deref>()>
136
149
static TrivialUntypedFunctionArgs<InlineSize> PrepareArgs (F&& f) {
137
150
// The callable is trivial and small enough, so we just store its bytes
@@ -154,30 +167,29 @@ class UntypedFunction final {
154
167
// Create function for lambdas and other callables that are nontrivial or
155
168
// large; it accepts every type of argument except those noted in its
156
169
// enable_if call.
157
- template <
158
- typename Signature,
159
- typename F,
160
- typename F_deref = typename std::remove_reference<F>::type,
161
- typename std::enable_if<
162
- // Not for function pointers; we have another overload for that below.
163
- !std::is_function<
164
- typename std::remove_pointer<F_deref>::type>::value &&
165
-
166
- // Not for nullptr; we have a constructor for that below.
167
- !std::is_same<std::nullptr_t ,
168
- typename std::remove_cv<F>::type>::value &&
169
-
170
- // Not for UntypedFunction objects; use move construction or
171
- // assignment.
172
- !std::is_same<UntypedFunction,
173
- typename std::remove_cv<F_deref>::type>::value &&
174
-
175
- // Only for nontrivial callables, or callables that won't fit in
176
- // VoidUnion::inline_storage.
177
- !(std::is_trivially_move_constructible<F_deref>::value &&
178
- std::is_trivially_destructible<F_deref>::value &&
179
- sizeof (F_deref) <= sizeof (webrtc_function_impl::VoidUnion::
180
- inline_storage))>::type* = nullptr >
170
+ template <typename Signature,
171
+ typename F,
172
+ typename F_deref = typename std::remove_reference<F>::type,
173
+ typename std::enable_if<
174
+ // Not for function pointers; we have another overload for that
175
+ // below.
176
+ !std::is_function<
177
+ typename std::remove_pointer<F_deref>::type>::value &&
178
+
179
+ // Not for nullptr; we have a constructor for that below.
180
+ !std::is_same<std::nullptr_t ,
181
+ typename std::remove_cv<F>::type>::value &&
182
+
183
+ // Not for UntypedFunction objects; use move construction or
184
+ // assignment.
185
+ !std::is_same<UntypedFunction,
186
+ typename std::remove_cv<F_deref>::type>::value &&
187
+
188
+ // Only for nontrivial callables, or callables that won't fit in
189
+ // inline storage.
190
+ !(std::is_trivially_move_constructible<F_deref>::value &&
191
+ std::is_trivially_destructible<F_deref>::value &&
192
+ sizeof (F_deref) <= kInlineStorageSize )>::type* = nullptr >
181
193
static NontrivialUntypedFunctionArgs PrepareArgs (F&& f) {
182
194
// The callable is either nontrivial or too large, so we can't keep it
183
195
// in the inline storage; use the heap instead.
0 commit comments