Arene Base
Fundamental Utilities For Safety Critical C++
Loading...
Searching...
No Matches
quantity.hpp
Go to the documentation of this file.
1// Copyright 2024, Toyota Motor Corporation
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4
5#ifndef INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_UNITS_QUANTITY_HPP_
6#define INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_UNITS_QUANTITY_HPP_
7
8// IWYU pragma: private, include "arene/base/units.hpp"
9// IWYU pragma: friend "(arene/base(?!/tests)|stdlib/include/stdlib_detail)/.*"
10
11// parasoft-begin-suppress AUTOSAR-A16_2_2-a-2 "Arene Base aggregate headers permitted by A16-2-2 Permit #1"
12
13#include "arene/base/compare/compare_three_way.hpp"
14#include "arene/base/compare/operators.hpp"
15#include "arene/base/compare/strong_ordering.hpp"
16#include "arene/base/constraints/constraints.hpp"
17#include "arene/base/contracts/contract.hpp"
18#include "arene/base/math/abs.hpp"
19#include "arene/base/math/gcd.hpp"
20#include "arene/base/stdlib_choice/common_type.hpp"
21#include "arene/base/stdlib_choice/cstdint.hpp"
22#include "arene/base/stdlib_choice/enable_if.hpp"
23#include "arene/base/stdlib_choice/is_integral.hpp"
24#include "arene/base/stdlib_choice/is_same.hpp"
25#include "arene/base/stdlib_choice/is_signed.hpp"
26#include "arene/base/stdlib_choice/is_unsigned.hpp"
27#include "arene/base/stdlib_choice/make_unsigned.hpp"
28#include "arene/base/stdlib_choice/move.hpp"
29#include "arene/base/stdlib_choice/numeric_limits.hpp"
30#include "arene/base/stdlib_choice/ratio.hpp"
31#include "arene/base/type_traits/always_false.hpp"
32#include "arene/base/units/units_conversion_traits.hpp"
33// parasoft-end-suppress AUTOSAR-A16_2_2-a-2
34
35namespace arene {
36namespace base {
37
38// IWYU pragma: begin_keep
39template <typename QuantityType, typename Rep = double>
40class quantity;
41// IWYU pragma: end_keep
42
43namespace quantity_detail {
44/// @brief Boolean variable that is @c true if the supplied type is an instantiation of @c quantity, @c false otherwise
45/// @tparam T The type to check
46template <typename T>
47extern constexpr bool is_quantity_v = false;
48
49/// @brief Specialization of a boolean variable for the case where the supplied type is an instantiation of @c quantity.
50/// Always @c true
51/// @tparam QuantityType The physical unit type for the quantity
52/// @tparam Rep The representation type for the quantity
53template <typename QuantityType, typename Rep>
54extern constexpr bool is_quantity_v<quantity<QuantityType, Rep>> = true;
55
56} // namespace quantity_detail
57
58/// @brief Traits class with information about if and how a physical unit of type @c QuantityType1 can be combined with
59/// a physical unit of type @c QuantityType2.
60///
61/// The physical unit types themselves are just tags used for the @c quantity class template rather than holding any
62/// values directly.
63///
64/// By default only addition and subtraction of identical quantity types are permitted.
65///
66/// Specializations may provide a @c sum_type type alias, specifying the physical unit type for the result of adding a
67/// quantity with the a physical unit type of @c QuantityType1 to a quantity with a physical unit type of @c
68/// QuantityType2
69///
70/// Specializations may provide a @c difference_type type alias, specifying the physical unit type for the result of
71/// subtracting a quantity with the a physical unit type of @c QuantityType2 from a quantity with a physical unit type
72/// of @c QuantityType1
73///
74/// Specializations may provide a @c product_type type alias, specifying the physical unit type for the result of
75/// multiplying a quantity with the a physical unit type of @c QuantityType1 by a quantity with a physical unit type of
76/// @c QuantityType2
77///
78/// Specializations may provide a @c ratio_type type alias, specifying the physical unit type for the result of
79/// dividing a quantity with the a physical unit type of @c QuantityType1 by a quantity with a physical unit type of
80/// @c QuantityType2
81///
82/// @tparam QuantityType1 The quantity type for the left-hand operand of an operation
83/// @tparam QuantityType2 The quantity type for the righ-hand operand of an operation
84template <typename QuantityType1, typename QuantityType2>
86
87/// @brief Specialization to allow addition and subtraction of a quantity type from itself
88/// @tparam QuantityType The quantity type for the operands of an operation
89template <typename QuantityType>
90struct units_combination_traits<QuantityType, QuantityType> {
91 /// @brief The physical quantity type resulting from adding quantities with a physical quantity type of @c
92 /// QuantityType
93 using sum_type = QuantityType;
94 /// @brief The physical quantity type resulting from subtracting quantities with a physical quantity type of @c
95 /// QuantityType
96 using difference_type = QuantityType;
97};
98
99namespace quantity_detail {
100/// @brief Obtain the absolute value of a signed integer, as the corresponding unsigned type, thus allowing the absolute
101/// value of the negative limit to be represented.
102/// @tparam T The type of the integer
103/// @param value The value for which the absolute value is required
104/// @return std::make_unsigned_t<T> holding the absolute value of the argument
105template <typename T, constraints<std::enable_if_t<std::is_signed<T>::value>> = nullptr>
106constexpr auto unsigned_abs(T value) noexcept -> std::make_unsigned_t<T> {
107 if (value == std::numeric_limits<T>::min()) {
108 constexpr std::make_unsigned_t<T> abs_min{static_cast<std::make_unsigned_t<T>>(std::numeric_limits<T>::max()) + 1U};
109 return abs_min;
110 }
111 return static_cast<std::make_unsigned_t<T>>(arene::base::abs(value));
112}
113
114/// @brief Obtain the absolute value of an unsigned integer, which is just the identity operation
115/// @tparam T The type of the integer
116/// @param value The value for which the absolute value is required
117/// @return T @c value
118template <typename T, constraints<std::enable_if_t<std::is_unsigned<T>::value>> = nullptr>
119constexpr auto unsigned_abs(T value) noexcept -> T {
120 return value;
121}
122
123/// @brief Overload of @c scale_value_by for scaling a value into an unsigned integer target by a signed scale factor,
124/// which causes a compilation error
125/// @tparam ScaleFactor The scale factor
126/// @tparam TargetRep The target representation
127/// @tparam Rep The source representation
128/// @param value The value to scale
129/// @return TargetRep Never returns due to compilation error triggered by @c static_assert
130template <
131 typename ScaleFactor,
132 typename TargetRep,
133 typename Rep,
134 constraints<
135 std::enable_if_t<std::is_unsigned<TargetRep>::value>,
136 std::enable_if_t<((ScaleFactor::num < 0) != (ScaleFactor::den < 0))>> = nullptr>
137constexpr auto scale_value_by(Rep value) noexcept -> TargetRep {
138 constexpr bool unsigned_scaled_by_positive_factor = always_false_v<ScaleFactor>;
139 static_assert(
140 unsigned_scaled_by_positive_factor,
141 "Scaling a value by a negative scale factor may yield a negative result that cannot be represented in "
142 "an unsigned field"
143 );
144 return static_cast<TargetRep>(value);
145}
146
147/// @brief Overload of @c scale_value_by for scaling a value by a positive scale factor into an unsigned integer target
148/// representation, where the value may overflow the target representation, which causes a compilation error
149/// @tparam ScaleFactor The scale factor
150/// @tparam TargetRep The target representation
151/// @tparam Rep The source representation
152/// @param value The value to scale
153/// @return TargetRep Never returns due to compilation error triggered by @c static_assert
154template <
155 typename ScaleFactor,
156 typename TargetRep,
157 typename Rep,
158 constraints<
159 std::enable_if_t<std::is_unsigned<TargetRep>::value>, //
160 std::enable_if_t<std::is_integral<Rep>::value>,
161 std::enable_if_t<
162 (static_cast<std::uint64_t>(std::numeric_limits<Rep>::max()) >
163 (std::numeric_limits<std::uint64_t>::max() / unsigned_abs(ScaleFactor::num)))>,
164 std::enable_if_t<((ScaleFactor::num < 0) == (ScaleFactor::den < 0))>> = nullptr>
165constexpr auto scale_value_by(Rep value) noexcept -> TargetRep {
166 constexpr bool scaling_calculation_does_not_overflow = always_false_v<ScaleFactor>;
167 static_assert(
168 scaling_calculation_does_not_overflow,
169 "The scaling calculation will overflow internally; please use a floating point representation"
170 );
171 return static_cast<TargetRep>(value);
172}
173
174/// @brief Scale an integral value by a positive scale factor into an unsigned integer target representation, where the
175/// value is guaranteed not to overflow the target representation
176/// @tparam ScaleFactor The scale factor
177/// @tparam TargetRep The target representation
178/// @tparam Rep The source representation
179/// @param value The value to scale
180/// @return TargetRep @c value scaled by @c ScaleFactor
181template <
182 typename ScaleFactor,
183 typename TargetRep,
184 typename Rep,
185 constraints<
186 std::enable_if_t<std::is_unsigned<TargetRep>::value>, //
187 std::enable_if_t<std::is_integral<Rep>::value>, //
188 std::enable_if_t<ScaleFactor::den != 0>,
189 std::enable_if_t<
190 (static_cast<std::uint64_t>(std::numeric_limits<Rep>::max()) <=
191 (std::numeric_limits<std::uint64_t>::max() / unsigned_abs(ScaleFactor::num)))>,
192 std::enable_if_t<((ScaleFactor::num < 0) == (ScaleFactor::den < 0))>> = nullptr>
193constexpr auto scale_value_by(Rep value) noexcept -> TargetRep {
194 if (value == Rep{}) {
195 return static_cast<TargetRep>(value);
196 }
197 std::uintmax_t const initial_value{value};
198 constexpr auto unsigned_den = quantity_detail::unsigned_abs(ScaleFactor::den);
199 constexpr auto unsigned_num = quantity_detail::unsigned_abs(ScaleFactor::num);
200 auto const initial_gcd = gcd(initial_value, unsigned_den);
201 auto const den = unsigned_den / initial_gcd;
202 auto const smaller_value = initial_value / initial_gcd;
203 // NOLINTNEXTLINE(clang-analyzer-core.DivideZero)
204 auto const initial_result = (smaller_value / den) * unsigned_num;
205 auto const remainder = smaller_value % den;
206 auto const final_result = initial_result + remainder * unsigned_num / den;
207 ARENE_INVARIANT(final_result <= static_cast<std::uint64_t>(std::numeric_limits<TargetRep>::max()));
208 return static_cast<TargetRep>(final_result);
209}
210
211/// @brief Scale a signed integral value into a signed integer target representation
212/// @tparam ScaleFactor The scale factor
213/// @tparam TargetRep The target representation
214/// @tparam Rep The source representation
215/// @param value The value to scale
216/// @return TargetRep @c value scaled by @c ScaleFactor
217template <
218 typename ScaleFactor,
219 typename TargetRep,
220 typename Rep,
221 constraints<
222 std::enable_if_t<std::is_integral<TargetRep>::value>, //
223 std::enable_if_t<std::is_integral<Rep>::value>, //
224 std::enable_if_t<std::is_signed<TargetRep>::value>, //
225 std::enable_if_t<std::is_signed<Rep>::value>> = nullptr>
226constexpr auto scale_value_by(Rep value) noexcept -> TargetRep {
227 constexpr bool sign_flipped{(ScaleFactor::num < 0) != (ScaleFactor::den < 0)};
228 bool const value_is_negative{value < static_cast<Rep>(0)};
229 bool const result_is_negative{sign_flipped != value_is_negative};
230 constexpr auto unsigned_den = quantity_detail::unsigned_abs(ScaleFactor::den);
231 constexpr auto unsigned_num = quantity_detail::unsigned_abs(ScaleFactor::num);
232 auto const unsigned_result = scale_value_by<std::ratio<unsigned_num, unsigned_den>, std::make_unsigned_t<TargetRep>>(
233 quantity_detail::unsigned_abs(value)
234 );
235 if (result_is_negative) {
236 ARENE_INVARIANT(unsigned_result <= quantity_detail::unsigned_abs(std::numeric_limits<TargetRep>::min()));
237 return static_cast<TargetRep>(-static_cast<std::int64_t>(unsigned_result));
238 }
239 ARENE_INVARIANT(
240 unsigned_result <= static_cast<std::make_unsigned_t<TargetRep>>(std::numeric_limits<TargetRep>::max())
241 );
242 return static_cast<TargetRep>(unsigned_result);
243}
244
245/// @brief Scale a value from one representation to another, where either the source or target is non-integral
246/// @tparam ScaleFactor The scale factor
247/// @tparam TargetRep The target representation
248/// @tparam Rep The source representation
249/// @param value The value to scale
250/// @return TargetRep @c value scaled by @c ScaleFactor
251template <
252 typename ScaleFactor,
253 typename TargetRep,
254 typename Rep,
255 constraints<std::enable_if_t<!std::is_integral<Rep>::value || !std::is_integral<TargetRep>::value>> = nullptr>
256constexpr auto scale_value_by(Rep value) noexcept -> TargetRep {
257 using intermediate_type = typename std::common_type<TargetRep, Rep>::type;
258 intermediate_type const scaled_intermediate{
259 static_cast<intermediate_type>(value) * static_cast<intermediate_type>(ScaleFactor::num) /
260 static_cast<intermediate_type>(ScaleFactor::den)
261 };
262 return static_cast<TargetRep>(scaled_intermediate);
263}
264
265/// @brief Constant indicating if there is a common type to use when converting from @c SourceQuantityType to @c
266/// TargetQuantityType.
267///
268/// @tparam SourceQuantityType The physical quantity type of the source
269/// @tparam TargetQuantityType The physical quantity type of the target
270///
271/// The value is @c true if there is, @c false otherwise
272template <typename SourceQuantityType, typename TargetQuantityType, typename = constraints<>>
273extern constexpr bool has_common_type_specified_v = false;
274
275/// @brief Constant indicating if there is a common type to use when converting from @c SourceQuantityType to @c
276/// TargetQuantityType.
277///
278/// @tparam SourceQuantityType The physical quantity type of the source
279/// @tparam TargetQuantityType The physical quantity type of the target
280///
281/// The value is @c true if there is, @c false otherwise. This specialization handles the case where @c
282/// units_conversion_traits specifies a common type
283template <typename SourceQuantityType, typename TargetQuantityType>
284extern constexpr bool has_common_type_specified_v<
285 SourceQuantityType,
286 TargetQuantityType,
287 constraints<typename units_conversion_traits<SourceQuantityType, TargetQuantityType>::common_type>> = true;
288
289/// @brief Constant indicating if there is a scale factor to use when converting from @c SourceQuantityType to @c
290/// TargetQuantityType.
291///
292/// @tparam SourceQuantityType The physical quantity type of the source
293/// @tparam TargetQuantityType The physical quantity type of the target
294///
295/// The value is @c true if there is, @c false otherwise
296template <typename SourceQuantityType, typename TargetQuantityType, typename = constraints<>>
297extern constexpr bool has_scale_factor_specified_v = false;
298
299/// @brief Constant indicating if there is a scale factor to use when converting from @c SourceQuantityType to @c
300/// TargetQuantityType.
301///
302/// @tparam SourceQuantityType The physical quantity type of the source
303/// @tparam TargetQuantityType The physical quantity type of the target
304///
305/// The value is @c true if there is, @c false otherwise. This specialization handles the case where @c
306/// units_conversion_traits specifies a scale factor
307template <typename SourceQuantityType, typename TargetQuantityType>
308extern constexpr bool has_scale_factor_specified_v<
309 SourceQuantityType,
310 TargetQuantityType,
311 constraints<typename units_conversion_traits<SourceQuantityType, TargetQuantityType>::scale_factor>> = true;
312
313/// @brief Constant indicating if quantities with a unit type of @c SourceQuantityType can be explicitly converted to
314/// quantities with a unit type of @c TargetQuantityType.
315///
316/// @tparam SourceQuantityType The physical quantity type of the source
317/// @tparam TargetQuantityType The physical quantity type of the target
318///
319/// Values can be converted if the Physical Unit Types are "compatible", or if there is a common type specified
320///
321/// The value is @c true if values can be converted, @c false otherwise.
322template <typename SourceQuantityType, typename TargetQuantityType>
323extern constexpr bool is_explicitly_convertible_v =
324 units_conversion_traits<SourceQuantityType, TargetQuantityType>::compatible ||
325 has_common_type_specified_v<SourceQuantityType, TargetQuantityType>;
326
327/// @brief Constant indicating if quantities with a unit type of @c SourceQuantityType can be implicitly converted to
328/// quantities with a unit type of @c TargetQuantityType.
329///
330/// @tparam SourceQuantityType The physical quantity type of the source
331/// @tparam TargetQuantityType The physical quantity type of the target
332///
333/// Values can be converted if the Physical Unit Types are "compatible"
334///
335/// The value is @c true if values can be converted, @c false otherwise.
336template <typename SourceQuantityType, typename TargetQuantityType>
337extern constexpr bool is_implicitly_convertible_v =
338 units_conversion_traits<SourceQuantityType, TargetQuantityType>::compatible;
339
340/// @brief The type of a scale factor that is the product of the two supplied scale factors
341///
342/// @tparam ScaleFactor1 The first scale factor
343/// @tparam ScaleFactor2 The second scale factor
344template <typename ScaleFactor1, typename ScaleFactor2>
345using combine_scale_factors_t = std::ratio_multiply<ScaleFactor1, ScaleFactor2>;
346
347/// @brief A helper class for retrieving the scale factor for converting quantities with a physical units type of @c
348/// SourceQuantityType to quantities with a physical units type of @c TargetQuantityType
349///
350/// @tparam SourceQuantityType The physical quantity type of the source
351/// @tparam TargetQuantityType The physical quantity type of the target
352template <typename SourceQuantityType, typename TargetQuantityType, typename = constraints<>>
353struct scale_factor_helper {
354 static_assert(
355 has_scale_factor_specified_v<SourceQuantityType, TargetQuantityType>,
356 "No scale factor specified for conversion between types"
357 );
358 /// @brief The scale factor for the conversion
359 using type = typename units_conversion_traits<SourceQuantityType, TargetQuantityType>::scale_factor;
360};
361
362/// @brief The scale factor for converting quantities with a physical units type of @c SourceQuantityType to quantities
363/// with a physical units type of @c TargetQuantityType
364///
365/// @tparam SourceQuantityType The physical quantity type of the source
366/// @tparam TargetQuantityType The physical quantity type of the target
367template <typename SourceQuantityType, typename TargetQuantityType>
368using scale_factor = typename scale_factor_helper<SourceQuantityType, TargetQuantityType>::type;
369
370/// @brief A boolean constant indicating if the common type for conversion between the source and target physical units
371/// types is one of them
372///
373/// @tparam SourceQuantityType The physical quantity type of the source
374/// @tparam TargetQuantityType The physical quantity type of the target
375///
376/// The value is @c true if one or other is the common type, @c false otherwise
377template <typename SourceQuantityType, typename TargetQuantityType, typename = constraints<>>
378extern constexpr bool common_type_is_source_or_target_v = false;
379
380/// @brief A boolean constant indicating if the common type for conversion between the source and target physical units
381/// types is one of them. This specialization handles the case that there is a specified common type
382///
383/// @tparam SourceQuantityType The physical quantity type of the source
384/// @tparam TargetQuantityType The physical quantity type of the target
385///
386/// The value is @c true if one or other is the common type, @c false otherwise
387template <typename SourceQuantityType, typename TargetQuantityType>
388extern constexpr bool common_type_is_source_or_target_v<
389 SourceQuantityType,
390 TargetQuantityType,
391 constraints<std::enable_if_t<has_common_type_specified_v<SourceQuantityType, TargetQuantityType>>>> =
392 std::is_same<
393 typename units_conversion_traits<SourceQuantityType, TargetQuantityType>::common_type,
394 SourceQuantityType>::value ||
395 std::is_same<
396 typename units_conversion_traits<SourceQuantityType, TargetQuantityType>::common_type,
397 TargetQuantityType>::value;
398
399/// @brief A specialization of @c scale_factor_helper for retrieving the scale factor between two physical units types
400/// when there is a common type specified for conversion, but it is neither one nor the other.
401///
402/// In this case, the conversion is done via converting from the source to the common type, and then from the common
403/// type to the target.
404///
405/// @tparam SourceQuantityType The physical quantity type of the source
406/// @tparam TargetQuantityType The physical quantity type of the target
407template <typename SourceQuantityType, typename TargetQuantityType>
408struct scale_factor_helper<
409 SourceQuantityType,
410 TargetQuantityType,
411 constraints<
412 std::enable_if_t<!is_implicitly_convertible_v<SourceQuantityType, TargetQuantityType>>,
413 std::enable_if_t<has_common_type_specified_v<SourceQuantityType, TargetQuantityType>>,
414 std::enable_if_t<!common_type_is_source_or_target_v<SourceQuantityType, TargetQuantityType>>>> {
415 /// @brief The common type between two unit types
416 using common_type = typename units_conversion_traits<SourceQuantityType, TargetQuantityType>::common_type;
417 /// @brief The type of the scale factor that is the product of the two unit types
418 using type = combine_scale_factors_t<
419 scale_factor<SourceQuantityType, common_type>,
420 scale_factor<common_type, TargetQuantityType>>;
421};
422
423/// @brief Boolean constant indicating if the scaled value for converting from @c SourceQuantityType to @c
424/// TargetQuantityType is guaranteed to be in the range of @c TargetRep if the source value is stored in @c SourceRep
425///
426/// @tparam SourceQuantityType The physical quantity type of the source
427/// @tparam TargetQuantityType The physical quantity type of the target
428/// @tparam SourceRep The representation type of the source
429/// @tparam TargetRep The representation type of the target
430template <
431 typename SourceQuantityType,
432 typename SourceRep,
433 typename TargetQuantityType,
434 typename TargetRep,
435 typename = constraints<>>
436extern constexpr bool scaled_value_in_range_v = false;
437
438/// @brief Boolean constant indicating if the maximum value of @c SourceRep when scaled by @c ScaleFactor fits in @c
439/// TargetRep
440///
441/// @tparam ScaleFactor The scale factor to use
442/// @tparam SourceRep The representation type of the source
443/// @tparam TargetRep The representation type of the target
444template <typename ScaleFactor, typename SourceRep, typename TargetRep, typename = constraints<>>
445extern constexpr bool scaled_max_fits_v = false;
446
447/// @brief Specialization of @c scaled_max_fits_v for the case where the target is not integral
448///
449/// @tparam ScaleFactor The scale factor to use
450/// @tparam SourceRep The representation type of the source
451/// @tparam TargetRep The representation type of the target
452template <typename ScaleFactor, typename SourceRep, typename TargetRep>
453extern constexpr bool scaled_max_fits_v<
454 ScaleFactor,
455 SourceRep,
456 TargetRep,
457 constraints<std::enable_if_t<!std::is_integral<TargetRep>::value>>> = true;
458
459/// @brief Specialization of @c scaled_max_fits_v for the case where both the source and target are integral
460///
461/// @tparam ScaleFactor The scale factor to use
462/// @tparam SourceRep The representation type of the source
463/// @tparam TargetRep The representation type of the target
464template <typename ScaleFactor, typename SourceRep, typename TargetRep>
465extern constexpr bool scaled_max_fits_v<
466 ScaleFactor,
467 SourceRep,
468 TargetRep,
469 constraints<
470 std::enable_if_t<std::is_integral<SourceRep>::value>,
471 std::enable_if_t<std::is_integral<TargetRep>::value>>> =
472 (static_cast<std::uint64_t>(std::numeric_limits<SourceRep>::max()) <=
473 (std::numeric_limits<std::uint64_t>::max() / quantity_detail::unsigned_abs(ScaleFactor::num))) &&
474 ((static_cast<std::uint64_t>(std::numeric_limits<SourceRep>::max()) *
475 quantity_detail::unsigned_abs(ScaleFactor::num) / quantity_detail::unsigned_abs(ScaleFactor::den)) <=
476 static_cast<std::uint64_t>(std::numeric_limits<TargetRep>::max()));
477
478/// @brief Specialization of @c scaled_value_in_range_v for the case that the source physical quantity should be
479/// implicitly convertible to the target physical quantity.
480///
481/// @tparam SourceQuantityType The physical quantity type of the source
482/// @tparam TargetQuantityType The physical quantity type of the target
483/// @tparam SourceRep The representation type of the source
484/// @tparam TargetRep The representation type of the target
485template <typename SourceQuantityType, typename SourceRep, typename TargetQuantityType, typename TargetRep>
486extern constexpr bool scaled_value_in_range_v<
487 SourceQuantityType,
488 SourceRep,
489 TargetQuantityType,
490 TargetRep,
491 constraints<std::enable_if_t<is_implicitly_convertible_v<SourceQuantityType, TargetQuantityType>>>> =
492 scaled_max_fits_v<scale_factor<SourceQuantityType, TargetQuantityType>, SourceRep, TargetRep>;
493
494} // namespace quantity_detail
495
496/// @brief A class representing a quantity of a physical units type.
497///
498/// Conversions and arithmetic are supported if indicated by the appropriate traits for the physical units tag type.
499/// This allows the mathematical operations of engineering equations to be performed using instances of @c quantity,
500/// ensuring that the units of the result are correct, and preventing errors due to passing incorrect values or values
501/// in the wrong units.
502///
503/// @tparam QuantityType A tag type representing the physical quantity
504/// @tparam Rep The arithmetic type to use for holding the value
505template <typename QuantityType, typename Rep>
507 /// @brief The type of the base class for defining ordering
509
510 /// @brief The stored value
511 Rep value_;
512
513 public:
514 // parasoft-begin-suppress AUTOSAR-A12_1_1-a-2 "False positive: This constructor delegates to another, which does
515 // initialize the base class"
516 /// @brief Default construct with a default-constructed representation value
517 constexpr quantity() noexcept
518 : quantity(Rep{}) {}
519 // parasoft-end-suppress AUTOSAR-A12_1_1-a
520 /// @brief Construct a @c quantity holding the specified representation value
521 /// @param store_value The value to store
522 explicit constexpr quantity(Rep store_value) noexcept
523 : ordering_base{},
525
526 // parasoft-begin-suppress AUTOSAR-A12_1_1-a-2 "False positive: This constructor delegates to another, which does
527 // initialize the base class"
528 /// @brief Implicitly convert from a quantity with a different physical units type or representation type, scaling the
529 /// value as appropriate.
530 ///
531 /// @pre the physical unit types are marked as being implicitly convertible, and the scaled value is guaranteed to be
532 /// in range, for integral representations.
533 /// @tparam OtherQuantityType The physical units type of the source quantity
534 /// @tparam OtherRep The representation type of the source quantity
535 /// @param other The other quantity
536 template <
537 typename OtherQuantityType,
538 typename OtherRep,
542 nullptr>
543 // NOLINTNEXTLINE(hicpp-explicit-conversions)
544 constexpr quantity(quantity<OtherQuantityType, OtherRep> const& other) noexcept
545 : quantity(other.template count_of<QuantityType, Rep>()) {}
546 // parasoft-end-suppress AUTOSAR-A12_1_1-a
547
548 /// @brief Get the numeric representation of the stored quantity, for the specified physical units type
549 ///
550 /// The value is scaled as appropriate
551 ///
552 /// @tparam OtherQuantityType The physical units type for which to retrieve the count
553 /// @tparam OtherRep The representation type to return the count in; defaults to @c Rep
554 /// @return OtherRep holding the scaled value
555 /// @pre The physical units type @c QuantityType must be marked as explicitly convertible to @c OtherQuantityType
556 template <
557 typename OtherQuantityType,
558 typename OtherRep = Rep,
560 nullptr>
561 constexpr auto count_of() const noexcept -> OtherRep {
563 value_
564 );
565 }
566
567 /// @brief Convert the stored quantity to the specified physical units type and representation
568 ///
569 /// The value is scaled as appropriate
570 ///
571 /// @tparam OtherQuantityType The physical units type for which to retrieve the count
572 /// @tparam OtherRep The representation type to return the count in; defaults to @c Rep
573 /// @return quantity<OtherQuantityType,OtherRep> holding the scaled value
574 /// @pre The physical units type @c QuantityType must be marked as explicitly convertible to @c OtherQuantityType
575 template <
576 typename OtherQuantityType,
577 typename OtherRep = Rep,
579 nullptr>
580 constexpr auto as() const noexcept -> quantity<OtherQuantityType, OtherRep> {
582 }
583
584 /// @brief three-way comparison between two quantities
585 ///
586 /// @param lhs The first object to compare
587 /// @param rhs The second object to compare
588 /// @return strong_ordering @c strong_ordering::less if @c lhs is less than @c rhs, @c strong_ordering::equal if they
589 /// hold the same value, and @c strong_ordering::greater if @c lhs is greater than @c rhs
590 static constexpr auto three_way_compare(quantity const& lhs, quantity const& rhs) noexcept -> strong_ordering {
592 }
593
594 /// @brief three-way comparison between two quantities with the same physical units but different representations
595 ///
596 /// @param lhs The first object to compare
597 /// @param rhs The second object to compare
598 /// @return strong_ordering @c strong_ordering::less if @c lhs is less than @c rhs, @c strong_ordering::equal if they
599 /// hold the same value, and @c strong_ordering::greater if @c lhs is greater than @c rhs
600 template <typename OtherRep>
601 static constexpr auto three_way_compare(quantity const& lhs, quantity<QuantityType, OtherRep> const& rhs) noexcept
602 -> strong_ordering {
604 return compare_three_way{}(static_cast<common_rep>(lhs.value_), rhs.template count_of<QuantityType, common_rep>());
605 }
606
607 /// @{
608 /// @brief three-way comparison between two quantities with different physical units
609 ///
610 /// @param lhs The first object to compare
611 /// @param rhs The second object to compare
612 /// @return strong_ordering @c strong_ordering::less if @c lhs is less than @c rhs, @c strong_ordering::equal if they
613 /// hold the same value, and @c strong_ordering::greater if @c lhs is greater than @c rhs
614 template <
615 typename OtherQuantityType,
616 typename OtherRep,
621 OtherRep,
623 std::common_type_t<Rep, OtherRep>>>> = nullptr>
624 static constexpr auto
630
631 /// @brief three-way comparison between two quantities with different physical units where one quantity type is not
632 /// within the scaled range of the other
633 ///
634 /// @param lhs The first object to compare
635 /// @param rhs The second object to compare
636 /// @return strong_ordering @c strong_ordering::less if @c lhs is less than @c rhs, @c strong_ordering::equal if they
637 /// hold the same value, and @c strong_ordering::greater if @c lhs is greater than @c rhs
638 template <
639 typename OtherQuantityType,
640 typename OtherRep,
645 OtherRep,
647 std::common_type_t<Rep, OtherRep>>>> = nullptr>
648 static constexpr auto
672 /// @}
673
674 // parasoft-begin-suppress AUTOSAR-A11_3_1-a-2 "Hidden friends permitted by A11-3-1 Permit #2"
675 // parasoft-begin-suppress AUTOSAR-M3_3_2-a-2 "False positive: cannot apply static here"
676 /// @brief Add two quantities of the same type
677 /// @tparam Q Template parameter introduced to provide constraints; equivalent to @c QuantityType
678 /// @param lhs The first quantity
679 /// @param rhs The second quantity
680 /// @return quantity<sum_type,Rep> A @c quantity with the physical units type specified as the @c
681 /// sum_type for @c QuantityType and @c QuantityType, and a representation of @c Rep, holding the sum of the two
682 /// quantity values
683 template <typename Q = QuantityType, constraints<typename units_combination_traits<Q, Q>::sum_type> = nullptr>
684 friend constexpr auto operator+(quantity const& lhs, quantity const& rhs) noexcept
686 return quantity<typename units_combination_traits<Q, Q>::sum_type, Rep>{
687 static_cast<Rep>(lhs.count_of<Q>() + rhs.template count_of<Q>())
688 };
689 }
690 // parasoft-end-suppress AUTOSAR-M3_3_2-a-2
691 // parasoft-end-suppress AUTOSAR-A11_3_1-a-2
692
693 // parasoft-begin-suppress AUTOSAR-A11_3_1-a-2 "Hidden friends permitted by A11-3-1 Permit #2"
694 // parasoft-begin-suppress AUTOSAR-M3_3_2-a-2 "False positive: cannot apply static here"
695 /// @{
696 /// @brief Add two quantities
697 /// @tparam OtherQuantityType The physical units type of the other quantity
698 /// @tparam OtherRep The representation type of the other quantity
699 /// @tparam Q Template parameter introduced to provide constraints; equivalent to @c QuantityType
700 /// @tparam R Template parameter introduced to provide constraints; equivalent to @c Rep
701 /// @param lhs The first quantity
702 /// @param rhs The second quantity
703 /// @return quantity<sum_type,CommonRep> A @c quantity with the physical units type specified as the @c
704 /// sum_type for @c QuantityType and @c OtherQuantityType, and a representation which is the common type of @c Rep
705 /// and @c OtherRep, holding the sum of the two quantity values
706 template <
707 typename OtherQuantityType,
708 typename OtherRep,
709 typename Q = QuantityType,
710 typename R = Rep,
711 typename CommonRep = std::common_type_t<Rep, OtherRep>,
719 /// @}
720 // parasoft-end-suppress AUTOSAR-M3_3_2-a-2
721 // parasoft-end-suppress AUTOSAR-A11_3_1-a-2
722
723 // parasoft-begin-suppress AUTOSAR-A11_3_1-a-2 "Hidden friends permitted by A11-3-1 Permit #2"
724 // parasoft-begin-suppress AUTOSAR-M3_3_2-a-2 "False positive: cannot apply static here"
725 /// @{
726 /// @brief Subtract two quantities
727 /// @tparam OtherQuantityType The physical units type of the other quantity
728 /// @tparam OtherRep The representation type of the other quantity
729 /// @tparam Q Template parameter introduced to provide constraints; equivalent to @c QuantityType
730 /// @tparam R Template parameter introduced to provide constraints; equivalent to @c Rep
731 /// @param lhs The first quantity
732 /// @param rhs The second quantity
733 /// @return quantity<difference_type,CommonRep> A @c quantity with the physical units type specified as the @c
734 /// difference_type for @c QuantityType and @c OtherQuantityType, and a representation which is the common type of @c
735 /// Rep and @c OtherRep, holding the difference of the two quantity values
736 template <
737 typename OtherQuantityType,
738 typename OtherRep,
739 typename Q = QuantityType,
740 typename R = Rep,
741 typename CommonRep = std::common_type_t<Rep, OtherRep>,
749 /// @}
750 // parasoft-end-suppress AUTOSAR-M3_3_2-a-2
751 // parasoft-end-suppress AUTOSAR-A11_3_1-a-2
752
753 // parasoft-begin-suppress AUTOSAR-A11_3_1-a-2 "Hidden friends permitted by A11-3-1 Permit #2"
754 // parasoft-begin-suppress AUTOSAR-M3_3_2-a-2 "False positive: cannot apply static here"
755 /// @{
756 /// @brief Multiply a quantity by a scalar
757 /// @tparam Scalar The type of the scalar
758 /// @tparam Q Template parameter introduced to provide constraints; equivalent to @c QuantityType
759 /// @tparam R Template parameter introduced to provide constraints; equivalent to @c Rep
760 /// @tparam CommonRep Template parameter introduced to provide constraints; the common representation type of @c Rep
761 /// and @c Scalar
762 /// @param lhs The left hand operand
763 /// @param rhs The right hand operand
764 /// @return quantity<Q,CommonRep> A @c quantity with the same physical units type, and a representation which is the
765 /// common type of @c Rep and @c Scalar, holding the product of the quantity value and the scalar value
766 template <
767 typename Scalar,
768 typename Q = QuantityType,
769 typename R = Rep,
771 typename CommonRep = std::common_type_t<Rep, Scalar>>
772 friend constexpr auto operator*(quantity const& lhs, Scalar const& rhs) noexcept -> quantity<Q, CommonRep> {
773 return quantity<Q, CommonRep>{lhs.count_of<Q, CommonRep>() * static_cast<CommonRep>(rhs)};
774 }
775 // parasoft-end-suppress AUTOSAR-M3_3_2-a-2
776 // parasoft-end-suppress AUTOSAR-A11_3_1-a-2
777
778 // parasoft-begin-suppress AUTOSAR-A11_3_1-a-2 "Hidden friends permitted by A11-3-1 Permit #2"
779 // parasoft-begin-suppress AUTOSAR-M3_3_2-a-2 "False positive: cannot apply static here"
780 /// @brief Multiply a quantity by a scalar
781 /// @tparam Scalar The type of the scalar
782 /// @tparam Q Template parameter introduced to provide constraints; equivalent to @c QuantityType
783 /// @tparam R Template parameter introduced to provide constraints; equivalent to @c Rep
784 /// @tparam CommonRep Template parameter introduced to provide constraints; the common representation type of @c Rep
785 /// and @c Scalar
786 /// @param lhs The left hand operand
787 /// @param rhs The right hand operand
788 /// @return quantity<Q,CommonRep> A @c quantity with the same physical units type, and a representation which is the
789 /// common type of @c Rep and @c Scalar, holding the quantity value multiplied by the scalar value
790 template <
791 typename Scalar,
792 typename Q = QuantityType,
793 typename R = Rep,
795 typename CommonRep = std::common_type_t<Rep, Scalar>>
796 friend constexpr auto operator*(Scalar const& lhs, quantity const& rhs) noexcept -> quantity<Q, CommonRep> {
797 return rhs * lhs;
798 }
799 /// @}
800 // parasoft-end-suppress AUTOSAR-M3_3_2-a-2
801 // parasoft-end-suppress AUTOSAR-A11_3_1-a-2
802
803 // parasoft-begin-suppress AUTOSAR-A11_3_1-a-2 "Hidden friends permitted by A11-3-1 Permit #2"
804 // parasoft-begin-suppress AUTOSAR-M3_3_2-a-2 "False positive: cannot apply static here"
805 /// @{
806 /// @brief Multiply two quantities
807 /// @tparam OtherQuantityType The physical units type of the other quantity
808 /// @tparam OtherRep The representation type of the other quantity
809 /// @tparam Q Template parameter introduced to provide constraints; equivalent to @c QuantityType
810 /// @tparam R Template parameter introduced to provide constraints; equivalent to @c Rep
811 /// @tparam CommonRep Template parameter introduced to provide constraints; the common representation type of @c Rep
812 /// and @c OtherRep
813 /// @param lhs The left hand operand
814 /// @param rhs The right hand operand
815 /// @return quantity<product_type,CommonRep> A @c quantity with the physical units type specified as the @c
816 /// product_type for @c QuantityType and @c OtherQuantityType, and a representation which is the common type of @c Rep
817 /// and @c OtherRep, holding the product of the two quantity values
818 /// @pre There is a @c product_type specified in @c units_combination_traits<QuantityType,OtherQuantityType>
819 template <
820 typename OtherQuantityType,
821 typename OtherRep,
822 typename Q = QuantityType,
823 typename R = Rep,
824 typename CommonRep = std::common_type_t<Rep, OtherRep>,
827 std::enable_if_t<!std::is_integral<CommonRep>::value>> = nullptr>
834 // parasoft-end-suppress AUTOSAR-M3_3_2-a-2
835 // parasoft-end-suppress AUTOSAR-A11_3_1-a-2
836
837 // parasoft-begin-suppress AUTOSAR-A11_3_1-a-2 "Hidden friends permitted by A11-3-1 Permit #2"
838 // parasoft-begin-suppress AUTOSAR-M3_3_2-a-2 "False positive: cannot apply static here"
839 /// @brief Multiply two quantities
840 /// @tparam OtherQuantityType The physical units type of the other quantity
841 /// @tparam OtherRep The representation type of the other quantity
842 /// @tparam Q Template parameter introduced to provide constraints; equivalent to @c QuantityType
843 /// @tparam R Template parameter introduced to provide constraints; equivalent to @c Rep
844 /// @tparam CommonRep Template parameter introduced to provide constraints; the common representation type of @c Rep
845 /// and @c OtherRep
846 /// @param lhs The left hand operand
847 /// @param rhs The right hand operand
848 /// @return quantity<product_type,CommonRep> A @c quantity with the physical units type specified as the @c
849 /// product_type for @c QuantityType and @c OtherQuantityType, and a representation which is the common type of @c Rep
850 /// and @c OtherRep, holding the left hand quantity value multiplied by the right hand quantity value
851 /// @pre There is a @c product_type specified in @c units_combination_traits<QuantityType,OtherQuantityType>
852 template <
853 typename OtherQuantityType,
854 typename OtherRep,
855 typename Q = QuantityType,
856 typename R = Rep,
857 typename CommonRep = std::common_type_t<Rep, OtherRep>,
863 nullptr>
870 /// @}
871 // parasoft-end-suppress AUTOSAR-M3_3_2-a-2
872 // parasoft-end-suppress AUTOSAR-A11_3_1-a-2
873
874 // parasoft-begin-suppress AUTOSAR-A11_3_1-a-2 "Hidden friends permitted by A11-3-1 Permit #2"
875 // parasoft-begin-suppress AUTOSAR-M3_3_2-a-2 "False positive: cannot apply static here"
876 /// @brief Divide a quantity by a scalar
877 /// @tparam Scalar The type of the scalar
878 /// @tparam Q Template parameter introduced to provide constraints; equivalent to @c QuantityType
879 /// @tparam R Template parameter introduced to provide constraints; equivalent to @c Rep
880 /// @tparam CommonRep Template parameter introduced to provide constraints; the common representation type of @c Rep
881 /// and @c Scalar
882 /// @param lhs The left hand operand
883 /// @param rhs The right hand operand
884 /// @return quantity<Q,CommonRep> A @c quantity with the same physical units type, and a representation which is the
885 /// common type of @c Rep and @c Scalar, holding the quantity value divided by the scalar value
886 template <
887 typename Scalar,
888 typename Q = QuantityType,
889 typename R = Rep,
891 typename CommonRep = std::common_type_t<Rep, Scalar>,
893 friend constexpr auto operator/(quantity const& lhs, Scalar const& rhs) noexcept -> quantity<Q, CommonRep> {
894 return quantity<Q, CommonRep>{static_cast<CommonRep>(lhs.count_of<Q, CommonRep>() / static_cast<CommonRep>(rhs))};
895 }
896 // parasoft-end-suppress AUTOSAR-M3_3_2-a-2
897 // parasoft-end-suppress AUTOSAR-A11_3_1-a-2
898
899 // parasoft-begin-suppress AUTOSAR-A11_3_1-a-2 "Hidden friends permitted by A11-3-1 Permit #2"
900 // parasoft-begin-suppress AUTOSAR-M3_3_2-a-2 "False positive: cannot apply static here"
901 /// @brief Divide two quantities
902 /// @tparam OtherQuantityType The physical units type of the other quantity
903 /// @tparam OtherRep The representation type of the other quantity
904 /// @tparam Q Template parameter introduced to provide constraints; equivalent to @c QuantityType
905 /// @tparam R Template parameter introduced to provide constraints; equivalent to @c Rep
906 /// @tparam CommonRep Template parameter introduced to provide constraints; the common representation type of @c Rep
907 /// and @c OtherRep
908 /// @param lhs The left hand operand
909 /// @param rhs The right hand operand
910 /// @return quantity<ratio_type,CommonRep> A @c quantity with the physical units type specified as the @c
911 /// ratio_type for @c QuantityType and @c OtherQuantityType, and a representation which is the common type of @c Rep
912 /// and @c OtherRep, holding the left hand quantity value divided by the right hand quantity value
913 /// @pre There is a @c ratio_type specified in @c units_combination_traits<QuantityType,OtherQuantityType>
914 template <
915 typename OtherQuantityType,
916 typename OtherRep,
917 typename Q = QuantityType,
918 typename R = Rep,
919 typename CommonRep = std::common_type_t<Rep, OtherRep>,
927 // parasoft-end-suppress AUTOSAR-M3_3_2-a-2
928 // parasoft-end-suppress AUTOSAR-A11_3_1-a-2
929};
930} // namespace base
931} // namespace arene
932
933#endif // INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_UNITS_QUANTITY_HPP_
constexpr quantity() noexcept
Default construct with a default-constructed representation value.
Definition quantity.hpp:517
constexpr quantity(quantity< OtherQuantityType, OtherRep > const &other) noexcept
Implicitly convert from a quantity with a different physical units type or representation type,...
Definition quantity.hpp:544
constexpr quantity(Rep store_value) noexcept
Construct a quantity holding the specified representation value.
Definition quantity.hpp:522
Definition array_exceptions_disabled.cpp:11
Copyright 2026, Toyota Motor Corporation.
Definition array_exceptions_disabled.cpp:10
Traits class with information about if and how a physical unit of type QuantityType1 can be combined ...
Definition quantity.hpp:85