GCC Code Coverage Report


Directory: include/tts/
File: include/tts/tools/erased.hpp
Date: 2026-10-14 16:28:14
Exec Total Coverage
Lines: 40 40 100.0%
Functions: 171 199 85.9%
Branches: 7 10 70.0%

Line Branch Exec Source
1 //======================================================================================================================
2 /*
3 TTS - Tiny Test System
4 Copyright : TTS Contributors & Maintainers
5 SPDX-License-Identifier: BSL-1.0
6 */
7 //======================================================================================================================
8 #pragma once
9
10 #include <tts/tools/preprocessor.hpp>
11
12 namespace tts::_
13 {
14 template<typename Signature> struct erased;
15
16 //====================================================================================================================
17 // A callable of any signature, stored without knowing its type. std::function is not an option
18 // here, see doc/compile_time.hpp.
19 //====================================================================================================================
20 template<typename R, typename... Args> struct erased<R(Args...)> // NOSONAR - erasure needs void*
21 {
22 using signature_t = R (*)(void*, Args...);
23 using cleanup_t = void (*)(void*);
24
25 erased() = default;
26
27 // Optimized path for simple function pointers (used by TTS_CASE)
28 // Avoids template instantiation and heap allocation for stateless tests
29 238 erased(R (*f)(Args...)) // NOSONAR
30 238 : payload {reinterpret_cast<void*>(f)} // NOSONAR Type erasure
31 238 , cleanup {destroy_nothing}
32 238 , invoker {invoke_ptr}
33 {
34 238 }
35
36 // Copy/transfer the function as the unknown payload holding states
37 template<typename Function>
38 213 erased(Function f) // NOSONAR
39
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 146 times.
213 : payload {new Function {TTS_MOVE(f)}} // NOSONAR Type erasure
40 213 , cleanup {destroy<Function>}
41 213 , invoker {invoke<Function>}
42 {
43 213 }
44
45 539 erased(erased&& other) noexcept
46 539 : payload {other.payload}
47 539 , cleanup {other.cleanup}
48 539 , invoker {other.invoker}
49 {
50 539 other.payload = nullptr;
51 539 }
52
53 107 erased& operator=(erased&& other) noexcept
54 {
55
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 98 times.
107 if(payload) cleanup(payload);
56
57 107 payload = other.payload;
58 107 cleanup = other.cleanup;
59 107 invoker = other.invoker;
60 107 other.payload = nullptr;
61
62 107 return *this;
63 }
64
65 erased(erased const&) = delete;
66 erased& operator=(erased const&) = delete;
67
68 2232 ~erased()
69 {
70
2/2
✓ Branch 0 taken 379 times.
✓ Branch 1 taken 737 times.
2232 if(payload) cleanup(payload);
71 2232 }
72
73 580 R operator()(Args... args) const
74 {
75
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 290 times.
580 assert(payload);
76 580 return invoker(payload, args...);
77 }
78
79 24 explicit operator bool() const
80 {
81 24 return payload != nullptr;
82 }
83
84 void* payload = nullptr;
85 cleanup_t cleanup = nullptr;
86 signature_t invoker = nullptr;
87
88 private:
89 94 template<typename T> static R invoke(void* data, Args... args) // NOSONAR Type erasure
90 {
91 94 return (*static_cast<T*>(data))(args...);
92 }
93
94 244 static R invoke_ptr(void* data, Args... args) // NOSONAR Type erasure
95 {
96 244 return reinterpret_cast<R (*)(Args...)>(data)(args...); // NOSONAR Type erasure
97 }
98
99 213 template<typename T> static void destroy(void* data) // NOSONAR
100 {
101
1/2
✓ Branch 0 taken 146 times.
✗ Branch 1 not taken.
213 delete static_cast<T*>(data); // NOSONAR Type erasure: delete is safe
102 213 }
103
104 238 static void destroy_nothing(void*) // NOSONAR
105 {
106 // Nothing to free.
107 238 }
108 };
109
110 using callable = erased<void()>;
111 }
112