GCC Code Coverage Report


Directory: include/sumty/
File: include/sumty/detail/auto_union.hpp
Date: 2024-04-28 13:27:51
Exec Total Coverage
Lines: 45 45 100.0%
Functions: 328 431 76.1%
Branches: 0 0 -%
Decisions: 0 0 -%

Line Branch Decision Exec Source
1 /* Copyright 2023 Jack A Bernard Jr.
2 *
3 * Licensed under the Apache License, Version 2.0 (the License);
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an AS IS BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef SUMTY_DETAIL_AUTO_UNION_HPP
17 #define SUMTY_DETAIL_AUTO_UNION_HPP
18
19 #include "sumty/detail/traits.hpp"
20 #include "sumty/detail/utils.hpp"
21 #include "sumty/utils.hpp" // IWYU pragma: keep
22
23 #include <cstddef>
24 #include <memory>
25 #include <type_traits>
26 #include <utility>
27
28 // NOLINTBEGIN(cert-oop54-cpp)
29 // NOLINTBEGIN(bugprone-unhandled-self-assignment)
30
31 namespace sumty::detail {
32
33 template <typename... T>
34 union auto_union;
35
36 template <>
37 union auto_union<> {
38 constexpr auto_union() noexcept {}
39
40 constexpr auto_union([[maybe_unused]] const auto_union& other) noexcept {}
41
42 constexpr auto_union([[maybe_unused]] auto_union&& other) noexcept {}
43
44 constexpr ~auto_union() noexcept {}
45
46 constexpr auto_union& operator=([[maybe_unused]] const auto_union& rhs) noexcept {
47 return *this;
48 }
49
50 constexpr auto_union& operator=([[maybe_unused]] auto_union&& rhs) noexcept {
51 return *this;
52 }
53 };
54
55 template <typename T0, typename... TN>
56 union auto_union<T0, TN...> {
57 SUMTY_NO_UNIQ_ADDR std::remove_const_t<T0> head_;
58 SUMTY_NO_UNIQ_ADDR auto_union<TN...> tail_;
59
60 171 constexpr auto_union() noexcept {}
61
62 constexpr auto_union([[maybe_unused]] const auto_union& other) noexcept {}
63
64 constexpr auto_union([[maybe_unused]] auto_union&& other) noexcept {}
65
66 171 constexpr ~auto_union() noexcept {}
67
68 constexpr auto_union& operator=([[maybe_unused]] const auto_union& rhs) noexcept {
69 return *this;
70 }
71
72 constexpr auto_union& operator=([[maybe_unused]] auto_union&& rhs) noexcept {
73 return *this;
74 }
75
76 template <size_t IDX>
77 [[nodiscard]] constexpr typename traits<select_t<IDX, T0, TN...>>::reference
78 488 get() noexcept {
79 if constexpr (IDX == 0) {
80 420 return head_;
81 } else {
82 68 return tail_.template get<IDX - 1>();
83 }
84 }
85
86 template <size_t IDX>
87 260 [[nodiscard]] constexpr typename traits<select_t<IDX, T0, TN...>>::const_reference get()
88 const noexcept {
89 if constexpr (IDX == 0) {
90 230 return head_;
91 } else {
92 30 return tail_.template get<IDX - 1>();
93 }
94 }
95
96 template <size_t IDX, typename... Args>
97 438 void construct(Args&&... args) {
98 if constexpr (IDX == 0) {
99 366 std::construct_at(&head_, std::forward<Args>(args)...);
100 } else {
101 72 tail_.template construct<IDX - 1>(std::forward<Args>(args)...);
102 }
103 438 }
104
105 template <size_t IDX>
106 438 void destroy() {
107 if constexpr (IDX == 0) {
108 366 std::destroy_at(&head_);
109 } else {
110 72 tail_.template destroy<IDX - 1>();
111 }
112 438 }
113 };
114
115 template <typename T0, typename... TN>
116 union auto_union<T0&&, TN...> {
117 SUMTY_NO_UNIQ_ADDR std::remove_const_t<T0> head_;
118 SUMTY_NO_UNIQ_ADDR auto_union<TN...> tail_;
119
120 constexpr auto_union() noexcept {}
121
122 constexpr auto_union([[maybe_unused]] const auto_union& other) noexcept {}
123
124 constexpr auto_union([[maybe_unused]] auto_union&& other) noexcept {}
125
126 constexpr ~auto_union() noexcept {}
127
128 constexpr auto_union& operator=([[maybe_unused]] const auto_union& rhs) noexcept {
129 return *this;
130 }
131
132 constexpr auto_union& operator=([[maybe_unused]] auto_union&& rhs) noexcept {
133 return *this;
134 }
135
136 template <size_t IDX>
137 [[nodiscard]] constexpr typename traits<select_t<IDX, T0, TN...>>::reference
138 get() noexcept {
139 if constexpr (IDX == 0) {
140 return head_;
141 } else {
142 return tail_.template get<IDX - 1>();
143 }
144 }
145
146 template <size_t IDX>
147 [[nodiscard]] constexpr typename traits<select_t<IDX, T0, TN...>>::const_reference get()
148 const noexcept {
149 if constexpr (IDX == 0) {
150 return head_;
151 } else {
152 return tail_.template get<IDX - 1>();
153 }
154 }
155
156 template <size_t IDX, typename... Args>
157 void construct(Args&&... args) {
158 if constexpr (IDX == 0) {
159 std::construct_at(&head_, std::forward<Args>(args)...);
160 } else {
161 tail_.template construct<IDX - 1>(std::forward<Args>(args)...);
162 }
163 }
164
165 template <size_t IDX>
166 void destroy() {
167 if constexpr (IDX == 0) {
168 std::destroy_at(&head_);
169 } else {
170 tail_.template destroy<IDX - 1>();
171 }
172 }
173 };
174
175 template <typename T0, typename... TN>
176 union auto_union<T0&, TN...> {
177 T0* head_;
178 SUMTY_NO_UNIQ_ADDR auto_union<TN...> tail_;
179
180 26 constexpr auto_union() noexcept {}
181
182 constexpr auto_union([[maybe_unused]] const auto_union& other) noexcept {}
183
184 constexpr auto_union([[maybe_unused]] auto_union&& other) noexcept {}
185
186 26 constexpr ~auto_union() noexcept {}
187
188 constexpr auto_union& operator=([[maybe_unused]] const auto_union& rhs) noexcept {
189 return *this;
190 }
191
192 constexpr auto_union& operator=([[maybe_unused]] auto_union&& rhs) noexcept {
193 return *this;
194 }
195
196 template <size_t IDX>
197 [[nodiscard]] constexpr typename traits<select_t<IDX, T0&, TN...>>::reference
198 256 get() noexcept {
199 if constexpr (IDX == 0) {
200 166 return *head_;
201 } else {
202 90 return tail_.template get<IDX - 1>();
203 }
204 }
205
206 template <size_t IDX>
207 [[nodiscard]] constexpr typename traits<select_t<IDX, T0&, TN...>>::const_reference
208 46 get() const noexcept {
209 if constexpr (IDX == 0) {
210 20 return *head_;
211 } else {
212 26 return tail_.template get<IDX - 1>();
213 }
214 }
215
216 template <size_t IDX, typename... Args>
217 128 void construct([[maybe_unused]] Args&&... args) {
218 if constexpr (IDX == 0) {
219 if constexpr (!std::is_base_of_v<never,
220 std::remove_cvref_t<first_t<Args...>>>) {
221 78 head_ = std::addressof(std::forward<Args>(args)...);
222 }
223 } else {
224 50 tail_.template construct<IDX - 1>(std::forward<Args>(args)...);
225 }
226 128 }
227
228 template <size_t IDX>
229 120 void destroy() {
230 50 if constexpr (IDX != 0) { tail_.template destroy<IDX - 1>(); }
231 120 }
232 };
233
234 template <typename... TN>
235 union auto_union<void, TN...> {
236 SUMTY_NO_UNIQ_ADDR auto_union<TN...> tail_;
237
238 242 constexpr auto_union() noexcept {}
239
240 constexpr auto_union([[maybe_unused]] const auto_union& other) noexcept {}
241
242 constexpr auto_union([[maybe_unused]] auto_union&& other) noexcept {}
243
244 242 constexpr ~auto_union() noexcept {}
245
246 constexpr auto_union& operator=([[maybe_unused]] const auto_union& rhs) noexcept {
247 return *this;
248 }
249
250 constexpr auto_union& operator=([[maybe_unused]] auto_union&& rhs) noexcept {
251 return *this;
252 }
253
254 template <size_t IDX>
255 [[nodiscard]] constexpr typename traits<select_t<IDX, void, TN...>>::reference
256 388 get() noexcept {
257 if constexpr (IDX != 0) {
258 376 return tail_.template get<IDX - 1>();
259 } else {
260 12 return;
261 }
262 }
263
264 template <size_t IDX>
265 [[nodiscard]] constexpr typename traits<select_t<IDX, void, TN...>>::const_reference
266 170 get() const noexcept {
267 if constexpr (IDX != 0) {
268 168 return tail_.template get<IDX - 1>();
269 } else {
270 2 return;
271 }
272 }
273
274 template <size_t IDX, typename... Args>
275 398 void construct([[maybe_unused]] Args&&... args) {
276 if constexpr (IDX != 0) {
277 232 tail_.template construct<IDX - 1>(std::forward<Args>(args)...);
278 }
279 398 }
280
281 template <size_t IDX>
282 384 void destroy() {
283 224 if constexpr (IDX != 0) { tail_.template destroy<IDX - 1>(); }
284 384 }
285 };
286
287 template <typename... TN>
288 union auto_union<never, TN...> {
289 SUMTY_NO_UNIQ_ADDR auto_union<TN...> tail_;
290
291 constexpr auto_union() noexcept {}
292
293 constexpr auto_union([[maybe_unused]] const auto_union& other) noexcept {}
294
295 constexpr auto_union([[maybe_unused]] auto_union&& other) noexcept {}
296
297 constexpr ~auto_union() noexcept {}
298
299 constexpr auto_union& operator=([[maybe_unused]] const auto_union& rhs) noexcept {
300 return *this;
301 }
302
303 constexpr auto_union& operator=([[maybe_unused]] auto_union&& rhs) noexcept {
304 return *this;
305 }
306
307 template <size_t IDX>
308 [[nodiscard]] constexpr typename traits<select_t<IDX, never, TN...>>::reference
309 get() noexcept { // NOLINT(bugprone-exception-escape)
310 if constexpr (IDX != 0) {
311 if (std::is_constant_evaluated()) {
312 throw 0; // NOLINT(hicpp-exception-baseclass)
313 } else {
314 void* ptr = nullptr;
315 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
316 return *reinterpret_cast<never*>(ptr);
317 }
318 } else {
319 return;
320 }
321 }
322
323 template <size_t IDX>
324 [[nodiscard]] constexpr typename traits<select_t<IDX, never, TN...>>::const_reference
325 get() const noexcept { // NOLINT(bugprone-exception-escape)
326 if constexpr (IDX != 0) {
327 if (std::is_constant_evaluated()) {
328 throw 0; // NOLINT(hicpp-exception-baseclass)
329 } else {
330 const void* ptr = nullptr;
331 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
332 return *reinterpret_cast<const never*>(ptr);
333 }
334 } else {
335 return;
336 }
337 }
338
339 template <size_t IDX, typename... Args>
340 void construct([[maybe_unused]] Args&&... args) {
341 if constexpr (IDX == 0) {
342 // This is done in hopes that the compile error will better
343 // explain what went wrong. `never` can't be instantiated,
344 // so this should hopefully cause an error that says as much.
345 [[maybe_unused]] never value{std::forward<Args>(args)...};
346 } else {
347 tail_.template construct<IDX - 1>(std::forward<Args>(args)...);
348 }
349 }
350
351 template <size_t IDX>
352 void destroy() {
353 if constexpr (IDX != 0) { tail_.template destroy<IDX - 1>(); }
354 }
355 };
356
357 } // namespace sumty::detail
358
359 // NOLINTEND(bugprone-unhandled-self-assignment)
360 // NOLINTEND(cert-oop54-cpp)
361
362 #endif
363