GCC Code Coverage Report


Directory: gridformat/
File: gridformat/common/type_traits.hpp
Date: 2024-11-10 16:24:00
Exec Total Coverage
Lines: 5 5 100.0%
Functions: 10 14 71.4%
Branches: 1 2 50.0%

Line Branch Exec Source
1 // SPDX-FileCopyrightText: 2022-2023 Dennis Gläser <dennis.glaeser@iws.uni-stuttgart.de>
2 // SPDX-License-Identifier: MIT
3 /*!
4 * \file
5 * \ingroup Common
6 * \brief Common type traits
7 */
8 #ifndef GRIDFORMAT_COMMON_TYPE_TRAITS_HPP_
9 #define GRIDFORMAT_COMMON_TYPE_TRAITS_HPP_
10
11 #include <span>
12 #include <array>
13 #include <ranges>
14 #include <variant>
15 #include <concepts>
16 #include <type_traits>
17 #include <algorithm>
18
19 #include <gridformat/common/exceptions.hpp>
20
21 namespace GridFormat {
22
23 //! \addtogroup Common
24 //! \{
25
26 struct Automatic {};
27 inline constexpr Automatic automatic;
28 template<typename T>
29 inline constexpr bool is_automatic = std::is_same_v<T, Automatic>;
30
31 struct None {};
32 inline constexpr None none;
33 template<typename T>
34 inline constexpr bool is_none = std::is_same_v<std::remove_cvref_t<T>, None>;
35
36 template<typename T>
37 struct IsScalar : public std::false_type {};
38 template<std::integral T>
39 struct IsScalar<T> : public std::true_type {};
40 template<std::floating_point T>
41 struct IsScalar<T> : public std::true_type {};
42
43 template<typename T>
44 inline constexpr bool is_scalar = IsScalar<T>::value;
45
46
47 template<typename T>
48 using LVReferenceOrValue = std::conditional_t<std::is_lvalue_reference_v<T>, T&, std::remove_cvref_t<T>>;
49
50
51 #ifndef DOXYGEN
52 namespace Detail {
53
54 template<std::integral auto v1>
55 inline constexpr bool all_equal() {
56 return true;
57 }
58
59 template<std::integral auto v1, std::integral auto v2, std::integral auto... vals>
60 inline constexpr bool all_equal() {
61 if constexpr (v1 == v2)
62 return all_equal<v2, vals...>();
63 else
64 return false;
65 }
66
67 } // namespace Detail
68 #endif // DOXYGEN
69
70 template<std::integral auto v1, std::integral auto... vals>
71 inline constexpr bool all_equal = Detail::all_equal<v1, vals...>();
72
73
74 #ifndef DOXYGEN
75 namespace Detail {
76
77 template<std::ranges::range R>
78 inline constexpr bool has_sub_range = std::ranges::range<std::ranges::range_value_t<R>>;
79
80 template<std::ranges::range R, typename Enable = void>
81 struct MDRangeValueType;
82
83 template<std::ranges::range R>
84 struct MDRangeValueType<R, std::enable_if_t<has_sub_range<R>>> {
85 using type = typename MDRangeValueType<std::ranges::range_value_t<R>>::type;
86 };
87
88 template<std::ranges::range R>
89 struct MDRangeValueType<R, std::enable_if_t<!has_sub_range<R>>> {
90 using type = std::ranges::range_value_t<R>;
91 };
92
93 template<std::ranges::range R, typename Enable = void>
94 struct MDRangeReferenceType;
95
96 template<std::ranges::range R>
97 struct MDRangeReferenceType<R, std::enable_if_t<has_sub_range<R>>> {
98 using type = typename MDRangeReferenceType<std::ranges::range_reference_t<R>>::type;
99 };
100
101 template<std::ranges::range R>
102 struct MDRangeReferenceType<R, std::enable_if_t<!has_sub_range<R>>> {
103 using type = std::ranges::range_reference_t<R>;
104 };
105
106 } // namespace Detail
107 #endif // DOXYGEN
108
109 template<std::ranges::range R>
110 using MDRangeValueType = typename Detail::MDRangeValueType<R>::type;
111
112 template<std::ranges::range R>
113 using MDRangeReferenceType = typename Detail::MDRangeReferenceType<R>::type;
114
115 template<std::ranges::range R> requires(is_scalar<MDRangeValueType<R>>)
116 using MDRangeScalar = MDRangeValueType<R>;
117
118 template<std::ranges::range R>
119 inline constexpr bool has_sub_range = Detail::has_sub_range<R>;
120
121
122 #ifndef DOXYGEN
123 namespace Detail {
124
125 template<std::ranges::range R, typename Enable = void>
126 struct MDRangeDimension;
127
128 template<std::ranges::range R>
129 struct MDRangeDimension<R, std::enable_if_t<Detail::has_sub_range<R>>> {
130 static constexpr std::size_t value = 1 + MDRangeDimension<std::ranges::range_value_t<R>>::value;
131 };
132
133 template<std::ranges::range R>
134 struct MDRangeDimension<R, std::enable_if_t<!Detail::has_sub_range<R>>> {
135 static constexpr std::size_t value = 1;
136 };
137
138 template<std::size_t i, std::size_t depth, std::ranges::range R>
139 struct MDRangeValueTypeAt;
140
141 template<std::size_t i, std::size_t depth, std::ranges::range R> requires(i < depth)
142 struct MDRangeValueTypeAt<i, depth, R> {
143 using type = typename MDRangeValueTypeAt<i+1, depth, std::ranges::range_value_t<R>>::type;
144 };
145
146 template<std::size_t i, std::size_t depth, std::ranges::range R> requires(i == depth)
147 struct MDRangeValueTypeAt<i, depth, R> {
148 using type = std::ranges::range_value_t<R>;
149 };
150
151 } // end namespace Detail
152 #endif // DOXYGEN
153
154 template<std::ranges::range R>
155 inline constexpr std::size_t mdrange_dimension = Detail::MDRangeDimension<R>::value;
156
157 template<std::size_t depth, std::ranges::range R> requires(depth < mdrange_dimension<R>)
158 using MDRangeValueTypeAt = typename Detail::MDRangeValueTypeAt<0, depth, R>::type;
159
160
161 #ifndef DOXYGEN
162 namespace Detail {
163
164 template<typename T, std::size_t s = sizeof(T)>
165 std::false_type is_incomplete(T*);
166 std::true_type is_incomplete(...);
167
168 } // end namespace Detail
169 #endif // DOXYGEN
170
171 template<typename T>
172 inline constexpr bool is_incomplete = decltype(Detail::is_incomplete(std::declval<T*>()))::value;
173
174 template<typename T>
175 inline constexpr bool is_complete = !is_incomplete<T>;
176
177 template<typename T, typename... Types>
178 inline constexpr bool is_any_of = (... or std::same_as<T, Types>);
179
180
181 #ifndef DOXYGEN
182 namespace Detail {
183
184 template<typename T, typename... Types>
185 struct UniqueVariant {
186 using type = std::conditional_t<
187 is_any_of<T, Types...>,
188 typename UniqueVariant<Types...>::type,
189 typename UniqueVariant<std::tuple<T>, Types...>::type
190 >;
191 };
192
193 template<typename T>
194 struct UniqueVariant<T> : public std::type_identity<std::variant<T>> {};
195
196 template<typename... Uniques>
197 struct UniqueVariant<std::tuple<Uniques...>> : public std::type_identity<std::variant<Uniques...>> {};
198
199 template<typename... Uniques, typename T, typename... Types>
200 struct UniqueVariant<std::tuple<Uniques...>, T, Types...> {
201 using type = std::conditional_t<
202 is_any_of<T, Uniques...>,
203 typename UniqueVariant<std::tuple<Uniques...>, Types...>::type,
204 typename UniqueVariant<std::tuple<Uniques..., T>, Types...>::type
205 >;
206 };
207
208 } // end namespace Detail
209 #endif // DOXYGEN
210
211 template<typename T, typename... Types>
212 using UniqueVariant = typename Detail::UniqueVariant<T, Types...>::type;
213
214
215 #ifndef DOXYGEN
216 namespace Detail {
217
218 template<typename T>
219 struct VariantOrClosure;
220 template<typename T, typename... Ts>
221 struct VariantOrClosure<std::variant<T, Ts...>> {
222 template<typename... _Ts>
223 using Variant = GridFormat::UniqueVariant<T, Ts..., _Ts...>;
224 };
225
226 template<typename T, typename... Types>
227 struct VariantOr {
228 using type = typename VariantOrClosure<T>::template Variant<Types...>;
229 };
230
231 } // namespace Detail
232 #endif // DOXYGEN
233
234 template<typename T, typename... Types>
235 using ExtendedVariant = typename Detail::VariantOr<T, Types...>::type;
236
237
238 #ifndef DOXYGEN
239 namespace Detail {
240
241 template<typename T>
242 struct MergedVariant;
243 template<typename... Ts>
244 struct MergedVariant<std::variant<Ts...>> {
245 template<typename T>
246 struct Closure;
247 template<typename... _Ts>
248 struct Closure<std::variant<_Ts...>> {
249 using type = GridFormat::ExtendedVariant<std::variant<Ts...>, _Ts...>;
250 };
251
252 template<typename V2>
253 using Variant = typename Closure<V2>::type;
254 };
255
256 } // namespace Detail
257 #endif // DOXYGEN
258
259 template<typename V1, typename V2>
260 using MergedVariant = typename Detail::MergedVariant<V1>::template Variant<V2>;
261
262
263 #ifndef DOXYGEN
264 namespace Detail {
265 template<typename Remove, typename Variant>
266 struct VariantWithoutSingleType;
267 template<typename Remove, typename T, typename... Ts>
268 struct VariantWithoutSingleType<Remove, std::variant<T, Ts...>> {
269 using type = std::conditional_t<
270 std::is_same_v<Remove, T>,
271 std::conditional_t<
272 sizeof...(Ts) == 0,
273 std::variant<>,
274 std::variant<Ts...>
275 >,
276 GridFormat::MergedVariant<
277 std::variant<T>,
278 typename VariantWithoutSingleType<Remove, std::variant<Ts...>>::type
279 >
280 >;
281 };
282 template<typename Remove>
283 struct VariantWithoutSingleType<Remove, std::variant<>> : public std::type_identity<std::variant<>> {};
284
285 template<typename Variant, typename... Remove>
286 struct VariantWithout;
287 template<typename... Ts>
288 struct VariantWithout<std::variant<Ts...>> : public std::type_identity<std::variant<Ts...>> {};
289 template<typename... Ts, typename R, typename... Remove>
290 struct VariantWithout<std::variant<Ts...>, R, Remove...> {
291 using type = typename VariantWithout<
292 typename VariantWithoutSingleType<R, std::variant<Ts...>>::type,
293 Remove...
294 >::type;
295 };
296
297 } // namespace Detail
298 #endif // DOXYGEN
299
300 template<typename T, typename... Remove>
301 using ReducedVariant = typename Detail::VariantWithout<T, Remove...>::type;
302
303
304 #ifndef DOXYGEN
305 namespace Detail {
306
307 template<typename T>
308 struct FieldScalar;
309
310 template<typename T> requires(is_scalar<T>)
311 struct FieldScalar<T> : public std::type_identity<T> {};
312
313 template<std::ranges::range R> requires(is_scalar<MDRangeScalar<R>>)
314 struct FieldScalar<R> : public std::type_identity<MDRangeScalar<R>> {};
315
316 } // end namespace Detail
317 #endif // DOXYGEN
318
319 template<typename T>
320 using FieldScalar = typename Detail::FieldScalar<T>::type;
321
322
323 #ifndef DOXYGEN
324 namespace Detail {
325
326 template<typename T>
327 concept HasStaticSizeFunction = requires {
328 { T::size() } -> std::convertible_to<std::size_t>;
329 { std::integral_constant<std::size_t, T::size()>{} };
330 };
331
332 template<typename T>
333 concept HasStaticSizeMember = requires {
334 { T::size } -> std::convertible_to<std::size_t>;
335 { std::integral_constant<std::size_t, T::size>{} };
336 };
337
338 } // namespace Detail
339 #endif // DOXYGEN
340
341 namespace Traits {
342
343 template<typename T>
344 struct StaticSize;
345 template<typename T, std::size_t s>
346 struct StaticSize<std::array<T, s>> {
347 static constexpr std::size_t value = s;
348 };
349 template<typename T, std::size_t s> requires(s != std::dynamic_extent)
350 struct StaticSize<std::span<T, s>> {
351 static constexpr std::size_t value = s;
352 };
353 template<typename T, std::size_t s>
354 struct StaticSize<T[s]> {
355 static constexpr std::size_t value = s;
356 };
357 template<Detail::HasStaticSizeMember T>
358 struct StaticSize<T> {
359 static constexpr std::size_t value = T::size;
360 };
361 template<Detail::HasStaticSizeFunction T>
362 struct StaticSize<T> {
363 static constexpr std::size_t value = T::size();
364 };
365 template<typename T> requires(is_complete<StaticSize<std::remove_const_t<T>>>)
366 struct StaticSize<T&> : public StaticSize<std::remove_const_t<T>> {};
367
368 } // namespace Traits
369
370 template<typename T>
371 inline constexpr std::size_t static_size = Traits::StaticSize<T>::value;
372
373 template<typename T>
374 inline constexpr bool has_static_size = is_complete<Traits::StaticSize<T>>;
375
376
377 #ifndef DOXYGEN
378 namespace Detail {
379 template<std::ranges::range T> requires(has_static_size<T>)
380 538 constexpr T make_range(std::ranges::range_value_t<T> value) {
381 T result;
382
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
538 std::ranges::fill(result, value);
383 538 return result;
384 }
385 } // namespace Detail
386 #endif // DOXYGEN
387
388 template<typename T>
389 struct DefaultValue;
390
391 template<typename T> requires(is_scalar<T>)
392 struct DefaultValue<T> {
393 17137 static constexpr T get() { return T{0}; }
394 };
395
396 template<std::ranges::range T> requires(has_static_size<T>)
397 struct DefaultValue<T> {
398 538 static constexpr T get() { return Detail::make_range<T>(DefaultValue<std::ranges::range_value_t<T>>::get()); }
399 };
400
401 // only available if the default value trait provides a constexpr get function
402 template<typename T>
403 inline constexpr T default_value = DefaultValue<T>::get();
404
405 //! \} group Common
406
407 } // end namespace GridFormat
408
409 #endif // GRIDFORMAT_COMMON_TYPE_TRAITS_HPP_
410