Arene Base
Fundamental Utilities For Safety Critical C++
Loading...
Searching...
No Matches
scaled_unit.hpp
Go to the documentation of this file.
1#ifndef INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_UNITS_SCALED_UNIT_HPP_
2#define INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_UNITS_SCALED_UNIT_HPP_
3
4// parasoft-begin-suppress AUTOSAR-A7_1_5-a-2 "Trailing return syntax permitted by A7-1-5 Permit #1 v1.0.0"
5
6#include "arene/base/constraints/constraints.hpp"
7#include "arene/base/math/float_properties.hpp"
8#include "arene/base/stdlib_choice/cstdint.hpp"
9#include "arene/base/stdlib_choice/enable_if.hpp"
10#include "arene/base/stdlib_choice/initializer_list.hpp"
11#include "arene/base/stdlib_choice/is_floating_point.hpp"
12#include "arene/base/stdlib_choice/ratio.hpp"
13#include "arene/base/type_info/type_name_string.hpp"
14#include "arene/base/type_list/index_of.hpp"
15#include "arene/base/type_list/remove_nth.hpp"
16#include "arene/base/type_list/sort.hpp"
17#include "arene/base/type_traits/is_one_of.hpp"
18#include "arene/base/units/is_unit.hpp"
19#include "arene/base/units/quantity_unit.hpp"
20
21namespace arene {
22namespace base {
23
24namespace scaled_unit_detail {
25
26/// @brief Helper trait to check if the specified type is an instance of @c std::ratio
27/// @tparam Type the type to check
28template <typename Type>
29extern constexpr bool is_ratio_v = false;
30
31/// @brief Helper trait to check if the specified type is an instance of @c std::ratio
32/// @tparam Numerator the numerator of the ratio
33/// @tparam Denominator the denominator of the ratio
34template <std::intmax_t Numerator, std::intmax_t Denominator>
35extern constexpr bool is_ratio_v<std::ratio<Numerator, Denominator>> = true;
36
37/// @brief Helper trait to check if the specified type is an instance of @c std::ratio equivalent to 1
38/// @tparam Type the type to check
39template <typename Type, typename = constraints<>>
40extern constexpr bool is_identity_ratio_v = false;
41
42/// @brief Helper trait to check if the specified type is an instance of @c std::ratio equivalent to 1
43/// @tparam Type the type to check
44template <typename Type>
45extern constexpr bool is_identity_ratio_v<Type, constraints<std::enable_if_t<is_ratio_v<Type>>>> =
46 (Type::num == Type::den);
47
48/// @brief Helper trait to check for a valid floating point wrapper scale: the @c Type must be a class with a public
49/// floating point @c constexpr @c static data member named @c value that is not infinity, NaN, zero or subnormal
50/// @tparam Type the type to check
51template <typename Type, typename = constraints<>>
52extern constexpr bool is_floating_point_wrapper_scale_v = false;
53
54/// @brief Helper trait to check for a valid floating point wrapper scale: the @c Type must be a class with a public
55/// floating point @c constexpr @c static data member named @c value that is not infinity, NaN, zero or subnormal
56/// @tparam Type the type to check
57template <typename Type>
58extern constexpr bool is_floating_point_wrapper_scale_v<
59 Type,
60 constraints<
61 std::enable_if_t<std::is_floating_point<decltype(Type::value)>::value>,
62 std::enable_if_t<isnormal(Type::value)>>> = true;
63
64/// @brief Helper trait to check for a valid scale: either a ratio or a valid floating point wrapper
65/// @tparam Type the type to check
66template <typename Type>
67extern constexpr bool is_valid_scale_v = is_floating_point_wrapper_scale_v<Type> || is_ratio_v<Type>;
68
69/// @brief Implementation class that represents the inverse of a floating point wrapper scale
70/// @tparam Type the type to invert
71template <typename Type>
72class inverse_unit_scale {
73 public:
74 // parasoft-begin-suppress AUTOSAR-M11_0_1-a "This member is the public API"
75 /// @brief The resulting scale factor
76 static constexpr double value{1. / Type::value};
77 // parasoft-end-suppress AUTOSAR-M11_0_1-a
78};
79
80/// @brief Helper class to select the implementation of an inverse of a scale
81/// @tparam Type the type to invert
82template <typename Type, typename = constraints<>>
83class inverse_unit_scale_helper {
84 static_assert(is_floating_point_wrapper_scale_v<Type>, "The type being inverted must be a floating point wrapper");
85
86 public:
87 /// @brief A type representing the inverse scale
88 using type = inverse_unit_scale<Type>;
89};
90
91/// @brief Implementation class for a quantity unit that is another unit scaled by some scale factor
92/// @tparam BaseUnit the underlying unit
93/// @tparam Scale the scale factor
94template <typename BaseUnit, typename Scale>
95class scaled_unit_impl : public quantity_unit<scaled_unit_impl<BaseUnit, Scale>, typename BaseUnit::unit_kind_type> {
96 public:
97 /// @brief The scale factor
98 using scale_factor = Scale;
99 /// @brief Denotes that quantity kind is implicit and does not mark a
100 /// boundary when aggregating and simplifying quantity kind types.
101 using is_implicit = void;
102};
103
104/// @brief Implementation class determining the representation type for a quantity unit that is another unit scaled by
105/// some scale factor
106/// @tparam BaseUnit the underlying unit
107/// @tparam Scale the scale factor
108template <typename BaseUnit, typename Scale, typename = constraints<>>
109class scaled_unit_helper {
110 static_assert(is_unit_v<BaseUnit>, "The supplied BaseUnit must be a valid quantity unit");
111 static_assert(is_valid_scale_v<Scale>, "The scale factor must be a ratio or a class wrapping a floating point scale");
112
113 public:
114 /// @brief The type to use to represent the scaled unit
115 using type = scaled_unit_impl<BaseUnit, Scale>;
116};
117
118} // namespace scaled_unit_detail
119
120/// @brief Type alias for a quantity unit that is another unit scaled by some scale factor
121/// @tparam BaseUnit the underlying unit
122/// @tparam Scale the scale factor
123template <typename BaseUnit, typename Scale>
125
126/// @brief A type that represents the inverse of a scale factor
127/// @tparam Type the type to invert
128template <typename Type>
130
131namespace scaled_unit_detail {
132
133// parasoft-begin-suppress AUTOSAR-M3_3_2-a "False positive: inline function used in multiple translation units"
134/// @brief Helper function to get the scale value from a class wrapping a floating point scale
135/// @tparam Type the class wrapping the scale
136/// @return The scale factor
137template <typename Type, constraints<std::enable_if_t<std::is_floating_point<decltype(Type::value)>::value>> = nullptr>
138constexpr auto scale_value() noexcept -> double {
139 return Type::value;
140}
141// parasoft-end-suppress AUTOSAR-M3_3_2-a
142
143/// @brief Helper function to get the scale value from a ratio
144/// @tparam Type the ratio
145/// @return The scale factor
146template <typename Type, constraints<std::enable_if_t<is_ratio_v<Type>>> = nullptr>
147constexpr auto scale_value() noexcept -> double {
148 return static_cast<double>(Type::num) / static_cast<double>(Type::den);
149}
150
151/// @brief Helper function to get the resulting scale factor from a combination of scale factors
152/// @param values the scale factors being combined
153/// @return The combined scale factor
154inline constexpr auto combined_scale_value(std::initializer_list<double> values) noexcept -> double {
155 double scale{1.};
156 for (auto const elem : values) {
157 // Multiply all the scale factors together
158 scale *= elem;
159 }
160 return scale;
161}
162
163/// @brief A template representing a scale factor combined from multiple individual scale factors
164/// @tparam Scales the scale factors that are combined
165template <typename... Scales>
166class combined_scales {
167 public:
168 // parasoft-begin-suppress AUTOSAR-M11_0_1-a "This member is the public API"
169 /// @brief The numeric value of the combined scale factor
170 static constexpr double value{combined_scale_value({scale_value<Scales>()...})};
171 // parasoft-end-suppress AUTOSAR-M11_0_1-a
172};
173
174/// @brief Helper template for canonicalizing the result of combining scale factors, so empty lists are represented as
175/// an identity ratio, single element lists are represented as the list element, and multi-element lists have a
176/// consistent order
177/// @tparam Scales the scale factors being combined
178template <typename Scales>
179class canonicalize_scale {
180 public:
181 /// @brief The resulting scale factor type
182 using type = Scales;
183};
184
185/// @brief Helper template for canonicalizing the result of combining scale factors, so empty lists are represented as
186/// an identity ratio, single element lists are represented as the list element, and multi-element lists have a
187/// consistent order
188template <>
189class canonicalize_scale<combined_scales<>> {
190 public:
191 /// @brief The resulting scale factor type
192 using type = std::ratio<1, 1>;
193};
194
195/// @brief Helper template for canonicalizing the result of combining scale factors, so empty lists are represented as
196/// an identity ratio, single element lists are represented as the list element, and multi-element lists have a
197/// consistent order
198/// @tparam Scale the solitary scale factor in the list
199template <typename Scale>
200class canonicalize_scale<combined_scales<Scale>> {
201 public:
202 /// @brief The resulting scale factor type
203 using type = Scale;
204};
205
206/// @brief Helper template that compares two scale factors to determine which should be ordered before the other when
207/// combining.
208///
209/// There should be at most one ratio in a list being sorted with this predicate. The resulting sorted order places the
210/// ratio (if there is one) first, followed by the other entries in order of their type name.
211/// @tparam LhsScale The left-hand scale being compared
212/// @tparam RhsScale The right-hand scale being compared
213template <typename LhsScale, typename RhsScale>
214class scale_sorts_before {
215 public:
216 // parasoft-begin-suppress AUTOSAR-M11_0_1-a "This member is the public API"
217 // parasoft-begin-suppress CERT_CPP-DCL56-a "False positive: type_name_v is initialized"
218 /// @brief The result of the comparison
219 static constexpr bool value{
220 !is_ratio_v<RhsScale> && (is_ratio_v<LhsScale> || (type_name_v<LhsScale> < type_name_v<RhsScale>))
221 };
222 // parasoft-end-suppress CERT_CPP-DCL56-a
223 // parasoft-end-suppress AUTOSAR-M11_0_1-a
224};
225
226/// @brief Helper template for canonicalizing the result of combining scale factors, so empty lists are represented as
227/// an identity ratio, single element lists are represented as the list element, and multi-element lists have a
228/// consistent order
229///
230/// The ratio goes first if there is one, then the rest, ordered by type name
231/// @tparam Scales the combined scale factors
232template <typename... Scales>
233class canonicalize_scale<combined_scales<Scales...>> {
234 public:
235 /// @brief The resulting scale factor type
236 using type = type_lists::sort_t<combined_scales<Scales...>, scale_sorts_before>;
237};
238
239/// @brief Helper class for combining two scales
240/// @tparam Scale1 the first scale to combine
241/// @tparam Scale2 the second scale to combine
242template <typename Scale1, typename Scale2, typename = constraints<>>
243class combine_scales_helper {
244 public:
245 /// @brief The resulting scale factor type
246 using type = combined_scales<Scale1, Scale2>;
247};
248
249/// @brief Type alias for combining two scales. The result is a type that represents the product of the two scales
250/// @tparam Scale1 the first scale to combine
251/// @tparam Scale2 the second scale to combine
252template <typename Scale1, typename Scale2>
253using combine_scales_t = typename canonicalize_scale<typename combine_scales_helper<Scale1, Scale2>::type>::type;
254
255/// @brief Helper class for combining two scales. The result is a type that represents the product of the two scales
256/// @tparam Scale1 the first scale to combine
257/// @tparam Scale2 the second scale to combine
258///
259/// @details This is where they are both ratios; the result is equivalent to <c>std::ratio_multiply<Scale1,Scale2></c>
260template <typename Scale1, typename Scale2>
261class combine_scales_helper<
262 Scale1,
263 Scale2,
264 constraints<std::enable_if_t<is_ratio_v<Scale1>>, std::enable_if_t<is_ratio_v<Scale2>>>> {
265 public:
266 /// @brief The resulting scale factor type
267 using type = std::ratio_multiply<Scale1, Scale2>;
268};
269
270/// @brief Helper class for combining two scales. The result is a type that represents the product of the two scales
271/// @tparam Scale1 the first scale to combine
272/// @tparam Scale2 the second scale to combine
273///
274/// @details This is where the second is a ratio, but not the first: other code assumes ratios are first, so switch the
275/// order.
276template <typename Scale1, typename Scale2>
277class combine_scales_helper<
278 Scale1,
279 Scale2,
280 constraints<std::enable_if_t<!is_ratio_v<Scale1>>, std::enable_if_t<is_ratio_v<Scale2>>>> {
281 public:
282 /// @brief The resulting scale factor type
283 using type = combine_scales_t<Scale2, Scale1>;
284};
285
286/// @brief Helper class for combining two scales. The result is a type that represents the product of the two scales
287/// @tparam Scales1 the individual elements of the first scale to combine
288/// @tparam Scale2 the second scale to combine
289///
290/// @details This is where the first is already a combined scale
291template <typename... Scales1, typename Scale2>
292class combine_scales_helper<
293 combined_scales<Scales1...>,
294 Scale2,
295 constraints<
296 std::enable_if_t<!is_ratio_v<Scale2>>,
297 std::enable_if_t<!is_one_of_v<inverse_unit_scale_t<Scale2>, Scales1...>>>> {
298 public:
299 /// @brief The resulting scale factor type
300 using type = combined_scales<Scales1..., Scale2>;
301};
302
303/// @brief Helper class for combining two scales. The result is a type that represents the product of the two scales
304/// @tparam Scales1 the individual elements of the first scale to combine
305/// @tparam Scale2 the second scale to combine
306///
307/// @details This is where the first is already a combined scale and the second is an inverse of one of the elements
308template <typename... Scales1, typename Scale2>
309class combine_scales_helper<
310 combined_scales<Scales1...>,
311 Scale2,
312 constraints<
313 std::enable_if_t<!is_ratio_v<Scale2>>,
314 std::enable_if_t<is_one_of_v<inverse_unit_scale_t<Scale2>, Scales1...>>>> {
315 public:
316 /// @brief The resulting scale factor type
317 using type = type_lists::remove_nth_t<
318 combined_scales<Scales1...>,
319 type_lists::index_of_v<combined_scales<Scales1...>, inverse_unit_scale_t<Scale2>>>;
320};
321
322/// @brief Helper class for combining two scales. The result is a type that represents the product of the two scales
323/// @tparam Scale1 the first scale to combine
324/// @tparam FirstScale2 the first element of the second scale to combine
325/// @tparam OtherScales2 the remaining elements of the second scale to combine
326///
327/// @details This is where the first is a ratio, and the second does not have a ratio element
328template <typename Scale1, typename FirstScale2, typename... OtherScales2>
329class combine_scales_helper<
330 Scale1,
331 combined_scales<FirstScale2, OtherScales2...>,
332 constraints<
333 std::enable_if_t<is_ratio_v<Scale1>>,
334 std::enable_if_t<!is_identity_ratio_v<Scale1>>,
335 std::enable_if_t<!is_ratio_v<FirstScale2>>>> {
336 public:
337 /// @brief The resulting scale factor type
338 using type = combined_scales<Scale1, FirstScale2, OtherScales2...>;
339};
340
341/// @brief Helper class for combining two scales. The result is a type that represents the product of the two scales
342/// @tparam Scale1 the first scale to combine
343/// @tparam FirstScale2 the first element of the second scale to combine
344/// @tparam OtherScales2 the remaining elements of the second scale to combine
345///
346/// @details This is where the first is a ratio, and the second has a ratio element
347template <typename Scale1, typename FirstScale2, typename... OtherScales2>
348class combine_scales_helper<
349 Scale1,
350 combined_scales<FirstScale2, OtherScales2...>,
351 constraints<std::enable_if_t<is_ratio_v<Scale1>>, std::enable_if_t<is_ratio_v<FirstScale2>>>> {
352 public:
353 /// @brief The resulting scale factor type
354 using type = combine_scales_t<std::ratio_multiply<Scale1, FirstScale2>, combined_scales<OtherScales2...>>;
355};
356
357/// @brief Helper class for combining two scales. The result is a type that represents the product of the two scales
358/// @tparam Scale1 the first scale to combine
359/// @tparam Scales2 the elements of the second scale to combine
360///
361/// @details This is where the first is an identity ratio, and the second is a combined scale
362template <typename Scale1, typename... Scales2>
363class combine_scales_helper<
364 Scale1,
365 combined_scales<Scales2...>,
366 constraints<std::enable_if_t<is_identity_ratio_v<Scale1>>>> {
367 public:
368 /// @brief The resulting scale factor type
369 using type = combined_scales<Scales2...>;
370};
371
372/// @brief Implementation class for a quantity unit that is another unit scaled by some scale factor
373/// @tparam BaseUnit the underlying unit
374/// @tparam BaseScale the existing scale factor
375/// @tparam Scale the additional scale factor
376template <typename BaseUnit, typename BaseScale, typename Scale>
377class scaled_unit_helper<
378 scaled_unit_impl<BaseUnit, BaseScale>,
379 Scale,
380 constraints<std::enable_if_t<!is_identity_ratio_v<Scale>>>> {
381 static_assert(is_valid_scale_v<Scale>, "The scale factor must be a ratio or a class wrapping a floating point scale");
382
383 public:
384 /// @brief The type to use to represent the scaled unit
385 using type = scaled_unit<BaseUnit, combine_scales_t<BaseScale, Scale>>;
386};
387
388/// @brief Implementation class for a quantity unit that is another unit scaled by some scale factor
389/// @tparam BaseUnit the underlying unit
390/// @tparam Scale the scale factor
391///
392/// This is for the case that the @c Scale is a ratio of 1
393template <typename BaseUnit, typename Scale>
394class scaled_unit_helper<BaseUnit, Scale, constraints<std::enable_if_t<is_identity_ratio_v<Scale>>>> {
395 static_assert(is_unit_v<BaseUnit>, "The supplied BaseUnit must be a valid quantity unit");
396 static_assert(is_valid_scale_v<Scale>, "The scale factor must be a ratio or a class wrapping a floating point scale");
397
398 public:
399 /// @brief The type to use to represent the scaled unit
400 using type = BaseUnit;
401};
402
403/// @brief Helper class to select the implementation of an inverse of a scale
404/// @tparam Type the type to invert
405template <typename Type>
406class inverse_unit_scale_helper<Type, constraints<std::enable_if_t<is_ratio_v<Type>>>> {
407 public:
408 /// @brief A type representing the inverse scale
409 using type = std::ratio<Type::den, Type::num>;
410};
411
412/// @brief Helper class to select the implementation of an inverse of a scale
413/// @tparam Type the type to invert
414template <typename Type>
415class inverse_unit_scale_helper<inverse_unit_scale<Type>> {
416 public:
417 /// @brief A type representing the inverse scale
418 using type = Type;
419};
420
421} // namespace scaled_unit_detail
422
423} // namespace base
424} // namespace arene
425
426#endif // INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_UNITS_SCALED_UNIT_HPP_
Definition array_exceptions_disabled.cpp:11
Copyright 2026, Toyota Motor Corporation.
Definition array_exceptions_disabled.cpp:10