Skip to content
This repository was archived by the owner on Oct 25, 2024. It is now read-only.

Commit 84ba18a

Browse files
Karl WibergCommit Bot
authored andcommitted
Make symbolic names for UntypedFunction's inline storage size
Because duplicating constant values in lots of places is bad. Bug: webrtc:11943 Change-Id: I00107718444bb0433d5ecd860ac0902f8afe2cb0 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/186842 Commit-Queue: Lahiru Ginnaliya Gamathige <[email protected]> Reviewed-by: Lahiru Ginnaliya Gamathige <[email protected]> Cr-Commit-Position: refs/heads/master@{#32334}
1 parent 3e3e166 commit 84ba18a

File tree

3 files changed

+47
-34
lines changed

3 files changed

+47
-34
lines changed

rtc_base/robo_caller_unittest.cc

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -135,15 +135,14 @@ struct LargeNonTrivial {
135135
TEST(RoboCaller, LargeNonTrivialTest) {
136136
RoboCaller<int&> c;
137137
int i = 0;
138-
static_assert(sizeof(LargeNonTrivial) > 16, "");
138+
static_assert(sizeof(LargeNonTrivial) > UntypedFunction::kInlineStorageSize,
139+
"");
139140
c.AddReceiver(LargeNonTrivial());
140141
c.Send(i);
141142

142143
EXPECT_EQ(i, 1);
143144
}
144145

145-
/* sizeof(LargeTrivial) = 20bytes which is greater than
146-
* the size check (16bytes) of the CSC library */
147146
struct LargeTrivial {
148147
int a[17];
149148
void operator()(int& x) { x = 1; }
@@ -154,7 +153,7 @@ TEST(RoboCaller, LargeTrivial) {
154153
LargeTrivial lt;
155154
int i = 0;
156155

157-
static_assert(sizeof(lt) > 16, "");
156+
static_assert(sizeof(lt) > UntypedFunction::kInlineStorageSize, "");
158157
c.AddReceiver(lt);
159158
c.Send(i);
160159

rtc_base/untyped_function.h

Lines changed: 42 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,14 @@ namespace webrtc_function_impl {
2424

2525
using FunVoid = void();
2626

27+
// Inline storage size is this many machine words.
28+
enum : size_t { kInlineStorageWords = 4 };
29+
2730
union VoidUnion {
2831
void* void_ptr;
2932
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;
3135
};
3236

3337
// Returns the number of elements of the `inline_storage` array required to
@@ -74,6 +78,16 @@ struct CallHelpers<RetT(ArgT...)> {
7478
// size.
7579
class UntypedFunction final {
7680
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+
7791
// The *UntypedFunctionArgs structs are used to transfer arguments from
7892
// PrepareArgs() to Create(). They are trivial, but may own heap allocations,
7993
// so make sure to pass them to Create() exactly once!
@@ -85,6 +99,8 @@ class UntypedFunction final {
8599
// other.
86100
template <size_t N>
87101
struct TrivialUntypedFunctionArgs {
102+
static_assert(N >= 1, "");
103+
static_assert(N <= webrtc_function_impl::kInlineStorageWords, "");
88104
// We use an uintptr_t array here instead of std::aligned_storage, because
89105
// the former can be efficiently passed in registers when using
90106
// TrivialUntypedFunctionArgs as a function argument. (We can't do the same
@@ -125,13 +141,10 @@ class UntypedFunction final {
125141
!std::is_same<UntypedFunction,
126142
typename std::remove_cv<F_deref>::type>::value &&
127143

128-
// Only for trivial callables that will fit in
129-
// VoidUnion::inline_storage.
144+
// Only for trivial callables that will fit in inline storage.
130145
std::is_trivially_move_constructible<F_deref>::value &&
131146
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,
135148
size_t InlineSize = webrtc_function_impl::InlineStorageSize<F_deref>()>
136149
static TrivialUntypedFunctionArgs<InlineSize> PrepareArgs(F&& f) {
137150
// The callable is trivial and small enough, so we just store its bytes
@@ -154,30 +167,29 @@ class UntypedFunction final {
154167
// Create function for lambdas and other callables that are nontrivial or
155168
// large; it accepts every type of argument except those noted in its
156169
// 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>
181193
static NontrivialUntypedFunctionArgs PrepareArgs(F&& f) {
182194
// The callable is either nontrivial or too large, so we can't keep it
183195
// in the inline storage; use the heap instead.

rtc_base/untyped_function_unittest.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ TEST(UntypedFunction, CallFunctionPointerWithRvalueReference) {
163163

164164
TEST(UntypedFunction, CallTrivialWithNoArgs) {
165165
int arr[] = {1, 2, 3};
166+
static_assert(sizeof(arr) <= UntypedFunction::kInlineStorageSize, "");
166167
auto uf = UntypedFunction::Create<int()>([arr] { return arr[1]; });
167168
EXPECT_TRUE(uf);
168169
EXPECT_TRUE(uf.IsTriviallyDestructible());
@@ -171,6 +172,7 @@ TEST(UntypedFunction, CallTrivialWithNoArgs) {
171172

172173
TEST(UntypedFunction, CallLargeTrivialWithNoArgs) {
173174
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
175+
static_assert(sizeof(arr) > UntypedFunction::kInlineStorageSize, "");
174176
auto uf = UntypedFunction::Create<int()>([arr] { return arr[4]; });
175177
EXPECT_TRUE(uf);
176178
EXPECT_FALSE(uf.IsTriviallyDestructible());

0 commit comments

Comments
 (0)