mirror of
https://github.com/mpusz/mp-units.git
synced 2025-08-01 03:14:29 +02:00
feat: 💥 initial implementation of implicit point origins
This commit is contained in:
@@ -33,8 +33,6 @@ inline constexpr struct dim_currency : base_dimension<"$"> {} dim_currency;
|
||||
|
||||
QUANTITY_SPEC(currency, dim_currency);
|
||||
|
||||
constexpr struct zero : absolute_point_origin<zero, currency> {} zero;
|
||||
|
||||
inline constexpr struct euro : named_unit<"EUR", kind_of<currency>> {} euro;
|
||||
inline constexpr struct us_dollar : named_unit<"USD", kind_of<currency>> {} us_dollar;
|
||||
inline constexpr struct great_british_pound : named_unit<"GBP", kind_of<currency>> {} great_british_pound;
|
||||
@@ -90,18 +88,19 @@ quantity<To, Rep> exchange_to(quantity<From, Rep> q)
|
||||
template<ReferenceOf<currency> auto To, ReferenceOf<currency> auto From, auto PO, typename Rep>
|
||||
quantity_point<To, PO, Rep> exchange_to(quantity_point<From, PO, Rep> q)
|
||||
{
|
||||
return quantity_point{zero + static_cast<Rep>(exchange_rate<q.unit, get_unit(To)>() *
|
||||
(q - q.absolute_point_origin).numerical_value_in(q.unit)) *
|
||||
To};
|
||||
return quantity_point{
|
||||
static_cast<Rep>(exchange_rate<q.unit, get_unit(To)>() * (q - q.absolute_point_origin).numerical_value_in(q.unit)) *
|
||||
To};
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace unit_symbols;
|
||||
|
||||
quantity_point price_usd = zero + 100 * USD;
|
||||
quantity_point price_usd{100 * USD};
|
||||
quantity_point price_euro = exchange_to<euro>(price_usd);
|
||||
|
||||
std::cout << price_usd.quantity_from(zero) << " -> " << price_euro.quantity_from(zero) << "\n";
|
||||
// std::cout << price_usd.quantity_from(zero) + price_euro.quantity_from(zero) << "\n"; // does not compile
|
||||
std::cout << price_usd.quantity_from_zero() << " -> " << price_euro.quantity_from_zero() << "\n";
|
||||
// std::cout << price_usd.quantity_from_zero() + price_euro.quantity_from_zero() << "\n"; // does
|
||||
// not compile
|
||||
}
|
||||
|
@@ -71,13 +71,28 @@ template<PointOrigin PO1, PointOrigin PO2>
|
||||
else if constexpr (detail::RelativePointOrigin<PO1> && detail::RelativePointOrigin<PO2>)
|
||||
return PO1::quantity_point == PO2::quantity_point;
|
||||
else if constexpr (detail::RelativePointOrigin<PO1>)
|
||||
return detail::same_absolute_point_origins(po1, po2) &&
|
||||
return same_absolute_point_origins(po1, po2) &&
|
||||
detail::is_eq_zero(PO1::quantity_point.quantity_from(PO1::quantity_point.absolute_point_origin));
|
||||
else if constexpr (detail::RelativePointOrigin<PO2>)
|
||||
return detail::same_absolute_point_origins(po1, po2) &&
|
||||
return same_absolute_point_origins(po1, po2) &&
|
||||
detail::is_eq_zero(PO2::quantity_point.quantity_from(PO2::quantity_point.absolute_point_origin));
|
||||
}
|
||||
|
||||
template<QuantitySpec auto QS>
|
||||
struct implicit_zeroth_point_origin_ : absolute_point_origin<implicit_zeroth_point_origin_<QS>, QS> {};
|
||||
|
||||
template<QuantitySpec auto QS>
|
||||
inline constexpr implicit_zeroth_point_origin_<QS> implicit_zeroth_point_origin;
|
||||
|
||||
template<Reference R>
|
||||
[[nodiscard]] consteval PointOriginFor<get_quantity_spec(R{})> auto zeroth_point_origin(R)
|
||||
{
|
||||
if constexpr (requires { get_unit(R{}).point_origin; })
|
||||
return get_unit(R{}).point_origin;
|
||||
else
|
||||
return implicit_zeroth_point_origin<get_quantity_spec(R{})>;
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<PointOrigin PO>
|
||||
@@ -100,7 +115,7 @@ template<PointOrigin PO>
|
||||
* @tparam PO a type that represents the origin point from which the quantity point is measured from
|
||||
* @tparam Rep a type to be used to represent values of a quantity point
|
||||
*/
|
||||
template<Reference auto R, PointOriginFor<get_quantity_spec(R)> auto PO,
|
||||
template<Reference auto R, PointOriginFor<get_quantity_spec(R)> auto PO = zeroth_point_origin(R),
|
||||
RepresentationOf<get_quantity_spec(R).character> Rep = double>
|
||||
class quantity_point {
|
||||
public:
|
||||
@@ -135,7 +150,14 @@ public:
|
||||
quantity_point(quantity_point&&) = default;
|
||||
|
||||
template<typename Q>
|
||||
requires std::same_as<std::remove_cvref_t<Q>, quantity_type>
|
||||
requires QuantityOf<std::remove_cvref_t<Q>, get_quantity_spec(R)> && std::constructible_from<quantity_type, Q> &&
|
||||
(point_origin == zeroth_point_origin(R)) && (point_origin == zeroth_point_origin(Q::reference))
|
||||
constexpr explicit quantity_point(Q&& q) : quantity_from_origin_is_an_implementation_detail_(std::forward<Q>(q))
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Q>
|
||||
requires QuantityOf<std::remove_cvref_t<Q>, get_quantity_spec(R)> && std::constructible_from<quantity_type, Q>
|
||||
constexpr quantity_point(Q&& q, std::remove_const_t<decltype(PO)>) :
|
||||
quantity_from_origin_is_an_implementation_detail_(std::forward<Q>(q))
|
||||
{
|
||||
@@ -219,6 +241,20 @@ public:
|
||||
return *this - PO2{};
|
||||
}
|
||||
|
||||
// returns always a value relative to the unit's zero
|
||||
// available only if point is defined in terms of a unit's zero point origin
|
||||
[[nodiscard]] constexpr Quantity auto quantity_from_zero() const
|
||||
requires(detail::same_absolute_point_origins(absolute_point_origin, zeroth_point_origin(R)))
|
||||
{
|
||||
// original quantity point unit can be lost in the below operation
|
||||
const auto q = quantity_from(zeroth_point_origin(R));
|
||||
if constexpr (requires { q.in(unit); })
|
||||
// restore it if possible (non-truncating)
|
||||
return q.in(unit);
|
||||
else
|
||||
return q;
|
||||
}
|
||||
|
||||
// unit conversions
|
||||
template<UnitCompatibleWith<unit, quantity_spec> U>
|
||||
requires detail::QuantityConvertibleTo<quantity_type, quantity<detail::make_reference(quantity_spec, U{}), Rep>>
|
||||
@@ -322,6 +358,9 @@ public:
|
||||
};
|
||||
|
||||
// CTAD
|
||||
template<Quantity Q>
|
||||
quantity_point(Q q) -> quantity_point<Q::reference, zeroth_point_origin(Q::reference), typename Q::rep>;
|
||||
|
||||
template<Quantity Q, PointOriginFor<Q::quantity_spec> PO>
|
||||
quantity_point(Q q, PO) -> quantity_point<Q::reference, PO{}, typename Q::rep>;
|
||||
|
||||
|
@@ -29,6 +29,7 @@
|
||||
#include <mp-units/bits/external/type_traits.h>
|
||||
#include <mp-units/bits/get_associated_quantity.h>
|
||||
#include <mp-units/bits/magnitude.h>
|
||||
#include <mp-units/bits/quantity_point_concepts.h>
|
||||
#include <mp-units/bits/quantity_spec_concepts.h>
|
||||
#include <mp-units/bits/ratio.h>
|
||||
#include <mp-units/bits/symbol_text.h>
|
||||
@@ -116,6 +117,14 @@ struct named_unit<Symbol, QS> {
|
||||
static constexpr auto quantity_spec = QS;
|
||||
};
|
||||
|
||||
template<basic_symbol_text Symbol, detail::QuantityKindSpec auto QS, PointOrigin auto PO>
|
||||
requires(!Symbol.empty()) && detail::BaseDimension<std::remove_const_t<decltype(QS.dimension)>>
|
||||
struct named_unit<Symbol, QS, PO> {
|
||||
static constexpr auto symbol = Symbol; ///< Unique base unit identifier
|
||||
static constexpr auto quantity_spec = QS;
|
||||
static constexpr auto point_origin = PO;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Specialization for a unit that can be reused by several base quantities
|
||||
*
|
||||
@@ -132,6 +141,13 @@ struct named_unit<Symbol> {
|
||||
static constexpr auto symbol = Symbol; ///< Unique base unit identifier
|
||||
};
|
||||
|
||||
template<basic_symbol_text Symbol, PointOrigin auto PO>
|
||||
requires(!Symbol.empty())
|
||||
struct named_unit<Symbol, PO> {
|
||||
static constexpr auto symbol = Symbol; ///< Unique base unit identifier
|
||||
static constexpr auto point_origin = PO;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Specialization for a unit with special name
|
||||
*
|
||||
@@ -146,6 +162,13 @@ struct named_unit<Symbol, U> : std::remove_const_t<decltype(U)> {
|
||||
static constexpr auto symbol = Symbol; ///< Unique unit identifier
|
||||
};
|
||||
|
||||
template<basic_symbol_text Symbol, Unit auto U, PointOrigin auto PO>
|
||||
requires(!Symbol.empty())
|
||||
struct named_unit<Symbol, U, PO> : std::remove_const_t<decltype(U)> {
|
||||
static constexpr auto symbol = Symbol; ///< Unique unit identifier
|
||||
static constexpr auto point_origin = PO;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Specialization for a unit with special name valid only for a specific quantity
|
||||
*
|
||||
@@ -162,6 +185,14 @@ struct named_unit<Symbol, U, QS> : std::remove_const_t<decltype(U)> {
|
||||
static constexpr auto quantity_spec = QS;
|
||||
};
|
||||
|
||||
template<basic_symbol_text Symbol, AssociatedUnit auto U, detail::QuantityKindSpec auto QS, PointOrigin auto PO>
|
||||
requires(!Symbol.empty()) && (QS.dimension == detail::get_associated_quantity(U).dimension)
|
||||
struct named_unit<Symbol, U, QS, PO> : std::remove_const_t<decltype(U)> {
|
||||
static constexpr auto symbol = Symbol; ///< Unique unit identifier
|
||||
static constexpr auto quantity_spec = QS;
|
||||
static constexpr auto point_origin = PO;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A prefixed unit
|
||||
*
|
||||
@@ -286,14 +317,14 @@ canonical_unit(M, U) -> canonical_unit<M, U>;
|
||||
|
||||
#endif
|
||||
|
||||
template<Unit T, basic_symbol_text Symbol, detail::QuantityKindSpec auto Q>
|
||||
[[nodiscard]] consteval auto get_canonical_unit_impl(T t, const named_unit<Symbol, Q>&);
|
||||
template<Unit T, basic_symbol_text Symbol, detail::QuantityKindSpec auto Q, auto... Args>
|
||||
[[nodiscard]] consteval auto get_canonical_unit_impl(T t, const named_unit<Symbol, Q, Args...>&);
|
||||
|
||||
template<Unit T, basic_symbol_text Symbol>
|
||||
[[nodiscard]] consteval auto get_canonical_unit_impl(T t, const named_unit<Symbol>&);
|
||||
template<Unit T, basic_symbol_text Symbol, auto... Args>
|
||||
[[nodiscard]] consteval auto get_canonical_unit_impl(T t, const named_unit<Symbol, Args...>&);
|
||||
|
||||
template<Unit T, basic_symbol_text Symbol, Unit auto U>
|
||||
[[nodiscard]] consteval auto get_canonical_unit_impl(T, const named_unit<Symbol, U>&);
|
||||
template<Unit T, basic_symbol_text Symbol, Unit auto U, auto... Args>
|
||||
[[nodiscard]] consteval auto get_canonical_unit_impl(T, const named_unit<Symbol, U, Args...>&);
|
||||
|
||||
template<typename T, typename F, int Num, int... Den>
|
||||
[[nodiscard]] consteval auto get_canonical_unit_impl(T, const power<F, Num, Den...>&);
|
||||
@@ -308,20 +339,20 @@ template<Unit T, auto M, typename U>
|
||||
return canonical_unit{M * base.mag, base.reference_unit};
|
||||
}
|
||||
|
||||
template<Unit T, basic_symbol_text Symbol, detail::QuantityKindSpec auto Q>
|
||||
[[nodiscard]] consteval auto get_canonical_unit_impl(T t, const named_unit<Symbol, Q>&)
|
||||
template<Unit T, basic_symbol_text Symbol, detail::QuantityKindSpec auto Q, auto... Args>
|
||||
[[nodiscard]] consteval auto get_canonical_unit_impl(T t, const named_unit<Symbol, Q, Args...>&)
|
||||
{
|
||||
return canonical_unit{mag<1>, t};
|
||||
}
|
||||
|
||||
template<Unit T, basic_symbol_text Symbol>
|
||||
[[nodiscard]] consteval auto get_canonical_unit_impl(T t, const named_unit<Symbol>&)
|
||||
template<Unit T, basic_symbol_text Symbol, auto... Args>
|
||||
[[nodiscard]] consteval auto get_canonical_unit_impl(T t, const named_unit<Symbol, Args...>&)
|
||||
{
|
||||
return canonical_unit{mag<1>, t};
|
||||
}
|
||||
|
||||
template<Unit T, basic_symbol_text Symbol, Unit auto U>
|
||||
[[nodiscard]] consteval auto get_canonical_unit_impl(T, const named_unit<Symbol, U>&)
|
||||
template<Unit T, basic_symbol_text Symbol, Unit auto U, auto... Args>
|
||||
[[nodiscard]] consteval auto get_canonical_unit_impl(T, const named_unit<Symbol, U, Args...>&)
|
||||
{
|
||||
return get_canonical_unit_impl(U, U);
|
||||
}
|
||||
|
@@ -1,38 +0,0 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2018 Mateusz Pusz
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mp-units/quantity_point.h>
|
||||
#include <mp-units/systems/si/units.h>
|
||||
|
||||
namespace mp_units::si {
|
||||
|
||||
// clang-format off
|
||||
inline constexpr struct absolute_zero : absolute_point_origin<absolute_zero, isq::thermodynamic_temperature> {} absolute_zero;
|
||||
inline constexpr struct zeroth_kelvin : decltype(absolute_zero) {} zeroth_kelvin;
|
||||
|
||||
inline constexpr struct ice_point : relative_point_origin<absolute_zero + 273.15 * kelvin> {} ice_point;
|
||||
inline constexpr struct zeroth_degree_Celsius : decltype(ice_point) {} zeroth_degree_Celsius;
|
||||
// clang-format on
|
||||
|
||||
} // namespace mp_units::si
|
@@ -23,7 +23,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <mp-units/systems/si/constants.h>
|
||||
#include <mp-units/systems/si/point_origins.h>
|
||||
#include <mp-units/systems/si/prefixes.h>
|
||||
#include <mp-units/systems/si/unit_symbols.h>
|
||||
#include <mp-units/systems/si/units.h>
|
||||
|
@@ -22,6 +22,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mp-units/quantity_point.h>
|
||||
#include <mp-units/systems/isq/atomic_and_nuclear_physics.h>
|
||||
#include <mp-units/systems/isq/base_quantities.h>
|
||||
#include <mp-units/systems/isq/space_and_time.h>
|
||||
@@ -39,7 +40,11 @@ inline constexpr struct metre : named_unit<"m", kind_of<isq::length>> {} metre;
|
||||
inline constexpr struct gram : named_unit<"g", kind_of<isq::mass>> {} gram;
|
||||
inline constexpr struct kilogram : decltype(kilo<gram>) {} kilogram;
|
||||
inline constexpr struct ampere : named_unit<"A", kind_of<isq::electric_current>> {} ampere;
|
||||
inline constexpr struct kelvin : named_unit<"K", kind_of<isq::thermodynamic_temperature>> {} kelvin;
|
||||
|
||||
inline constexpr struct absolute_zero : absolute_point_origin<absolute_zero, isq::thermodynamic_temperature> {} absolute_zero;
|
||||
inline constexpr struct zeroth_kelvin : decltype(absolute_zero) {} zeroth_kelvin;
|
||||
inline constexpr struct kelvin : named_unit<"K", kind_of<isq::thermodynamic_temperature>, zeroth_kelvin> {} kelvin;
|
||||
|
||||
inline constexpr struct mole : named_unit<"mol", kind_of<isq::amount_of_substance>> {} mole;
|
||||
inline constexpr struct candela : named_unit<"cd", kind_of<isq::luminous_intensity>> {} candela;
|
||||
|
||||
@@ -68,7 +73,11 @@ inline constexpr struct siemens : named_unit<"S", one / ohm> {} siemens;
|
||||
inline constexpr struct weber : named_unit<"Wb", volt * second> {} weber;
|
||||
inline constexpr struct tesla : named_unit<"T", weber / square(metre)> {} tesla;
|
||||
inline constexpr struct henry : named_unit<"H", weber / ampere> {} henry;
|
||||
inline constexpr struct degree_Celsius : named_unit<basic_symbol_text{"°C", "`C"}, kelvin> {} degree_Celsius;
|
||||
|
||||
inline constexpr struct ice_point : relative_point_origin<quantity_point{273.15 * kelvin}> {} ice_point;
|
||||
inline constexpr struct zeroth_degree_Celsius : decltype(ice_point) {} zeroth_degree_Celsius;
|
||||
inline constexpr struct degree_Celsius : named_unit<basic_symbol_text{"°C", "`C"}, kelvin, zeroth_degree_Celsius> {} degree_Celsius;
|
||||
|
||||
inline constexpr struct lumen : named_unit<"lm", candela * steradian> {} lumen;
|
||||
inline constexpr struct lux : named_unit<"lx", lumen / square(metre)> {} lux;
|
||||
inline constexpr struct becquerel : named_unit<"Bq", one / second, kind_of<isq::activity>> {} becquerel;
|
||||
|
@@ -110,9 +110,9 @@ inline constexpr struct troy_pound : named_unit<"lb t", mag<12> * troy_once> {}
|
||||
inline constexpr struct inch_of_mercury : named_unit<"inHg", mag<ratio(3'386'389, 1'000)> * si::pascal> {} inch_of_mercury;
|
||||
|
||||
// https://en.wikipedia.org/wiki/United_States_customary_units#Temperature
|
||||
inline constexpr struct degree_Fahrenheit : named_unit<basic_symbol_text{"°F", "`F"}, mag<ratio{5, 9}> * si::degree_Celsius> {} degree_Fahrenheit;
|
||||
inline constexpr struct zeroth_degree_Fahrenheit : relative_point_origin<si::zeroth_degree_Celsius - 32 * (mag<ratio{5, 9}> * si::degree_Celsius)> {} zeroth_degree_Fahrenheit;
|
||||
inline constexpr struct degree_Fahrenheit : named_unit<basic_symbol_text{"°F", "`F"}, mag<ratio{5, 9}> * si::degree_Celsius, zeroth_degree_Fahrenheit> {} degree_Fahrenheit;
|
||||
|
||||
inline constexpr struct zeroth_degree_Fahrenheit : relative_point_origin<si::zeroth_degree_Celsius - 32 * degree_Fahrenheit> {} zeroth_degree_Fahrenheit;
|
||||
// clang-format on
|
||||
|
||||
namespace unit_symbols {
|
||||
|
@@ -253,7 +253,7 @@ static_assert(quantity_point<si::degree_Celsius, si::ice_point>::dimension == is
|
||||
static_assert(quantity_point<si::degree_Celsius, si::ice_point>::unit == si::degree_Celsius);
|
||||
static_assert(is_of_type<quantity_point<si::degree_Celsius, si::ice_point>::point_origin, struct si::ice_point>);
|
||||
static_assert(
|
||||
is_of_type<quantity_point<si::degree_Celsius, si::ice_point>::absolute_point_origin, struct si::absolute_zero>);
|
||||
is_of_type<quantity_point<si::degree_Celsius, si::ice_point>::absolute_point_origin, struct si::zeroth_kelvin>);
|
||||
|
||||
static_assert(quantity_point<isq::Celsius_temperature[si::degree_Celsius], si::ice_point>::reference ==
|
||||
isq::Celsius_temperature[si::degree_Celsius]);
|
||||
@@ -266,7 +266,7 @@ static_assert(is_of_type<quantity_point<isq::Celsius_temperature[si::degree_Cels
|
||||
struct si::ice_point>);
|
||||
static_assert(
|
||||
is_of_type<quantity_point<isq::Celsius_temperature[si::degree_Celsius], si::ice_point>::absolute_point_origin,
|
||||
struct si::absolute_zero>);
|
||||
struct si::zeroth_kelvin>);
|
||||
|
||||
|
||||
//////////////////
|
||||
|
Reference in New Issue
Block a user