mirror of
https://github.com/mpusz/mp-units.git
synced 2025-08-04 12:54:25 +02:00
refactor: implementation cleanup + support for units as references started
This commit is contained in:
@@ -44,15 +44,16 @@ constexpr quantity<isq::speed[m / s]> fixed_double_si_avg_speed(quantity<isq::le
|
|||||||
return d / t;
|
return d / t;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr quantity_of<isq::speed> auto avg_speed(quantity_of<isq::length> auto d, quantity_of<isq::time> auto t)
|
constexpr QuantityOf<isq::speed> auto avg_speed(QuantityOf<isq::length> auto d, QuantityOf<isq::time> auto t)
|
||||||
{
|
{
|
||||||
return quantity_cast<isq::speed>(d / t);
|
return quantity_cast<isq::speed>(d / t);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<quantity_of<isq::length> D, quantity_of<isq::time> T, quantity_of<isq::speed> V>
|
template<QuantityOf<isq::length> D, QuantityOf<isq::time> T, QuantityOf<isq::speed> V>
|
||||||
void print_result(D distance, T duration, V speed)
|
void print_result(D distance, T duration, V speed)
|
||||||
{
|
{
|
||||||
const auto result_in_kmph = quantity_cast<km / h>(speed);
|
constexpr auto kmph = si::kilo<si::metre> / si::hour;
|
||||||
|
const auto result_in_kmph = quantity_cast<kmph>(speed);
|
||||||
std::cout << "Average speed of a car that makes " << distance << " in " << duration << " is " << result_in_kmph
|
std::cout << "Average speed of a car that makes " << distance << " in " << duration << " is " << result_in_kmph
|
||||||
<< ".\n";
|
<< ".\n";
|
||||||
}
|
}
|
||||||
|
@@ -53,10 +53,10 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] constexpr quantity_of<isq::weight> auto filled_weight() const
|
[[nodiscard]] constexpr QuantityOf<isq::weight> auto filled_weight() const
|
||||||
{
|
{
|
||||||
const weak_quantity_of<isq::volume> auto volume = base_ * height_;
|
const WeakQuantityOf<isq::volume> auto volume = base_ * height_;
|
||||||
const weak_quantity_of<isq::mass> auto mass = density_ * volume;
|
const WeakQuantityOf<isq::mass> auto mass = density_ * volume;
|
||||||
return quantity_cast<isq::weight>(mass * g);
|
return quantity_cast<isq::weight>(mass * g);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,9 +96,9 @@ int main()
|
|||||||
const auto spare_capacity = box.spare_capacity(measured_mass);
|
const auto spare_capacity = box.spare_capacity(measured_mass);
|
||||||
const auto filled_weight = box.filled_weight();
|
const auto filled_weight = box.filled_weight();
|
||||||
|
|
||||||
const weak_quantity_of<isq::mass_change_rate> auto input_flow_rate = measured_mass / fill_time;
|
const WeakQuantityOf<isq::mass_change_rate> auto input_flow_rate = measured_mass / fill_time;
|
||||||
const weak_quantity_of<isq::speed> auto float_rise_rate = fill_level / fill_time;
|
const WeakQuantityOf<isq::speed> auto float_rise_rate = fill_level / fill_time;
|
||||||
const quantity_of<isq::time> auto fill_time_left = (height / fill_level - 1) * fill_time;
|
const QuantityOf<isq::time> auto fill_time_left = (height / fill_level - 1) * fill_time;
|
||||||
|
|
||||||
const auto fill_percent = (fill_level / height)[percent];
|
const auto fill_percent = (fill_level / height)[percent];
|
||||||
|
|
||||||
|
@@ -105,7 +105,7 @@ struct glider {
|
|||||||
std::array<polar_point, 1> polar;
|
std::array<polar_point, 1> polar;
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr mp_units::weak_quantity_of<mp_units::dimensionless> auto glide_ratio(const glider::polar_point& polar)
|
constexpr mp_units::WeakQuantityOf<mp_units::dimensionless> auto glide_ratio(const glider::polar_point& polar)
|
||||||
{
|
{
|
||||||
return polar.v / -polar.climb;
|
return polar.v / -polar.climb;
|
||||||
}
|
}
|
||||||
|
@@ -95,15 +95,15 @@ constexpr mp_units::quantity<mp_units::dimensionless[mp_units::one]> kalman_gain
|
|||||||
}
|
}
|
||||||
|
|
||||||
// state update
|
// state update
|
||||||
template<typename Q, QuantityOrQuantityPoint QM, mp_units::quantity_of<mp_units::dimensionless> K>
|
template<typename Q, QuantityOrQuantityPoint QM, mp_units::QuantityOf<mp_units::dimensionless> K>
|
||||||
requires(Q::quantity_spec == QM::quantity_spec)
|
requires(Q::quantity_spec == QM::quantity_spec)
|
||||||
constexpr state<Q> state_update(const state<Q>& predicted, QM measured, K gain)
|
constexpr state<Q> state_update(const state<Q>& predicted, QM measured, K gain)
|
||||||
{
|
{
|
||||||
return {get<0>(predicted) + gain * (measured - get<0>(predicted))};
|
return {get<0>(predicted) + gain * (measured - get<0>(predicted))};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Q1, typename Q2, QuantityOrQuantityPoint QM, mp_units::quantity_of<mp_units::dimensionless> K,
|
template<typename Q1, typename Q2, QuantityOrQuantityPoint QM, mp_units::QuantityOf<mp_units::dimensionless> K,
|
||||||
mp_units::quantity_of<mp_units::isq::time> T>
|
mp_units::QuantityOf<mp_units::isq::time> T>
|
||||||
requires(Q1::quantity_spec == QM::quantity_spec)
|
requires(Q1::quantity_spec == QM::quantity_spec)
|
||||||
constexpr state<Q1, Q2> state_update(const state<Q1, Q2>& predicted, QM measured, std::array<K, 2> gain, T interval)
|
constexpr state<Q1, Q2> state_update(const state<Q1, Q2>& predicted, QM measured, std::array<K, 2> gain, T interval)
|
||||||
{
|
{
|
||||||
@@ -113,7 +113,7 @@ constexpr state<Q1, Q2> state_update(const state<Q1, Q2>& predicted, QM measured
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename Q1, typename Q2, typename Q3, QuantityOrQuantityPoint QM,
|
template<typename Q1, typename Q2, typename Q3, QuantityOrQuantityPoint QM,
|
||||||
mp_units::quantity_of<mp_units::dimensionless> K, mp_units::quantity_of<mp_units::isq::time> T>
|
mp_units::QuantityOf<mp_units::dimensionless> K, mp_units::QuantityOf<mp_units::isq::time> T>
|
||||||
requires(Q1::quantity_spec == QM::quantity_spec)
|
requires(Q1::quantity_spec == QM::quantity_spec)
|
||||||
constexpr state<Q1, Q2, Q3> state_update(const state<Q1, Q2, Q3>& predicted, QM measured, std::array<K, 3> gain,
|
constexpr state<Q1, Q2, Q3> state_update(const state<Q1, Q2, Q3>& predicted, QM measured, std::array<K, 3> gain,
|
||||||
T interval)
|
T interval)
|
||||||
@@ -125,14 +125,14 @@ constexpr state<Q1, Q2, Q3> state_update(const state<Q1, Q2, Q3>& predicted, QM
|
|||||||
}
|
}
|
||||||
|
|
||||||
// covariance update
|
// covariance update
|
||||||
template<mp_units::Quantity Q, mp_units::quantity_of<mp_units::dimensionless> K>
|
template<mp_units::Quantity Q, mp_units::QuantityOf<mp_units::dimensionless> K>
|
||||||
constexpr Q covariance_update(Q uncertainty, K gain)
|
constexpr Q covariance_update(Q uncertainty, K gain)
|
||||||
{
|
{
|
||||||
return (1 - gain) * uncertainty;
|
return (1 - gain) * uncertainty;
|
||||||
}
|
}
|
||||||
|
|
||||||
// state extrapolation
|
// state extrapolation
|
||||||
template<typename Q1, typename Q2, mp_units::quantity_of<mp_units::isq::time> T>
|
template<typename Q1, typename Q2, mp_units::QuantityOf<mp_units::isq::time> T>
|
||||||
constexpr state<Q1, Q2> state_extrapolation(const state<Q1, Q2>& estimated, T interval)
|
constexpr state<Q1, Q2> state_extrapolation(const state<Q1, Q2>& estimated, T interval)
|
||||||
{
|
{
|
||||||
const auto q1 = get<0>(estimated) + get<1>(estimated) * interval;
|
const auto q1 = get<0>(estimated) + get<1>(estimated) * interval;
|
||||||
@@ -140,7 +140,7 @@ constexpr state<Q1, Q2> state_extrapolation(const state<Q1, Q2>& estimated, T in
|
|||||||
return {q1, q2};
|
return {q1, q2};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Q1, typename Q2, typename Q3, mp_units::quantity_of<mp_units::isq::time> T>
|
template<typename Q1, typename Q2, typename Q3, mp_units::QuantityOf<mp_units::isq::time> T>
|
||||||
constexpr state<Q1, Q2, Q3> state_extrapolation(const state<Q1, Q2, Q3>& estimated, T interval)
|
constexpr state<Q1, Q2, Q3> state_extrapolation(const state<Q1, Q2, Q3>& estimated, T interval)
|
||||||
{
|
{
|
||||||
const auto q1 = get<0>(estimated) + get<1>(estimated) * interval + get<2>(estimated) * pow<2>(interval) / 2;
|
const auto q1 = get<0>(estimated) + get<1>(estimated) * interval + get<2>(estimated) * pow<2>(interval) / 2;
|
||||||
|
@@ -38,7 +38,7 @@ void print_header(const kalman::State auto& initial)
|
|||||||
"Next Estimate");
|
"Next Estimate");
|
||||||
}
|
}
|
||||||
|
|
||||||
void print(auto iteration, quantity_of<dimensionless> auto gain, Quantity auto measured,
|
void print(auto iteration, QuantityOf<dimensionless> auto gain, Quantity auto measured,
|
||||||
const kalman::State auto& current, const kalman::State auto& next)
|
const kalman::State auto& current, const kalman::State auto& next)
|
||||||
{
|
{
|
||||||
std::cout << STD_FMT::format("{:2} | {:9} | {:8} | {:14} | {:14}\n", iteration, gain, measured, current, next);
|
std::cout << STD_FMT::format("{:2} | {:9} | {:8} | {:14} | {:14}\n", iteration, gain, measured, current, next);
|
||||||
|
@@ -40,7 +40,7 @@ void print_header(kalman::estimation<Q> initial)
|
|||||||
"Next Estimate");
|
"Next Estimate");
|
||||||
}
|
}
|
||||||
|
|
||||||
template<Quantity Q, quantity_of<dimensionless> K>
|
template<Quantity Q, QuantityOf<dimensionless> K>
|
||||||
void print(auto iteration, K gain, Q measured, kalman::estimation<Q> current, kalman::estimation<Q> next)
|
void print(auto iteration, K gain, Q measured, kalman::estimation<Q> current, kalman::estimation<Q> next)
|
||||||
{
|
{
|
||||||
std::cout << STD_FMT::format("{:2} | {:5%.2Q} | {:8} | {:>16.2} | {:>16.2}\n", iteration, gain, measured, current,
|
std::cout << STD_FMT::format("{:2} | {:5%.2Q} | {:8} | {:>16.2} | {:>16.2}\n", iteration, gain, measured, current,
|
||||||
@@ -60,7 +60,7 @@ int main()
|
|||||||
const auto measurement_uncertainty = pow<2>(5. * isq::height[m]);
|
const auto measurement_uncertainty = pow<2>(5. * isq::height[m]);
|
||||||
|
|
||||||
auto update = [=]<Quantity Q>(const estimation<Q>& previous, const Q& measurement,
|
auto update = [=]<Quantity Q>(const estimation<Q>& previous, const Q& measurement,
|
||||||
quantity_of<dimensionless> auto gain) {
|
QuantityOf<dimensionless> auto gain) {
|
||||||
return estimation{state_update(previous.state, measurement, gain), covariance_update(previous.uncertainty, gain)};
|
return estimation{state_update(previous.state, measurement, gain), covariance_update(previous.uncertainty, gain)};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -41,7 +41,7 @@ void print_header(kalman::estimation<QP> initial)
|
|||||||
"Next Estimate");
|
"Next Estimate");
|
||||||
}
|
}
|
||||||
|
|
||||||
template<QuantityPoint QP, quantity_of<dimensionless> K>
|
template<QuantityPoint QP, QuantityOf<dimensionless> K>
|
||||||
void print(auto iteration, K gain, QP measured, kalman::estimation<QP> current, kalman::estimation<QP> next)
|
void print(auto iteration, K gain, QP measured, kalman::estimation<QP> current, kalman::estimation<QP> next)
|
||||||
{
|
{
|
||||||
std::cout << STD_FMT::format("{:2} | {:7%.4Q} | {:10%.3Q %q} | {:>18.3} | {:>18.3}\n", iteration, gain,
|
std::cout << STD_FMT::format("{:2} | {:7%.4Q} | {:10%.3Q %q} | {:>18.3} | {:>18.3}\n", iteration, gain,
|
||||||
@@ -64,7 +64,7 @@ int main()
|
|||||||
const auto measurement_uncertainty = pow<2>(0.1 * deg_C);
|
const auto measurement_uncertainty = pow<2>(0.1 * deg_C);
|
||||||
|
|
||||||
auto update = [=]<QuantityPoint QP>(const estimation<QP>& previous, const QP& meassurement,
|
auto update = [=]<QuantityPoint QP>(const estimation<QP>& previous, const QP& meassurement,
|
||||||
quantity_of<dimensionless> auto gain) {
|
QuantityOf<dimensionless> auto gain) {
|
||||||
return estimation{state_update(previous.state, meassurement, gain), covariance_update(previous.uncertainty, gain)};
|
return estimation{state_update(previous.state, meassurement, gain), covariance_update(previous.uncertainty, gain)};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -41,7 +41,7 @@ void print_header(kalman::estimation<QP> initial)
|
|||||||
"Next Estimate");
|
"Next Estimate");
|
||||||
}
|
}
|
||||||
|
|
||||||
template<QuantityPoint QP, quantity_of<dimensionless> K>
|
template<QuantityPoint QP, QuantityOf<dimensionless> K>
|
||||||
void print(auto iteration, K gain, QP measured, kalman::estimation<QP> current, kalman::estimation<QP> next)
|
void print(auto iteration, K gain, QP measured, kalman::estimation<QP> current, kalman::estimation<QP> next)
|
||||||
{
|
{
|
||||||
std::cout << STD_FMT::format("{:2} | {:7%.4Q} | {:10%.3Q %q} | {:>18.3} | {:>18.3}\n", iteration, gain,
|
std::cout << STD_FMT::format("{:2} | {:7%.4Q} | {:10%.3Q %q} | {:>18.3} | {:>18.3}\n", iteration, gain,
|
||||||
@@ -64,7 +64,7 @@ int main()
|
|||||||
const auto measurement_uncertainty = pow<2>(0.1 * deg_C);
|
const auto measurement_uncertainty = pow<2>(0.1 * deg_C);
|
||||||
|
|
||||||
auto update = [=]<QuantityPoint QP>(const estimation<QP>& previous, const QP& meassurement,
|
auto update = [=]<QuantityPoint QP>(const estimation<QP>& previous, const QP& meassurement,
|
||||||
quantity_of<dimensionless> auto gain) {
|
QuantityOf<dimensionless> auto gain) {
|
||||||
return estimation{state_update(previous.state, meassurement, gain), covariance_update(previous.uncertainty, gain)};
|
return estimation{state_update(previous.state, meassurement, gain), covariance_update(previous.uncertainty, gain)};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -41,7 +41,7 @@ void print_header(kalman::estimation<QP> initial)
|
|||||||
"Next Estimate");
|
"Next Estimate");
|
||||||
}
|
}
|
||||||
|
|
||||||
template<QuantityPoint QP, quantity_of<dimensionless> K>
|
template<QuantityPoint QP, QuantityOf<dimensionless> K>
|
||||||
void print(auto iteration, K gain, QP measured, kalman::estimation<QP> current, kalman::estimation<QP> next)
|
void print(auto iteration, K gain, QP measured, kalman::estimation<QP> current, kalman::estimation<QP> next)
|
||||||
{
|
{
|
||||||
std::cout << STD_FMT::format("{:2} | {:7%.3Q} | {:10%.3Q %q} | {:>16.2} | {:>16.2}\n", iteration, gain,
|
std::cout << STD_FMT::format("{:2} | {:7%.3Q} | {:10%.3Q %q} | {:>16.2} | {:>16.2}\n", iteration, gain,
|
||||||
@@ -64,7 +64,7 @@ int main()
|
|||||||
const auto measurement_uncertainty = pow<2>(0.1 * deg_C);
|
const auto measurement_uncertainty = pow<2>(0.1 * deg_C);
|
||||||
|
|
||||||
auto update = [=]<QuantityPoint QP>(const estimation<QP>& previous, const QP& meassurement,
|
auto update = [=]<QuantityPoint QP>(const estimation<QP>& previous, const QP& meassurement,
|
||||||
quantity_of<dimensionless> auto gain) {
|
QuantityOf<dimensionless> auto gain) {
|
||||||
return estimation{state_update(previous.state, meassurement, gain), covariance_update(previous.uncertainty, gain)};
|
return estimation{state_update(previous.state, meassurement, gain), covariance_update(previous.uncertainty, gain)};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -245,7 +245,7 @@ struct quantity_formatter {
|
|||||||
template<std::input_iterator It, std::sentinel_for<It> S>
|
template<std::input_iterator It, std::sentinel_for<It> S>
|
||||||
void on_quantity_unit(It, S)
|
void on_quantity_unit(It, S)
|
||||||
{
|
{
|
||||||
out = unit_symbol_to<CharT>(out, Reference.unit, specs.unit);
|
out = unit_symbol_to<CharT>(out, get_unit(Reference), specs.unit);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -396,9 +396,9 @@ private:
|
|||||||
if (begin == end || *begin == '}') {
|
if (begin == end || *begin == '}') {
|
||||||
// default format should print value followed by the unit separated with 1 space
|
// default format should print value followed by the unit separated with 1 space
|
||||||
out = mp_units::detail::format_units_quantity_value<CharT>(out, q.number(), specs.rep, ctx.locale());
|
out = mp_units::detail::format_units_quantity_value<CharT>(out, q.number(), specs.rep, ctx.locale());
|
||||||
if constexpr (!std::derived_from<decltype(Reference.unit), mp_units::derived_unit<>>) {
|
if constexpr (!std::derived_from<decltype(get_unit(Reference)), mp_units::derived_unit<>>) {
|
||||||
*out++ = CharT(' ');
|
*out++ = CharT(' ');
|
||||||
out = unit_symbol_to<CharT>(out, Reference.unit);
|
out = unit_symbol_to<CharT>(out, get_unit(Reference));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// user provided format
|
// user provided format
|
||||||
|
@@ -35,9 +35,9 @@ template<typename CharT, class Traits, auto R, typename Rep>
|
|||||||
void to_stream(std::basic_ostream<CharT, Traits>& os, const quantity<R, Rep>& q)
|
void to_stream(std::basic_ostream<CharT, Traits>& os, const quantity<R, Rep>& q)
|
||||||
{
|
{
|
||||||
os << q.number();
|
os << q.number();
|
||||||
if constexpr (!std::derived_from<decltype(R.unit), derived_unit<>>) {
|
if constexpr (!std::derived_from<decltype(get_unit(R)), derived_unit<>>) {
|
||||||
os << " ";
|
os << " ";
|
||||||
unit_symbol_to<CharT>(std::ostream_iterator<CharT>(os), R.unit);
|
unit_symbol_to<CharT>(std::ostream_iterator<CharT>(os), get_unit(R));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -33,6 +33,32 @@ check_libcxx_in_use(${projectPrefix}LIBCXX)
|
|||||||
add_library(
|
add_library(
|
||||||
mp-units-core
|
mp-units-core
|
||||||
INTERFACE
|
INTERFACE
|
||||||
|
|
||||||
|
include/mp_units/bits/external/fixed_string.h
|
||||||
|
include/mp_units/bits/external/hacks.h
|
||||||
|
include/mp_units/bits/external/type_list.h
|
||||||
|
include/mp_units/bits/external/type_name.h
|
||||||
|
include/mp_units/bits/external/type_traits.h
|
||||||
|
|
||||||
|
include/mp_units/bits/algorithm.h
|
||||||
|
include/mp_units/bits/dimension_concepts.h
|
||||||
|
include/mp_units/bits/expression_template.h
|
||||||
|
include/mp_units/bits/magnitude.h
|
||||||
|
include/mp_units/bits/math_concepts.h
|
||||||
|
include/mp_units/bits/prime.h
|
||||||
|
include/mp_units/bits/quantity_cast.h
|
||||||
|
include/mp_units/bits/quantity_concepts.h
|
||||||
|
include/mp_units/bits/quantity_point_concepts.h
|
||||||
|
include/mp_units/bits/quantity_spec_concepts.h
|
||||||
|
include/mp_units/bits/ratio_maths.h
|
||||||
|
include/mp_units/bits/ratio.h
|
||||||
|
include/mp_units/bits/reference_concepts.h
|
||||||
|
include/mp_units/bits/representation_concepts.h
|
||||||
|
include/mp_units/bits/symbol_text.h
|
||||||
|
include/mp_units/bits/text_tools.h
|
||||||
|
include/mp_units/bits/unit_concepts.h
|
||||||
|
|
||||||
|
include/mp_units/concepts.h
|
||||||
include/mp_units/customization_points.h
|
include/mp_units/customization_points.h
|
||||||
include/mp_units/dimension.h
|
include/mp_units/dimension.h
|
||||||
include/mp_units/quantity.h
|
include/mp_units/quantity.h
|
||||||
|
110
src/core/include/mp_units/bits/dimension_concepts.h
Normal file
110
src/core/include/mp_units/bits/dimension_concepts.h
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
// 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/bits/expression_template.h>
|
||||||
|
#include <mp_units/bits/external/type_traits.h>
|
||||||
|
#include <mp_units/bits/symbol_text.h>
|
||||||
|
|
||||||
|
namespace mp_units {
|
||||||
|
|
||||||
|
template<basic_symbol_text Symbol>
|
||||||
|
struct base_dimension;
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<basic_symbol_text Symbol>
|
||||||
|
void to_base_base_dimension(const volatile base_dimension<Symbol>*);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline constexpr bool is_specialization_of_base_dimension = false;
|
||||||
|
|
||||||
|
template<basic_symbol_text Symbol>
|
||||||
|
inline constexpr bool is_specialization_of_base_dimension<base_dimension<Symbol>> = true;
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A concept matching all named base dimensions in the library.
|
||||||
|
*
|
||||||
|
* Satisfied by all dimension types derived from a specialization of `base_dimension`.
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
concept BaseDimension =
|
||||||
|
requires(T* t) { detail::to_base_base_dimension(t); } && (!detail::is_specialization_of_base_dimension<T>);
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline constexpr bool is_dimension_one = false;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline constexpr bool is_power_of_dim = requires {
|
||||||
|
requires is_specialization_of_power<T> && (BaseDimension<typename T::factor> || is_dimension_one<typename T::factor>);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline constexpr bool is_per_of_dims = false;
|
||||||
|
|
||||||
|
template<typename... Ts>
|
||||||
|
inline constexpr bool is_per_of_dims<per<Ts...>> =
|
||||||
|
(... && (BaseDimension<Ts> || is_dimension_one<Ts> || is_power_of_dim<Ts>));
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
concept DerivedDimensionExpr =
|
||||||
|
BaseDimension<T> || detail::is_dimension_one<T> || detail::is_power_of_dim<T> || detail::is_per_of_dims<T>;
|
||||||
|
|
||||||
|
template<DerivedDimensionExpr... Expr>
|
||||||
|
struct derived_dimension;
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<typename... Expr>
|
||||||
|
void to_base_specialization_of_derived_dimension(const volatile derived_dimension<Expr...>*);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline constexpr bool is_derived_from_specialization_of_derived_dimension =
|
||||||
|
requires(T* t) { to_base_specialization_of_derived_dimension(t); };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A concept matching all derived dimensions in the library.
|
||||||
|
*
|
||||||
|
* Satisfied by all dimension types either being a specialization of `derived_dimension`
|
||||||
|
* or derived from it (inheritance needed to properly handle `dimension_one`).
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
concept DerivedDimension = detail::is_derived_from_specialization_of_derived_dimension<T>;
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A concept matching all dimensions in the library.
|
||||||
|
*
|
||||||
|
* Satisfied by all dimension types for which either `BaseDimension<T>` or `DerivedDimension<T>` is `true`.
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
concept Dimension = BaseDimension<T> || detail::DerivedDimension<T>;
|
||||||
|
|
||||||
|
} // namespace mp_units
|
@@ -36,7 +36,7 @@ UNITS_DIAGNOSTIC_IGNORE_LOSS_OF_DATA
|
|||||||
|
|
||||||
namespace mp_units {
|
namespace mp_units {
|
||||||
|
|
||||||
template<Reference auto R, RepresentationOf<R.quantity_spec.character> Rep>
|
template<Reference auto R, RepresentationOf<get_quantity_spec(R).character> Rep>
|
||||||
class quantity;
|
class quantity;
|
||||||
|
|
||||||
// template<PointOrigin O, UnitOf<typename O::dimension> U, Representation Rep>
|
// template<PointOrigin O, UnitOf<typename O::dimension> U, Representation Rep>
|
||||||
@@ -57,12 +57,12 @@ class quantity;
|
|||||||
*/
|
*/
|
||||||
template<Quantity To, auto R, typename Rep>
|
template<Quantity To, auto R, typename Rep>
|
||||||
requires(interconvertible(To::reference, R)) &&
|
requires(interconvertible(To::reference, R)) &&
|
||||||
((R.unit == To::unit && std::constructible_from<typename To::rep, Rep>) ||
|
((get_unit(R) == To::unit && std::constructible_from<typename To::rep, Rep>) ||
|
||||||
(R.unit != To::unit)) // && scalable_with_<typename To::rep>))
|
(get_unit(R) != To::unit)) // && scalable_with_<typename To::rep>))
|
||||||
// TODO how to constrain the second part here?
|
// TODO how to constrain the second part here?
|
||||||
[[nodiscard]] constexpr auto quantity_cast(const quantity<R, Rep>& q)
|
[[nodiscard]] constexpr auto quantity_cast(const quantity<R, Rep>& q)
|
||||||
{
|
{
|
||||||
if constexpr (R.unit == To::unit) {
|
if constexpr (get_unit(R) == To::unit) {
|
||||||
// no scaling of the number needed
|
// no scaling of the number needed
|
||||||
return To(static_cast<TYPENAME To::rep>(q.number())); // this is the only (and recommended) way to do
|
return To(static_cast<TYPENAME To::rep>(q.number())); // this is the only (and recommended) way to do
|
||||||
// a truncating conversion on a number, so we are
|
// a truncating conversion on a number, so we are
|
||||||
@@ -91,7 +91,8 @@ template<Quantity To, auto R, typename Rep>
|
|||||||
return std::intmax_t{};
|
return std::intmax_t{};
|
||||||
}());
|
}());
|
||||||
|
|
||||||
constexpr Magnitude auto c_mag = detail::get_canonical_unit(R.unit).mag / detail::get_canonical_unit(To::unit).mag;
|
constexpr Magnitude auto c_mag =
|
||||||
|
detail::get_canonical_unit(get_unit(R)).mag / detail::get_canonical_unit(To::unit).mag;
|
||||||
constexpr Magnitude auto num = numerator(c_mag);
|
constexpr Magnitude auto num = numerator(c_mag);
|
||||||
constexpr Magnitude auto den = denominator(c_mag);
|
constexpr Magnitude auto den = denominator(c_mag);
|
||||||
constexpr Magnitude auto irr = c_mag * (den / num);
|
constexpr Magnitude auto irr = c_mag * (den / num);
|
||||||
@@ -101,26 +102,6 @@ template<Quantity To, auto R, typename Rep>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Explicit cast of a quantity
|
|
||||||
*
|
|
||||||
* Implicit conversions between quantities of different types are allowed only for "safe"
|
|
||||||
* (i.e. non-truncating) conversion. In truncating cases an explicit cast have to be used.
|
|
||||||
*
|
|
||||||
* This cast gets a target reference to cast to. For example:
|
|
||||||
*
|
|
||||||
* auto v = quantity_cast<isq::velocity[km / h]>(q);
|
|
||||||
*
|
|
||||||
* @tparam ToR a reference to use for a target quantity
|
|
||||||
*/
|
|
||||||
template<Reference auto ToR, auto R, typename Rep>
|
|
||||||
requires(interconvertible(ToR, R))
|
|
||||||
[[nodiscard]] constexpr auto quantity_cast(const quantity<R, Rep>& q)
|
|
||||||
{
|
|
||||||
return quantity_cast<quantity<ToR, Rep>>(q);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Explicit cast of a quantity
|
* @brief Explicit cast of a quantity
|
||||||
*
|
*
|
||||||
@@ -134,7 +115,7 @@ template<Reference auto ToR, auto R, typename Rep>
|
|||||||
* @tparam ToQS a quantity specification to use for a target quantity
|
* @tparam ToQS a quantity specification to use for a target quantity
|
||||||
*/
|
*/
|
||||||
template<QuantitySpec auto ToQS, auto R, typename Rep>
|
template<QuantitySpec auto ToQS, auto R, typename Rep>
|
||||||
requires(interconvertible(ToQS, R.quantity_spec))
|
requires(interconvertible(ToQS, get_quantity_spec(R)))
|
||||||
[[nodiscard]] constexpr auto quantity_cast(const quantity<R, Rep>& q)
|
[[nodiscard]] constexpr auto quantity_cast(const quantity<R, Rep>& q)
|
||||||
{
|
{
|
||||||
constexpr reference<ToQS, quantity<R, Rep>::unit> r;
|
constexpr reference<ToQS, quantity<R, Rep>::unit> r;
|
||||||
@@ -154,7 +135,7 @@ template<QuantitySpec auto ToQS, auto R, typename Rep>
|
|||||||
* @tparam ToU a unit to use for a target quantity
|
* @tparam ToU a unit to use for a target quantity
|
||||||
*/
|
*/
|
||||||
template<Unit auto ToU, auto R, typename Rep>
|
template<Unit auto ToU, auto R, typename Rep>
|
||||||
requires(interconvertible(ToU, R.unit))
|
requires(interconvertible(ToU, get_unit(R)))
|
||||||
[[nodiscard]] constexpr auto quantity_cast(const quantity<R, Rep>& q)
|
[[nodiscard]] constexpr auto quantity_cast(const quantity<R, Rep>& q)
|
||||||
{
|
{
|
||||||
constexpr reference<quantity<R, Rep>::quantity_spec, ToU> r;
|
constexpr reference<quantity<R, Rep>::quantity_spec, ToU> r;
|
||||||
@@ -174,7 +155,7 @@ template<Unit auto ToU, auto R, typename Rep>
|
|||||||
* @tparam ToRep a representation type to use for a target quantity
|
* @tparam ToRep a representation type to use for a target quantity
|
||||||
*/
|
*/
|
||||||
template<Representation ToRep, auto R, typename Rep>
|
template<Representation ToRep, auto R, typename Rep>
|
||||||
requires RepresentationOf<ToRep, R.quantity_spec.character> && std::constructible_from<ToRep, Rep>
|
requires RepresentationOf<ToRep, get_quantity_spec(R).character> && std::constructible_from<ToRep, Rep>
|
||||||
[[nodiscard]] constexpr auto quantity_cast(const quantity<R, Rep>& q)
|
[[nodiscard]] constexpr auto quantity_cast(const quantity<R, Rep>& q)
|
||||||
{
|
{
|
||||||
return quantity_cast<quantity<R, ToRep>>(q);
|
return quantity_cast<quantity<R, ToRep>>(q);
|
||||||
@@ -189,7 +170,8 @@ template<Representation ToRep, auto R, typename Rep>
|
|||||||
// * This cast gets the target quantity point type to cast to or anything that works for quantity_cast. For example:
|
// * This cast gets the target quantity point type to cast to or anything that works for quantity_cast. For example:
|
||||||
// *
|
// *
|
||||||
// * auto q1 = mp_units::quantity_point_cast<decltype(quantity_point{0_q_s})>(quantity_point{1_q_ms});
|
// * auto q1 = mp_units::quantity_point_cast<decltype(quantity_point{0_q_s})>(quantity_point{1_q_ms});
|
||||||
// * auto q1 = mp_units::quantity_point_cast<mp_units::isq::si::time<mp_units::isq::si::second>>(quantity_point{1_q_ms});
|
// * auto q1 =
|
||||||
|
// mp_units::quantity_point_cast<mp_units::isq::si::time<mp_units::isq::si::second>>(quantity_point{1_q_ms});
|
||||||
// * auto q1 = mp_units::quantity_point_cast<mp_units::isq::si::dim_acceleration>(quantity_point{200_q_Gal});
|
// * auto q1 = mp_units::quantity_point_cast<mp_units::isq::si::dim_acceleration>(quantity_point{200_q_Gal});
|
||||||
// * auto q1 = mp_units::quantity_point_cast<mp_units::isq::si::second>(quantity_point{1_q_ms});
|
// * auto q1 = mp_units::quantity_point_cast<mp_units::isq::si::second>(quantity_point{1_q_ms});
|
||||||
// * auto q1 = mp_units::quantity_point_cast<int>(quantity_point{1_q_ms});
|
// * auto q1 = mp_units::quantity_point_cast<int>(quantity_point{1_q_ms});
|
||||||
|
@@ -22,100 +22,14 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <mp_units/bits/external/type_traits.h>
|
#include <mp_units/bits/quantity_spec_concepts.h>
|
||||||
|
#include <mp_units/bits/reference_concepts.h>
|
||||||
|
#include <mp_units/bits/representation_concepts.h>
|
||||||
#include <mp_units/customization_points.h>
|
#include <mp_units/customization_points.h>
|
||||||
#include <mp_units/dimension.h>
|
|
||||||
#include <mp_units/unit.h>
|
|
||||||
|
|
||||||
namespace mp_units {
|
namespace mp_units {
|
||||||
|
|
||||||
/**
|
template<Reference auto R, RepresentationOf<get_quantity_spec(R).character> Rep>
|
||||||
* @brief Quantity character
|
|
||||||
*
|
|
||||||
* Scalars, vectors and tensors are mathematical objects that can be used to
|
|
||||||
* denote certain physical quantities and their values. They are as such
|
|
||||||
* independent of the particular choice of a coordinate system, whereas
|
|
||||||
* each scalar component of a vector or a tensor and each component vector and
|
|
||||||
* component tensor depend on that choice.
|
|
||||||
*
|
|
||||||
* A scalar is a physical quantity that has magnitude but no direction.
|
|
||||||
*
|
|
||||||
* Vectors are physical quantities that possess both magnitude and direction
|
|
||||||
* and whose operations obey the axioms of a vector space.
|
|
||||||
*
|
|
||||||
* Tensors can be used to describe more general physical quantities.
|
|
||||||
* For example, the Cauchy stress tensor possess magnitude, direction,
|
|
||||||
* and orientation qualities.
|
|
||||||
*/
|
|
||||||
enum class quantity_character { scalar, vector, tensor };
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline constexpr bool is_specialization_of_derived_quantity_spec = false;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Concept matching quantity specification types
|
|
||||||
*
|
|
||||||
* Satisfied by all `derived_quantity_spec` specializations.
|
|
||||||
*/
|
|
||||||
template<typename T>
|
|
||||||
concept DerivedQuantitySpec = detail::is_specialization_of_derived_quantity_spec<T>;
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
concept QuantitySpec = NamedQuantitySpec<T> || DerivedQuantitySpec<T>;
|
|
||||||
|
|
||||||
template<QuantitySpec auto Q, Unit auto U>
|
|
||||||
struct reference;
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline constexpr bool is_specialization_of_reference = false;
|
|
||||||
|
|
||||||
template<auto Q, auto U>
|
|
||||||
inline constexpr bool is_specialization_of_reference<reference<Q, U>> = true;
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A concept matching all references in the library.
|
|
||||||
*
|
|
||||||
* Satisfied by all specializations of @c reference.
|
|
||||||
*/
|
|
||||||
template<typename T>
|
|
||||||
concept Reference = detail::is_specialization_of_reference<T>;
|
|
||||||
|
|
||||||
template<typename T, typename U>
|
|
||||||
concept common_type_with_ = // exposition only
|
|
||||||
(std::same_as<std::common_type_t<T, U>, std::common_type_t<U, T>>) &&
|
|
||||||
(std::constructible_from<std::common_type_t<T, U>, T>) && (std::constructible_from<std::common_type_t<T, U>, U>);
|
|
||||||
|
|
||||||
template<typename T, typename U = T>
|
|
||||||
concept scalable_number_ = // exposition only
|
|
||||||
(std::regular_invocable<std::multiplies<>, T, U>) && (std::regular_invocable<std::divides<>, T, U>);
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
concept castable_number_ = // exposition only
|
|
||||||
common_type_with_<T, std::intmax_t> && scalable_number_<std::common_type_t<T, std::intmax_t>>;
|
|
||||||
|
|
||||||
// TODO Fix it according to quantity_cast implementation
|
|
||||||
template<typename T>
|
|
||||||
concept scalable_ = // exposition only
|
|
||||||
castable_number_<T> || (requires { typename T::value_type; } && castable_number_<typename T::value_type> &&
|
|
||||||
scalable_number_<T, std::common_type_t<typename T::value_type, std::intmax_t>>);
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
concept Representation = (is_scalar<T> || is_vector<T> || is_tensor<T>) && std::regular<T> && scalable_<T>;
|
|
||||||
|
|
||||||
template<typename T, quantity_character Ch>
|
|
||||||
concept RepresentationOf = Representation<T> && ((Ch == quantity_character::scalar && is_scalar<T>) ||
|
|
||||||
(Ch == quantity_character::vector && is_vector<T>) ||
|
|
||||||
(Ch == quantity_character::tensor && is_tensor<T>));
|
|
||||||
|
|
||||||
template<Reference auto R, RepresentationOf<R.quantity_spec.character> Rep>
|
|
||||||
class quantity;
|
class quantity;
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
@@ -125,18 +39,24 @@ void to_base_specialization_of_quantity(const volatile quantity<R, Rep>*);
|
|||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A concept matching all quantities in the library
|
||||||
|
*
|
||||||
|
* Satisfied by all types being a either specialization or derived from `quantity`
|
||||||
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
concept Quantity = requires(T* t) { detail::to_base_specialization_of_quantity(t); };
|
concept Quantity = requires(T* t) { detail::to_base_specialization_of_quantity(t); };
|
||||||
|
|
||||||
namespace detail {
|
/**
|
||||||
|
* @brief A concept matching all quantities with provided dimension or reference
|
||||||
template<QuantitySpec Q1, QuantitySpec Q2>
|
*
|
||||||
[[nodiscard]] consteval bool is_kind_of(Q1, Q2)
|
* Satisfied by all quantities with a dimension/reference being the instantiation derived from
|
||||||
{
|
* the provided dimension/reference type.
|
||||||
return std::derived_from<Q1, Q2>;
|
*/
|
||||||
}
|
template<typename Q, auto V>
|
||||||
|
concept QuantityOf = Quantity<Q> && ((Dimension<std::remove_const_t<decltype(V)>> && Q::dimension == V) ||
|
||||||
} // namespace detail
|
(QuantitySpec<std::remove_const_t<decltype(V)>> && Q::quantity_spec == V) ||
|
||||||
|
(Reference<std::remove_const_t<decltype(V)>> && Q::reference == V));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A concept matching all quantities with provided dimension or reference
|
* @brief A concept matching all quantities with provided dimension or reference
|
||||||
@@ -145,102 +65,27 @@ template<QuantitySpec Q1, QuantitySpec Q2>
|
|||||||
* the provided dimension/reference type.
|
* the provided dimension/reference type.
|
||||||
*/
|
*/
|
||||||
template<typename Q, auto V>
|
template<typename Q, auto V>
|
||||||
concept quantity_of = Quantity<Q> &&
|
concept WeakQuantityOf =
|
||||||
((Dimension<std::remove_const_t<decltype(V)>> && Q::dimension == V) ||
|
Quantity<Q> && ((Dimension<std::remove_const_t<decltype(V)>> && Q::dimension == V) ||
|
||||||
(QuantitySpec<std::remove_const_t<decltype(V)>> && detail::is_kind_of(Q::quantity_spec, V)) ||
|
(QuantitySpec<std::remove_const_t<decltype(V)>> && interconvertible(Q::quantity_spec, V)) ||
|
||||||
(Reference<std::remove_const_t<decltype(V)>> && Q::reference == V));
|
(Reference<std::remove_const_t<decltype(V)>> && Q::dimension == V.dimension && Q::unit == V.unit));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A concept matching all quantities with provided dimension or reference
|
* @brief A concept matching all external quantities like types
|
||||||
*
|
*
|
||||||
* Satisfied by all quantities with a dimension/reference being the instantiation derived from
|
* Satisfied by all external types (not-defined in mp-units) that via a `quantity_like_traits` provide
|
||||||
* the provided dimension/reference type.
|
* all quantity-specific information.
|
||||||
*/
|
*/
|
||||||
template<typename Q, auto V>
|
|
||||||
concept weak_quantity_of = Quantity<Q> &&
|
|
||||||
((Dimension<std::remove_const_t<decltype(V)>> && Q::dimension == V) ||
|
|
||||||
(QuantitySpec<std::remove_const_t<decltype(V)>> && interconvertible(Q::quantity_spec, V)) ||
|
|
||||||
(Reference<std::remove_const_t<decltype(V)>> && Q::dimension == V.dimension &&
|
|
||||||
Q::unit == V.unit));
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
concept quantity_like = requires(T q) {
|
concept QuantityLike = requires(T q) {
|
||||||
quantity_like_traits<T>::reference;
|
quantity_like_traits<T>::reference;
|
||||||
typename quantity_like_traits<T>::rep;
|
typename quantity_like_traits<T>::rep;
|
||||||
requires Reference<std::remove_const_t<decltype(quantity_like_traits<T>::reference)>>;
|
requires Reference<std::remove_const_t<decltype(quantity_like_traits<T>::reference)>>;
|
||||||
requires RepresentationOf<typename quantity_like_traits<T>::rep,
|
requires RepresentationOf<typename quantity_like_traits<T>::rep,
|
||||||
quantity_like_traits<T>::reference.quantity_spec.character>;
|
get_quantity_spec(quantity_like_traits<T>::reference).character>;
|
||||||
{
|
{
|
||||||
quantity_like_traits<T>::number(q)
|
quantity_like_traits<T>::number(q)
|
||||||
} -> std::convertible_to<typename quantity_like_traits<T>::rep>;
|
} -> std::convertible_to<typename quantity_like_traits<T>::rep>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template<QuantitySpec auto Q>
|
|
||||||
struct absolute_point_origin {
|
|
||||||
static constexpr QuantitySpec auto quantity_spec = Q;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline constexpr bool is_quantity_point = false;
|
|
||||||
|
|
||||||
template<auto Q>
|
|
||||||
void to_base_specialization_of_absolute_point_origin(const volatile absolute_point_origin<Q>*);
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline constexpr bool is_derived_from_specialization_of_absolute_point_origin =
|
|
||||||
requires(T * t) { to_base_specialization_of_absolute_point_origin(t); };
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
concept QuantityPoint = detail::is_quantity_point<T>;
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
concept point_origin = QuantityPoint<T> || detail::is_derived_from_specialization_of_absolute_point_origin<T>;
|
|
||||||
|
|
||||||
template<typename T, auto Q>
|
|
||||||
concept point_origin_for = point_origin<T> && QuantitySpec<std::remove_const_t<decltype(Q)>> &&
|
|
||||||
detail::is_kind_of(Q, T::quantity_spec);
|
|
||||||
|
|
||||||
template<Reference auto R, point_origin_for<R.quantity_spec> auto PO, RepresentationOf<R.quantity_spec.character> Rep>
|
|
||||||
class quantity_point;
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
template<auto R, auto PO, typename Rep>
|
|
||||||
void to_base_specialization_of_quantity_point(const volatile quantity_point<R, PO, Rep>*);
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
requires requires(T* t) { detail::to_base_specialization_of_quantity_point(t); }
|
|
||||||
inline constexpr bool is_quantity_point<T> = true;
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
template<typename QP, auto V>
|
|
||||||
concept quantity_point_of =
|
|
||||||
QuantityPoint<QP> &&
|
|
||||||
((Dimension<std::remove_const_t<decltype(V)>> && QP::dimension == V) ||
|
|
||||||
(QuantitySpec<std::remove_const_t<decltype(V)>> && detail::is_kind_of(QP::quantity_spec, V)) ||
|
|
||||||
(Reference<std::remove_const_t<decltype(V)>> && QP::reference == V) ||
|
|
||||||
(point_origin<std::remove_const_t<decltype(V)>> &&
|
|
||||||
std::same_as<std::remove_const_t<decltype(QP::absolute_point_origin)>, std::remove_const_t<decltype(V)>>));
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
concept quantity_point_like = requires(T q) {
|
|
||||||
quantity_point_like_traits<T>::reference;
|
|
||||||
quantity_point_like_traits<T>::point_origin;
|
|
||||||
typename quantity_point_like_traits<T>::rep;
|
|
||||||
requires Reference<std::remove_const_t<decltype(quantity_point_like_traits<T>::reference)>>;
|
|
||||||
requires point_origin<std::remove_const_t<decltype(quantity_point_like_traits<T>::point_origin)>>;
|
|
||||||
requires RepresentationOf<typename quantity_point_like_traits<T>::rep,
|
|
||||||
quantity_point_like_traits<T>::reference.quantity_spec.character>;
|
|
||||||
requires std::constructible_from<
|
|
||||||
typename quantity_point<quantity_point_like_traits<T>::reference, quantity_point_like_traits<T>::point_origin,
|
|
||||||
typename quantity_point_like_traits<T>::rep>::quantity_type,
|
|
||||||
decltype(quantity_point_like_traits<T>::relative(q))>;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace mp_units
|
} // namespace mp_units
|
||||||
|
124
src/core/include/mp_units/bits/quantity_point_concepts.h
Normal file
124
src/core/include/mp_units/bits/quantity_point_concepts.h
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
// 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/bits/quantity_spec_concepts.h>
|
||||||
|
#include <mp_units/bits/reference_concepts.h>
|
||||||
|
#include <mp_units/bits/representation_concepts.h>
|
||||||
|
#include <mp_units/customization_points.h>
|
||||||
|
|
||||||
|
namespace mp_units {
|
||||||
|
|
||||||
|
template<QuantitySpec auto Q>
|
||||||
|
struct absolute_point_origin;
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline constexpr bool is_quantity_point = false;
|
||||||
|
|
||||||
|
template<auto Q>
|
||||||
|
void to_base_specialization_of_absolute_point_origin(const volatile absolute_point_origin<Q>*);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline constexpr bool is_derived_from_specialization_of_absolute_point_origin =
|
||||||
|
requires(T* t) { to_base_specialization_of_absolute_point_origin(t); };
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A concept matching all quantity points in the library
|
||||||
|
*
|
||||||
|
* Satisfied by all types being a either specialization or derived from `quantity_point`
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
concept QuantityPoint = detail::is_quantity_point<T>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A concept matching all quantity point origins in the library
|
||||||
|
*
|
||||||
|
* Satisfied by either quantity points or by all types derived from `absolute_point_origin` class template.
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
concept PointOrigin = QuantityPoint<T> || detail::is_derived_from_specialization_of_absolute_point_origin<T>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A concept matching all quantity point origins for a specified quantity type in the library
|
||||||
|
*
|
||||||
|
* Satisfied by all quantity point origins that are defined using a provided quantity specification.
|
||||||
|
*/
|
||||||
|
template<typename T, auto Q>
|
||||||
|
concept PointOriginFor = PointOrigin<T> && QuantitySpec<std::remove_const_t<decltype(Q)>> && Q == T::quantity_spec;
|
||||||
|
|
||||||
|
template<Reference auto R, PointOriginFor<get_quantity_spec(R)> auto PO,
|
||||||
|
RepresentationOf<get_quantity_spec(R).character> Rep>
|
||||||
|
class quantity_point;
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<auto R, auto PO, typename Rep>
|
||||||
|
void to_base_specialization_of_quantity_point(const volatile quantity_point<R, PO, Rep>*);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
requires requires(T* t) { detail::to_base_specialization_of_quantity_point(t); }
|
||||||
|
inline constexpr bool is_quantity_point<T> = true;
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A concept matching all quantity points with provided dimension or reference
|
||||||
|
*
|
||||||
|
* Satisfied by all quantity points with a dimension/reference being the instantiation derived from
|
||||||
|
* the provided dimension/reference type.
|
||||||
|
*/
|
||||||
|
template<typename QP, auto V>
|
||||||
|
concept QuantityPointOf =
|
||||||
|
QuantityPoint<QP> &&
|
||||||
|
((Dimension<std::remove_const_t<decltype(V)>> && QP::dimension == V) ||
|
||||||
|
(QuantitySpec<std::remove_const_t<decltype(V)>> && QP::quantity_spec == V) ||
|
||||||
|
(Reference<std::remove_const_t<decltype(V)>> && QP::reference == V) ||
|
||||||
|
(PointOrigin<std::remove_const_t<decltype(V)>> &&
|
||||||
|
std::same_as<std::remove_const_t<decltype(QP::absolute_point_origin)>, std::remove_const_t<decltype(V)>>));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A concept matching all external quantity point like types
|
||||||
|
*
|
||||||
|
* Satisfied by all external types (not-defined in mp-units) that via a `quantity_point_like_traits` provide
|
||||||
|
* all quantity_point-specific information.
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
concept QuantityPointLike = requires(T q) {
|
||||||
|
quantity_point_like_traits<T>::reference;
|
||||||
|
quantity_point_like_traits<T>::point_origin;
|
||||||
|
typename quantity_point_like_traits<T>::rep;
|
||||||
|
requires Reference<std::remove_const_t<decltype(quantity_point_like_traits<T>::reference)>>;
|
||||||
|
requires PointOrigin<std::remove_const_t<decltype(quantity_point_like_traits<T>::point_origin)>>;
|
||||||
|
requires RepresentationOf<typename quantity_point_like_traits<T>::rep,
|
||||||
|
get_quantity_spec(quantity_point_like_traits<T>::reference).character>;
|
||||||
|
requires std::constructible_from<
|
||||||
|
typename quantity_point<quantity_point_like_traits<T>::reference, quantity_point_like_traits<T>::point_origin,
|
||||||
|
typename quantity_point_like_traits<T>::rep>::quantity_type,
|
||||||
|
decltype(quantity_point_like_traits<T>::relative(q))>;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mp_units
|
137
src/core/include/mp_units/bits/quantity_spec_concepts.h
Normal file
137
src/core/include/mp_units/bits/quantity_spec_concepts.h
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
// 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/bits/dimension_concepts.h>
|
||||||
|
#include <mp_units/bits/expression_template.h>
|
||||||
|
|
||||||
|
namespace mp_units {
|
||||||
|
|
||||||
|
#ifdef __cpp_explicit_this_parameter
|
||||||
|
template<auto...>
|
||||||
|
#else
|
||||||
|
template<typename, auto...>
|
||||||
|
#endif
|
||||||
|
struct quantity_spec;
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
#ifdef __cpp_explicit_this_parameter
|
||||||
|
template<auto... Args>
|
||||||
|
void to_base_specialization_of_quantity_spec(const volatile quantity_spec<Args...>*);
|
||||||
|
#else
|
||||||
|
template<typename T, auto... Args>
|
||||||
|
void to_base_specialization_of_quantity_spec(const volatile quantity_spec<T, Args...>*);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cpp_explicit_this_parameter
|
||||||
|
template<BaseDimension auto Dim, auto... Args>
|
||||||
|
template<auto... Args>
|
||||||
|
void to_base_specialization_of_base_quantity_spec(const volatile quantity_spec<Dim, Args...>*);
|
||||||
|
#else
|
||||||
|
template<typename Self, BaseDimension auto Dim, auto... Args>
|
||||||
|
void to_base_specialization_of_base_quantity_spec(const volatile quantity_spec<Self, Dim, Args...>*);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline constexpr bool is_specialization_of_quantity_spec = false;
|
||||||
|
|
||||||
|
#ifdef __cpp_explicit_this_parameter
|
||||||
|
template<auto... Args>
|
||||||
|
inline constexpr bool is_specialization_of_quantity_spec<quantity_spec<Args...>> = true;
|
||||||
|
#else
|
||||||
|
template<typename T, auto... Args>
|
||||||
|
inline constexpr bool is_specialization_of_quantity_spec<quantity_spec<T, Args...>> = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Concept matching all named quantity specification types
|
||||||
|
*
|
||||||
|
* Satisfied by all types that derive from `quantity_spec`.
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
concept NamedQuantitySpec = requires(T* t) { detail::to_base_specialization_of_quantity_spec(t); } &&
|
||||||
|
(!detail::is_specialization_of_quantity_spec<T>);
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Concept matching all named base quantity specification types
|
||||||
|
*
|
||||||
|
* Satisfied by all types that derive from `quantity_spec` taking a base dimension
|
||||||
|
* as a template parameter.
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
concept BaseQuantitySpec =
|
||||||
|
detail::NamedQuantitySpec<T> && requires(T* t) { detail::to_base_specialization_of_base_quantity_spec(t); };
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline constexpr bool is_dimensionless = false;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline constexpr bool is_power_of_quantity_spec = requires {
|
||||||
|
requires is_specialization_of_power<T> &&
|
||||||
|
(NamedQuantitySpec<typename T::factor> || is_dimensionless<typename T::factor>);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline constexpr bool is_per_of_quantity_specs = false;
|
||||||
|
|
||||||
|
template<typename... Ts>
|
||||||
|
inline constexpr bool is_per_of_quantity_specs<per<Ts...>> =
|
||||||
|
(... && (NamedQuantitySpec<Ts> || is_dimensionless<Ts> || is_power_of_quantity_spec<Ts>));
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
concept DerivedQuantitySpecExpr = detail::NamedQuantitySpec<T> || detail::is_dimensionless<T> ||
|
||||||
|
detail::is_power_of_quantity_spec<T> || detail::is_per_of_quantity_specs<T>;
|
||||||
|
|
||||||
|
|
||||||
|
template<DerivedQuantitySpecExpr... Expr>
|
||||||
|
struct derived_quantity_spec;
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline constexpr bool is_derived_from_specialization_of_derived_quantity_spec = false;
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
inline constexpr bool is_derived_from_specialization_of_derived_quantity_spec<derived_quantity_spec<Args...>> = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Concept matching all derived quantity specification types
|
||||||
|
*
|
||||||
|
* Satisfied by all `derived_quantity_spec` specializations.
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
concept DerivedQuantitySpec = detail::is_derived_from_specialization_of_derived_quantity_spec<T>;
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
concept QuantitySpec = detail::NamedQuantitySpec<T> || detail::DerivedQuantitySpec<T>;
|
||||||
|
|
||||||
|
} // namespace mp_units
|
51
src/core/include/mp_units/bits/reference_concepts.h
Normal file
51
src/core/include/mp_units/bits/reference_concepts.h
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
// 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/bits/quantity_spec_concepts.h>
|
||||||
|
#include <mp_units/bits/unit_concepts.h>
|
||||||
|
|
||||||
|
namespace mp_units {
|
||||||
|
|
||||||
|
template<QuantitySpec auto Q, Unit auto U>
|
||||||
|
struct reference;
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline constexpr bool is_specialization_of_reference = false;
|
||||||
|
|
||||||
|
template<auto Q, auto U>
|
||||||
|
inline constexpr bool is_specialization_of_reference<reference<Q, U>> = true;
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A concept matching all references in the library.
|
||||||
|
*
|
||||||
|
* Satisfied by all specializations of @c reference.
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
concept Reference = AssociatedUnit<T> || detail::is_specialization_of_reference<T>;
|
||||||
|
|
||||||
|
} // namespace mp_units
|
80
src/core/include/mp_units/bits/representation_concepts.h
Normal file
80
src/core/include/mp_units/bits/representation_concepts.h
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
// 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/customization_points.h>
|
||||||
|
#include <concepts>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <functional>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace mp_units {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Quantity character
|
||||||
|
*
|
||||||
|
* Scalars, vectors and tensors are mathematical objects that can be used to
|
||||||
|
* denote certain physical quantities and their values. They are as such
|
||||||
|
* independent of the particular choice of a coordinate system, whereas
|
||||||
|
* each scalar component of a vector or a tensor and each component vector and
|
||||||
|
* component tensor depend on that choice.
|
||||||
|
*
|
||||||
|
* A scalar is a physical quantity that has magnitude but no direction.
|
||||||
|
*
|
||||||
|
* Vectors are physical quantities that possess both magnitude and direction
|
||||||
|
* and whose operations obey the axioms of a vector space.
|
||||||
|
*
|
||||||
|
* Tensors can be used to describe more general physical quantities.
|
||||||
|
* For example, the Cauchy stress tensor possess magnitude, direction,
|
||||||
|
* and orientation qualities.
|
||||||
|
*/
|
||||||
|
enum class quantity_character { scalar, vector, tensor };
|
||||||
|
|
||||||
|
template<typename T, typename U>
|
||||||
|
concept common_type_with_ = // exposition only
|
||||||
|
std::same_as<std::common_type_t<T, U>, std::common_type_t<U, T>> &&
|
||||||
|
std::constructible_from<std::common_type_t<T, U>, T> && std::constructible_from<std::common_type_t<T, U>, U>;
|
||||||
|
|
||||||
|
template<typename T, typename U = T>
|
||||||
|
concept scalable_number_ = // exposition only
|
||||||
|
std::regular_invocable<std::multiplies<>, T, U> && std::regular_invocable<std::divides<>, T, U>;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
concept castable_number_ = // exposition only
|
||||||
|
common_type_with_<T, std::intmax_t> && scalable_number_<std::common_type_t<T, std::intmax_t>>;
|
||||||
|
|
||||||
|
// TODO Fix it according to quantity_cast implementation
|
||||||
|
template<typename T>
|
||||||
|
concept scalable_ = // exposition only
|
||||||
|
castable_number_<T> || (requires { typename T::value_type; } && castable_number_<typename T::value_type> &&
|
||||||
|
scalable_number_<T, std::common_type_t<typename T::value_type, std::intmax_t>>);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
concept Representation = (is_scalar<T> || is_vector<T> || is_tensor<T>)&&std::regular<T> && scalable_<T>;
|
||||||
|
|
||||||
|
template<typename T, quantity_character Ch>
|
||||||
|
concept RepresentationOf = Representation<T> && ((Ch == quantity_character::scalar && is_scalar<T>) ||
|
||||||
|
(Ch == quantity_character::vector && is_vector<T>) ||
|
||||||
|
(Ch == quantity_character::tensor && is_tensor<T>));
|
||||||
|
|
||||||
|
} // namespace mp_units
|
159
src/core/include/mp_units/bits/unit_concepts.h
Normal file
159
src/core/include/mp_units/bits/unit_concepts.h
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
// 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/bits/expression_template.h>
|
||||||
|
#include <mp_units/bits/magnitude.h>
|
||||||
|
#include <mp_units/bits/symbol_text.h>
|
||||||
|
|
||||||
|
namespace mp_units {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline constexpr bool is_unit = false;
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A concept matching all unit types in the library
|
||||||
|
*
|
||||||
|
* Satisfied by all unit types provided by the library.
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
concept Unit = detail::is_unit<T>;
|
||||||
|
|
||||||
|
template<Magnitude auto M, Unit U>
|
||||||
|
struct scaled_unit;
|
||||||
|
|
||||||
|
template<basic_symbol_text Symbol, auto...>
|
||||||
|
struct named_unit;
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<basic_symbol_text Symbol, auto... Args>
|
||||||
|
void to_base_specialization_of_named_unit(const volatile named_unit<Symbol, Args...>*);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline constexpr bool is_specialization_of_named_unit = false;
|
||||||
|
|
||||||
|
template<basic_symbol_text Symbol, auto... Args>
|
||||||
|
inline constexpr bool is_specialization_of_named_unit<named_unit<Symbol, Args...>> = true;
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A concept matching all units with special names
|
||||||
|
*
|
||||||
|
* Satisfied by all unit types derived from the specialization of `named_unit`.
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
concept NamedUnit = Unit<T> && requires(T* t) { detail::to_base_specialization_of_named_unit(t); } &&
|
||||||
|
(!detail::is_specialization_of_named_unit<T>);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prevents assignment of a prefix to specific units
|
||||||
|
*
|
||||||
|
* By default all named units allow assigning a prefix for them. There are some notable exceptions like
|
||||||
|
* `hour` or `degree_Celsius`. For those a partial specialization with the value `false` should be
|
||||||
|
* provided.
|
||||||
|
*/
|
||||||
|
template<NamedUnit auto V>
|
||||||
|
inline constexpr bool unit_can_be_prefixed = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A concept to be used to define prefixes for a unit
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
concept PrefixableUnit = NamedUnit<T> && unit_can_be_prefixed<T{}>;
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline constexpr bool is_power_of_unit =
|
||||||
|
requires { requires is_specialization_of_power<T> && Unit<typename T::factor>; };
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline constexpr bool is_per_of_units = false;
|
||||||
|
|
||||||
|
template<typename... Ts>
|
||||||
|
inline constexpr bool is_per_of_units<per<Ts...>> = (... && (Unit<Ts> || is_power_of_unit<Ts>));
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
concept DerivedUnitExpr = Unit<T> || detail::is_power_of_unit<T> || detail::is_per_of_units<T>;
|
||||||
|
|
||||||
|
template<DerivedUnitExpr... Expr>
|
||||||
|
struct derived_unit;
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<auto M, typename U>
|
||||||
|
void is_unit_impl(const scaled_unit<M, U>*);
|
||||||
|
|
||||||
|
template<basic_symbol_text Symbol, auto... Args>
|
||||||
|
void is_unit_impl(const named_unit<Symbol, Args...>*);
|
||||||
|
|
||||||
|
template<typename... Expr>
|
||||||
|
void is_unit_impl(const derived_unit<Expr...>*);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
requires requires(T* t) { is_unit_impl(t); }
|
||||||
|
inline constexpr bool is_unit<T> = true;
|
||||||
|
|
||||||
|
template<Unit U>
|
||||||
|
[[nodiscard]] consteval bool has_associated_quantity(U);
|
||||||
|
|
||||||
|
template<typename U, auto... Vs>
|
||||||
|
[[nodiscard]] consteval bool has_associated_quantity(power<U, Vs...>)
|
||||||
|
{
|
||||||
|
return has_associated_quantity(U{});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Us>
|
||||||
|
[[nodiscard]] consteval bool has_associated_quantity(type_list<Us...>)
|
||||||
|
{
|
||||||
|
return (... && has_associated_quantity(Us{}));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<Unit U>
|
||||||
|
[[nodiscard]] consteval bool has_associated_quantity(U)
|
||||||
|
{
|
||||||
|
if constexpr (requires { U::reference_unit; })
|
||||||
|
return has_associated_quantity(U::reference_unit);
|
||||||
|
else if constexpr (requires { typename U::_num_; })
|
||||||
|
return has_associated_quantity(typename U::_num_{}) && has_associated_quantity(typename U::_den_{});
|
||||||
|
else
|
||||||
|
return requires { U::base_quantity; };
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A concept matching all units that can be used as quantity references
|
||||||
|
*/
|
||||||
|
template<typename U>
|
||||||
|
concept AssociatedUnit = Unit<U> && detail::has_associated_quantity(U{});
|
||||||
|
|
||||||
|
} // namespace mp_units
|
31
src/core/include/mp_units/concepts.h
Normal file
31
src/core/include/mp_units/concepts.h
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
// 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/bits/dimension_concepts.h>
|
||||||
|
#include <mp_units/bits/quantity_concepts.h>
|
||||||
|
#include <mp_units/bits/quantity_point_concepts.h>
|
||||||
|
#include <mp_units/bits/quantity_spec_concepts.h>
|
||||||
|
#include <mp_units/bits/reference_concepts.h>
|
||||||
|
#include <mp_units/bits/representation_concepts.h>
|
||||||
|
#include <mp_units/bits/unit_concepts.h>
|
@@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <mp_units/bits/dimension_concepts.h>
|
||||||
#include <mp_units/bits/expression_template.h>
|
#include <mp_units/bits/expression_template.h>
|
||||||
#include <mp_units/bits/external/type_traits.h>
|
#include <mp_units/bits/external/type_traits.h>
|
||||||
#include <mp_units/bits/symbol_text.h>
|
#include <mp_units/bits/symbol_text.h>
|
||||||
@@ -63,55 +64,14 @@ struct base_dimension {
|
|||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
template<basic_symbol_text Symbol>
|
|
||||||
void to_base_base_dimension(const volatile base_dimension<Symbol>*);
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline constexpr bool is_specialization_of_base_dimension = false;
|
|
||||||
|
|
||||||
template<basic_symbol_text Symbol>
|
|
||||||
inline constexpr bool is_specialization_of_base_dimension<base_dimension<Symbol>> = true;
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A concept matching all named base dimensions in the library.
|
|
||||||
*
|
|
||||||
* Satisfied by all dimension types derived from a specialization of `base_dimension`.
|
|
||||||
*/
|
|
||||||
template<typename T>
|
|
||||||
concept BaseDimension = requires(T* t) { detail::to_base_base_dimension(t); } &&
|
|
||||||
(!detail::is_specialization_of_base_dimension<T>);
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
template<BaseDimension Lhs, BaseDimension Rhs>
|
template<BaseDimension Lhs, BaseDimension Rhs>
|
||||||
struct base_dimension_less : std::bool_constant<(Lhs::symbol < Rhs::symbol)> {};
|
struct base_dimension_less : std::bool_constant<(Lhs::symbol < Rhs::symbol)> {};
|
||||||
|
|
||||||
template<typename T1, typename T2>
|
template<typename T1, typename T2>
|
||||||
using type_list_of_base_dimension_less = expr_less<T1, T2, base_dimension_less>;
|
using type_list_of_base_dimension_less = expr_less<T1, T2, base_dimension_less>;
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline constexpr bool is_dimension_one = false;
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline constexpr bool is_power_of_dim = requires {
|
|
||||||
requires is_specialization_of_power<T> && (BaseDimension<typename T::factor> || is_dimension_one<typename T::factor>);
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline constexpr bool is_per_of_dims = false;
|
|
||||||
|
|
||||||
template<typename... Ts>
|
|
||||||
inline constexpr bool is_per_of_dims<per<Ts...>> =
|
|
||||||
(... && (BaseDimension<Ts> || is_dimension_one<Ts> || is_power_of_dim<Ts>));
|
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
concept DerivedDimensionExpr =
|
|
||||||
BaseDimension<T> || detail::is_dimension_one<T> || detail::is_power_of_dim<T> || detail::is_per_of_dims<T>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A dimension of a derived quantity
|
* @brief A dimension of a derived quantity
|
||||||
*
|
*
|
||||||
@@ -154,8 +114,8 @@ concept DerivedDimensionExpr =
|
|||||||
* @note User should not instantiate this type! It is not exported from the C++ module. The library will
|
* @note User should not instantiate this type! It is not exported from the C++ module. The library will
|
||||||
* instantiate this type automatically based on the dimensional arithmetic equation provided by the user.
|
* instantiate this type automatically based on the dimensional arithmetic equation provided by the user.
|
||||||
*/
|
*/
|
||||||
template<DerivedDimensionExpr... Ds>
|
template<DerivedDimensionExpr... Expr>
|
||||||
struct derived_dimension : detail::expr_fractions<derived_dimension<>, Ds...> {};
|
struct derived_dimension : detail::expr_fractions<derived_dimension<>, Expr...> {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Dimension one
|
* @brief Dimension one
|
||||||
@@ -172,33 +132,8 @@ namespace detail {
|
|||||||
template<>
|
template<>
|
||||||
inline constexpr bool is_dimension_one<struct dimension_one> = true;
|
inline constexpr bool is_dimension_one<struct dimension_one> = true;
|
||||||
|
|
||||||
template<typename... Ds>
|
|
||||||
void to_base_specialization_of_derived_dimension(const volatile derived_dimension<Ds...>*);
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline constexpr bool is_derived_from_specialization_of_derived_dimension =
|
|
||||||
requires(T * t) { to_base_specialization_of_derived_dimension(t); };
|
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A concept matching all derived dimensions in the library.
|
|
||||||
*
|
|
||||||
* Satisfied by all dimension types either being a specialization of `derived_dimension`
|
|
||||||
* or derived from it (inheritance needed to properly handle `dimension_one`).
|
|
||||||
*/
|
|
||||||
template<typename T>
|
|
||||||
concept DerivedDimension = detail::is_derived_from_specialization_of_derived_dimension<T>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A concept matching all dimensions in the library.
|
|
||||||
*
|
|
||||||
* Satisfied by all dimension types for which either `BaseDimension<T>` or `DerivedDimension<T>` is `true`.
|
|
||||||
*/
|
|
||||||
template<typename T>
|
|
||||||
concept Dimension = BaseDimension<T> || DerivedDimension<T>;
|
|
||||||
|
|
||||||
|
|
||||||
// Operators
|
// Operators
|
||||||
|
|
||||||
template<Dimension Lhs, Dimension Rhs>
|
template<Dimension Lhs, Dimension Rhs>
|
||||||
|
@@ -23,8 +23,13 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <mp_units/bits/dimension_concepts.h>
|
||||||
#include <mp_units/bits/quantity_cast.h>
|
#include <mp_units/bits/quantity_cast.h>
|
||||||
#include <mp_units/bits/quantity_concepts.h>
|
#include <mp_units/bits/quantity_concepts.h>
|
||||||
|
#include <mp_units/bits/quantity_spec_concepts.h>
|
||||||
|
#include <mp_units/bits/reference_concepts.h>
|
||||||
|
#include <mp_units/bits/representation_concepts.h>
|
||||||
|
#include <mp_units/bits/unit_concepts.h>
|
||||||
#include <mp_units/customization_points.h>
|
#include <mp_units/customization_points.h>
|
||||||
#include <mp_units/dimension.h>
|
#include <mp_units/dimension.h>
|
||||||
#include <mp_units/quantity_spec.h>
|
#include <mp_units/quantity_spec.h>
|
||||||
@@ -40,32 +45,31 @@ namespace mp_units {
|
|||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
concept quantity_one = quantity_of<T, dimensionless[one]>;
|
concept QuantityOne = QuantityOf<T, dimensionless[one]>;
|
||||||
|
|
||||||
template<quantity_like Q>
|
template<QuantityLike Q>
|
||||||
using quantity_like_type = quantity<quantity_like_traits<Q>::reference, typename quantity_like_traits<Q>::rep>;
|
using quantity_like_type = quantity<quantity_like_traits<Q>::reference, typename quantity_like_traits<Q>::rep>;
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
template<typename T, typename Arg>
|
template<typename T, typename Arg>
|
||||||
concept rep_safe_constructible_from_ = // exposition only
|
concept RepSafeConstructibleFrom = // exposition only
|
||||||
std::constructible_from<T, Arg> && (treat_as_floating_point<T> || !treat_as_floating_point<Arg>);
|
std::constructible_from<T, Arg> && (treat_as_floating_point<T> || !treat_as_floating_point<Arg>);
|
||||||
|
|
||||||
// QFrom ratio is an exact multiple of QTo
|
// QFrom ratio is an exact multiple of QTo
|
||||||
template<typename QFrom, typename QTo>
|
template<typename QFrom, typename QTo>
|
||||||
concept harmonic_ = // exposition only
|
concept Harmonic = // exposition only
|
||||||
Quantity<QFrom> && Quantity<QTo> &&
|
Quantity<QFrom> && Quantity<QTo> &&
|
||||||
is_integral(detail::get_canonical_unit(QFrom::unit).mag / detail::get_canonical_unit(QTo::unit).mag);
|
is_integral(get_canonical_unit(QFrom::unit).mag / get_canonical_unit(QTo::unit).mag);
|
||||||
|
|
||||||
template<typename QFrom, typename QTo>
|
template<typename QFrom, typename QTo>
|
||||||
concept quantity_convertible_to_ = // exposition only
|
concept QuantityConvertibleTo = // exposition only
|
||||||
Quantity<QFrom> && Quantity<QTo> && requires(QFrom q) { quantity_cast<QTo>(q); } &&
|
Quantity<QFrom> && Quantity<QTo> && requires(QFrom q) { quantity_cast<QTo>(q); } &&
|
||||||
(treat_as_floating_point<typename QTo::rep> ||
|
(treat_as_floating_point<typename QTo::rep> ||
|
||||||
(!treat_as_floating_point<typename QFrom::rep> && harmonic_<QFrom, QTo>));
|
(!treat_as_floating_point<typename QFrom::rep> && Harmonic<QFrom, QTo>));
|
||||||
|
|
||||||
template<quantity_character Ch, typename Func, typename T, typename U>
|
template<quantity_character Ch, typename Func, typename T, typename U>
|
||||||
concept invoke_result_of_ =
|
concept InvokeResultOf = std::regular_invocable<Func, T, U> && RepresentationOf<std::invoke_result_t<Func, T, U>, Ch>;
|
||||||
std::regular_invocable<Func, T, U> && RepresentationOf<std::invoke_result_t<Func, T, U>, Ch>;
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A quantity
|
* @brief A quantity
|
||||||
@@ -76,16 +80,16 @@ concept invoke_result_of_ =
|
|||||||
* @tparam R a reference of the quantity providing all information about quantity properties
|
* @tparam R a reference of the quantity providing all information about quantity properties
|
||||||
* @tparam Rep a type to be used to represent values of a quantity
|
* @tparam Rep a type to be used to represent values of a quantity
|
||||||
*/
|
*/
|
||||||
template<Reference auto R, RepresentationOf<R.quantity_spec.character> Rep = double>
|
template<Reference auto R, RepresentationOf<get_quantity_spec(R).character> Rep = double>
|
||||||
class quantity {
|
class quantity {
|
||||||
public:
|
public:
|
||||||
Rep number_; // needs to be public for a structural type
|
Rep number_; // needs to be public for a structural type
|
||||||
|
|
||||||
// member types and values
|
// member types and values
|
||||||
static constexpr Reference auto reference = R;
|
static constexpr Reference auto reference = R;
|
||||||
static constexpr QuantitySpec auto quantity_spec = reference.quantity_spec;
|
static constexpr QuantitySpec auto quantity_spec = get_quantity_spec(reference);
|
||||||
static constexpr Dimension auto dimension = reference.dimension;
|
static constexpr Dimension auto dimension = quantity_spec.dimension;
|
||||||
static constexpr Unit auto unit = reference.unit;
|
static constexpr Unit auto unit = get_unit(reference);
|
||||||
using rep = Rep;
|
using rep = Rep;
|
||||||
|
|
||||||
// static member functions
|
// static member functions
|
||||||
@@ -119,18 +123,18 @@ public:
|
|||||||
quantity(quantity&&) = default;
|
quantity(quantity&&) = default;
|
||||||
|
|
||||||
template<typename Value>
|
template<typename Value>
|
||||||
requires rep_safe_constructible_from_<rep, Value>
|
requires detail::RepSafeConstructibleFrom<rep, Value>
|
||||||
constexpr explicit(!detail::quantity_one<quantity>) quantity(Value&& v) : number_(std::forward<Value>(v))
|
constexpr explicit(!detail::QuantityOne<quantity>) quantity(Value&& v) : number_(std::forward<Value>(v))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template<quantity_convertible_to_<quantity> Q>
|
template<detail::QuantityConvertibleTo<quantity> Q>
|
||||||
constexpr explicit(false) quantity(const Q& q) : number_(quantity_cast<quantity>(q).number())
|
constexpr explicit(false) quantity(const Q& q) : number_(quantity_cast<quantity>(q).number())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template<quantity_like Q>
|
template<QuantityLike Q>
|
||||||
requires quantity_convertible_to_<detail::quantity_like_type<Q>, quantity>
|
requires detail::QuantityConvertibleTo<detail::quantity_like_type<Q>, quantity>
|
||||||
constexpr explicit quantity(const Q& q) : quantity(detail::quantity_like_type<Q>(quantity_like_traits<Q>::number(q)))
|
constexpr explicit quantity(const Q& q) : quantity(detail::quantity_like_type<Q>(quantity_like_traits<Q>::number(q)))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -151,7 +155,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<Unit U>
|
template<Unit U>
|
||||||
requires quantity_convertible_to_<quantity, quantity<::mp_units::reference<quantity_spec, U{}>{}, Rep>>
|
requires detail::QuantityConvertibleTo<quantity, quantity<::mp_units::reference<quantity_spec, U{}>{}, Rep>>
|
||||||
[[nodiscard]] constexpr quantity<::mp_units::reference<quantity_spec, U{}>{}, Rep> operator[](U) const
|
[[nodiscard]] constexpr quantity<::mp_units::reference<quantity_spec, U{}>{}, Rep> operator[](U) const
|
||||||
{
|
{
|
||||||
return quantity<::mp_units::reference<quantity_spec, U{}>{}, Rep>{*this};
|
return quantity<::mp_units::reference<quantity_spec, U{}>{}, Rep>{*this};
|
||||||
@@ -252,7 +256,7 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<detail::quantity_one Q>
|
template<detail::QuantityOne Q>
|
||||||
constexpr quantity& operator*=(const Q& rhs)
|
constexpr quantity& operator*=(const Q& rhs)
|
||||||
requires requires(rep a, const typename Q::rep b) {
|
requires requires(rep a, const typename Q::rep b) {
|
||||||
{
|
{
|
||||||
@@ -277,7 +281,7 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<detail::quantity_one Q>
|
template<detail::QuantityOne Q>
|
||||||
constexpr quantity& operator/=(const Q& rhs)
|
constexpr quantity& operator/=(const Q& rhs)
|
||||||
requires requires(rep a, const typename Q::rep b) {
|
requires requires(rep a, const typename Q::rep b) {
|
||||||
{
|
{
|
||||||
@@ -303,7 +307,7 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<detail::quantity_one Q>
|
template<detail::QuantityOne Q>
|
||||||
constexpr quantity& operator%=(const Q& rhs)
|
constexpr quantity& operator%=(const Q& rhs)
|
||||||
requires(!treat_as_floating_point<rep>) && (!treat_as_floating_point<typename Q::rep>) &&
|
requires(!treat_as_floating_point<rep>) && (!treat_as_floating_point<typename Q::rep>) &&
|
||||||
requires(rep a, const typename Q::rep b) {
|
requires(rep a, const typename Q::rep b) {
|
||||||
@@ -336,7 +340,7 @@ public:
|
|||||||
requires requires { // TODO: Simplify when Clang catches up.
|
requires requires { // TODO: Simplify when Clang catches up.
|
||||||
requires !Quantity<Value>;
|
requires !Quantity<Value>;
|
||||||
requires unit == ::mp_units::one;
|
requires unit == ::mp_units::one;
|
||||||
requires invoke_result_of_<R.quantity_spec.character, std::plus<>, rep, Value>;
|
requires detail::InvokeResultOf<quantity_spec.character, std::plus<>, rep, Value>;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
return ::mp_units::quantity(lhs.number() + rhs);
|
return ::mp_units::quantity(lhs.number() + rhs);
|
||||||
@@ -347,7 +351,7 @@ public:
|
|||||||
requires requires { // TODO: Simplify when Clang catches up.
|
requires requires { // TODO: Simplify when Clang catches up.
|
||||||
requires !Quantity<Value>;
|
requires !Quantity<Value>;
|
||||||
requires unit == ::mp_units::one;
|
requires unit == ::mp_units::one;
|
||||||
requires invoke_result_of_<R.quantity_spec.character, std::plus<>, Value, rep>;
|
requires detail::InvokeResultOf<quantity_spec.character, std::plus<>, Value, rep>;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
return ::mp_units::quantity(lhs + rhs.number());
|
return ::mp_units::quantity(lhs + rhs.number());
|
||||||
@@ -358,7 +362,7 @@ public:
|
|||||||
requires requires { // TODO: Simplify when Clang catches up.
|
requires requires { // TODO: Simplify when Clang catches up.
|
||||||
requires !Quantity<Value>;
|
requires !Quantity<Value>;
|
||||||
requires unit == ::mp_units::one;
|
requires unit == ::mp_units::one;
|
||||||
requires invoke_result_of_<R.quantity_spec.character, std::minus<>, rep, Value>;
|
requires detail::InvokeResultOf<quantity_spec.character, std::minus<>, rep, Value>;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
return ::mp_units::quantity(lhs.number() - rhs);
|
return ::mp_units::quantity(lhs.number() - rhs);
|
||||||
@@ -369,14 +373,14 @@ public:
|
|||||||
requires requires { // TODO: Simplify when Clang catches up.
|
requires requires { // TODO: Simplify when Clang catches up.
|
||||||
requires !Quantity<Value>;
|
requires !Quantity<Value>;
|
||||||
requires unit == ::mp_units::one;
|
requires unit == ::mp_units::one;
|
||||||
requires invoke_result_of_<R.quantity_spec.character, std::minus<>, Value, rep>;
|
requires detail::InvokeResultOf<quantity_spec.character, std::minus<>, Value, rep>;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
return ::mp_units::quantity(lhs - rhs.number());
|
return ::mp_units::quantity(lhs - rhs.number());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<Representation Value>
|
template<Representation Value>
|
||||||
requires invoke_result_of_<R.quantity_spec.character, std::multiplies<>, rep, const Value&>
|
requires detail::InvokeResultOf<quantity_spec.character, std::multiplies<>, rep, const Value&>
|
||||||
[[nodiscard]] friend constexpr Quantity auto operator*(const quantity& q, const Value& v)
|
[[nodiscard]] friend constexpr Quantity auto operator*(const quantity& q, const Value& v)
|
||||||
{
|
{
|
||||||
using ret = quantity<R, std::invoke_result_t<std::multiplies<>, rep, Value>>;
|
using ret = quantity<R, std::invoke_result_t<std::multiplies<>, rep, Value>>;
|
||||||
@@ -384,7 +388,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<Representation Value>
|
template<Representation Value>
|
||||||
requires invoke_result_of_<R.quantity_spec.character, std::multiplies<>, const Value&, rep>
|
requires detail::InvokeResultOf<quantity_spec.character, std::multiplies<>, const Value&, rep>
|
||||||
[[nodiscard]] friend constexpr Quantity auto operator*(const Value& v, const quantity& q)
|
[[nodiscard]] friend constexpr Quantity auto operator*(const Value& v, const quantity& q)
|
||||||
{
|
{
|
||||||
using ret = quantity<R, std::invoke_result_t<std::multiplies<>, Value, rep>>;
|
using ret = quantity<R, std::invoke_result_t<std::multiplies<>, Value, rep>>;
|
||||||
@@ -392,7 +396,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename Value>
|
template<typename Value>
|
||||||
requires(!Quantity<Value>) && invoke_result_of_<R.quantity_spec.character, std::divides<>, rep, const Value&>
|
requires(!Quantity<Value>) && detail::InvokeResultOf<quantity_spec.character, std::divides<>, rep, const Value&>
|
||||||
[[nodiscard]] friend constexpr Quantity auto operator/(const quantity& q, const Value& v)
|
[[nodiscard]] friend constexpr Quantity auto operator/(const quantity& q, const Value& v)
|
||||||
{
|
{
|
||||||
gsl_ExpectsAudit(v != quantity_values<Value>::zero());
|
gsl_ExpectsAudit(v != quantity_values<Value>::zero());
|
||||||
@@ -401,7 +405,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename Value>
|
template<typename Value>
|
||||||
requires(!Quantity<Value>) && invoke_result_of_<R.quantity_spec.character, std::divides<>, const Value&, rep>
|
requires(!Quantity<Value>) && detail::InvokeResultOf<quantity_spec.character, std::divides<>, const Value&, rep>
|
||||||
[[nodiscard]] friend constexpr Quantity auto operator/(const Value& v, const quantity& q)
|
[[nodiscard]] friend constexpr Quantity auto operator/(const Value& v, const quantity& q)
|
||||||
{
|
{
|
||||||
return (dimensionless[::mp_units::one] / reference)(v / q.number());
|
return (dimensionless[::mp_units::one] / reference)(v / q.number());
|
||||||
@@ -409,7 +413,7 @@ public:
|
|||||||
|
|
||||||
template<typename Value>
|
template<typename Value>
|
||||||
requires(!Quantity<Value>) && (!treat_as_floating_point<rep>) && (!treat_as_floating_point<Value>) &&
|
requires(!Quantity<Value>) && (!treat_as_floating_point<rep>) && (!treat_as_floating_point<Value>) &&
|
||||||
invoke_result_of_<R.quantity_spec.character, std::modulus<>, rep, const Value&>
|
detail::InvokeResultOf<quantity_spec.character, std::modulus<>, rep, const Value&>
|
||||||
[[nodiscard]] friend constexpr Quantity auto operator%(const quantity& q, const Value& v)
|
[[nodiscard]] friend constexpr Quantity auto operator%(const quantity& q, const Value& v)
|
||||||
{
|
{
|
||||||
gsl_ExpectsAudit(v != quantity_values<Value>::zero());
|
gsl_ExpectsAudit(v != quantity_values<Value>::zero());
|
||||||
@@ -418,7 +422,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] friend constexpr Quantity auto operator%(const quantity& lhs, const quantity& rhs)
|
[[nodiscard]] friend constexpr Quantity auto operator%(const quantity& lhs, const quantity& rhs)
|
||||||
requires(!treat_as_floating_point<rep>) && invoke_result_of_<R.quantity_spec.character, std::modulus<>, rep, rep>
|
requires(!treat_as_floating_point<rep>) && detail::InvokeResultOf<quantity_spec.character, std::modulus<>, rep, rep>
|
||||||
{
|
{
|
||||||
gsl_ExpectsAudit(rhs.number() != quantity_values<rep>::zero());
|
gsl_ExpectsAudit(rhs.number() != quantity_values<rep>::zero());
|
||||||
using ret = quantity<R, std::invoke_result_t<std::modulus<>, rep, rep>>;
|
using ret = quantity<R, std::invoke_result_t<std::modulus<>, rep, rep>>;
|
||||||
@@ -450,14 +454,14 @@ template<auto R, RepresentationOf<R.quantity_spec.character> Rep>
|
|||||||
explicit(false) quantity(Rep&&) -> quantity<R, Rep>;
|
explicit(false) quantity(Rep&&) -> quantity<R, Rep>;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template<quantity_like Q>
|
template<QuantityLike Q>
|
||||||
explicit quantity(Q) -> quantity<quantity_like_traits<Q>::reference, typename quantity_like_traits<Q>::rep>;
|
explicit quantity(Q) -> quantity<quantity_like_traits<Q>::reference, typename quantity_like_traits<Q>::rep>;
|
||||||
|
|
||||||
// non-member binary operators
|
// non-member binary operators
|
||||||
template<Quantity Q1, Quantity Q2>
|
template<Quantity Q1, Quantity Q2>
|
||||||
requires(get_kind(Q1::quantity_spec) == get_kind(Q2::quantity_spec)) &&
|
requires(get_kind(Q1::quantity_spec) == get_kind(Q2::quantity_spec)) &&
|
||||||
invoke_result_of_<common_quantity_spec(Q1::quantity_spec, Q2::quantity_spec).character, std::plus<>,
|
detail::InvokeResultOf<common_quantity_spec(Q1::quantity_spec, Q2::quantity_spec).character, std::plus<>,
|
||||||
typename Q1::rep, typename Q2::rep>
|
typename Q1::rep, typename Q2::rep>
|
||||||
[[nodiscard]] constexpr Quantity auto operator+(const Q1& lhs, const Q2& rhs)
|
[[nodiscard]] constexpr Quantity auto operator+(const Q1& lhs, const Q2& rhs)
|
||||||
{
|
{
|
||||||
constexpr auto ref = common_reference(Q1::reference, Q2::reference);
|
constexpr auto ref = common_reference(Q1::reference, Q2::reference);
|
||||||
@@ -467,8 +471,8 @@ template<Quantity Q1, Quantity Q2>
|
|||||||
|
|
||||||
template<Quantity Q1, Quantity Q2>
|
template<Quantity Q1, Quantity Q2>
|
||||||
requires(get_kind(Q1::quantity_spec) == get_kind(Q2::quantity_spec)) &&
|
requires(get_kind(Q1::quantity_spec) == get_kind(Q2::quantity_spec)) &&
|
||||||
invoke_result_of_<common_quantity_spec(Q1::quantity_spec, Q2::quantity_spec).character, std::minus<>,
|
detail::InvokeResultOf<common_quantity_spec(Q1::quantity_spec, Q2::quantity_spec).character, std::minus<>,
|
||||||
typename Q1::rep, typename Q2::rep>
|
typename Q1::rep, typename Q2::rep>
|
||||||
[[nodiscard]] constexpr Quantity auto operator-(const Q1& lhs, const Q2& rhs)
|
[[nodiscard]] constexpr Quantity auto operator-(const Q1& lhs, const Q2& rhs)
|
||||||
{
|
{
|
||||||
constexpr auto ref = common_reference(Q1::reference, Q2::reference);
|
constexpr auto ref = common_reference(Q1::reference, Q2::reference);
|
||||||
@@ -477,16 +481,16 @@ template<Quantity Q1, Quantity Q2>
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<Quantity Q1, Quantity Q2>
|
template<Quantity Q1, Quantity Q2>
|
||||||
requires invoke_result_of_<(Q1::quantity_spec * Q2::quantity_spec).character, std::multiplies<>, typename Q1::rep,
|
requires detail::InvokeResultOf<(Q1::quantity_spec * Q2::quantity_spec).character, std::multiplies<>,
|
||||||
typename Q2::rep>
|
typename Q1::rep, typename Q2::rep>
|
||||||
[[nodiscard]] constexpr Quantity auto operator*(const Q1& lhs, const Q2& rhs)
|
[[nodiscard]] constexpr Quantity auto operator*(const Q1& lhs, const Q2& rhs)
|
||||||
{
|
{
|
||||||
return (Q1::reference * Q2::reference)(lhs.number() * rhs.number());
|
return (Q1::reference * Q2::reference)(lhs.number() * rhs.number());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<Quantity Q1, Quantity Q2>
|
template<Quantity Q1, Quantity Q2>
|
||||||
requires invoke_result_of_<(Q1::quantity_spec / Q2::quantity_spec).character, std::divides<>, typename Q1::rep,
|
requires detail::InvokeResultOf<(Q1::quantity_spec / Q2::quantity_spec).character, std::divides<>, typename Q1::rep,
|
||||||
typename Q2::rep>
|
typename Q2::rep>
|
||||||
[[nodiscard]] constexpr Quantity auto operator/(const Q1& lhs, const Q2& rhs)
|
[[nodiscard]] constexpr Quantity auto operator/(const Q1& lhs, const Q2& rhs)
|
||||||
{
|
{
|
||||||
gsl_ExpectsAudit(rhs.number() != quantity_values<typename Q2::rep>::zero());
|
gsl_ExpectsAudit(rhs.number() != quantity_values<typename Q2::rep>::zero());
|
||||||
@@ -495,8 +499,8 @@ template<Quantity Q1, Quantity Q2>
|
|||||||
|
|
||||||
template<Quantity Q1, Quantity Q2>
|
template<Quantity Q1, Quantity Q2>
|
||||||
requires(!treat_as_floating_point<typename Q1::rep>) && (!treat_as_floating_point<typename Q2::rep>) &&
|
requires(!treat_as_floating_point<typename Q1::rep>) && (!treat_as_floating_point<typename Q2::rep>) &&
|
||||||
(interconvertible(Q1::reference, Q2::reference) || quantity_of<Q2, dimensionless>) &&
|
(interconvertible(Q1::reference, Q2::reference) || QuantityOf<Q2, dimensionless>) &&
|
||||||
invoke_result_of_<Q1::reference.character, std::modulus<>, typename Q1::rep, typename Q2::rep>
|
detail::InvokeResultOf<Q1::reference.character, std::modulus<>, typename Q1::rep, typename Q2::rep>
|
||||||
[[nodiscard]] constexpr Quantity auto operator%(const Q1& lhs, const Q2& rhs)
|
[[nodiscard]] constexpr Quantity auto operator%(const Q1& lhs, const Q2& rhs)
|
||||||
{
|
{
|
||||||
gsl_ExpectsAudit(rhs.number() != quantity_values<typename Q2::rep>::zero());
|
gsl_ExpectsAudit(rhs.number() != quantity_values<typename Q2::rep>::zero());
|
||||||
|
@@ -23,15 +23,21 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <mp_units/bits/quantity_point_concepts.h>
|
||||||
#include <mp_units/customization_points.h>
|
#include <mp_units/customization_points.h>
|
||||||
#include <mp_units/quantity.h>
|
#include <mp_units/quantity.h>
|
||||||
#include <compare>
|
#include <compare>
|
||||||
|
|
||||||
namespace mp_units {
|
namespace mp_units {
|
||||||
|
|
||||||
|
template<QuantitySpec auto Q>
|
||||||
|
struct absolute_point_origin {
|
||||||
|
static constexpr QuantitySpec auto quantity_spec = Q;
|
||||||
|
};
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
[[nodiscard]] consteval point_origin auto get_absolute_point_origin(point_origin auto po)
|
[[nodiscard]] consteval PointOrigin auto get_absolute_point_origin(PointOrigin auto po)
|
||||||
{
|
{
|
||||||
if constexpr (requires { po.absolute_point_origin; })
|
if constexpr (requires { po.absolute_point_origin; })
|
||||||
return po.absolute_point_origin;
|
return po.absolute_point_origin;
|
||||||
@@ -39,7 +45,7 @@ namespace detail {
|
|||||||
return po;
|
return po;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<quantity_point_like QP>
|
template<QuantityPointLike QP>
|
||||||
using quantity_point_like_type =
|
using quantity_point_like_type =
|
||||||
quantity_point<quantity_point_like_traits<QP>::reference, quantity_point_like_traits<QP>::point_origin,
|
quantity_point<quantity_point_like_traits<QP>::reference, quantity_point_like_traits<QP>::point_origin,
|
||||||
typename quantity_point_like_traits<QP>::rep>;
|
typename quantity_point_like_traits<QP>::rep>;
|
||||||
@@ -55,17 +61,17 @@ using quantity_point_like_type =
|
|||||||
* @tparam PO a type that represents the origin point from which the quantity point is measured from
|
* @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
|
* @tparam Rep a type to be used to represent values of a quantity point
|
||||||
*/
|
*/
|
||||||
template<Reference auto R, point_origin_for<R.quantity_spec> auto PO = absolute_point_origin<R.quantity_spec>{},
|
template<Reference auto R, PointOriginFor<get_quantity_spec(R)> auto PO = absolute_point_origin<get_quantity_spec(R)>{},
|
||||||
RepresentationOf<R.quantity_spec.character> Rep = double>
|
RepresentationOf<get_quantity_spec(R).character> Rep = double>
|
||||||
class quantity_point {
|
class quantity_point {
|
||||||
public:
|
public:
|
||||||
// member types and values
|
// member types and values
|
||||||
static constexpr Reference auto reference = R;
|
static constexpr Reference auto reference = R;
|
||||||
static constexpr QuantitySpec auto quantity_spec = reference.quantity_spec;
|
static constexpr QuantitySpec auto quantity_spec = get_quantity_spec(reference);
|
||||||
static constexpr Dimension auto dimension = reference.dimension;
|
static constexpr Dimension auto dimension = quantity_spec.dimension;
|
||||||
static constexpr Unit auto unit = reference.unit;
|
static constexpr Unit auto unit = get_unit(reference);
|
||||||
static constexpr point_origin auto absolute_point_origin = detail::get_absolute_point_origin(PO);
|
static constexpr PointOrigin auto absolute_point_origin = detail::get_absolute_point_origin(PO);
|
||||||
static constexpr point_origin auto point_origin = PO;
|
static constexpr PointOrigin auto point_origin = PO;
|
||||||
using rep = Rep;
|
using rep = Rep;
|
||||||
using quantity_type = quantity<reference, Rep>;
|
using quantity_type = quantity<reference, Rep>;
|
||||||
|
|
||||||
@@ -95,13 +101,13 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template<quantity_point_of<point_origin> QP2>
|
template<QuantityPointOf<point_origin> QP2>
|
||||||
requires std::convertible_to<typename QP2::quantity_type, quantity_type>
|
requires std::convertible_to<typename QP2::quantity_type, quantity_type>
|
||||||
constexpr explicit(false) quantity_point(const QP2& qp) : q_(qp.relative())
|
constexpr explicit(false) quantity_point(const QP2& qp) : q_(qp.relative())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template<quantity_point_like QP>
|
template<QuantityPointLike QP>
|
||||||
requires std::same_as<std::remove_const_t<decltype(quantity_point_like_traits<QP>::point_origin)>,
|
requires std::same_as<std::remove_const_t<decltype(quantity_point_like_traits<QP>::point_origin)>,
|
||||||
std::remove_const_t<decltype(point_origin)>> &&
|
std::remove_const_t<decltype(point_origin)>> &&
|
||||||
std::convertible_to<typename detail::quantity_point_like_type<QP>::quantity_type, quantity_type>
|
std::convertible_to<typename detail::quantity_point_like_type<QP>::quantity_type, quantity_type>
|
||||||
@@ -195,21 +201,21 @@ public:
|
|||||||
return quantity_point<q_type::reference, point_origin, typename q_type::rep>(q);
|
return quantity_point<q_type::reference, point_origin, typename q_type::rep>(q);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<quantity_point_of<absolute_point_origin> QP>
|
template<QuantityPointOf<absolute_point_origin> QP>
|
||||||
[[nodiscard]] friend constexpr Quantity auto operator-(const quantity_point& lhs, const QP& rhs)
|
[[nodiscard]] friend constexpr Quantity auto operator-(const quantity_point& lhs, const QP& rhs)
|
||||||
requires requires(quantity_type q) { q - rhs.absolute(); }
|
requires requires(quantity_type q) { q - rhs.absolute(); }
|
||||||
{
|
{
|
||||||
return lhs.absolute() - rhs.absolute();
|
return lhs.absolute() - rhs.absolute();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<quantity_point_of<absolute_point_origin> QP>
|
template<QuantityPointOf<absolute_point_origin> QP>
|
||||||
requires std::three_way_comparable_with<quantity_type, typename QP::quantity_type>
|
requires std::three_way_comparable_with<quantity_type, typename QP::quantity_type>
|
||||||
[[nodiscard]] friend constexpr auto operator<=>(const quantity_point& lhs, const QP& rhs)
|
[[nodiscard]] friend constexpr auto operator<=>(const quantity_point& lhs, const QP& rhs)
|
||||||
{
|
{
|
||||||
return lhs.relative() <=> rhs.relative();
|
return lhs.relative() <=> rhs.relative();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<quantity_point_of<absolute_point_origin> QP>
|
template<QuantityPointOf<absolute_point_origin> QP>
|
||||||
requires std::equality_comparable_with<quantity_type, typename QP::quantity_type>
|
requires std::equality_comparable_with<quantity_type, typename QP::quantity_type>
|
||||||
[[nodiscard]] friend constexpr bool operator==(const quantity_point& lhs, const QP& rhs)
|
[[nodiscard]] friend constexpr bool operator==(const quantity_point& lhs, const QP& rhs)
|
||||||
{
|
{
|
||||||
@@ -224,12 +230,12 @@ explicit quantity_point(Rep) -> quantity_point<dimensionless[one], absolute_poin
|
|||||||
template<Quantity Q>
|
template<Quantity Q>
|
||||||
explicit quantity_point(Q) -> quantity_point<Q::reference, absolute_point_origin<Q::quantity_spec>{}, typename Q::rep>;
|
explicit quantity_point(Q) -> quantity_point<Q::reference, absolute_point_origin<Q::quantity_spec>{}, typename Q::rep>;
|
||||||
|
|
||||||
template<quantity_like Q>
|
template<QuantityLike Q>
|
||||||
explicit quantity_point(Q)
|
explicit quantity_point(Q)
|
||||||
-> quantity_point<quantity_like_traits<Q>::reference, absolute_point_origin<quantity_like_traits<Q>::quantity_spec>{},
|
-> quantity_point<quantity_like_traits<Q>::reference, absolute_point_origin<quantity_like_traits<Q>::quantity_spec>{},
|
||||||
typename quantity_like_traits<Q>::rep>;
|
typename quantity_like_traits<Q>::rep>;
|
||||||
|
|
||||||
template<quantity_point_like QP>
|
template<QuantityPointLike QP>
|
||||||
explicit quantity_point(QP)
|
explicit quantity_point(QP)
|
||||||
-> quantity_point<quantity_point_like_traits<QP>::reference, quantity_point_like_traits<QP>::point_origin,
|
-> quantity_point<quantity_point_like_traits<QP>::reference, quantity_point_like_traits<QP>::point_origin,
|
||||||
typename quantity_point_like_traits<QP>::rep>;
|
typename quantity_point_like_traits<QP>::rep>;
|
||||||
|
@@ -23,10 +23,65 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <mp_units/bits/quantity_concepts.h>
|
#include <mp_units/bits/quantity_concepts.h>
|
||||||
#include <mp_units/unit.h>
|
#include <mp_units/bits/reference_concepts.h>
|
||||||
|
#include <mp_units/bits/representation_concepts.h>
|
||||||
|
#include <mp_units/quantity_spec.h>
|
||||||
|
|
||||||
namespace mp_units {
|
namespace mp_units {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<AssociatedUnit U>
|
||||||
|
[[nodiscard]] consteval auto get_associated_quantity(U);
|
||||||
|
|
||||||
|
template<typename U, auto... Vs>
|
||||||
|
[[nodiscard]] consteval auto get_associated_quantity(power<U, Vs...>)
|
||||||
|
{
|
||||||
|
return get_associated_quantity(U{});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Us>
|
||||||
|
[[nodiscard]] consteval auto get_associated_quantity(type_list<Us...>)
|
||||||
|
{
|
||||||
|
return (dimensionless * ... * get_associated_quantity(Us{}));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<AssociatedUnit U>
|
||||||
|
[[nodiscard]] consteval auto get_associated_quantity(U)
|
||||||
|
{
|
||||||
|
if constexpr (requires { U::reference_unit; })
|
||||||
|
return get_associated_quantity(U::reference_unit);
|
||||||
|
else if constexpr (requires { typename U::_num_; })
|
||||||
|
return get_associated_quantity(typename U::_num_{}) / get_associated_quantity(typename U::_den_{});
|
||||||
|
else if constexpr (requires { U::base_quantity; })
|
||||||
|
return U::base_quantity;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
[[nodiscard]] consteval QuantitySpec auto get_quantity_spec(AssociatedUnit auto u)
|
||||||
|
{
|
||||||
|
return detail::get_associated_quantity(u);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<auto Q, auto U>
|
||||||
|
[[nodiscard]] consteval QuantitySpec auto get_quantity_spec(reference<Q, U>)
|
||||||
|
{
|
||||||
|
return Q;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] consteval Unit auto get_unit(AssociatedUnit auto u) { return u; }
|
||||||
|
|
||||||
|
template<auto Q, auto U>
|
||||||
|
[[nodiscard]] consteval Unit auto get_unit(reference<Q, U>)
|
||||||
|
{
|
||||||
|
return U;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<Reference auto R, RepresentationOf<get_quantity_spec(R).character> Rep>
|
||||||
|
class quantity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Quantity reference type
|
* @brief Quantity reference type
|
||||||
*
|
*
|
||||||
@@ -39,7 +94,7 @@ namespace mp_units {
|
|||||||
*
|
*
|
||||||
* @code{.cpp}
|
* @code{.cpp}
|
||||||
* Reference auto kmph = isq::speed[km / h];
|
* Reference auto kmph = isq::speed[km / h];
|
||||||
* quantity_of<isq::speed[km / h]> auto speed = 90 * kmph;
|
* QuantityOf<isq::speed[km / h]> auto speed = 90 * kmph;
|
||||||
* @endcode
|
* @endcode
|
||||||
*
|
*
|
||||||
* The following syntaxes are not allowed:
|
* The following syntaxes are not allowed:
|
||||||
@@ -47,10 +102,6 @@ namespace mp_units {
|
|||||||
*/
|
*/
|
||||||
template<QuantitySpec auto Q, Unit auto U>
|
template<QuantitySpec auto Q, Unit auto U>
|
||||||
struct reference {
|
struct reference {
|
||||||
static constexpr QuantitySpec auto quantity_spec = Q;
|
|
||||||
static constexpr Dimension auto dimension = Q.dimension;
|
|
||||||
static constexpr Unit auto unit = U;
|
|
||||||
|
|
||||||
template<RepresentationOf<Q.character> Rep>
|
template<RepresentationOf<Q.character> Rep>
|
||||||
// TODO can we somehow return an explicit quantity type here?
|
// TODO can we somehow return an explicit quantity type here?
|
||||||
[[nodiscard]] constexpr std::same_as<quantity<reference{}, Rep>> auto operator()(Rep&& value) const
|
[[nodiscard]] constexpr std::same_as<quantity<reference{}, Rep>> auto operator()(Rep&& value) const
|
||||||
@@ -59,54 +110,103 @@ struct reference {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Reference
|
template<auto Q1, auto U1, auto Q2, auto U2>
|
||||||
|
[[nodiscard]] consteval bool operator==(reference<Q1, U1>, reference<Q2, U2>)
|
||||||
|
{
|
||||||
|
return Q1 == Q2 && U1 == U2;
|
||||||
|
}
|
||||||
|
|
||||||
template<Reference R1, Reference R2>
|
template<auto Q1, auto U1, AssociatedUnit U2>
|
||||||
[[nodiscard]] consteval reference<R1::quantity_spec * R2::quantity_spec, R1::unit * R2::unit> operator*(R1, R2)
|
[[nodiscard]] consteval bool operator==(reference<Q1, U1>, U2 u2)
|
||||||
|
{
|
||||||
|
return Q1 == get_quantity_spec(u2) && U1 == u2;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<auto Q1, auto U1, auto Q2, auto U2>
|
||||||
|
[[nodiscard]] consteval reference<Q1 * Q2, U1 * U2> operator*(reference<Q1, U1>, reference<Q2, U2>)
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<Reference R1, Reference R2>
|
template<auto Q1, auto U1, AssociatedUnit U2>
|
||||||
[[nodiscard]] consteval reference<R1::quantity_spec / R2::quantity_spec, R1::unit / R2::unit> operator/(R1, R2)
|
[[nodiscard]] consteval reference<Q1 * get_quantity_spec(U2{}), U1* U2{}> operator*(reference<Q1, U1>, U2)
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO remove when all code is refactored to a new syntax
|
template<AssociatedUnit U1, auto Q2, auto U2>
|
||||||
template<Representation Rep, Reference R>
|
[[nodiscard]] consteval reference<get_quantity_spec(U1{}) * Q2, U1{} * U2> operator*(U1, reference<Q2, U2>)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<auto Q1, auto U1, auto Q2, auto U2>
|
||||||
|
[[nodiscard]] consteval reference<Q1 / Q2, U1 / U2> operator/(reference<Q1, U1>, reference<Q2, U2>)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<auto Q1, auto U1, AssociatedUnit U2>
|
||||||
|
[[nodiscard]] consteval reference<Q1 / get_quantity_spec(U2{}), U1 / U2{}> operator/(reference<Q1, U1>, U2)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<AssociatedUnit U1, auto Q2, auto U2>
|
||||||
|
[[nodiscard]] consteval reference<get_quantity_spec(U1{}) / Q2, U1{} / U2> operator/(U1, reference<Q2, U2>)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<Reference R, RepresentationOf<get_quantity_spec(R{}).character> Rep>
|
||||||
[[nodiscard]] constexpr quantity<R{}, Rep> operator*(const Rep& lhs, R)
|
[[nodiscard]] constexpr quantity<R{}, Rep> operator*(const Rep& lhs, R)
|
||||||
{
|
{
|
||||||
return quantity<R{}, Rep>(lhs);
|
return quantity<R{}, Rep>(lhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO remove when all code is refactored to a new syntax
|
|
||||||
void /*Use `q * (1 * r)` rather than `q * r`.*/ operator*(Quantity auto, Reference auto) = delete;
|
void /*Use `q * (1 * r)` rather than `q * r`.*/ operator*(Quantity auto, Reference auto) = delete;
|
||||||
|
|
||||||
template<Reference R1, Reference R2>
|
template<auto Q1, auto U1, auto Q2, auto U2>
|
||||||
[[nodiscard]] consteval bool operator==(R1, R2)
|
[[nodiscard]] consteval bool interconvertible(reference<Q1, U1>, reference<Q2, U2>)
|
||||||
{
|
{
|
||||||
return R1::quantity_spec == R2::quantity_spec && R1::unit == R2::unit;
|
return interconvertible(Q1, Q2) && interconvertible(U1, U2);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<Reference R1, Reference R2>
|
template<auto Q1, auto U1, AssociatedUnit U2>
|
||||||
[[nodiscard]] consteval bool interconvertible(R1, R2)
|
[[nodiscard]] consteval bool interconvertible(reference<Q1, U1>, U2 u2)
|
||||||
{
|
{
|
||||||
return interconvertible(R1::quantity_spec, R2::quantity_spec) && interconvertible(R1::unit, R2::unit);
|
return interconvertible(Q1, get_quantity_spec(u2)) && interconvertible(U1, u2);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<AssociatedUnit U1, auto Q2, auto U2>
|
||||||
|
[[nodiscard]] consteval bool interconvertible(U1 u1, reference<Q2, U2> r2)
|
||||||
|
{
|
||||||
|
return interconvertible(r2, u1);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] consteval auto common_reference(AssociatedUnit auto u1, AssociatedUnit auto u2,
|
||||||
|
AssociatedUnit auto... rest)
|
||||||
|
requires requires {
|
||||||
|
{
|
||||||
|
common_unit(u1, u2, rest...)
|
||||||
|
} -> AssociatedUnit;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
return common_unit(u1, u2, rest...);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] consteval auto common_reference(Reference auto r1, Reference auto r2, Reference auto... rest)
|
[[nodiscard]] consteval auto common_reference(Reference auto r1, Reference auto r2, Reference auto... rest)
|
||||||
requires requires {
|
requires requires {
|
||||||
{
|
{
|
||||||
common_quantity_spec(r1.quantity_spec, r2.quantity_spec, rest.quantity_spec...)
|
common_quantity_spec(get_quantity_spec(r1), get_quantity_spec(r2), get_quantity_spec(rest)...)
|
||||||
} -> QuantitySpec;
|
} -> QuantitySpec;
|
||||||
{
|
{
|
||||||
common_unit(r1.unit, r2.unit, rest.unit...)
|
common_unit(get_unit(r1), get_unit(r2), get_unit(rest)...)
|
||||||
} -> Unit;
|
} -> Unit;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
return reference<common_quantity_spec(r1.quantity_spec, r2.quantity_spec, rest.quantity_spec...),
|
return reference<common_quantity_spec(get_quantity_spec(r1), get_quantity_spec(r2), get_quantity_spec(rest)...),
|
||||||
common_unit(r1.unit, r2.unit, rest.unit...)>{};
|
common_unit(get_unit(r1), get_unit(r2), get_unit(rest)...)>{};
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace mp_units
|
} // namespace mp_units
|
||||||
|
@@ -56,7 +56,7 @@ namespace mp_units {
|
|||||||
* @tparam CoU coherent unit for a quantity in this system
|
* @tparam CoU coherent unit for a quantity in this system
|
||||||
*/
|
*/
|
||||||
template<QuantitySpec auto Q, Unit auto CoU>
|
template<QuantitySpec auto Q, Unit auto CoU>
|
||||||
requires(!detail::associated_unit<std::remove_const_t<decltype(CoU)>>) || (CoU == one)
|
requires(!AssociatedUnit<std::remove_const_t<decltype(CoU)>>) || (CoU == one)
|
||||||
struct system_reference {
|
struct system_reference {
|
||||||
static constexpr auto quantity_spec = Q;
|
static constexpr auto quantity_spec = Q;
|
||||||
static constexpr auto coherent_unit = CoU;
|
static constexpr auto coherent_unit = CoU;
|
||||||
|
@@ -28,84 +28,17 @@
|
|||||||
#include <mp_units/bits/external/type_name.h>
|
#include <mp_units/bits/external/type_name.h>
|
||||||
#include <mp_units/bits/external/type_traits.h>
|
#include <mp_units/bits/external/type_traits.h>
|
||||||
#include <mp_units/bits/magnitude.h>
|
#include <mp_units/bits/magnitude.h>
|
||||||
|
#include <mp_units/bits/quantity_spec_concepts.h>
|
||||||
#include <mp_units/bits/ratio.h>
|
#include <mp_units/bits/ratio.h>
|
||||||
#include <mp_units/bits/symbol_text.h>
|
#include <mp_units/bits/symbol_text.h>
|
||||||
#include <mp_units/bits/text_tools.h>
|
#include <mp_units/bits/text_tools.h>
|
||||||
|
#include <mp_units/bits/unit_concepts.h>
|
||||||
#include <mp_units/dimension.h>
|
#include <mp_units/dimension.h>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace mp_units {
|
namespace mp_units {
|
||||||
|
|
||||||
#ifdef __cpp_explicit_this_parameter
|
|
||||||
template<auto...>
|
|
||||||
#else
|
|
||||||
template<typename, auto...>
|
|
||||||
#endif
|
|
||||||
struct quantity_spec;
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
#ifdef __cpp_explicit_this_parameter
|
|
||||||
template<auto... Args>
|
|
||||||
void to_base_specialization_of_quantity_spec(const volatile quantity_spec<Args...>*);
|
|
||||||
#else
|
|
||||||
template<typename T, auto... Args>
|
|
||||||
void to_base_specialization_of_quantity_spec(const volatile quantity_spec<T, Args...>*);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cpp_explicit_this_parameter
|
|
||||||
template<BaseDimension auto Dim, auto... Args>
|
|
||||||
template<auto... Args>
|
|
||||||
void to_base_specialization_of_base_quantity_spec(const volatile quantity_spec<Dim, Args...>*);
|
|
||||||
#else
|
|
||||||
template<typename Self, BaseDimension auto Dim, auto... Args>
|
|
||||||
void to_base_specialization_of_base_quantity_spec(const volatile quantity_spec<Self, Dim, Args...>*);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline constexpr bool is_specialization_of_quantity_spec = false;
|
|
||||||
|
|
||||||
#ifdef __cpp_explicit_this_parameter
|
|
||||||
template<auto... Args>
|
|
||||||
inline constexpr bool is_specialization_of_quantity_spec<quantity_spec<Args...>> = true;
|
|
||||||
#else
|
|
||||||
template<typename T, auto... Args>
|
|
||||||
inline constexpr bool is_specialization_of_quantity_spec<quantity_spec<T, Args...>> = true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Concept matching quantity specification types
|
|
||||||
*
|
|
||||||
* Satisfied by all types that derive from `quantity_spec`.
|
|
||||||
*/
|
|
||||||
template<typename T>
|
|
||||||
concept NamedQuantitySpec = requires(T* t) { detail::to_base_specialization_of_quantity_spec(t); } &&
|
|
||||||
(!detail::is_specialization_of_quantity_spec<T>);
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
concept BaseQuantitySpec =
|
|
||||||
NamedQuantitySpec<T> && requires(T* t) { detail::to_base_specialization_of_base_quantity_spec(t); };
|
|
||||||
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline constexpr bool is_unit = false;
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A concept matching all unit types in the library
|
|
||||||
*
|
|
||||||
* Satisfied by all unit types provided by the library.
|
|
||||||
*/
|
|
||||||
template<typename T>
|
|
||||||
concept Unit = detail::is_unit<T>;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Unit being a scaled version of another unit
|
* @brief Unit being a scaled version of another unit
|
||||||
*
|
*
|
||||||
@@ -213,29 +146,6 @@ struct named_unit<Symbol, U> : std::remove_const_t<decltype(U)> {
|
|||||||
static constexpr auto symbol = Symbol; ///< Unique unit identifier
|
static constexpr auto symbol = Symbol; ///< Unique unit identifier
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
template<basic_symbol_text Symbol, auto... Args>
|
|
||||||
void to_base_specialization_of_named_unit(const volatile named_unit<Symbol, Args...>*);
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline constexpr bool is_specialization_of_named_unit = false;
|
|
||||||
|
|
||||||
template<basic_symbol_text Symbol, auto... Args>
|
|
||||||
inline constexpr bool is_specialization_of_named_unit<named_unit<Symbol, Args...>> = true;
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A concept matching all units with special names
|
|
||||||
*
|
|
||||||
* Satisfied by all unit types derived from the specialization of `named_unit`.
|
|
||||||
*/
|
|
||||||
template<typename T>
|
|
||||||
concept NamedUnit = Unit<T> && requires(T* t) { detail::to_base_specialization_of_named_unit(t); } &&
|
|
||||||
(!detail::is_specialization_of_named_unit<T>);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A unit of a physical constant
|
* @brief A unit of a physical constant
|
||||||
*
|
*
|
||||||
@@ -278,28 +188,10 @@ void to_base_specialization_of_constant_unit(const volatile constant_unit<Symbol
|
|||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline constexpr bool is_derived_from_specialization_of_constant_unit =
|
inline constexpr bool is_derived_from_specialization_of_constant_unit =
|
||||||
requires(T * t) { to_base_specialization_of_constant_unit(t); };
|
requires(T* t) { to_base_specialization_of_constant_unit(t); };
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Prevents assignment of a prefix to specific units
|
|
||||||
*
|
|
||||||
* By default all named units allow assigning a prefix for them. There are some notable exceptions like
|
|
||||||
* `hour` or `degree_Celsius`. For those a partial specialization with the value `false` should be
|
|
||||||
* provided.
|
|
||||||
*/
|
|
||||||
template<NamedUnit auto V>
|
|
||||||
inline constexpr bool unit_can_be_prefixed = true;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A concept to be used to define prefixes for a unit
|
|
||||||
*/
|
|
||||||
template<typename T>
|
|
||||||
concept PrefixableUnit = NamedUnit<T> && unit_can_be_prefixed<T{}>;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A prefixed unit
|
* @brief A prefixed unit
|
||||||
*
|
*
|
||||||
@@ -328,23 +220,6 @@ struct prefixed_unit : std::remove_const_t<decltype(M * U)> {
|
|||||||
static constexpr auto symbol = Symbol + U.symbol;
|
static constexpr auto symbol = Symbol + U.symbol;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline constexpr bool is_power_of_unit =
|
|
||||||
requires { requires is_specialization_of_power<T> && Unit<typename T::factor>; };
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline constexpr bool is_per_of_units = false;
|
|
||||||
|
|
||||||
template<typename... Ts>
|
|
||||||
inline constexpr bool is_per_of_units<per<Ts...>> = (... && (Unit<Ts> || is_power_of_unit<Ts>));
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
concept DerivedUnitExpr = Unit<T> || detail::is_power_of_unit<T> || detail::is_per_of_units<T>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Measurement unit for a derived quantity
|
* @brief Measurement unit for a derived quantity
|
||||||
*
|
*
|
||||||
@@ -390,8 +265,8 @@ concept DerivedUnitExpr = Unit<T> || detail::is_power_of_unit<T> || detail::is_p
|
|||||||
* @note User should not instantiate this type! It is not exported from the C++ module. The library will
|
* @note User should not instantiate this type! It is not exported from the C++ module. The library will
|
||||||
* instantiate this type automatically based on the unit arithmetic equation provided by the user.
|
* instantiate this type automatically based on the unit arithmetic equation provided by the user.
|
||||||
*/
|
*/
|
||||||
template<DerivedUnitExpr... Us>
|
template<DerivedUnitExpr... Expr>
|
||||||
struct derived_unit : detail::expr_fractions<derived_unit<>, Us...> {};
|
struct derived_unit : detail::expr_fractions<derived_unit<>, Expr...> {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Unit one
|
* @brief Unit one
|
||||||
@@ -404,19 +279,6 @@ inline constexpr struct one : derived_unit<> {} one;
|
|||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
template<auto M, typename U>
|
|
||||||
void is_unit_impl(const volatile scaled_unit<M, U>*);
|
|
||||||
|
|
||||||
template<basic_symbol_text Symbol, auto... Args>
|
|
||||||
void is_unit_impl(const volatile named_unit<Symbol, Args...>*);
|
|
||||||
|
|
||||||
template<typename... Us>
|
|
||||||
void is_unit_impl(const volatile derived_unit<Us...>*);
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
requires requires(T* t) { is_unit_impl(t); }
|
|
||||||
inline constexpr bool is_unit<T> = true;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A canonical representation of a unit
|
* @brief A canonical representation of a unit
|
||||||
*
|
*
|
||||||
@@ -452,8 +314,8 @@ template<Unit T, basic_symbol_text Symbol, Unit auto U>
|
|||||||
template<typename T, typename F, int Num, int... Den>
|
template<typename T, typename F, int Num, int... Den>
|
||||||
[[nodiscard]] consteval auto get_canonical_unit_impl(T, const power<F, Num, Den...>&);
|
[[nodiscard]] consteval auto get_canonical_unit_impl(T, const power<F, Num, Den...>&);
|
||||||
|
|
||||||
template<Unit T, typename... Us>
|
template<Unit T, typename... Expr>
|
||||||
[[nodiscard]] consteval auto get_canonical_unit_impl(T, const derived_unit<Us...>&);
|
[[nodiscard]] consteval auto get_canonical_unit_impl(T, const derived_unit<Expr...>&);
|
||||||
|
|
||||||
template<Unit T, auto M, typename U>
|
template<Unit T, auto M, typename U>
|
||||||
[[nodiscard]] consteval auto get_canonical_unit_impl(T, const scaled_unit<M, U>&)
|
[[nodiscard]] consteval auto get_canonical_unit_impl(T, const scaled_unit<M, U>&)
|
||||||
@@ -511,16 +373,39 @@ template<typename... Us>
|
|||||||
return canonical_unit{mag, u};
|
return canonical_unit{mag, u};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<Unit T, typename... Us>
|
template<Unit T, typename... Expr>
|
||||||
[[nodiscard]] consteval auto get_canonical_unit_impl(T, const derived_unit<Us...>&)
|
[[nodiscard]] consteval auto get_canonical_unit_impl(T, const derived_unit<Expr...>&)
|
||||||
{
|
{
|
||||||
auto num = get_canonical_unit_impl(typename derived_unit<Us...>::_num_{});
|
auto num = get_canonical_unit_impl(typename derived_unit<Expr...>::_num_{});
|
||||||
auto den = get_canonical_unit_impl(typename derived_unit<Us...>::_den_{});
|
auto den = get_canonical_unit_impl(typename derived_unit<Expr...>::_den_{});
|
||||||
return canonical_unit{num.mag / den.mag, num.reference_unit / den.reference_unit};
|
return canonical_unit{num.mag / den.mag, num.reference_unit / den.reference_unit};
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] consteval auto get_canonical_unit(Unit auto u) { return get_canonical_unit_impl(u, u); }
|
[[nodiscard]] consteval auto get_canonical_unit(Unit auto u) { return get_canonical_unit_impl(u, u); }
|
||||||
|
|
||||||
|
template<Unit U>
|
||||||
|
requires requires { U::base_quantity.dimension; }
|
||||||
|
using to_base_dimension = std::remove_const_t<decltype(U::base_quantity.dimension)>;
|
||||||
|
|
||||||
|
template<Unit U>
|
||||||
|
requires requires { U::base_quantity.dimension; }
|
||||||
|
[[nodiscard]] consteval Dimension auto get_dimension_for_impl(U)
|
||||||
|
{
|
||||||
|
return U::base_quantity.dimension;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Expr>
|
||||||
|
requires expr_projectable<derived_unit<Expr...>, to_base_dimension>
|
||||||
|
[[nodiscard]] consteval Dimension auto get_dimension_for_impl(const derived_unit<Expr...>& u)
|
||||||
|
{
|
||||||
|
return expr_map<to_base_dimension, derived_dimension, struct dimension_one, type_list_of_base_dimension_less>(u);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] consteval Dimension auto get_dimension_for(AssociatedUnit auto u)
|
||||||
|
{
|
||||||
|
return get_dimension_for_impl(get_canonical_unit(u).reference_unit);
|
||||||
|
}
|
||||||
|
|
||||||
template<Unit Lhs, Unit Rhs>
|
template<Unit Lhs, Unit Rhs>
|
||||||
[[nodiscard]] consteval bool less(Lhs, Rhs)
|
[[nodiscard]] consteval bool less(Lhs, Rhs)
|
||||||
{
|
{
|
||||||
@@ -640,12 +525,13 @@ template<typename... Us1, typename... Us2>
|
|||||||
return (... && same_canonical_reference_unit(Us1{}, Us2{}));
|
return (... && same_canonical_reference_unit(Us1{}, Us2{}));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Us1, typename... Us2>
|
template<typename... Expr1, typename... Expr2>
|
||||||
[[nodiscard]] consteval bool same_canonical_reference_unit(const derived_unit<Us1...>&, const derived_unit<Us2...>&)
|
[[nodiscard]] consteval bool same_canonical_reference_unit(const derived_unit<Expr1...>&, const derived_unit<Expr2...>&)
|
||||||
{
|
{
|
||||||
return same_canonical_reference_unit(typename derived_unit<Us1...>::_num_{},
|
return same_canonical_reference_unit(typename derived_unit<Expr1...>::_num_{},
|
||||||
typename derived_unit<Us2...>::_num_{}) &&
|
typename derived_unit<Expr2...>::_num_{}) &&
|
||||||
same_canonical_reference_unit(typename derived_unit<Us1...>::_den_{}, typename derived_unit<Us2...>::_den_{});
|
same_canonical_reference_unit(typename derived_unit<Expr1...>::_den_{},
|
||||||
|
typename derived_unit<Expr2...>::_den_{});
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
@@ -898,11 +784,11 @@ constexpr Out unit_symbol_impl(Out out, const type_list<Nums...>& nums, const ty
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename CharT, std::output_iterator<CharT> Out, typename... Us>
|
template<typename CharT, std::output_iterator<CharT> Out, typename... Expr>
|
||||||
constexpr Out unit_symbol_impl(Out out, const derived_unit<Us...>&, unit_symbol_formatting fmt, bool negative_power)
|
constexpr Out unit_symbol_impl(Out out, const derived_unit<Expr...>&, unit_symbol_formatting fmt, bool negative_power)
|
||||||
{
|
{
|
||||||
gsl_Expects(negative_power == false);
|
gsl_Expects(negative_power == false);
|
||||||
return unit_symbol_impl<CharT>(out, typename derived_unit<Us...>::_num_{}, typename derived_unit<Us...>::_den_{},
|
return unit_symbol_impl<CharT>(out, typename derived_unit<Expr...>::_num_{}, typename derived_unit<Expr...>::_den_{},
|
||||||
fmt);
|
fmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -23,6 +23,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <mp_units/customization_points.h>
|
#include <mp_units/customization_points.h>
|
||||||
|
#include <mp_units/quantity_point.h>
|
||||||
#include <mp_units/systems/isq/space_and_time.h>
|
#include <mp_units/systems/isq/space_and_time.h>
|
||||||
#include <mp_units/systems/si/prefixes.h>
|
#include <mp_units/systems/si/prefixes.h>
|
||||||
#include <mp_units/systems/si/units.h>
|
#include <mp_units/systems/si/units.h>
|
||||||
@@ -80,7 +81,7 @@ struct quantity_point_like_traits<std::chrono::time_point<C, std::chrono::durati
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<quantity_of<isq::time> Q>
|
template<QuantityOf<isq::time> Q>
|
||||||
[[nodiscard]] constexpr auto to_chrono_duration(const Q& q)
|
[[nodiscard]] constexpr auto to_chrono_duration(const Q& q)
|
||||||
{
|
{
|
||||||
constexpr auto canonical = detail::get_canonical_unit(Q::unit);
|
constexpr auto canonical = detail::get_canonical_unit(Q::unit);
|
||||||
@@ -88,7 +89,7 @@ template<quantity_of<isq::time> Q>
|
|||||||
return std::chrono::duration<typename Q::rep, std::ratio<r.num, r.den>>{q.number()};
|
return std::chrono::duration<typename Q::rep, std::ratio<r.num, r.den>>{q.number()};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<quantity_point_of<isq::time> QP>
|
template<QuantityPointOf<isq::time> QP>
|
||||||
requires is_specialization_of<std::remove_const_t<decltype(QP::absolute_point_origin)>, chrono_point_origin>
|
requires is_specialization_of<std::remove_const_t<decltype(QP::absolute_point_origin)>, chrono_point_origin>
|
||||||
[[nodiscard]] constexpr auto to_chrono_time_point(const QP& qp)
|
[[nodiscard]] constexpr auto to_chrono_time_point(const QP& qp)
|
||||||
{
|
{
|
||||||
|
@@ -109,7 +109,7 @@ template<Quantity Q>
|
|||||||
* @param q Quantity being the base of the operation
|
* @param q Quantity being the base of the operation
|
||||||
* @return Quantity The value of the same quantity type
|
* @return Quantity The value of the same quantity type
|
||||||
*/
|
*/
|
||||||
template<quantity_of<dimension_one> Q>
|
template<QuantityOf<dimension_one> Q>
|
||||||
[[nodiscard]] inline Q exp(const Q& q)
|
[[nodiscard]] inline Q exp(const Q& q)
|
||||||
requires requires { exp(q.number()); } || requires { std::exp(q.number()); }
|
requires requires { exp(q.number()); } || requires { std::exp(q.number()); }
|
||||||
{
|
{
|
||||||
@@ -153,12 +153,12 @@ template<Representation Rep, Reference R>
|
|||||||
* @return Quantity The rounded quantity with unit type To
|
* @return Quantity The rounded quantity with unit type To
|
||||||
*/
|
*/
|
||||||
template<Unit auto To, auto R, typename Rep>
|
template<Unit auto To, auto R, typename Rep>
|
||||||
[[nodiscard]] constexpr quantity<reference<R.quantity_spec, To>{}, Rep> floor(const quantity<R, Rep>& q) noexcept
|
[[nodiscard]] constexpr quantity<reference<get_quantity_spec(R), To>{}, Rep> floor(const quantity<R, Rep>& q) noexcept
|
||||||
requires((!treat_as_floating_point<Rep>) || requires { floor(q.number()); } ||
|
requires((!treat_as_floating_point<Rep>) || requires { floor(q.number()); } ||
|
||||||
requires { std::floor(q.number()); }) &&
|
requires { std::floor(q.number()); }) &&
|
||||||
(To == R.unit || requires {
|
(To == get_unit(R) || requires {
|
||||||
::mp_units::quantity_cast<To>(q);
|
::mp_units::quantity_cast<To>(q);
|
||||||
quantity<reference<R.quantity_spec, To>{}, Rep>::one();
|
quantity<reference<get_quantity_spec(R), To>{}, Rep>::one();
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
const auto handle_signed_results = [&]<typename T>(const T& res) {
|
const auto handle_signed_results = [&]<typename T>(const T& res) {
|
||||||
@@ -169,14 +169,14 @@ template<Unit auto To, auto R, typename Rep>
|
|||||||
};
|
};
|
||||||
if constexpr (treat_as_floating_point<Rep>) {
|
if constexpr (treat_as_floating_point<Rep>) {
|
||||||
using std::floor;
|
using std::floor;
|
||||||
if constexpr (To == R.unit) {
|
if constexpr (To == get_unit(R)) {
|
||||||
return quantity<reference<R.quantity_spec, To>{}, Rep>(floor(q.number()));
|
return quantity<reference<get_quantity_spec(R), To>{}, Rep>(floor(q.number()));
|
||||||
} else {
|
} else {
|
||||||
return handle_signed_results(
|
return handle_signed_results(
|
||||||
quantity<reference<R.quantity_spec, To>{}, Rep>(floor(quantity_cast<To>(q).number())));
|
quantity<reference<get_quantity_spec(R), To>{}, Rep>(floor(quantity_cast<To>(q).number())));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if constexpr (To == R.unit) {
|
if constexpr (To == get_unit(R)) {
|
||||||
return quantity_cast<To>(q);
|
return quantity_cast<To>(q);
|
||||||
} else {
|
} else {
|
||||||
return handle_signed_results(quantity_cast<To>(q));
|
return handle_signed_results(quantity_cast<To>(q));
|
||||||
@@ -191,11 +191,11 @@ template<Unit auto To, auto R, typename Rep>
|
|||||||
* @return Quantity The rounded quantity with unit type To
|
* @return Quantity The rounded quantity with unit type To
|
||||||
*/
|
*/
|
||||||
template<Unit auto To, auto R, typename Rep>
|
template<Unit auto To, auto R, typename Rep>
|
||||||
[[nodiscard]] constexpr quantity<reference<R.quantity_spec, To>{}, Rep> ceil(const quantity<R, Rep>& q) noexcept
|
[[nodiscard]] constexpr quantity<reference<get_quantity_spec(R), To>{}, Rep> ceil(const quantity<R, Rep>& q) noexcept
|
||||||
requires((!treat_as_floating_point<Rep>) || requires { ceil(q.number()); } || requires { std::ceil(q.number()); }) &&
|
requires((!treat_as_floating_point<Rep>) || requires { ceil(q.number()); } || requires { std::ceil(q.number()); }) &&
|
||||||
(To == R.unit || requires {
|
(To == get_unit(R) || requires {
|
||||||
::mp_units::quantity_cast<To>(q);
|
::mp_units::quantity_cast<To>(q);
|
||||||
quantity<reference<R.quantity_spec, To>{}, Rep>::one();
|
quantity<reference<get_quantity_spec(R), To>{}, Rep>::one();
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
const auto handle_signed_results = [&]<typename T>(const T& res) {
|
const auto handle_signed_results = [&]<typename T>(const T& res) {
|
||||||
@@ -206,14 +206,14 @@ template<Unit auto To, auto R, typename Rep>
|
|||||||
};
|
};
|
||||||
if constexpr (treat_as_floating_point<Rep>) {
|
if constexpr (treat_as_floating_point<Rep>) {
|
||||||
using std::ceil;
|
using std::ceil;
|
||||||
if constexpr (To == R.unit) {
|
if constexpr (To == get_unit(R)) {
|
||||||
return quantity<reference<R.quantity_spec, To>{}, Rep>(ceil(q.number()));
|
return quantity<reference<get_quantity_spec(R), To>{}, Rep>(ceil(q.number()));
|
||||||
} else {
|
} else {
|
||||||
return handle_signed_results(
|
return handle_signed_results(
|
||||||
quantity<reference<R.quantity_spec, To>{}, Rep>(ceil(quantity_cast<To>(q).number())));
|
quantity<reference<get_quantity_spec(R), To>{}, Rep>(ceil(quantity_cast<To>(q).number())));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if constexpr (To == R.unit) {
|
if constexpr (To == get_unit(R)) {
|
||||||
return quantity_cast<To>(q);
|
return quantity_cast<To>(q);
|
||||||
} else {
|
} else {
|
||||||
return handle_signed_results(quantity_cast<To>(q));
|
return handle_signed_results(quantity_cast<To>(q));
|
||||||
@@ -230,18 +230,18 @@ template<Unit auto To, auto R, typename Rep>
|
|||||||
* @return Quantity The rounded quantity with unit type To
|
* @return Quantity The rounded quantity with unit type To
|
||||||
*/
|
*/
|
||||||
template<Unit auto To, auto R, typename Rep>
|
template<Unit auto To, auto R, typename Rep>
|
||||||
[[nodiscard]] constexpr quantity<reference<R.quantity_spec, To>{}, Rep> round(const quantity<R, Rep>& q) noexcept
|
[[nodiscard]] constexpr quantity<reference<get_quantity_spec(R), To>{}, Rep> round(const quantity<R, Rep>& q) noexcept
|
||||||
requires((!treat_as_floating_point<Rep>) || requires { round(q.number()); } ||
|
requires((!treat_as_floating_point<Rep>) || requires { round(q.number()); } ||
|
||||||
requires { std::round(q.number()); }) &&
|
requires { std::round(q.number()); }) &&
|
||||||
(To == R.unit || requires {
|
(To == get_unit(R) || requires {
|
||||||
::mp_units::floor<To>(q);
|
::mp_units::floor<To>(q);
|
||||||
quantity<reference<R.quantity_spec, To>{}, Rep>::one();
|
quantity<reference<get_quantity_spec(R), To>{}, Rep>::one();
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
if constexpr (To == R.unit) {
|
if constexpr (To == get_unit(R)) {
|
||||||
if constexpr (treat_as_floating_point<Rep>) {
|
if constexpr (treat_as_floating_point<Rep>) {
|
||||||
using std::round;
|
using std::round;
|
||||||
return quantity<reference<R.quantity_spec, To>{}, Rep>(round(q.number()));
|
return quantity<reference<get_quantity_spec(R), To>{}, Rep>(round(q.number()));
|
||||||
} else {
|
} else {
|
||||||
return quantity_cast<To>(q);
|
return quantity_cast<To>(q);
|
||||||
}
|
}
|
||||||
@@ -268,7 +268,7 @@ template<Unit auto To, auto R, typename Rep>
|
|||||||
* without undue overflow or underflow at intermediate stages of the computation
|
* without undue overflow or underflow at intermediate stages of the computation
|
||||||
*/
|
*/
|
||||||
template<Quantity Q1, Quantity Q2>
|
template<Quantity Q1, Quantity Q2>
|
||||||
[[nodiscard]] inline quantity_of<common_reference(Q1::reference, Q2::reference)> auto hypot(const Q1& x,
|
[[nodiscard]] inline QuantityOf<common_reference(Q1::reference, Q2::reference)> auto hypot(const Q1& x,
|
||||||
const Q2& y) noexcept
|
const Q2& y) noexcept
|
||||||
requires requires { common_reference(Q1::reference, Q2::reference); } &&
|
requires requires { common_reference(Q1::reference, Q2::reference); } &&
|
||||||
(
|
(
|
||||||
@@ -284,7 +284,7 @@ template<Quantity Q1, Quantity Q2>
|
|||||||
* without undue overflow or underflow at intermediate stages of the computation
|
* without undue overflow or underflow at intermediate stages of the computation
|
||||||
*/
|
*/
|
||||||
template<Quantity Q1, Quantity Q2, Quantity Q3>
|
template<Quantity Q1, Quantity Q2, Quantity Q3>
|
||||||
[[nodiscard]] inline quantity_of<common_reference(Q1::reference, Q2::reference, Q3::reference)> auto hypot(
|
[[nodiscard]] inline QuantityOf<common_reference(Q1::reference, Q2::reference, Q3::reference)> auto hypot(
|
||||||
const Q1& x, const Q2& y, const Q3& z) noexcept
|
const Q1& x, const Q2& y, const Q3& z) noexcept
|
||||||
requires requires { common_reference(Q1::reference, Q2::reference, Q3::reference); } &&
|
requires requires { common_reference(Q1::reference, Q2::reference, Q3::reference); } &&
|
||||||
(
|
(
|
||||||
@@ -299,54 +299,54 @@ template<Quantity Q1, Quantity Q2, Quantity Q3>
|
|||||||
|
|
||||||
namespace isq {
|
namespace isq {
|
||||||
|
|
||||||
template<weak_quantity_of<angular_measure> Q>
|
template<WeakQuantityOf<angular_measure> Q>
|
||||||
requires treat_as_floating_point<typename Q::rep>
|
requires treat_as_floating_point<typename Q::rep>
|
||||||
[[nodiscard]] inline quantity_of<dimensionless[one]> auto sin(const Q& q) noexcept
|
[[nodiscard]] inline QuantityOf<dimensionless[one]> auto sin(const Q& q) noexcept
|
||||||
requires requires { sin(q.number()); } || requires { std::sin(q.number()); }
|
requires requires { sin(q.number()); } || requires { std::sin(q.number()); }
|
||||||
{
|
{
|
||||||
using std::sin;
|
using std::sin;
|
||||||
return quantity{sin(q[si::radian].number())};
|
return quantity{sin(q[si::radian].number())};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<weak_quantity_of<angular_measure> Q>
|
template<WeakQuantityOf<angular_measure> Q>
|
||||||
requires treat_as_floating_point<typename Q::rep>
|
requires treat_as_floating_point<typename Q::rep>
|
||||||
[[nodiscard]] inline quantity_of<dimensionless[one]> auto cos(const Q& q) noexcept
|
[[nodiscard]] inline QuantityOf<dimensionless[one]> auto cos(const Q& q) noexcept
|
||||||
requires requires { cos(q.number()); } || requires { std::cos(q.number()); }
|
requires requires { cos(q.number()); } || requires { std::cos(q.number()); }
|
||||||
{
|
{
|
||||||
using std::cos;
|
using std::cos;
|
||||||
return quantity{cos(q[si::radian].number())};
|
return quantity{cos(q[si::radian].number())};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<weak_quantity_of<angular_measure> Q>
|
template<WeakQuantityOf<angular_measure> Q>
|
||||||
requires treat_as_floating_point<typename Q::rep>
|
requires treat_as_floating_point<typename Q::rep>
|
||||||
[[nodiscard]] inline quantity_of<dimensionless[one]> auto tan(const Q& q) noexcept
|
[[nodiscard]] inline QuantityOf<dimensionless[one]> auto tan(const Q& q) noexcept
|
||||||
requires requires { tan(q.number()); } || requires { std::tan(q.number()); }
|
requires requires { tan(q.number()); } || requires { std::tan(q.number()); }
|
||||||
{
|
{
|
||||||
using std::tan;
|
using std::tan;
|
||||||
return quantity{tan(q[si::radian].number())};
|
return quantity{tan(q[si::radian].number())};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<quantity_of<dimension_one> Q>
|
template<QuantityOf<dimension_one> Q>
|
||||||
requires treat_as_floating_point<typename Q::rep>
|
requires treat_as_floating_point<typename Q::rep>
|
||||||
[[nodiscard]] inline quantity_of<angular_measure[si::radian]> auto asin(const Q& q) noexcept
|
[[nodiscard]] inline QuantityOf<angular_measure[si::radian]> auto asin(const Q& q) noexcept
|
||||||
requires requires { asin(q.number()); } || requires { std::asin(q.number()); }
|
requires requires { asin(q.number()); } || requires { std::asin(q.number()); }
|
||||||
{
|
{
|
||||||
using std::asin;
|
using std::asin;
|
||||||
return asin(quantity_cast<one>(q).number()) * angular_measure[si::radian];
|
return asin(quantity_cast<one>(q).number()) * angular_measure[si::radian];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<quantity_of<dimension_one> Q>
|
template<QuantityOf<dimension_one> Q>
|
||||||
requires treat_as_floating_point<typename Q::rep>
|
requires treat_as_floating_point<typename Q::rep>
|
||||||
[[nodiscard]] inline quantity_of<angular_measure[si::radian]> auto acos(const Q& q) noexcept
|
[[nodiscard]] inline QuantityOf<angular_measure[si::radian]> auto acos(const Q& q) noexcept
|
||||||
requires requires { acos(q.number()); } || requires { std::acos(q.number()); }
|
requires requires { acos(q.number()); } || requires { std::acos(q.number()); }
|
||||||
{
|
{
|
||||||
using std::acos;
|
using std::acos;
|
||||||
return acos(quantity_cast<one>(q).number()) * angular_measure[si::radian];
|
return acos(quantity_cast<one>(q).number()) * angular_measure[si::radian];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<quantity_of<dimension_one> Q>
|
template<QuantityOf<dimension_one> Q>
|
||||||
requires treat_as_floating_point<typename Q::rep>
|
requires treat_as_floating_point<typename Q::rep>
|
||||||
[[nodiscard]] inline quantity_of<angular_measure[si::radian]> auto atan(const Q& q) noexcept
|
[[nodiscard]] inline QuantityOf<angular_measure[si::radian]> auto atan(const Q& q) noexcept
|
||||||
requires requires { atan(q.number()); } || requires { std::atan(q.number()); }
|
requires requires { atan(q.number()); } || requires { std::atan(q.number()); }
|
||||||
{
|
{
|
||||||
using std::atan;
|
using std::atan;
|
||||||
@@ -357,55 +357,55 @@ template<quantity_of<dimension_one> Q>
|
|||||||
|
|
||||||
namespace angular {
|
namespace angular {
|
||||||
|
|
||||||
// TODO cannot use `weak_quantity_of<angle>` as it is not interconvertible with `isq_angle::angular_measure`
|
// TODO cannot use `WeakQuantityOf<angle>` as it is not interconvertible with `isq_angle::angular_measure`
|
||||||
template<quantity_of<dim_angle> Q>
|
template<QuantityOf<dim_angle> Q>
|
||||||
requires treat_as_floating_point<typename Q::rep>
|
requires treat_as_floating_point<typename Q::rep>
|
||||||
[[nodiscard]] inline quantity_of<dimensionless[one]> auto sin(const Q& q) noexcept
|
[[nodiscard]] inline QuantityOf<dimensionless[one]> auto sin(const Q& q) noexcept
|
||||||
requires requires { sin(q.number()); } || requires { std::sin(q.number()); }
|
requires requires { sin(q.number()); } || requires { std::sin(q.number()); }
|
||||||
{
|
{
|
||||||
using std::sin;
|
using std::sin;
|
||||||
return quantity{sin(q[radian].number())};
|
return quantity{sin(q[radian].number())};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<quantity_of<dim_angle> Q>
|
template<QuantityOf<dim_angle> Q>
|
||||||
requires treat_as_floating_point<typename Q::rep>
|
requires treat_as_floating_point<typename Q::rep>
|
||||||
[[nodiscard]] inline quantity_of<dimensionless[one]> auto cos(const Q& q) noexcept
|
[[nodiscard]] inline QuantityOf<dimensionless[one]> auto cos(const Q& q) noexcept
|
||||||
requires requires { cos(q.number()); } || requires { std::cos(q.number()); }
|
requires requires { cos(q.number()); } || requires { std::cos(q.number()); }
|
||||||
{
|
{
|
||||||
using std::cos;
|
using std::cos;
|
||||||
return quantity{cos(q[radian].number())};
|
return quantity{cos(q[radian].number())};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<quantity_of<dim_angle> Q>
|
template<QuantityOf<dim_angle> Q>
|
||||||
requires treat_as_floating_point<typename Q::rep>
|
requires treat_as_floating_point<typename Q::rep>
|
||||||
[[nodiscard]] inline quantity_of<dimensionless[one]> auto tan(const Q& q) noexcept
|
[[nodiscard]] inline QuantityOf<dimensionless[one]> auto tan(const Q& q) noexcept
|
||||||
requires requires { tan(q.number()); } || requires { std::tan(q.number()); }
|
requires requires { tan(q.number()); } || requires { std::tan(q.number()); }
|
||||||
{
|
{
|
||||||
using std::tan;
|
using std::tan;
|
||||||
return quantity{tan(q[radian].number())};
|
return quantity{tan(q[radian].number())};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<quantity_of<dimension_one> Q>
|
template<QuantityOf<dimension_one> Q>
|
||||||
requires treat_as_floating_point<typename Q::rep>
|
requires treat_as_floating_point<typename Q::rep>
|
||||||
[[nodiscard]] inline quantity_of<angle[radian]> auto asin(const Q& q) noexcept
|
[[nodiscard]] inline QuantityOf<angle[radian]> auto asin(const Q& q) noexcept
|
||||||
requires requires { asin(q.number()); } || requires { std::asin(q.number()); }
|
requires requires { asin(q.number()); } || requires { std::asin(q.number()); }
|
||||||
{
|
{
|
||||||
using std::asin;
|
using std::asin;
|
||||||
return asin(quantity_cast<one>(q).number()) * angle[radian];
|
return asin(quantity_cast<one>(q).number()) * angle[radian];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<quantity_of<dimension_one> Q>
|
template<QuantityOf<dimension_one> Q>
|
||||||
requires treat_as_floating_point<typename Q::rep>
|
requires treat_as_floating_point<typename Q::rep>
|
||||||
[[nodiscard]] inline quantity_of<angle[radian]> auto acos(const Q& q) noexcept
|
[[nodiscard]] inline QuantityOf<angle[radian]> auto acos(const Q& q) noexcept
|
||||||
requires requires { acos(q.number()); } || requires { std::acos(q.number()); }
|
requires requires { acos(q.number()); } || requires { std::acos(q.number()); }
|
||||||
{
|
{
|
||||||
using std::acos;
|
using std::acos;
|
||||||
return acos(quantity_cast<one>(q).number()) * angle[radian];
|
return acos(quantity_cast<one>(q).number()) * angle[radian];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<quantity_of<dimension_one> Q>
|
template<QuantityOf<dimension_one> Q>
|
||||||
requires treat_as_floating_point<typename Q::rep>
|
requires treat_as_floating_point<typename Q::rep>
|
||||||
[[nodiscard]] inline quantity_of<angle[radian]> auto atan(const Q& q) noexcept
|
[[nodiscard]] inline QuantityOf<angle[radian]> auto atan(const Q& q) noexcept
|
||||||
requires requires { atan(q.number()); } || requires { std::atan(q.number()); }
|
requires requires { atan(q.number()); } || requires { std::atan(q.number()); }
|
||||||
{
|
{
|
||||||
using std::atan;
|
using std::atan;
|
||||||
|
@@ -60,13 +60,13 @@ inline constexpr auto energy = force * length;
|
|||||||
// concepts verification
|
// concepts verification
|
||||||
static_assert(BaseDimension<length_>);
|
static_assert(BaseDimension<length_>);
|
||||||
static_assert(!BaseDimension<std::remove_const_t<decltype(frequency)>>);
|
static_assert(!BaseDimension<std::remove_const_t<decltype(frequency)>>);
|
||||||
static_assert(!DerivedDimension<length_>);
|
static_assert(!detail::DerivedDimension<length_>);
|
||||||
static_assert(DerivedDimension<std::remove_const_t<decltype(frequency)>>);
|
static_assert(detail::DerivedDimension<std::remove_const_t<decltype(frequency)>>);
|
||||||
static_assert(Dimension<length_>);
|
static_assert(Dimension<length_>);
|
||||||
static_assert(Dimension<std::remove_const_t<decltype(frequency)>>);
|
static_assert(Dimension<std::remove_const_t<decltype(frequency)>>);
|
||||||
|
|
||||||
static_assert(DerivedDimension<dimension_one_>);
|
static_assert(detail::DerivedDimension<dimension_one_>);
|
||||||
static_assert(DerivedDimension<decltype(length / length)>); // dimension_one
|
static_assert(detail::DerivedDimension<decltype(length / length)>); // dimension_one
|
||||||
static_assert(BaseDimension<decltype(speed * time)>); // length
|
static_assert(BaseDimension<decltype(speed * time)>); // length
|
||||||
|
|
||||||
// derived dimension expression template syntax verification
|
// derived dimension expression template syntax verification
|
||||||
|
@@ -397,7 +397,6 @@ template<auto& s>
|
|||||||
concept invalid_operations = requires {
|
concept invalid_operations = requires {
|
||||||
requires !requires { s < s; };
|
requires !requires { s < s; };
|
||||||
requires !requires { s / 2; };
|
requires !requires { s / 2; };
|
||||||
requires !requires { 2 * s; };
|
|
||||||
requires !requires { s * 2; };
|
requires !requires { s * 2; };
|
||||||
requires !requires { s + 2; };
|
requires !requires { s + 2; };
|
||||||
requires !requires { 2 + s; };
|
requires !requires { 2 + s; };
|
||||||
@@ -411,16 +410,9 @@ concept invalid_operations = requires {
|
|||||||
requires !requires { 2 < s; };
|
requires !requires { 2 < s; };
|
||||||
requires !requires { s + time[second]; };
|
requires !requires { s + time[second]; };
|
||||||
requires !requires { s - time[second]; };
|
requires !requires { s - time[second]; };
|
||||||
requires !requires { s* time[second]; };
|
|
||||||
requires !requires { s / time[second]; };
|
|
||||||
requires !requires { s == time[second]; };
|
|
||||||
requires !requires { s < time[second]; };
|
requires !requires { s < time[second]; };
|
||||||
requires !requires { time[second] + s; };
|
requires !requires { time[second] + s; };
|
||||||
requires !requires { time[second] - s; };
|
requires !requires { time[second] - s; };
|
||||||
requires !requires { time[second] * s; };
|
|
||||||
requires !requires { time[second] / s; };
|
|
||||||
requires !requires { time[second] == s; };
|
|
||||||
requires !requires { time[second] < s; };
|
|
||||||
requires !requires { s + 1 * time[second]; };
|
requires !requires { s + 1 * time[second]; };
|
||||||
requires !requires { s - 1 * time[second]; };
|
requires !requires { s - 1 * time[second]; };
|
||||||
requires !requires { s * 1 * time[second]; };
|
requires !requires { s * 1 * time[second]; };
|
||||||
|
Reference in New Issue
Block a user