1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <lib/fit/function.h>
6 #include <lib/stdcompat/bit.h>
7
8 #include <algorithm>
9 #include <array>
10 #include <cstddef>
11 #include <cstdint>
12 #include <memory>
13 #include <type_traits>
14
15 #include "gtest/gtest.h"
16
17 #include "pw_polyfill/language_feature_macros.h"
18
19 namespace {
20
21 using ::std::size_t;
22
23 using Closure = void();
24 using ClosureWrongReturnType = int();
25 using BinaryOp = int(int a, int b);
26 using BinaryOpWrongReturnType = void(int a, int b);
27 using MoveOp = std::unique_ptr<int>(std::unique_ptr<int> value);
28 using BooleanGenerator = bool();
29 using IntGenerator = int();
30
31 class BuildableFromInt {
32 public:
33 BuildableFromInt(int);
34 BuildableFromInt& operator=(int);
35 };
36
37 using BuildableFromIntGenerator = BuildableFromInt();
38
39 // A big object which causes a function target to be heap allocated.
40 struct Big {
41 int data[64]{};
42 };
43 // An object with a very large alignment requirement that cannot be placed in a
44 // fit::inline_function.
45 struct alignas(64) BigAlignment {
46 int data[64]{};
47 };
48 constexpr size_t HugeCallableSize = sizeof(Big) + sizeof(void*) * 4;
49
50 // An object that looks like an "empty" std::function.
51 template <typename>
52 struct EmptyFunction;
53 template <typename R, typename... Args>
54 struct EmptyFunction<R(Args...)> {
operator ()__anon339fe1ef0111::EmptyFunction55 R operator()(Args... args) const { return fptr(args...); }
operator ==__anon339fe1ef0111::EmptyFunction56 bool operator==(decltype(nullptr)) const { return true; }
57
58 R(*fptr)
59 (Args...) = nullptr;
60 };
61
62 struct alignas(4 * alignof(void*)) LargeAlignedCallable {
operator ()__anon339fe1ef0111::LargeAlignedCallable63 void operator()() { calls += 1; }
64
65 int8_t calls = 0;
66 };
67
68 // An object whose state we can examine from the outside.
69 struct SlotMachine {
operator ()__anon339fe1ef0111::SlotMachine70 void operator()() { value++; }
operator ()__anon339fe1ef0111::SlotMachine71 int operator()(int a, int b) {
72 value += a * b;
73 return value;
74 }
75
76 int value = 0;
77 };
78
79 // A move-only object which increments a counter when uniquely destroyed.
80 class DestructionObserver {
81 public:
DestructionObserver(int * counter)82 DestructionObserver(int* counter) : counter_(counter) {}
DestructionObserver(DestructionObserver && other)83 DestructionObserver(DestructionObserver&& other) : counter_(other.counter_) {
84 other.counter_ = nullptr;
85 }
86 DestructionObserver(const DestructionObserver& other) = delete;
87
~DestructionObserver()88 ~DestructionObserver() {
89 if (counter_)
90 *counter_ += 1;
91 }
92
93 DestructionObserver& operator=(const DestructionObserver& other) = delete;
operator =(DestructionObserver && other)94 DestructionObserver& operator=(DestructionObserver&& other) {
95 if (counter_)
96 *counter_ += 1;
97 counter_ = other.counter_;
98 other.counter_ = nullptr;
99 return *this;
100 }
101
102 private:
103 int* counter_;
104 };
105
106 // Simple Allocator that only allows 1 object to be allocated/deallocated per call. All template
107 // instantiations share the same resources.
108 template <typename T>
109 class SingleObjectAllocator;
110
111 // Shared resources for SingleObjectAllocator template instantiations.
112 class SingleObjectAllocatorResources final {
113 private:
114 template <typename T>
115 friend class SingleObjectAllocator;
116
117 // Tuned to current tests. May need to be changed if test requirements change.
118 static constexpr size_t kObjectSize{HugeCallableSize};
119 static constexpr size_t kObjectAlignment{alignof(LargeAlignedCallable)};
120 static constexpr size_t kMaxNumObjects{2u};
121
122 struct Obj {
123 alignas(kObjectAlignment) std::byte obj[kObjectSize];
124 };
125
126 inline static std::array<Obj, kMaxNumObjects> heap_;
127 // Store `bool`s separately instead of in `Obj`, so there doesn't end up being a large amount of
128 // padding from the aligned `obj` arrays in the `Obj` structs.
129 inline static std::array<bool, kMaxNumObjects> in_use_{};
130 };
131
132 template <typename T>
133 class SingleObjectAllocator final {
134 public:
135 using value_type = T;
136 using pointer = value_type*;
137 using size_type = size_t;
138
139 struct is_always_equal : public std::true_type {};
140
141 constexpr SingleObjectAllocator() = default;
142 template <typename U>
SingleObjectAllocator(const SingleObjectAllocator<U> &)143 constexpr SingleObjectAllocator(const SingleObjectAllocator<U>&) {}
144 template <typename U>
SingleObjectAllocator(SingleObjectAllocator<U> &&)145 constexpr SingleObjectAllocator(SingleObjectAllocator<U>&&) {}
146
allocate(size_type n)147 pointer allocate(size_type n) {
148 if (n != 1u) {
149 return nullptr;
150 }
151 for (size_t index{0u}; index < in_use_.size(); ++index) {
152 if (!in_use_.at(index)) {
153 in_use_.at(index) = true;
154 return reinterpret_cast<pointer>(&heap_.at(index).obj);
155 }
156 }
157 return nullptr;
158 }
159
deallocate(pointer p,size_type n)160 void deallocate(pointer p, size_type n) {
161 ASSERT_EQ(n, 1u);
162 for (size_t index{0u}; index < heap_.size(); ++index) {
163 if (reinterpret_cast<pointer>(&heap_.at(index).obj) == p) {
164 ASSERT_TRUE(in_use_.at(index));
165 in_use_.at(index) = false;
166 return;
167 }
168 }
169 FAIL();
170 }
171
max_size() const172 constexpr size_type max_size() const { return 1u; }
173
174 template <typename U>
operator ==(const SingleObjectAllocator<U> &) const175 constexpr bool operator==(const SingleObjectAllocator<U>&) const {
176 return true;
177 }
178 template <typename U>
operator !=(const SingleObjectAllocator<U> &) const179 constexpr bool operator!=(const SingleObjectAllocator<U>&) const {
180 return false;
181 }
182
183 private:
184 // Shared resources.
185 static_assert(sizeof(value_type) <= SingleObjectAllocatorResources::kObjectSize);
186 static_assert(alignof(value_type) <= SingleObjectAllocatorResources::kObjectAlignment);
187 inline static auto& heap_ = SingleObjectAllocatorResources::heap_;
188 inline static auto& in_use_ = SingleObjectAllocatorResources::in_use_;
189 static_assert(heap_.size() == in_use_.size());
190 };
191
192 template <typename ClosureFunction>
closure()193 void closure() {
194 static_assert(fit::is_nullable<ClosureFunction>::value, "");
195
196 // default initialization
197 ClosureFunction fdefault;
198 EXPECT_FALSE(!!fdefault);
199
200 // nullptr initialization
201 ClosureFunction fnull(nullptr);
202 EXPECT_FALSE(!!fnull);
203
204 // null function pointer initialization
205 Closure* fptr = nullptr;
206 ClosureFunction ffunc(fptr);
207 EXPECT_FALSE(!!ffunc);
208
209 // "empty std::function" initialization
210 EmptyFunction<Closure> empty;
211 ClosureFunction fwrapper(empty);
212 EXPECT_FALSE(!!fwrapper);
213
214 // inline callable initialization
215 int finline_value = 0;
216 ClosureFunction finline([&finline_value] { finline_value++; });
217 EXPECT_TRUE(!!finline);
218 finline();
219 EXPECT_EQ(1, finline_value);
220 finline();
221 EXPECT_EQ(2, finline_value);
222
223 // heap callable initialization
224 int fheap_value = 0;
225 ClosureFunction fheap([&fheap_value, big = Big()] { fheap_value++; });
226 EXPECT_TRUE(!!fheap);
227 fheap();
228 EXPECT_EQ(1, fheap_value);
229 fheap();
230 EXPECT_EQ(2, fheap_value);
231
232 // move initialization of a nullptr
233 ClosureFunction fnull2(std::move(fnull));
234 EXPECT_FALSE(!!fnull2);
235
236 // move initialization of an inline callable
237 ClosureFunction finline2(std::move(finline));
238 EXPECT_TRUE(!!finline2);
239 EXPECT_FALSE(!!finline);
240 finline2();
241 EXPECT_EQ(3, finline_value);
242 finline2();
243 EXPECT_EQ(4, finline_value);
244
245 // move initialization of a heap callable
246 ClosureFunction fheap2(std::move(fheap));
247 EXPECT_TRUE(!!fheap2);
248 EXPECT_FALSE(!!fheap);
249 fheap2();
250 EXPECT_EQ(3, fheap_value);
251 fheap2();
252 EXPECT_EQ(4, fheap_value);
253
254 // inline mutable lambda
255 int fmutinline_value = 0;
256 ClosureFunction fmutinline([&fmutinline_value, x = 1]() mutable {
257 x *= 2;
258 fmutinline_value = x;
259 });
260 EXPECT_TRUE(!!fmutinline);
261 fmutinline();
262 EXPECT_EQ(2, fmutinline_value);
263 fmutinline();
264 EXPECT_EQ(4, fmutinline_value);
265
266 // heap-allocated mutable lambda
267 int fmutheap_value = 0;
268 ClosureFunction fmutheap([&fmutheap_value, big = Big(), x = 1]() mutable {
269 x *= 2;
270 fmutheap_value = x;
271 });
272 EXPECT_TRUE(!!fmutheap);
273 fmutheap();
274 EXPECT_EQ(2, fmutheap_value);
275 fmutheap();
276 EXPECT_EQ(4, fmutheap_value);
277
278 // move assignment of non-null
279 ClosureFunction fnew([] {});
280 fnew = std::move(finline2);
281 EXPECT_TRUE(!!fnew);
282 fnew();
283 EXPECT_EQ(5, finline_value);
284 fnew();
285 EXPECT_EQ(6, finline_value);
286
287 // move assignment of self
288 fnew = std::move(fnew);
289 EXPECT_TRUE(!!fnew);
290 fnew();
291 EXPECT_EQ(7, finline_value);
292
293 // move assignment of null
294 fnew = std::move(fnull);
295 EXPECT_FALSE(!!fnew);
296
297 // callable assignment with operator=
298 int fnew_value = 0;
299 fnew = [&fnew_value] { fnew_value++; };
300 EXPECT_TRUE(!!fnew);
301 fnew();
302 EXPECT_EQ(1, fnew_value);
303 fnew();
304 EXPECT_EQ(2, fnew_value);
305
306 // nullptr assignment
307 fnew = nullptr;
308 EXPECT_FALSE(!!fnew);
309
310 // swap (currently null)
311 swap(fnew, fheap2);
312 EXPECT_TRUE(!!fnew);
313 EXPECT_FALSE(!!fheap);
314 fnew();
315 EXPECT_EQ(5, fheap_value);
316 fnew();
317 EXPECT_EQ(6, fheap_value);
318
319 // swap with self
320 swap(fnew, fnew);
321 EXPECT_TRUE(!!fnew);
322 fnew();
323 EXPECT_EQ(7, fheap_value);
324 fnew();
325 EXPECT_EQ(8, fheap_value);
326
327 // swap with non-null
328 swap(fnew, fmutinline);
329 EXPECT_TRUE(!!fmutinline);
330 EXPECT_TRUE(!!fnew);
331 fmutinline();
332 EXPECT_EQ(9, fheap_value);
333 fmutinline();
334 EXPECT_EQ(10, fheap_value);
335 fnew();
336 EXPECT_EQ(8, fmutinline_value);
337 fnew();
338 EXPECT_EQ(16, fmutinline_value);
339
340 // nullptr comparison operators
341 EXPECT_TRUE(fnull == nullptr);
342 EXPECT_FALSE(fnull != nullptr);
343 EXPECT_TRUE(nullptr == fnull);
344 EXPECT_FALSE(nullptr != fnull);
345 EXPECT_FALSE(fnew == nullptr);
346 EXPECT_TRUE(fnew != nullptr);
347 EXPECT_FALSE(nullptr == fnew);
348 EXPECT_TRUE(nullptr != fnew);
349
350 // null function pointer assignment
351 fnew = fptr;
352 EXPECT_FALSE(!!fnew);
353
354 // "empty std::function" assignment
355 fmutinline = empty;
356 EXPECT_FALSE(!!fmutinline);
357
358 // target access
359 ClosureFunction fslot;
360 EXPECT_NULL(fslot.template target<decltype(nullptr)>());
361 fslot = SlotMachine{42};
362 fslot();
363 SlotMachine* fslottarget = fslot.template target<SlotMachine>();
364 EXPECT_EQ(43, fslottarget->value);
365 const SlotMachine* fslottargetconst =
366 const_cast<const ClosureFunction&>(fslot).template target<SlotMachine>();
367 EXPECT_EQ(fslottarget, fslottargetconst);
368 fslot = nullptr;
369 EXPECT_NULL(fslot.template target<decltype(nullptr)>());
370 }
371
372 template <typename BinaryOpFunction>
binary_op()373 void binary_op() {
374 static_assert(fit::is_nullable<BinaryOpFunction>::value, "");
375
376 // default initialization
377 BinaryOpFunction fdefault;
378 EXPECT_FALSE(!!fdefault);
379
380 // nullptr initialization
381 BinaryOpFunction fnull(nullptr);
382 EXPECT_FALSE(!!fnull);
383
384 // null function pointer initialization
385 BinaryOp* fptr = nullptr;
386 BinaryOpFunction ffunc(fptr);
387 EXPECT_FALSE(!!ffunc);
388
389 // "empty std::function" initialization
390 EmptyFunction<BinaryOp> empty;
391 BinaryOpFunction fwrapper(empty);
392 EXPECT_FALSE(!!fwrapper);
393
394 // inline callable initialization
395 int finline_value = 0;
396 BinaryOpFunction finline([&finline_value](int a, int b) {
397 finline_value++;
398 return a + b;
399 });
400 EXPECT_TRUE(!!finline);
401 EXPECT_EQ(10, finline(3, 7));
402 EXPECT_EQ(1, finline_value);
403 EXPECT_EQ(10, finline(3, 7));
404 EXPECT_EQ(2, finline_value);
405
406 // heap callable initialization
407 int fheap_value = 0;
408 BinaryOpFunction fheap([&fheap_value, big = Big()](int a, int b) {
409 fheap_value++;
410 return a + b;
411 });
412 EXPECT_TRUE(!!fheap);
413 EXPECT_EQ(10, fheap(3, 7));
414 EXPECT_EQ(1, fheap_value);
415 EXPECT_EQ(10, fheap(3, 7));
416 EXPECT_EQ(2, fheap_value);
417
418 // move initialization of a nullptr
419 BinaryOpFunction fnull2(std::move(fnull));
420 EXPECT_FALSE(!!fnull2);
421
422 // move initialization of an inline callable
423 BinaryOpFunction finline2(std::move(finline));
424 EXPECT_TRUE(!!finline2);
425 EXPECT_FALSE(!!finline);
426 EXPECT_EQ(10, finline2(3, 7));
427 EXPECT_EQ(3, finline_value);
428 EXPECT_EQ(10, finline2(3, 7));
429 EXPECT_EQ(4, finline_value);
430
431 // move initialization of a heap callable
432 BinaryOpFunction fheap2(std::move(fheap));
433 EXPECT_TRUE(!!fheap2);
434 EXPECT_FALSE(!!fheap);
435 EXPECT_EQ(10, fheap2(3, 7));
436 EXPECT_EQ(3, fheap_value);
437 EXPECT_EQ(10, fheap2(3, 7));
438 EXPECT_EQ(4, fheap_value);
439
440 // inline mutable lambda
441 int fmutinline_value = 0;
442 BinaryOpFunction fmutinline([&fmutinline_value, x = 1](int a, int b) mutable {
443 x *= 2;
444 fmutinline_value = x;
445 return a + b;
446 });
447 EXPECT_TRUE(!!fmutinline);
448 EXPECT_EQ(10, fmutinline(3, 7));
449 EXPECT_EQ(2, fmutinline_value);
450 EXPECT_EQ(10, fmutinline(3, 7));
451 EXPECT_EQ(4, fmutinline_value);
452
453 // heap-allocated mutable lambda
454 int fmutheap_value = 0;
455 BinaryOpFunction fmutheap([&fmutheap_value, big = Big(), x = 1](int a, int b) mutable {
456 x *= 2;
457 fmutheap_value = x;
458 return a + b;
459 });
460 EXPECT_TRUE(!!fmutheap);
461 EXPECT_EQ(10, fmutheap(3, 7));
462 EXPECT_EQ(2, fmutheap_value);
463 EXPECT_EQ(10, fmutheap(3, 7));
464 EXPECT_EQ(4, fmutheap_value);
465
466 // move assignment of non-null
467 BinaryOpFunction fnew([](int a, int b) { return 0; });
468 fnew = std::move(finline2);
469 EXPECT_TRUE(!!fnew);
470 EXPECT_EQ(10, fnew(3, 7));
471 EXPECT_EQ(5, finline_value);
472 EXPECT_EQ(10, fnew(3, 7));
473 EXPECT_EQ(6, finline_value);
474
475 // self-assignment of non-null
476 fnew = std::move(fnew);
477 EXPECT_TRUE(!!fnew);
478 EXPECT_EQ(10, fnew(3, 7));
479 EXPECT_EQ(7, finline_value);
480
481 // move assignment of null
482 fnew = std::move(fnull);
483 EXPECT_FALSE(!!fnew);
484
485 // self-assignment of non-null
486 fnew = std::move(fnew);
487 EXPECT_FALSE(!!fnew);
488
489 // callable assignment with operator=
490 int fnew_value = 0;
491 fnew = [&fnew_value](int a, int b) {
492 fnew_value++;
493 return a + b;
494 };
495 EXPECT_TRUE(!!fnew);
496 EXPECT_EQ(10, fnew(3, 7));
497 EXPECT_EQ(1, fnew_value);
498 EXPECT_EQ(10, fnew(3, 7));
499 EXPECT_EQ(2, fnew_value);
500
501 // nullptr assignment
502 fnew = nullptr;
503 EXPECT_FALSE(!!fnew);
504
505 // swap (currently null)
506 swap(fnew, fheap2);
507 EXPECT_TRUE(!!fnew);
508 EXPECT_FALSE(!!fheap);
509 EXPECT_EQ(10, fnew(3, 7));
510 EXPECT_EQ(5, fheap_value);
511 EXPECT_EQ(10, fnew(3, 7));
512 EXPECT_EQ(6, fheap_value);
513
514 // swap with self
515 swap(fnew, fnew);
516 EXPECT_TRUE(!!fnew);
517 EXPECT_EQ(10, fnew(3, 7));
518 EXPECT_EQ(7, fheap_value);
519 EXPECT_EQ(10, fnew(3, 7));
520 EXPECT_EQ(8, fheap_value);
521
522 // swap with non-null
523 swap(fnew, fmutinline);
524 EXPECT_TRUE(!!fmutinline);
525 EXPECT_TRUE(!!fnew);
526 EXPECT_EQ(10, fmutinline(3, 7));
527 EXPECT_EQ(9, fheap_value);
528 EXPECT_EQ(10, fmutinline(3, 7));
529 EXPECT_EQ(10, fheap_value);
530 EXPECT_EQ(10, fnew(3, 7));
531 EXPECT_EQ(8, fmutinline_value);
532 EXPECT_EQ(10, fnew(3, 7));
533 EXPECT_EQ(16, fmutinline_value);
534
535 // nullptr comparison operators
536 EXPECT_TRUE(fnull == nullptr);
537 EXPECT_FALSE(fnull != nullptr);
538 EXPECT_TRUE(nullptr == fnull);
539 EXPECT_FALSE(nullptr != fnull);
540 EXPECT_FALSE(fnew == nullptr);
541 EXPECT_TRUE(fnew != nullptr);
542 EXPECT_FALSE(nullptr == fnew);
543 EXPECT_TRUE(nullptr != fnew);
544
545 // null function pointer assignment
546 fnew = fptr;
547 EXPECT_FALSE(!!fnew);
548
549 // "empty std::function" assignment
550 fmutinline = empty;
551 EXPECT_FALSE(!!fmutinline);
552
553 // target access
554 BinaryOpFunction fslot;
555 EXPECT_NULL(fslot.template target<decltype(nullptr)>());
556 fslot = SlotMachine{42};
557 EXPECT_EQ(54, fslot(3, 4));
558 SlotMachine* fslottarget = fslot.template target<SlotMachine>();
559 EXPECT_EQ(54, fslottarget->value);
560 const SlotMachine* fslottargetconst =
561 const_cast<const BinaryOpFunction&>(fslot).template target<SlotMachine>();
562 EXPECT_EQ(fslottarget, fslottargetconst);
563 fslot = nullptr;
564 EXPECT_NULL(fslot.template target<decltype(nullptr)>());
565 }
566
TEST(FunctionTests,sized_function_size_bounds)567 TEST(FunctionTests, sized_function_size_bounds) {
568 auto empty = [] {};
569 fit::function<Closure, sizeof(empty)> fempty(std::move(empty));
570 static_assert(sizeof(fempty) >= sizeof(empty), "size bounds");
571
572 auto small = [x = 1, y = 2] {
573 (void)x; // suppress unused lambda capture warning
574 (void)y;
575 };
576 fit::function<Closure, sizeof(small)> fsmall(std::move(small));
577 static_assert(sizeof(fsmall) >= sizeof(small), "size bounds");
578 fsmall = [] {};
579
580 auto big = [big = Big(), x = 1] { (void)x; };
581 fit::function<Closure, sizeof(big)> fbig(std::move(big));
582 static_assert(sizeof(fbig) >= sizeof(big), "size bounds");
583 fbig = [x = 1, y = 2] {
584 (void)x;
585 (void)y;
586 };
587 fbig = [] {};
588
589 // These statements do compile though the lambda will be copied to the heap
590 // when they exceed the inline size.
591 fempty = [x = 1, y = 2] {
592 (void)x;
593 (void)y;
594 };
595 fsmall = [big = Big(), x = 1] { (void)x; };
596 fbig = [big = Big(), x = 1, y = 2] {
597 (void)x;
598 (void)y;
599 };
600 }
601
TEST(FunctionTests,inline_function_size_bounds)602 TEST(FunctionTests, inline_function_size_bounds) {
603 auto empty = [] {};
604 fit::inline_function<Closure, sizeof(empty)> fempty(std::move(empty));
605 static_assert(sizeof(fempty) >= sizeof(empty), "size bounds");
606
607 auto small = [x = 1, y = 2] {
608 (void)x; // suppress unused lambda capture warning
609 (void)y;
610 };
611 fit::inline_function<Closure, sizeof(small)> fsmall(std::move(small));
612 static_assert(sizeof(fsmall) >= sizeof(small), "size bounds");
613 fsmall = [] {};
614
615 auto big = [big = Big(), x = 1] { (void)x; };
616 fit::inline_function<Closure, sizeof(big)> fbig(std::move(big));
617 static_assert(sizeof(fbig) >= sizeof(big), "size bounds");
618 fbig = [x = 1, y = 2] {
619 (void)x;
620 (void)y;
621 };
622 fbig = [] {};
623
624 // These statements do not compile because the lambdas are too big to fit.
625 #if 0
626 fempty = [ x = 1, y = 2 ] {
627 (void)x;
628 (void)y;
629 };
630 fsmall = [ big = Big(), x = 1 ] { (void)x; };
631 fbig = [ big = Big(), x = 1, y = 2 ] {
632 (void)x;
633 (void)y;
634 };
635 #endif
636 }
637
TEST(FunctionTests,inline_function_alignment_check)638 TEST(FunctionTests, inline_function_alignment_check) {
639 // These statements do not compile because the alignment is too large.
640 #if 0
641 auto big = [big = BigAlignment()] { };
642 fit::inline_function<Closure, sizeof(big)> fbig(std::move(big));
643 #endif
644 }
645
TEST(FunctionTests,move_only_argument_and_result)646 TEST(FunctionTests, move_only_argument_and_result) {
647 std::unique_ptr<int> arg(new int());
648 fit::function<MoveOp> f([](std::unique_ptr<int> value) {
649 *value += 1;
650 return value;
651 });
652 arg = f(std::move(arg));
653 EXPECT_EQ(1, *arg);
654 arg = f(std::move(arg));
655 EXPECT_EQ(2, *arg);
656 }
657
implicit_construction_helper(fit::closure closure)658 void implicit_construction_helper(fit::closure closure) {}
659
TEST(FunctionTests,implicit_construction)660 TEST(FunctionTests, implicit_construction) {
661 // ensure we can implicitly construct from nullptr
662 implicit_construction_helper(nullptr);
663
664 // ensure we can implicitly construct from a lambda
665 implicit_construction_helper([] {});
666 }
667
arg_count(fit::closure)668 int arg_count(fit::closure) { return 0; }
arg_count(fit::function<void (int)>)669 int arg_count(fit::function<void(int)>) { return 1; }
670
TEST(FunctionTests,overload_resolution)671 TEST(FunctionTests, overload_resolution) {
672 EXPECT_EQ(0, arg_count([] {}));
673 EXPECT_EQ(1, arg_count([](int) {}));
674 }
675
TEST(FunctionTests,sharing)676 TEST(FunctionTests, sharing) {
677 fit::function<Closure> fnull;
678 fit::function<Closure> fnullshare1 = fnull.share();
679 fit::function<Closure> fnullshare2 = fnull.share();
680 fit::function<Closure> fnullshare3 = fnullshare1.share();
681 EXPECT_FALSE(!!fnull);
682 EXPECT_FALSE(!!fnullshare1);
683 EXPECT_FALSE(!!fnullshare2);
684 EXPECT_FALSE(!!fnullshare3);
685
686 int finlinevalue = 1;
687 int finlinedestroy = 0;
688 fit::function<Closure> finline = [&finlinevalue, d = DestructionObserver(&finlinedestroy)] {
689 finlinevalue++;
690 };
691 fit::function<Closure> finlineshare1 = finline.share();
692 fit::function<Closure> finlineshare2 = finline.share();
693 fit::function<Closure> finlineshare3 = finlineshare1.share();
694 EXPECT_TRUE(!!finline);
695 EXPECT_TRUE(!!finlineshare1);
696 EXPECT_TRUE(!!finlineshare2);
697 EXPECT_TRUE(!!finlineshare3);
698 finline();
699 EXPECT_EQ(2, finlinevalue);
700 finlineshare1();
701 EXPECT_EQ(3, finlinevalue);
702 finlineshare2();
703 EXPECT_EQ(4, finlinevalue);
704 finlineshare3();
705 EXPECT_EQ(5, finlinevalue);
706 finlineshare2();
707 EXPECT_EQ(6, finlinevalue);
708 finline();
709 EXPECT_EQ(7, finlinevalue);
710 EXPECT_EQ(0, finlinedestroy);
711 finline = nullptr;
712 EXPECT_EQ(0, finlinedestroy);
713 finlineshare3 = nullptr;
714 EXPECT_EQ(0, finlinedestroy);
715 finlineshare2 = nullptr;
716 EXPECT_EQ(0, finlinedestroy);
717 finlineshare1 = nullptr;
718 EXPECT_EQ(1, finlinedestroy);
719
720 int fheapvalue = 1;
721 int fheapdestroy = 0;
722 fit::function<Closure> fheap = [&fheapvalue, big = Big(),
723 d = DestructionObserver(&fheapdestroy)] { fheapvalue++; };
724 fit::function<Closure> fheapshare1 = fheap.share();
725 fit::function<Closure> fheapshare2 = fheap.share();
726 fit::function<Closure> fheapshare3 = fheapshare1.share();
727 EXPECT_TRUE(!!fheap);
728 EXPECT_TRUE(!!fheapshare1);
729 EXPECT_TRUE(!!fheapshare2);
730 EXPECT_TRUE(!!fheapshare3);
731 fheap();
732 EXPECT_EQ(2, fheapvalue);
733 fheapshare1();
734 EXPECT_EQ(3, fheapvalue);
735 fheapshare2();
736 EXPECT_EQ(4, fheapvalue);
737 fheapshare3();
738 EXPECT_EQ(5, fheapvalue);
739 fheapshare2();
740 EXPECT_EQ(6, fheapvalue);
741 fheap();
742 EXPECT_EQ(7, fheapvalue);
743 EXPECT_EQ(0, fheapdestroy);
744 fheap = nullptr;
745 EXPECT_EQ(0, fheapdestroy);
746 fheapshare3 = nullptr;
747 EXPECT_EQ(0, fheapdestroy);
748 fheapshare2 = nullptr;
749 EXPECT_EQ(0, fheapdestroy);
750 fheapshare1 = nullptr;
751 EXPECT_EQ(1, fheapdestroy);
752
753 // target access now available after share()
754 using ClosureFunction = fit::function<Closure, HugeCallableSize>;
755 ClosureFunction fslot = SlotMachine{42};
756 fslot();
757 SlotMachine* fslottarget = fslot.template target<SlotMachine>();
758 EXPECT_EQ(43, fslottarget->value);
759
760 auto shared_fslot = fslot.share();
761 shared_fslot();
762 fslottarget = shared_fslot.template target<SlotMachine>();
763 EXPECT_EQ(44, fslottarget->value);
764 fslot();
765 EXPECT_EQ(45, fslottarget->value);
766 fslot = nullptr;
767 EXPECT_NULL(fslot.template target<decltype(nullptr)>());
768 shared_fslot();
769 EXPECT_EQ(46, fslottarget->value);
770 shared_fslot = nullptr;
771 EXPECT_NULL(shared_fslot.template target<decltype(nullptr)>());
772
773 // These statements do not compile because inline functions cannot be shared
774 #if 0
775 fit::inline_function<Closure> fbad;
776 fbad.share();
777 #endif
778 }
779
TEST(FunctionTests,sharing_with_custom_allocator)780 TEST(FunctionTests, sharing_with_custom_allocator) {
781 int fheapvalue = 1;
782 int fheapdestroy = 0;
783 fit::function<Closure, fit::default_inline_target_size, SingleObjectAllocator<std::byte>> fheap =
784 [&fheapvalue, big = Big(), d = DestructionObserver(&fheapdestroy)] { fheapvalue++; };
785 fit::function<Closure, fit::default_inline_target_size, SingleObjectAllocator<std::byte>>
786 fheapshare1 = fheap.share();
787 fit::function<Closure, fit::default_inline_target_size, SingleObjectAllocator<std::byte>>
788 fheapshare2 = fheap.share();
789 fit::function<Closure, fit::default_inline_target_size, SingleObjectAllocator<std::byte>>
790 fheapshare3 = fheapshare1.share();
791 EXPECT_TRUE(!!fheap);
792 EXPECT_TRUE(!!fheapshare1);
793 EXPECT_TRUE(!!fheapshare2);
794 EXPECT_TRUE(!!fheapshare3);
795 fheap();
796 EXPECT_EQ(2, fheapvalue);
797 fheapshare1();
798 EXPECT_EQ(3, fheapvalue);
799 fheapshare2();
800 EXPECT_EQ(4, fheapvalue);
801 fheapshare3();
802 EXPECT_EQ(5, fheapvalue);
803 fheapshare2();
804 EXPECT_EQ(6, fheapvalue);
805 fheap();
806 EXPECT_EQ(7, fheapvalue);
807 EXPECT_EQ(0, fheapdestroy);
808 fheap = nullptr;
809 EXPECT_EQ(0, fheapdestroy);
810 fheapshare3 = nullptr;
811 EXPECT_EQ(0, fheapdestroy);
812 fheapshare2 = nullptr;
813 EXPECT_EQ(0, fheapdestroy);
814 fheapshare1 = nullptr;
815 EXPECT_EQ(1, fheapdestroy);
816 }
817
818 struct Obj {
Call__anon339fe1ef0111::Obj819 void Call() { calls++; }
820
AddOne__anon339fe1ef0111::Obj821 int AddOne(int x) {
822 calls++;
823 return x + 1;
824 }
825
Sum__anon339fe1ef0111::Obj826 int Sum(int a, int b, int c) {
827 calls++;
828 return a + b + c;
829 }
830
AddAndReturn__anon339fe1ef0111::Obj831 std::unique_ptr<int> AddAndReturn(std::unique_ptr<int> value) {
832 (*value)++;
833 return value;
834 }
835
836 uint32_t calls = 0;
837 };
838
TEST(FunctionTests,deprecated_bind_member)839 TEST(FunctionTests, deprecated_bind_member) {
840 Obj obj;
841 auto move_only_value = std::make_unique<int>(4);
842
843 static_assert(sizeof(fit::bind_member(&obj, &Obj::AddOne)) == 3 * sizeof(void*));
844 fit::bind_member(&obj, &Obj::Call)();
845 EXPECT_EQ(23, fit::bind_member(&obj, &Obj::AddOne)(22));
846 EXPECT_EQ(6, fit::bind_member(&obj, &Obj::Sum)(1, 2, 3));
847 move_only_value = fit::bind_member(&obj, &Obj::AddAndReturn)(std::move(move_only_value));
848 EXPECT_EQ(5, *move_only_value);
849 EXPECT_EQ(3, obj.calls);
850 }
851
TEST(FunctionTests,bind_member)852 TEST(FunctionTests, bind_member) {
853 Obj obj;
854 auto move_only_value = std::make_unique<int>(4);
855
856 static_assert(sizeof(fit::bind_member<&Obj::AddOne>(&obj)) == sizeof(void*));
857 fit::bind_member<&Obj::Call> (&obj)();
858 EXPECT_EQ(23, fit::bind_member<&Obj::AddOne>(&obj)(22));
859 EXPECT_EQ(6, fit::bind_member<&Obj::Sum>(&obj)(1, 2, 3));
860 move_only_value = fit::bind_member<&Obj::AddAndReturn>(&obj)(std::move(move_only_value));
861 fit::function<int(int, int, int)> f(fit::bind_member<&Obj::Sum>(&obj));
862 EXPECT_EQ(6, f(1, 2, 3));
863 EXPECT_EQ(5, *move_only_value);
864 EXPECT_EQ(4, obj.calls);
865 }
866
TEST(FunctionTests,callback_once)867 TEST(FunctionTests, callback_once) {
868 fit::callback<Closure> cbnull;
869 fit::callback<Closure> cbnullshare1 = cbnull.share();
870 fit::callback<Closure> cbnullshare2 = cbnull.share();
871 fit::callback<Closure> cbnullshare3 = cbnullshare1.share();
872 EXPECT_FALSE(!!cbnull);
873 EXPECT_FALSE(!!cbnullshare1);
874 EXPECT_FALSE(!!cbnullshare2);
875 EXPECT_FALSE(!!cbnullshare3);
876
877 int cbinlinevalue = 1;
878 int cbinlinedestroy = 0;
879 fit::callback<Closure> cbinline = [&cbinlinevalue, d = DestructionObserver(&cbinlinedestroy)] {
880 cbinlinevalue++;
881 };
882 EXPECT_TRUE(!!cbinline);
883 EXPECT_FALSE(cbinline == nullptr);
884 EXPECT_EQ(1, cbinlinevalue);
885 EXPECT_EQ(0, cbinlinedestroy);
886 cbinline(); // releases resources even if never shared
887 EXPECT_FALSE(!!cbinline);
888 EXPECT_TRUE(cbinline == nullptr);
889 EXPECT_EQ(2, cbinlinevalue);
890 EXPECT_EQ(1, cbinlinedestroy);
891
892 cbinlinevalue = 1;
893 cbinlinedestroy = 0;
894 cbinline = [&cbinlinevalue, d = DestructionObserver(&cbinlinedestroy)] { cbinlinevalue++; };
895 fit::callback<Closure> cbinlineshare1 = cbinline.share();
896 fit::callback<Closure> cbinlineshare2 = cbinline.share();
897 fit::callback<Closure> cbinlineshare3 = cbinlineshare1.share();
898 EXPECT_TRUE(!!cbinline);
899 EXPECT_TRUE(!!cbinlineshare1);
900 EXPECT_TRUE(!!cbinlineshare2);
901 EXPECT_TRUE(!!cbinlineshare3);
902 EXPECT_EQ(1, cbinlinevalue);
903 EXPECT_EQ(0, cbinlinedestroy);
904 cbinline();
905 EXPECT_EQ(2, cbinlinevalue);
906 EXPECT_EQ(1, cbinlinedestroy);
907 EXPECT_FALSE(!!cbinline);
908 EXPECT_TRUE(cbinline == nullptr);
909 // cbinline(); // should abort
910 EXPECT_FALSE(!!cbinlineshare1);
911 EXPECT_TRUE(cbinlineshare1 == nullptr);
912 // cbinlineshare1(); // should abort
913 EXPECT_FALSE(!!cbinlineshare2);
914 // cbinlineshare2(); // should abort
915 EXPECT_FALSE(!!cbinlineshare3);
916 // cbinlineshare3(); // should abort
917 EXPECT_EQ(1, cbinlinedestroy);
918 cbinlineshare3 = nullptr;
919 EXPECT_EQ(1, cbinlinedestroy);
920 cbinline = nullptr;
921 EXPECT_EQ(1, cbinlinedestroy);
922
923 int cbheapvalue = 1;
924 int cbheapdestroy = 0;
925 fit::callback<Closure> cbheap = [&cbheapvalue, big = Big(),
926 d = DestructionObserver(&cbheapdestroy)] { cbheapvalue++; };
927 EXPECT_TRUE(!!cbheap);
928 EXPECT_FALSE(cbheap == nullptr);
929 EXPECT_EQ(1, cbheapvalue);
930 EXPECT_EQ(0, cbheapdestroy);
931 cbheap(); // releases resources even if never shared
932 EXPECT_FALSE(!!cbheap);
933 EXPECT_TRUE(cbheap == nullptr);
934 EXPECT_EQ(2, cbheapvalue);
935 EXPECT_EQ(1, cbheapdestroy);
936
937 cbheapvalue = 1;
938 cbheapdestroy = 0;
939 cbheap = [&cbheapvalue, big = Big(), d = DestructionObserver(&cbheapdestroy)] { cbheapvalue++; };
940 fit::callback<Closure> cbheapshare1 = cbheap.share();
941 fit::callback<Closure> cbheapshare2 = cbheap.share();
942 fit::callback<Closure> cbheapshare3 = cbheapshare1.share();
943 EXPECT_TRUE(!!cbheap);
944 EXPECT_TRUE(!!cbheapshare1);
945 EXPECT_TRUE(!!cbheapshare2);
946 EXPECT_TRUE(!!cbheapshare3);
947 EXPECT_EQ(1, cbheapvalue);
948 EXPECT_EQ(0, cbheapdestroy);
949 cbheap();
950 EXPECT_EQ(2, cbheapvalue);
951 EXPECT_EQ(1, cbheapdestroy);
952 EXPECT_FALSE(!!cbheap);
953 EXPECT_TRUE(cbheap == nullptr);
954 // cbheap(); // should abort
955 EXPECT_FALSE(!!cbheapshare1);
956 EXPECT_TRUE(cbheapshare1 == nullptr);
957 // cbheapshare1(); // should abort
958 EXPECT_FALSE(!!cbheapshare2);
959 // cbheapshare2(); // should abort
960 EXPECT_FALSE(!!cbheapshare3);
961 // cbheapshare3(); // should abort
962 EXPECT_EQ(1, cbheapdestroy);
963 cbheapshare3 = nullptr;
964 EXPECT_EQ(1, cbheapdestroy);
965 cbheap = nullptr;
966 EXPECT_EQ(1, cbheapdestroy);
967
968 // Verify new design, splitting out fit::callback, still supports
969 // assignment of move-only "Callables" (that is, lambdas made move-only
970 // because they capture a move-only object, like a fit::function, for
971 // example!)
972 fit::function<void()> fn_to_wrap = []() {};
973 fit::function<void()> fn_from_lambda;
974 fn_from_lambda = [fn = fn_to_wrap.share()]() mutable { fn(); };
975
976 // Same test for fit::callback
977 fit::callback<void()> cb_to_wrap = []() {};
978 fit::callback<void()> cb_from_lambda;
979 cb_from_lambda = [cb = std::move(cb_to_wrap)]() mutable { cb(); };
980
981 // |fit::function| objects can be constructed from or assigned from
982 // a |fit::callback|, if the result and arguments are compatible.
983 fit::function<Closure> fn = []() {};
984 fit::callback<Closure> cb = []() {};
985 fit::callback<Closure> cb_assign;
986 cb_assign = std::move(fn);
987 fit::callback<Closure> cb_construct = std::move(fn);
988 fit::callback<Closure> cb_share = fn.share();
989
990 static_assert(!std::is_convertible<fit::function<void()>*, fit::callback<void()>*>::value, "");
991 static_assert(!std::is_constructible<fit::function<void()>, fit::callback<void()>>::value, "");
992 static_assert(!std::is_assignable<fit::function<void()>, fit::callback<void()>>::value, "");
993 static_assert(!std::is_constructible<fit::function<void()>, decltype(cb.share())>::value, "");
994 #if 0
995 // These statements do not compile because inline callbacks cannot be shared
996 fit::inline_callback<Closure> cbbad;
997 cbbad.share();
998
999 {
1000 // Attempts to copy, move, or share a callback into a fit::function<>
1001 // should not compile. This is verified by static_assert above, and
1002 // was verified interactively using the compiler.
1003 fit::callback<Closure> cb = []() {};
1004 fit::function<Closure> fn = []() {};
1005 fit::function<Closure> fn_assign;
1006 fn_assign = cb; // BAD
1007 fn_assign = std::move(cb); // BAD
1008 fit::function<Closure> fn_construct = cb; // BAD
1009 fit::function<Closure> fn_construct2 = std::move(cb); // BAD
1010 fit::function<Closure> fn_share = cb.share(); // BAD
1011 }
1012
1013 #endif
1014 }
1015
TEST(FunctionTests,callback_with_custom_allocator)1016 TEST(FunctionTests, callback_with_custom_allocator) {
1017 int cbheapvalue = 1;
1018 int cbheapdestroy = 0;
1019 fit::callback<Closure, fit::default_inline_target_size, SingleObjectAllocator<std::byte>> cbheap =
1020 [&cbheapvalue, big = Big(), d = DestructionObserver(&cbheapdestroy)] { cbheapvalue++; };
1021
1022 EXPECT_TRUE(!!cbheap);
1023 EXPECT_FALSE(cbheap == nullptr);
1024 EXPECT_EQ(1, cbheapvalue);
1025 EXPECT_EQ(0, cbheapdestroy);
1026 cbheap();
1027 EXPECT_FALSE(!!cbheap);
1028 EXPECT_TRUE(cbheap == nullptr);
1029 EXPECT_EQ(2, cbheapvalue);
1030 EXPECT_EQ(1, cbheapdestroy);
1031 }
1032
1033 PW_CONSTINIT const fit::function<void()> kDefaultConstructed;
1034 PW_CONSTINIT const fit::function<void()> kNullptrConstructed(nullptr);
1035
TEST(FunctionTests,null_constructors_are_constexpr)1036 TEST(FunctionTests, null_constructors_are_constexpr) {
1037 EXPECT_EQ(kDefaultConstructed, nullptr);
1038 EXPECT_EQ(kNullptrConstructed, nullptr);
1039 }
1040
TEST(FunctionTests,function_with_callable_aligned_larger_than_inline_size)1041 TEST(FunctionTests, function_with_callable_aligned_larger_than_inline_size) {
1042 static_assert(sizeof(LargeAlignedCallable) > sizeof(void*), "Should not fit inline in function.");
1043
1044 fit::function<void(), sizeof(void*)> function = LargeAlignedCallable();
1045
1046 static_assert(alignof(LargeAlignedCallable) > alignof(decltype(function)));
1047
1048 // Verify that the allocated target is aligned correctly.
1049 LargeAlignedCallable* callable_ptr = function.target<LargeAlignedCallable>();
1050 EXPECT_EQ(cpp20::bit_cast<uintptr_t>(callable_ptr) % alignof(LargeAlignedCallable), 0u);
1051
1052 function();
1053 EXPECT_EQ(callable_ptr->calls, 1);
1054 }
1055
TEST(FunctionTests,function_with_callable_aligned_larger_than_inline_size_with_custom_allocator)1056 TEST(FunctionTests, function_with_callable_aligned_larger_than_inline_size_with_custom_allocator) {
1057 static_assert(sizeof(LargeAlignedCallable) > sizeof(void*), "Should not fit inline in function.");
1058
1059 fit::function<void(), sizeof(void*), SingleObjectAllocator<std::byte>> function =
1060 LargeAlignedCallable();
1061
1062 static_assert(alignof(LargeAlignedCallable) > alignof(decltype(function)));
1063
1064 // Verify that the allocated target is aligned correctly.
1065 LargeAlignedCallable* callable_ptr = function.target<LargeAlignedCallable>();
1066 EXPECT_EQ(cpp20::bit_cast<uintptr_t>(callable_ptr) % alignof(LargeAlignedCallable), 0u);
1067
1068 function();
1069 EXPECT_EQ(callable_ptr->calls, 1);
1070 }
1071
1072 // Test that function inline sizes round up to the nearest word.
1073 template <size_t bytes>
1074 using Function = fit::function<void(), bytes>; // Use an alias for brevity
1075
1076 static_assert(std::is_same<Function<0>, Function<sizeof(void*)>>::value, "");
1077 static_assert(std::is_same<Function<1>, Function<sizeof(void*)>>::value, "");
1078 static_assert(std::is_same<Function<sizeof(void*) - 1>, Function<sizeof(void*)>>::value, "");
1079 static_assert(std::is_same<Function<sizeof(void*)>, Function<sizeof(void*)>>::value, "");
1080 static_assert(std::is_same<Function<sizeof(void*) + 1>, Function<2 * sizeof(void*)>>::value, "");
1081 static_assert(std::is_same<Function<2 * sizeof(void*)>, Function<2 * sizeof(void*)>>::value, "");
1082
1083 // Also test the inline_function, callback, and inline_callback aliases.
1084 static_assert(
1085 std::is_same_v<fit::inline_function<void(), 0>, fit::inline_function<void(), sizeof(void*)>>,
1086 "");
1087 static_assert(
1088 std::is_same_v<fit::inline_function<void(), 1>, fit::inline_function<void(), sizeof(void*)>>,
1089 "");
1090 static_assert(std::is_same_v<fit::callback<void(), 0>, fit::callback<void(), sizeof(void*)>>, "");
1091 static_assert(std::is_same_v<fit::callback<void(), 1>, fit::callback<void(), sizeof(void*)>>, "");
1092 static_assert(
1093 std::is_same_v<fit::inline_callback<void(), 0>, fit::inline_callback<void(), sizeof(void*)>>,
1094 "");
1095 static_assert(
1096 std::is_same_v<fit::inline_callback<void(), 1>, fit::inline_callback<void(), sizeof(void*)>>,
1097 "");
1098
TEST(FunctionTests,rounding_function)1099 TEST(FunctionTests, rounding_function) {
1100 EXPECT_EQ(5, fit::internal::RoundUpToMultiple(0, 5));
1101 EXPECT_EQ(5, fit::internal::RoundUpToMultiple(1, 5));
1102 EXPECT_EQ(5, fit::internal::RoundUpToMultiple(4, 5));
1103 EXPECT_EQ(5, fit::internal::RoundUpToMultiple(5, 5));
1104 EXPECT_EQ(10, fit::internal::RoundUpToMultiple(6, 5));
1105 EXPECT_EQ(10, fit::internal::RoundUpToMultiple(9, 5));
1106 EXPECT_EQ(10, fit::internal::RoundUpToMultiple(10, 5));
1107 }
1108
1109 // Test that the alignment of function and callback is always the minimum of alignof(max_align_t)
1110 // and largest possible alignment for the specified inline target size.
ExpectedAlignment(size_t alignment_32,size_t alignment_64)1111 constexpr size_t ExpectedAlignment(size_t alignment_32, size_t alignment_64) {
1112 if (sizeof(void*) == 4) {
1113 return std::min(alignment_32, alignof(max_align_t));
1114 }
1115 if (sizeof(void*) == 8) {
1116 return std::min(alignment_64, alignof(max_align_t));
1117 }
1118 return 0; // Word sizes other than 32/64 are not supported, will need to update test.
1119 }
1120
1121 static_assert(alignof(fit::function<void(), 0>) == ExpectedAlignment(4, 8), "");
1122 static_assert(alignof(fit::function<void(), 1>) == ExpectedAlignment(4, 8), "");
1123 static_assert(alignof(fit::function<int(), 4>) == ExpectedAlignment(4, 8), "");
1124 static_assert(alignof(fit::function<bool(), 8>) == ExpectedAlignment(8, 8), "");
1125 static_assert(alignof(fit::function<float(int), 9>) == ExpectedAlignment(8, 16), "");
1126 static_assert(alignof(fit::function<float(int), 25>) == ExpectedAlignment(16, 16), "");
1127 static_assert(alignof(fit::inline_function<void(), 1>) == ExpectedAlignment(4, 8), "");
1128 static_assert(alignof(fit::inline_function<void(), 9>) == ExpectedAlignment(8, 16), "");
1129 static_assert(alignof(fit::callback<void(), 0>) == ExpectedAlignment(4, 8), "");
1130 static_assert(alignof(fit::callback<void(), 1>) == ExpectedAlignment(4, 8), "");
1131 static_assert(alignof(fit::callback<int(), 4>) == ExpectedAlignment(4, 8), "");
1132 static_assert(alignof(fit::callback<bool(), 8>) == ExpectedAlignment(8, 8), "");
1133 static_assert(alignof(fit::callback<float(int), 9>) == ExpectedAlignment(8, 16), "");
1134 static_assert(alignof(fit::callback<float(int), 25>) == ExpectedAlignment(16, 16), "");
1135 static_assert(alignof(fit::inline_callback<void(), 1>) == ExpectedAlignment(4, 8), "");
1136 static_assert(alignof(fit::inline_callback<void(), 9>) == ExpectedAlignment(8, 16), "");
1137 static_assert(alignof(fit::inline_callback<void(), 25>) == ExpectedAlignment(16, 16), "");
1138
1139 namespace test_copy_move_constructions {
1140
1141 template <typename F>
1142 class assert_move_only {
1143 static_assert(!std::is_copy_assignable<F>::value);
1144 static_assert(!std::is_copy_constructible<F>::value);
1145 static_assert(std::is_move_assignable<F>::value);
1146 static_assert(std::is_move_constructible<F>::value);
1147
1148 // It seems that just testing `!std::is_copy_assignable<F>` is not enough,
1149 // as the `fit::function` class could use a perfect-forwarding mechanism
1150 // that still allows expressions of the form `fit::function func1 = func2`
1151 // to compile, even though `std::is_copy_assignable<F>` is false.
1152 template <typename T, typename = void>
1153 struct test : std::false_type {};
1154 template <typename T>
1155 struct test<T, std::void_t<decltype(T::v1 = T::v2)>> : std::true_type {};
1156
1157 struct NoAssign {
1158 static F v1;
1159 static F v2;
1160 };
1161 static_assert(!test<NoAssign>::value);
1162
1163 struct CanAssign {
1164 static int v1;
1165 static int v2;
1166 };
1167 static_assert(test<CanAssign>::value);
1168
1169 template <typename T, typename = void>
1170 struct test_construct : std::false_type {};
1171 template <typename T>
1172 struct test_construct<T, std::void_t<decltype(T{std::declval<const T&>()})>> : std::true_type {};
1173
1174 static_assert(!test_construct<F>::value);
1175 static_assert(test_construct<int>::value);
1176 };
1177
1178 template class assert_move_only<fit::function<void()>>;
1179 template class assert_move_only<fit::callback<void()>>;
1180
1181 } // namespace test_copy_move_constructions
1182
1183 namespace test_conversions {
1184 static_assert(std::is_convertible<Closure, fit::function<Closure>>::value, "");
1185 static_assert(std::is_convertible<BinaryOp, fit::function<BinaryOp>>::value, "");
1186 static_assert(std::is_assignable<fit::function<Closure>, Closure>::value, "");
1187 static_assert(std::is_assignable<fit::function<BinaryOp>, BinaryOp>::value, "");
1188
1189 static_assert(std::is_assignable<fit::function<BooleanGenerator>, IntGenerator>::value, "");
1190 static_assert(std::is_assignable<fit::function<BuildableFromIntGenerator>, IntGenerator>::value,
1191 "");
1192 static_assert(!std::is_assignable<fit::function<IntGenerator>, BuildableFromIntGenerator>::value,
1193 "");
1194
1195 static_assert(!std::is_convertible<BinaryOp, fit::function<Closure>>::value, "");
1196 static_assert(!std::is_convertible<Closure, fit::function<BinaryOp>>::value, "");
1197 static_assert(!std::is_assignable<fit::function<Closure>, BinaryOp>::value, "");
1198 static_assert(!std::is_assignable<fit::function<BinaryOp>, Closure>::value, "");
1199
1200 static_assert(!std::is_convertible<ClosureWrongReturnType, fit::function<Closure>>::value, "");
1201 static_assert(!std::is_convertible<BinaryOpWrongReturnType, fit::function<BinaryOp>>::value, "");
1202 static_assert(!std::is_assignable<fit::function<Closure>, ClosureWrongReturnType>::value, "");
1203 static_assert(!std::is_assignable<fit::function<BinaryOp>, BinaryOpWrongReturnType>::value, "");
1204
1205 static_assert(!std::is_convertible<void, fit::function<Closure>>::value, "");
1206 static_assert(!std::is_convertible<void, fit::function<BinaryOp>>::value, "");
1207 static_assert(!std::is_assignable<void, fit::function<Closure>>::value, "");
1208 static_assert(!std::is_assignable<void, fit::function<BinaryOp>>::value, "");
1209
1210 static_assert(std::is_same<fit::function<BinaryOp>::result_type, int>::value, "");
1211 static_assert(std::is_same<fit::callback<BinaryOp>::result_type, int>::value, "");
1212 } // namespace test_conversions
1213
TEST(FunctionTests,closure_fit_function_Closure)1214 TEST(FunctionTests, closure_fit_function_Closure) { closure<fit::function<Closure>>(); }
TEST(FunctionTests,binary_op_fit_function_BinaryOp)1215 TEST(FunctionTests, binary_op_fit_function_BinaryOp) { binary_op<fit::function<BinaryOp>>(); }
TEST(FunctionTests,closure_fit_function_Closure_0u)1216 TEST(FunctionTests, closure_fit_function_Closure_0u) { closure<fit::function<Closure, 0u>>(); }
TEST(FunctionTests,binary_op_fit_function_BinaryOp_0u)1217 TEST(FunctionTests, binary_op_fit_function_BinaryOp_0u) {
1218 binary_op<fit::function<BinaryOp, 0u>>();
1219 }
TEST(FunctionTests,closure_fit_function_Closure_HugeCallableSize)1220 TEST(FunctionTests, closure_fit_function_Closure_HugeCallableSize) {
1221 closure<fit::function<Closure, HugeCallableSize>>();
1222 }
TEST(FunctionTests,binary_op_fit_function_BinaryOp_HugeCallableSize)1223 TEST(FunctionTests, binary_op_fit_function_BinaryOp_HugeCallableSize) {
1224 binary_op<fit::function<BinaryOp, HugeCallableSize>>();
1225 }
TEST(FunctionTests,closure_fit_inline_function_Closure_HugeCallableSize)1226 TEST(FunctionTests, closure_fit_inline_function_Closure_HugeCallableSize) {
1227 closure<fit::inline_function<Closure, HugeCallableSize>>();
1228 }
TEST(FunctionTests,binary_op_fit_inline_function_BinaryOp_HugeCallableSize)1229 TEST(FunctionTests, binary_op_fit_inline_function_BinaryOp_HugeCallableSize) {
1230 binary_op<fit::inline_function<BinaryOp, HugeCallableSize>>();
1231 }
TEST(FunctionTests,closure_fit_function_Closure_SingleObjectAllocator)1232 TEST(FunctionTests, closure_fit_function_Closure_SingleObjectAllocator) {
1233 closure<
1234 fit::function<Closure, fit::default_inline_target_size, SingleObjectAllocator<std::byte>>>();
1235 }
TEST(FunctionTests,binary_op_fit_function_BinaryOp_SingleObjectAllocator)1236 TEST(FunctionTests, binary_op_fit_function_BinaryOp_SingleObjectAllocator) {
1237 binary_op<
1238 fit::function<BinaryOp, fit::default_inline_target_size, SingleObjectAllocator<std::byte>>>();
1239 }
1240
TEST(FunctionTests,bind_return_reference)1241 TEST(FunctionTests, bind_return_reference) {
1242 struct TestClass {
1243 int& member() { return member_; }
1244 int member_ = 0;
1245 };
1246
1247 TestClass instance;
1248 // Ensure that references to the original values are returned, not copies.
1249 fit::function<int&()> func = fit::bind_member<&TestClass::member>(&instance);
1250 EXPECT_EQ(&func(), &instance.member_);
1251
1252 fit::function<int&()> func_deprecated = fit::bind_member(&instance, &TestClass::member);
1253 EXPECT_EQ(&func_deprecated(), &instance.member_);
1254 }
1255
1256 } // namespace
1257