5#ifndef INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_UNITS_QUANTITY_HPP_
6#define INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_UNITS_QUANTITY_HPP_
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"
39template <
typename QuantityType,
typename Rep =
double>
43namespace quantity_detail {
47extern constexpr bool is_quantity_v =
false;
53template <
typename QuantityType,
typename Rep>
54extern constexpr bool is_quantity_v<quantity<QuantityType, Rep>> =
true;
84template <
typename QuantityType1,
typename QuantityType2>
89template <
typename QuantityType>
93 using sum_type = QuantityType;
96 using difference_type = QuantityType;
99namespace quantity_detail {
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};
111 return static_cast<std::make_unsigned_t<T>>(arene::base::abs(value));
118template <
typename T, constraints<std::enable_if_t<std::is_unsigned<T>::value>> =
nullptr>
119constexpr auto unsigned_abs(T value)
noexcept -> T {
131 typename ScaleFactor,
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>;
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 "
144 return static_cast<TargetRep>(value);
155 typename ScaleFactor,
159 std::enable_if_t<std::is_unsigned<TargetRep>::value>,
160 std::enable_if_t<std::is_integral<Rep>::value>,
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>;
168 scaling_calculation_does_not_overflow,
169 "The scaling calculation will overflow internally; please use a floating point representation"
171 return static_cast<TargetRep>(value);
182 typename ScaleFactor,
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>,
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);
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;
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);
218 typename ScaleFactor,
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)
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));
240 unsigned_result <=
static_cast<std::make_unsigned_t<TargetRep>>(std::numeric_limits<TargetRep>::max())
242 return static_cast<TargetRep>(unsigned_result);
252 typename ScaleFactor,
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)
262 return static_cast<TargetRep>(scaled_intermediate);
272template <
typename SourceQuantityType,
typename TargetQuantityType,
typename = constraints<>>
273extern constexpr bool has_common_type_specified_v =
false;
283template <
typename SourceQuantityType,
typename TargetQuantityType>
284extern constexpr bool has_common_type_specified_v<
287 constraints<
typename units_conversion_traits<SourceQuantityType, TargetQuantityType>::common_type>> =
true;
296template <
typename SourceQuantityType,
typename TargetQuantityType,
typename = constraints<>>
297extern constexpr bool has_scale_factor_specified_v =
false;
307template <
typename SourceQuantityType,
typename TargetQuantityType>
308extern constexpr bool has_scale_factor_specified_v<
311 constraints<
typename units_conversion_traits<SourceQuantityType, TargetQuantityType>::scale_factor>> =
true;
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>;
336template <
typename SourceQuantityType,
typename TargetQuantityType>
337extern constexpr bool is_implicitly_convertible_v =
338 units_conversion_traits<SourceQuantityType, TargetQuantityType>::compatible;
344template <
typename ScaleFactor1,
typename ScaleFactor2>
345using combine_scale_factors_t = std::ratio_multiply<ScaleFactor1, ScaleFactor2>;
352template <
typename SourceQuantityType,
typename TargetQuantityType,
typename = constraints<>>
353struct scale_factor_helper {
355 has_scale_factor_specified_v<SourceQuantityType, TargetQuantityType>,
356 "No scale factor specified for conversion between types"
359 using type =
typename units_conversion_traits<SourceQuantityType, TargetQuantityType>::scale_factor;
367template <
typename SourceQuantityType,
typename TargetQuantityType>
368using scale_factor =
typename scale_factor_helper<SourceQuantityType, TargetQuantityType>::type;
377template <
typename SourceQuantityType,
typename TargetQuantityType,
typename = constraints<>>
378extern constexpr bool common_type_is_source_or_target_v =
false;
387template <
typename SourceQuantityType,
typename TargetQuantityType>
388extern constexpr bool common_type_is_source_or_target_v<
391 constraints<std::enable_if_t<has_common_type_specified_v<SourceQuantityType, TargetQuantityType>>>> =
393 typename units_conversion_traits<SourceQuantityType, TargetQuantityType>::common_type,
394 SourceQuantityType>::value ||
396 typename units_conversion_traits<SourceQuantityType, TargetQuantityType>::common_type,
397 TargetQuantityType>::value;
407template <
typename SourceQuantityType,
typename TargetQuantityType>
408struct scale_factor_helper<
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>>>> {
416 using common_type =
typename units_conversion_traits<SourceQuantityType, TargetQuantityType>::common_type;
418 using type = combine_scale_factors_t<
419 scale_factor<SourceQuantityType, common_type>,
420 scale_factor<common_type, TargetQuantityType>>;
431 typename SourceQuantityType,
433 typename TargetQuantityType,
435 typename = constraints<>>
436extern constexpr bool scaled_value_in_range_v =
false;
444template <
typename ScaleFactor,
typename SourceRep,
typename TargetRep,
typename = constraints<>>
445extern constexpr bool scaled_max_fits_v =
false;
452template <
typename ScaleFactor,
typename SourceRep,
typename TargetRep>
453extern constexpr bool scaled_max_fits_v<
457 constraints<std::enable_if_t<!std::is_integral<TargetRep>::value>>> =
true;
464template <
typename ScaleFactor,
typename SourceRep,
typename TargetRep>
465extern constexpr bool scaled_max_fits_v<
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()));
485template <
typename SourceQuantityType,
typename SourceRep,
typename TargetQuantityType,
typename TargetRep>
486extern constexpr bool scaled_value_in_range_v<
491 constraints<std::enable_if_t<is_implicitly_convertible_v<SourceQuantityType, TargetQuantityType>>>> =
492 scaled_max_fits_v<scale_factor<SourceQuantityType, TargetQuantityType>, SourceRep, TargetRep>;
505template <
typename QuantityType,
typename Rep>
522 explicit constexpr quantity(Rep store_value)
noexcept
624 static constexpr auto
648 static constexpr auto
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