2#ifndef LIBSBX_UNITS_QUANTITY_HPP_
3#define LIBSBX_UNITS_QUANTITY_HPP_
10#include <fmt/format.h>
14template<
typename Type>
15concept representation = (std::is_integral_v<Type> && !std::is_same_v<Type, bool> ) || std::is_floating_point_v<Type>;
17template<
typename Type>
18concept ratio =
requires {
19 { Type::num } -> std::convertible_to<std::intmax_t>;
20 { Type::den } -> std::convertible_to<std::intmax_t>;
23template<
typename LhsDimension,
typename RhsDimension = LhsDimension,
typename ResultDimension = LhsDimension>
24concept addable_dimensions = std::is_same_v<LhsDimension, RhsDimension> ||
requires(LhsDimension dimension1, ResultDimension dimension2) {
25 { dimension1 + dimension2 } -> std::same_as<ResultDimension>;
26 { dimension2 + dimension1 } -> std::same_as<ResultDimension>;
29template<
typename LhsDimension,
typename RhsDimension = LhsDimension,
typename ResultDimension = LhsDimension>
30concept subtractable_dimensions = std::is_same_v<LhsDimension, RhsDimension> ||
requires(LhsDimension dimension1, ResultDimension dimension2) {
31 { dimension1 - dimension2 } -> std::same_as<ResultDimension>;
32 { dimension2 - dimension1 } -> std::same_as<ResultDimension>;
35template<
typename LhsDimension,
typename RhsDimension = LhsDimension,
typename ResultDimension = LhsDimension>
36concept multipliable_dimensions = std::is_same_v<LhsDimension, RhsDimension> ||
requires(LhsDimension dimension1, ResultDimension dimension2) {
37 { dimension1 * dimension2 } -> std::same_as<ResultDimension>;
38 { dimension2 * dimension1 } -> std::same_as<ResultDimension>;
41template<
typename LhsDimension,
typename RhsDimension = LhsDimension,
typename ResultDimension = LhsDimension>
42concept dividable_dimensions = std::is_same_v<LhsDimension, RhsDimension> ||
requires(LhsDimension dimension1, ResultDimension dimension2) {
43 { dimension1 / dimension2 } -> std::same_as<ResultDimension>;
44 { dimension2 / dimension1 } -> std::same_as<ResultDimension>;
47template<ratio Ratio, ratio OtherRatio>
49 using type = std::ratio<Ratio::num + OtherRatio::num, Ratio::den * OtherRatio::den>;
52template<ratio Ratio, ratio OtherRatio>
53using ratio_multiply_t =
typename ratio_multiply<Ratio, OtherRatio>::type;
55template<representation Representation, ratio Ratio, ratio OtherRatio>
57 static constexpr auto value =
58 static_cast<Representation
>(OtherRatio::num) /
static_cast<Representation
>(OtherRatio::den) *
59 static_cast<Representation
>(Ratio::den) /
static_cast<Representation
>(Ratio::num);
62template<representation Representation, ratio R1, ratio R2>
65template<
typename Dimension, representation Representation, ratio Ratio = std::ratio<1, 1>>
70 using dimension_type = Dimension;
71 using value_type = Representation;
72 using ratio_type = Ratio;
76 template<std::convertible_to<value_type> Type>
77 constexpr explicit quantity(Type value) noexcept
78 : _value{
static_cast<value_type
>(value)} { }
80 template<representation OtherRepresentation, ratio OtherRatio = ratio_type>
82 : _value{quantity_cast<quantity>(other)} { }
90 constexpr auto operator=(
const quantity& other)
noexcept ->
quantity& =
default;
94 template<representation OtherRepresentation, ratio OtherRatio>
96 _value =
static_cast<value_type
>(other.value()) * ratio_conversion_v<value_type, Ratio, OtherRatio>;
101 template<representation OtherRepresentation, ratio OtherRatio>
103 _value +=
static_cast<value_type
>(other.value()) * ratio_conversion_v<value_type, Ratio, OtherRatio>;
108 template<representation OtherRepresentation, ratio OtherRatio>
110 _value -=
static_cast<value_type
>(other.value()) * ratio_conversion_v<value_type, Ratio, OtherRatio>;
115 constexpr auto operator-()
const noexcept ->
quantity {
119 template<
typename Type>
120 constexpr auto operator/(
const Type other) ->
quantity {
124 constexpr auto value()
const noexcept -> value_type {
128 constexpr operator value_type()
const noexcept {
138template<
typename Dimension, representation Representation, ratio Ratio>
140 return lhs.value() == rhs.value();
143template<
typename Dimension, representation Representation, ratio Ratio>
144constexpr auto operator<=>(
const quantity<Dimension, Representation, Ratio>& lhs,
const quantity<Dimension, Representation, Ratio>& rhs)
noexcept -> std::partial_ordering {
145 return lhs.value() <=> rhs.value();
148template<
typename Dimension, representation LhsRepresentation, ratio LhsRatio, representation RhsRepresentation, ratio RhsRatio>
149constexpr auto operator+(quantity<Dimension, LhsRepresentation, LhsRatio> lhs,
const quantity<Dimension, RhsRepresentation, RhsRatio>& rhs) -> quantity<Dimension, LhsRepresentation, LhsRatio> {
153template<
typename Dimension, representation LhsRepresentation, ratio LhsRatio, representation RhsRepresentation, ratio RhsRatio>
154constexpr auto operator-(quantity<Dimension, LhsRepresentation, LhsRatio> lhs,
const quantity<Dimension, RhsRepresentation, RhsRatio>& rhs) -> quantity<Dimension, LhsRepresentation, LhsRatio> {
158template<
typename Dimension, representation Representation, ratio Ratio>
159constexpr auto operator-(
const quantity<Dimension, Representation, Ratio>& value) -> quantity<Dimension, Representation, Ratio> {
163template<
typename TargetQuantity, representation FromRepresentation, ratio FromRatio>
164constexpr auto quantity_cast(
const quantity<typename TargetQuantity::dimension_type, FromRepresentation, FromRatio>& from) -> TargetQuantity {
165 using value_type =
typename TargetQuantity::value_type;
166 using to_ratio =
typename TargetQuantity::ratio_type;
168 using ratio_type = std::conditional_t<std::is_floating_point_v<value_type>, value_type, std::float_t>;
170 const auto ratio = ratio_conversion_v<ratio_type, to_ratio, FromRatio>;
172 return TargetQuantity{
static_cast<value_type
>(from.value()) *
static_cast<value_type
>(ratio)};
177template<
typename Dimension, sbx::units::representation Representation, sbx::units::ratio Ratio>
178struct fmt::formatter<sbx::units::quantity<Dimension, Representation, Ratio>> : fmt::formatter<Representation> {
180 using base_type = fmt::formatter<Representation>;
182 template<
typename FormatContext>
184 return base_type::format(quantity.value(), context);
Definition: quantity.hpp:66
Definition: quantity.hpp:56
Definition: quantity.hpp:48