1#ifndef LIBSBX_UNITS_QUANTITY_HPP_
2#define LIBSBX_UNITS_QUANTITY_HPP_
13template<
typename Type>
14concept representation = (std::is_integral_v<Type> && !std::is_same_v<Type, bool> ) || std::is_floating_point_v<Type>;
16template<
typename Type>
17concept ratio =
requires {
18 { Type::num } -> std::convertible_to<std::intmax_t>;
19 { Type::den } -> std::convertible_to<std::intmax_t>;
22template<
typename LhsDimension,
typename RhsDimension = LhsDimension,
typename ResultDimension = LhsDimension>
23concept addable_dimensions = std::is_same_v<LhsDimension, RhsDimension> ||
requires(LhsDimension dimension1, ResultDimension dimension2) {
24 { dimension1 + dimension2 } -> std::same_as<ResultDimension>;
25 { dimension2 + dimension1 } -> std::same_as<ResultDimension>;
28template<
typename LhsDimension,
typename RhsDimension = LhsDimension,
typename ResultDimension = LhsDimension>
29concept subtractable_dimensions = std::is_same_v<LhsDimension, RhsDimension> ||
requires(LhsDimension dimension1, ResultDimension dimension2) {
30 { dimension1 - dimension2 } -> std::same_as<ResultDimension>;
31 { dimension2 - dimension1 } -> std::same_as<ResultDimension>;
34template<
typename LhsDimension,
typename RhsDimension = LhsDimension,
typename ResultDimension = LhsDimension>
35concept multipliable_dimensions = std::is_same_v<LhsDimension, RhsDimension> ||
requires(LhsDimension dimension1, ResultDimension dimension2) {
36 { dimension1 * dimension2 } -> std::same_as<ResultDimension>;
37 { dimension2 * dimension1 } -> std::same_as<ResultDimension>;
40template<
typename LhsDimension,
typename RhsDimension = LhsDimension,
typename ResultDimension = LhsDimension>
41concept dividable_dimensions = std::is_same_v<LhsDimension, RhsDimension> ||
requires(LhsDimension dimension1, ResultDimension dimension2) {
42 { dimension1 / dimension2 } -> std::same_as<ResultDimension>;
43 { dimension2 / dimension1 } -> std::same_as<ResultDimension>;
46template<ratio Ratio, ratio OtherRatio>
48 using type = std::ratio<Ratio::num + OtherRatio::num, Ratio::den * OtherRatio::den>;
51template<ratio Ratio, ratio OtherRatio>
52using ratio_multiply_t =
typename ratio_multiply<Ratio, OtherRatio>::type;
54template<representation Representation, ratio Ratio, ratio OtherRatio>
56 static constexpr auto value =
57 static_cast<Representation
>(OtherRatio::num) /
static_cast<Representation
>(OtherRatio::den) *
58 static_cast<Representation
>(Ratio::den) /
static_cast<Representation
>(Ratio::num);
61template<representation Representation, ratio R1, ratio R2>
64template<
typename Dimension, representation Representation, ratio Ratio = std::ratio<1, 1>>
69 using dimension_type = Dimension;
70 using value_type = Representation;
71 using ratio_type = Ratio;
75 template<std::convertible_to<value_type> Type>
76 constexpr explicit quantity(Type value) noexcept
77 : _value{
static_cast<value_type
>(value)} { }
79 template<representation OtherRepresentation, ratio OtherRatio = ratio_type>
81 : _value{quantity_cast<quantity>(other)} { }
89 constexpr auto operator=(
const quantity& other)
noexcept ->
quantity& =
default;
93 template<representation OtherRepresentation, ratio OtherRatio>
95 _value =
static_cast<value_type
>(other.value()) * ratio_conversion_v<value_type, Ratio, OtherRatio>;
100 template<representation OtherRepresentation, ratio OtherRatio>
102 _value +=
static_cast<value_type
>(other.value()) * ratio_conversion_v<value_type, Ratio, OtherRatio>;
107 template<representation OtherRepresentation, ratio OtherRatio>
109 _value -=
static_cast<value_type
>(other.value()) * ratio_conversion_v<value_type, Ratio, OtherRatio>;
114 constexpr auto operator-()
const noexcept ->
quantity {
118 constexpr auto value()
const noexcept -> value_type {
122 constexpr operator value_type()
const noexcept {
132template<
typename Dimension, representation Representation, ratio Ratio>
134 return lhs.value() == rhs.value();
137template<
typename Dimension, representation Representation, ratio Ratio>
138constexpr auto operator<=>(
const quantity<Dimension, Representation, Ratio>& lhs,
const quantity<Dimension, Representation, Ratio>& rhs)
noexcept -> std::partial_ordering {
139 return lhs.value() <=> rhs.value();
142template<
typename Dimension, representation LhsRepresentation, ratio LhsRatio, representation RhsRepresentation, ratio RhsRatio>
143constexpr auto operator+(quantity<Dimension, LhsRepresentation, LhsRatio> lhs,
const quantity<Dimension, RhsRepresentation, RhsRatio>& rhs) -> quantity<Dimension, LhsRepresentation, LhsRatio> {
147template<
typename Dimension, representation LhsRepresentation, ratio LhsRatio, representation RhsRepresentation, ratio RhsRatio>
148constexpr auto operator-(quantity<Dimension, LhsRepresentation, LhsRatio> lhs,
const quantity<Dimension, RhsRepresentation, RhsRatio>& rhs) -> quantity<Dimension, LhsRepresentation, LhsRatio> {
152template<
typename Dimension, representation Representation, ratio Ratio>
153constexpr auto operator-(
const quantity<Dimension, Representation, Ratio>& value) -> quantity<Dimension, Representation, Ratio> {
157template<
typename TargetQuantity, representation FromRepresentation, ratio FromRatio>
158constexpr auto quantity_cast(
const quantity<typename TargetQuantity::dimension_type, FromRepresentation, FromRatio>& from) -> TargetQuantity {
159 using value_type =
typename TargetQuantity::value_type;
160 using to_ratio =
typename TargetQuantity::ratio_type;
162 using ratio_type = std::conditional_t<std::is_floating_point_v<value_type>, value_type, std::float_t>;
164 const auto ratio = ratio_conversion_v<ratio_type, to_ratio, FromRatio>;
166 return TargetQuantity{
static_cast<value_type
>(from.value()) *
static_cast<value_type
>(ratio)};
171template<
typename Dimension, sbx::units::representation Representation, sbx::units::ratio Ratio>
172struct fmt::formatter<sbx::units::quantity<Dimension, Representation, Ratio>> {
174 template<
typename ParseContext>
175 constexpr auto parse(ParseContext& context) ->
decltype(context.begin()) {
176 return context.begin();
179 template<
typename FormatContext>
181 return fmt::format_to(context.out(),
"{}", quantity.value());
Definition: quantity.hpp:65
Definition: quantity.hpp:55
Definition: quantity.hpp:47