forked from mpusz/mp-units
Merge branch 'master' into chiphogg/prime-wheel
This commit is contained in:
@@ -23,8 +23,8 @@
|
||||
#pragma once
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include <units/bits/external/fixed_string.h>
|
||||
#include <units/bits/basic_concepts.h>
|
||||
#include <units/bits/external/fixed_string.h>
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#include <type_traits>
|
||||
@@ -38,7 +38,7 @@ namespace units {
|
||||
* in the subset can be expressed in terms of the other quantities within that subset. They are referred to as
|
||||
* being mutually independent since a base quantity cannot be expressed as a product of powers of the other base
|
||||
* quantities.
|
||||
*
|
||||
*
|
||||
* Base unit is a measurement unit that is adopted by convention for a base quantity in a specific system of units.
|
||||
*
|
||||
* Pair of Symbol and Unit template parameters form an unique identifier of the base dimension. The same identifiers can
|
||||
@@ -61,7 +61,6 @@ struct base_dimension {
|
||||
template<BaseDimension D1, BaseDimension D2>
|
||||
struct base_dimension_less :
|
||||
std::bool_constant<(D1::symbol < D2::symbol) ||
|
||||
(D1::symbol == D2::symbol && D1::base_unit::symbol < D1::base_unit::symbol)> {
|
||||
};
|
||||
(D1::symbol == D2::symbol && D1::base_unit::symbol < D1::base_unit::symbol)> {};
|
||||
|
||||
} // namespace units
|
||||
|
||||
@@ -29,11 +29,12 @@
|
||||
namespace units::detail {
|
||||
|
||||
template<Exponent E>
|
||||
requires (E::den == 1 || E::den == 2) // TODO provide support for any den
|
||||
requires(E::den == 1 || E::den == 2) // TODO provide support for any den
|
||||
constexpr ratio exp_ratio()
|
||||
{
|
||||
const ratio base_ratio = E::dimension::base_unit::ratio;
|
||||
const ratio positive_ratio = E::num * E::den < 0 ? ratio(base_ratio.den, base_ratio.num, -base_ratio.exp) : base_ratio;
|
||||
const ratio positive_ratio =
|
||||
E::num * E::den < 0 ? ratio(base_ratio.den, base_ratio.num, -base_ratio.exp) : base_ratio;
|
||||
const std::intmax_t N = E::num * E::den < 0 ? -E::num : E::num;
|
||||
const ratio ratio_pow = pow<N>(positive_ratio);
|
||||
return E::den == 2 ? sqrt(ratio_pow) : ratio_pow;
|
||||
|
||||
@@ -26,9 +26,9 @@
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include <units/bits/external/fixed_string.h>
|
||||
#include <units/bits/external/type_traits.h>
|
||||
#include <units/customization_points.h>
|
||||
#include <units/ratio.h>
|
||||
#include <units/bits/external/type_traits.h>
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#include <cstdint>
|
||||
@@ -73,7 +73,7 @@ concept Prefix = requires(T* t) { detail::to_prefix_base(t); };
|
||||
* Satisfied by all ratio values for which `R.num > 0` and `R.den > 0`.
|
||||
*/
|
||||
template<ratio R>
|
||||
concept UnitRatio = R.num > 0 && R.den > 0;
|
||||
concept UnitRatio = (R.num > 0) && (R.den > 0);
|
||||
|
||||
// Unit
|
||||
template<ratio R, typename U>
|
||||
@@ -136,10 +136,10 @@ concept Exponent = detail::is_exponent<T>;
|
||||
namespace detail {
|
||||
|
||||
template<Exponent... Es>
|
||||
requires (BaseDimension<typename Es::dimension> && ...)
|
||||
requires(BaseDimension<typename Es::dimension> && ...)
|
||||
struct derived_dimension_base;
|
||||
|
||||
} // namespace detail
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* @brief A concept matching all derived dimensions in the library.
|
||||
@@ -170,7 +170,7 @@ auto default_unit()
|
||||
return typename D::coherent_unit{};
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* @brief Returns a 'default' unit of the dimension
|
||||
@@ -200,10 +200,7 @@ using dimension_unit = decltype(detail::default_unit<D>());
|
||||
* @tparam D Dimension type to use for verification.
|
||||
*/
|
||||
template<typename U, typename D>
|
||||
concept UnitOf =
|
||||
Unit<U> &&
|
||||
Dimension<D> &&
|
||||
std::same_as<typename U::reference, typename dimension_unit<D>::reference>;
|
||||
concept UnitOf = Unit<U> && Dimension<D> && std::same_as<typename U::reference, typename dimension_unit<D>::reference>;
|
||||
|
||||
// PointOrigin
|
||||
|
||||
@@ -217,13 +214,13 @@ struct point_origin;
|
||||
*/
|
||||
template<typename T>
|
||||
concept PointOrigin = is_derived_from_specialization_of<T, point_origin> &&
|
||||
requires {
|
||||
typename T::dimension;
|
||||
requires Dimension<typename T::dimension>;
|
||||
typename T::point_origin;
|
||||
requires std::same_as<typename T::point_origin, point_origin<typename T::dimension>>;
|
||||
requires !std::same_as<T, point_origin<typename T::dimension>>;
|
||||
};
|
||||
requires {
|
||||
typename T::dimension;
|
||||
requires Dimension<typename T::dimension>;
|
||||
typename T::point_origin;
|
||||
requires std::same_as<typename T::point_origin, point_origin<typename T::dimension>>;
|
||||
requires !std::same_as<T, point_origin<typename T::dimension>>;
|
||||
};
|
||||
|
||||
// RebindablePointOriginFor
|
||||
|
||||
@@ -247,8 +244,7 @@ using rebind_point_origin_dimension = typename conditional<is_same_v<typename O:
|
||||
*/
|
||||
template<typename T, typename D>
|
||||
concept RebindablePointOriginFor =
|
||||
requires { typename rebind_point_origin_dimension<T, D>; } &&
|
||||
PointOrigin<rebind_point_origin_dimension<T, D>> &&
|
||||
requires { typename rebind_point_origin_dimension<T, D>; } && PointOrigin<rebind_point_origin_dimension<T, D>> &&
|
||||
std::same_as<D, typename rebind_point_origin_dimension<T, D>::dimension>;
|
||||
|
||||
// Kind
|
||||
@@ -260,13 +256,11 @@ struct _kind_base;
|
||||
} // namespace detail
|
||||
|
||||
template<typename T, template<typename...> typename Base>
|
||||
concept kind_impl_ =
|
||||
is_derived_from_specialization_of<T, Base> &&
|
||||
requires {
|
||||
typename T::base_kind;
|
||||
typename T::dimension;
|
||||
requires Dimension<typename T::dimension>;
|
||||
};
|
||||
concept kind_impl_ = is_derived_from_specialization_of<T, Base> && requires {
|
||||
typename T::base_kind;
|
||||
typename T::dimension;
|
||||
requires Dimension<typename T::dimension>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A concept matching all kind types
|
||||
@@ -274,10 +268,8 @@ concept kind_impl_ =
|
||||
* Satisfied by all kind types derived from an specialization of @c kind.
|
||||
*/
|
||||
template<typename T>
|
||||
concept Kind =
|
||||
kind_impl_<T, detail::_kind_base> &&
|
||||
kind_impl_<typename T::base_kind, detail::_kind_base> &&
|
||||
std::same_as<typename T::base_kind, typename T::base_kind::base_kind>;
|
||||
concept Kind = kind_impl_<T, detail::_kind_base> && kind_impl_<typename T::base_kind, detail::_kind_base> &&
|
||||
std::same_as<typename T::base_kind, typename T::base_kind::base_kind>;
|
||||
|
||||
// PointKind
|
||||
namespace detail {
|
||||
@@ -294,9 +286,7 @@ struct _point_kind_base;
|
||||
*/
|
||||
template<typename T>
|
||||
concept PointKind =
|
||||
kind_impl_<T, detail::_point_kind_base> &&
|
||||
requires { typename T::origin; } &&
|
||||
PointOrigin<typename T::origin> &&
|
||||
kind_impl_<T, detail::_point_kind_base> && requires { typename T::origin; } && PointOrigin<typename T::origin> &&
|
||||
std::same_as<typename T::dimension, typename T::base_kind::dimension> &&
|
||||
std::same_as<typename T::dimension, typename T::origin::dimension>;
|
||||
|
||||
@@ -394,30 +384,26 @@ concept QuantityPointLike = detail::is_quantity_point_like<T>;
|
||||
// Representation
|
||||
|
||||
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>;
|
||||
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>;
|
||||
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>>;
|
||||
concept castable_number_ = // exposition only
|
||||
common_type_with_<T, std::intmax_t> && scalable_number_<std::common_type_t<T, std::intmax_t>>;
|
||||
|
||||
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>>);
|
||||
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, typename U>
|
||||
concept scalable_with_ = // exposition only
|
||||
common_type_with_<T, U> &&
|
||||
scalable_<std::common_type_t<T, U>>;
|
||||
concept scalable_with_ = // exposition only
|
||||
common_type_with_<T, U> && scalable_<std::common_type_t<T, U>>;
|
||||
|
||||
// WrappedQuantity
|
||||
namespace detail {
|
||||
@@ -427,7 +413,9 @@ inline constexpr bool is_wrapped_quantity = false;
|
||||
|
||||
template<typename T>
|
||||
requires requires { typename T::value_type; }
|
||||
inline constexpr bool is_wrapped_quantity<T> = Quantity<typename T::value_type> || QuantityLike<typename T::value_type> || is_wrapped_quantity<typename T::value_type>;
|
||||
inline constexpr bool is_wrapped_quantity<T> =
|
||||
Quantity<typename T::value_type> || QuantityLike<typename T::value_type> ||
|
||||
is_wrapped_quantity<typename T::value_type>;
|
||||
|
||||
template<typename T>
|
||||
requires requires { typename T::quantity_type; }
|
||||
@@ -442,7 +430,7 @@ inline constexpr bool is_wrapped_quantity<T> = Quantity<typename T::quantity_typ
|
||||
* recursively (i.e. `std::optional<si::length<si::metre>>`).
|
||||
*/
|
||||
template<typename T>
|
||||
concept wrapped_quantity_ = // exposition only
|
||||
concept wrapped_quantity_ = // exposition only
|
||||
detail::is_wrapped_quantity<T>;
|
||||
|
||||
/**
|
||||
@@ -451,39 +439,39 @@ concept wrapped_quantity_ = // exposition only
|
||||
* Satisfied by types that satisfy `(!Quantity<T>) && (!WrappedQuantity<T>) && std::regular<T>`.
|
||||
*/
|
||||
template<typename T>
|
||||
concept Representation =
|
||||
(!Quantity<T>) &&
|
||||
(!QuantityLike<T>) &&
|
||||
(!wrapped_quantity_<T>) &&
|
||||
std::regular<T> &&
|
||||
scalable_<T>;
|
||||
concept Representation = (!Quantity<T>) && (!QuantityLike<T>) &&
|
||||
(!wrapped_quantity_<T>) && std::regular<T> && scalable_<T>;
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
requires requires(T q) {
|
||||
typename quantity_like_traits<T>::dimension;
|
||||
typename quantity_like_traits<T>::unit;
|
||||
typename quantity_like_traits<T>::rep;
|
||||
requires Dimension<typename quantity_like_traits<T>::dimension>;
|
||||
requires Unit<typename quantity_like_traits<T>::unit>;
|
||||
requires Representation<typename quantity_like_traits<T>::rep>;
|
||||
{ quantity_like_traits<T>::number(q) } -> std::convertible_to<typename quantity_like_traits<T>::rep>;
|
||||
}
|
||||
typename quantity_like_traits<T>::dimension;
|
||||
typename quantity_like_traits<T>::unit;
|
||||
typename quantity_like_traits<T>::rep;
|
||||
requires Dimension<typename quantity_like_traits<T>::dimension>;
|
||||
requires Unit<typename quantity_like_traits<T>::unit>;
|
||||
requires Representation<typename quantity_like_traits<T>::rep>;
|
||||
{
|
||||
quantity_like_traits<T>::number(q)
|
||||
} -> std::convertible_to<typename quantity_like_traits<T>::rep>;
|
||||
}
|
||||
inline constexpr bool is_quantity_like<T> = true;
|
||||
|
||||
template<typename T>
|
||||
requires requires(T q) {
|
||||
typename quantity_point_like_traits<T>::dimension;
|
||||
typename quantity_point_like_traits<T>::unit;
|
||||
typename quantity_point_like_traits<T>::rep;
|
||||
requires Dimension<typename quantity_point_like_traits<T>::dimension>;
|
||||
requires Unit<typename quantity_point_like_traits<T>::unit>;
|
||||
requires Representation<typename quantity_point_like_traits<T>::rep>;
|
||||
{ quantity_point_like_traits<T>::relative(q) } -> QuantityLike;
|
||||
}
|
||||
typename quantity_point_like_traits<T>::dimension;
|
||||
typename quantity_point_like_traits<T>::unit;
|
||||
typename quantity_point_like_traits<T>::rep;
|
||||
requires Dimension<typename quantity_point_like_traits<T>::dimension>;
|
||||
requires Unit<typename quantity_point_like_traits<T>::unit>;
|
||||
requires Representation<typename quantity_point_like_traits<T>::rep>;
|
||||
{
|
||||
quantity_point_like_traits<T>::relative(q)
|
||||
} -> QuantityLike;
|
||||
}
|
||||
inline constexpr bool is_quantity_point_like<T> = true;
|
||||
|
||||
} // namespace detail
|
||||
} // namespace detail
|
||||
|
||||
} // namespace units
|
||||
|
||||
@@ -59,7 +59,7 @@ struct common_quantity_reference_impl<reference<D, U1>, reference<D, U2>> {
|
||||
};
|
||||
|
||||
template<typename D1, typename U1, typename D2, typename U2>
|
||||
requires same_unit_reference<dimension_unit<D1>, dimension_unit<D2>>::value
|
||||
requires(same_unit_reference<dimension_unit<D1>, dimension_unit<D2>>::value)
|
||||
struct common_quantity_reference_impl<reference<D1, U1>, reference<D2, U2>> {
|
||||
using type = reference<D1, downcast_unit<D1, common_ratio(U1::ratio, U2::ratio)>>;
|
||||
};
|
||||
@@ -77,8 +77,8 @@ struct common_quantity_reference_impl<reference<D1, U1>, reference<D2, U2>> {
|
||||
|
||||
template<Quantity Q1, QuantityEquivalentTo<Q1> Q2>
|
||||
using common_quantity_reference =
|
||||
TYPENAME detail::common_quantity_reference_impl <
|
||||
std::remove_const_t<decltype(Q1::reference)>, std::remove_const_t<decltype(Q2::reference)>>::type;
|
||||
TYPENAME detail::common_quantity_reference_impl<std::remove_const_t<decltype(Q1::reference)>,
|
||||
std::remove_const_t<decltype(Q2::reference)>>::type;
|
||||
|
||||
} // namespace detail
|
||||
} // namespace units
|
||||
@@ -91,33 +91,37 @@ struct common_type<Q1, Q2> {
|
||||
private:
|
||||
using ref = units::detail::common_quantity_reference<Q1, Q2>;
|
||||
public:
|
||||
using type = units::quantity<typename ref::dimension, typename ref::unit, common_type_t<typename Q1::rep, typename Q2::rep>>;
|
||||
using type =
|
||||
units::quantity<typename ref::dimension, typename ref::unit, common_type_t<typename Q1::rep, typename Q2::rep>>;
|
||||
};
|
||||
|
||||
template<units::QuantityPoint QP1, units::QuantityPointEquivalentTo<QP1> QP2>
|
||||
requires requires { typename common_type_t<typename QP1::rep, typename QP2::rep>; }
|
||||
struct common_type<QP1, QP2> {
|
||||
using type = units::quantity_point<
|
||||
units::rebind_point_origin_dimension<typename QP1::origin,
|
||||
typename common_type_t<typename QP1::quantity_type, typename QP2::quantity_type>::dimension>,
|
||||
typename common_type_t<typename QP1::quantity_type, typename QP2::quantity_type>::unit,
|
||||
typename common_type_t<typename QP1::quantity_type, typename QP2::quantity_type>::rep>;
|
||||
using type =
|
||||
units::quantity_point<units::rebind_point_origin_dimension<
|
||||
typename QP1::origin, typename common_type_t<typename QP1::quantity_type,
|
||||
typename QP2::quantity_type>::dimension>,
|
||||
typename common_type_t<typename QP1::quantity_type, typename QP2::quantity_type>::unit,
|
||||
typename common_type_t<typename QP1::quantity_type, typename QP2::quantity_type>::rep>;
|
||||
};
|
||||
|
||||
template<units::QuantityKind QK1, units::QuantityKindEquivalentTo<QK1> QK2>
|
||||
requires requires { typename common_type_t<typename QK1::rep, typename QK2::rep>; }
|
||||
struct common_type<QK1, QK2> {
|
||||
using type = units::quantity_kind<typename QK1::kind_type,
|
||||
typename common_type_t<typename QK1::quantity_type, typename QK2::quantity_type>::unit,
|
||||
typename common_type_t<typename QK1::quantity_type, typename QK2::quantity_type>::rep>;
|
||||
using type =
|
||||
units::quantity_kind<typename QK1::kind_type,
|
||||
typename common_type_t<typename QK1::quantity_type, typename QK2::quantity_type>::unit,
|
||||
typename common_type_t<typename QK1::quantity_type, typename QK2::quantity_type>::rep>;
|
||||
};
|
||||
|
||||
template<units::QuantityPointKind QPK1, units::QuantityPointKindEquivalentTo<QPK1> QPK2>
|
||||
requires requires { typename common_type_t<typename QPK1::rep, typename QPK2::rep>; }
|
||||
struct common_type<QPK1, QPK2> {
|
||||
using type = units::quantity_point_kind<typename QPK1::point_kind_type,
|
||||
using type = units::quantity_point_kind<
|
||||
typename QPK1::point_kind_type,
|
||||
typename common_type_t<typename QPK1::quantity_kind_type, typename QPK2::quantity_kind_type>::unit,
|
||||
typename common_type_t<typename QPK1::quantity_kind_type, typename QPK2::quantity_kind_type>::rep>;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace std
|
||||
|
||||
@@ -76,105 +76,105 @@ struct decimal_fp {
|
||||
// >>> for i in range(1, 100):
|
||||
// ... print(f"/* log({i:>2d}) = */ {math.log(i):.16f},")
|
||||
constexpr std::array<double, 99> log_table{
|
||||
/* log( 1) = */ 0.0000000000000000,
|
||||
/* log( 2) = */ 0.6931471805599453,
|
||||
/* log( 3) = */ 1.0986122886681098,
|
||||
/* log( 4) = */ 1.3862943611198906,
|
||||
/* log( 5) = */ 1.6094379124341003,
|
||||
/* log( 6) = */ 1.7917594692280550,
|
||||
/* log( 7) = */ 1.9459101490553132,
|
||||
/* log( 8) = */ 2.0794415416798357,
|
||||
/* log( 9) = */ 2.1972245773362196,
|
||||
/* log(10) = */ 2.3025850929940459,
|
||||
/* log(11) = */ 2.3978952727983707,
|
||||
/* log(12) = */ 2.4849066497880004,
|
||||
/* log(13) = */ 2.5649493574615367,
|
||||
/* log(14) = */ 2.6390573296152584,
|
||||
/* log(15) = */ 2.7080502011022101,
|
||||
/* log(16) = */ 2.7725887222397811,
|
||||
/* log(17) = */ 2.8332133440562162,
|
||||
/* log(18) = */ 2.8903717578961645,
|
||||
/* log(19) = */ 2.9444389791664403,
|
||||
/* log(20) = */ 2.9957322735539909,
|
||||
/* log(21) = */ 3.0445224377234230,
|
||||
/* log(22) = */ 3.0910424533583161,
|
||||
/* log(23) = */ 3.1354942159291497,
|
||||
/* log(24) = */ 3.1780538303479458,
|
||||
/* log(25) = */ 3.2188758248682006,
|
||||
/* log(26) = */ 3.2580965380214821,
|
||||
/* log(27) = */ 3.2958368660043291,
|
||||
/* log(28) = */ 3.3322045101752038,
|
||||
/* log(29) = */ 3.3672958299864741,
|
||||
/* log(30) = */ 3.4011973816621555,
|
||||
/* log(31) = */ 3.4339872044851463,
|
||||
/* log(32) = */ 3.4657359027997265,
|
||||
/* log(33) = */ 3.4965075614664802,
|
||||
/* log(34) = */ 3.5263605246161616,
|
||||
/* log(35) = */ 3.5553480614894135,
|
||||
/* log(36) = */ 3.5835189384561099,
|
||||
/* log(37) = */ 3.6109179126442243,
|
||||
/* log(38) = */ 3.6375861597263857,
|
||||
/* log(39) = */ 3.6635616461296463,
|
||||
/* log(40) = */ 3.6888794541139363,
|
||||
/* log(41) = */ 3.7135720667043080,
|
||||
/* log(42) = */ 3.7376696182833684,
|
||||
/* log(43) = */ 3.7612001156935624,
|
||||
/* log(44) = */ 3.7841896339182610,
|
||||
/* log(45) = */ 3.8066624897703196,
|
||||
/* log(46) = */ 3.8286413964890951,
|
||||
/* log(47) = */ 3.8501476017100584,
|
||||
/* log(48) = */ 3.8712010109078911,
|
||||
/* log(49) = */ 3.8918202981106265,
|
||||
/* log(50) = */ 3.9120230054281460,
|
||||
/* log(51) = */ 3.9318256327243257,
|
||||
/* log(52) = */ 3.9512437185814275,
|
||||
/* log(53) = */ 3.9702919135521220,
|
||||
/* log(54) = */ 3.9889840465642745,
|
||||
/* log(55) = */ 4.0073331852324712,
|
||||
/* log(56) = */ 4.0253516907351496,
|
||||
/* log(57) = */ 4.0430512678345503,
|
||||
/* log(58) = */ 4.0604430105464191,
|
||||
/* log(59) = */ 4.0775374439057197,
|
||||
/* log(60) = */ 4.0943445622221004,
|
||||
/* log(61) = */ 4.1108738641733114,
|
||||
/* log(62) = */ 4.1271343850450917,
|
||||
/* log(63) = */ 4.1431347263915326,
|
||||
/* log(64) = */ 4.1588830833596715,
|
||||
/* log(65) = */ 4.1743872698956368,
|
||||
/* log(66) = */ 4.1896547420264252,
|
||||
/* log(67) = */ 4.2046926193909657,
|
||||
/* log(68) = */ 4.2195077051761070,
|
||||
/* log(69) = */ 4.2341065045972597,
|
||||
/* log(70) = */ 4.2484952420493594,
|
||||
/* log(71) = */ 4.2626798770413155,
|
||||
/* log(72) = */ 4.2766661190160553,
|
||||
/* log(73) = */ 4.2904594411483910,
|
||||
/* log(74) = */ 4.3040650932041702,
|
||||
/* log(75) = */ 4.3174881135363101,
|
||||
/* log(76) = */ 4.3307333402863311,
|
||||
/* log(77) = */ 4.3438054218536841,
|
||||
/* log(78) = */ 4.3567088266895917,
|
||||
/* log(79) = */ 4.3694478524670215,
|
||||
/* log(80) = */ 4.3820266346738812,
|
||||
/* log(81) = */ 4.3944491546724391,
|
||||
/* log(82) = */ 4.4067192472642533,
|
||||
/* log(83) = */ 4.4188406077965983,
|
||||
/* log(84) = */ 4.4308167988433134,
|
||||
/* log(85) = */ 4.4426512564903167,
|
||||
/* log(86) = */ 4.4543472962535073,
|
||||
/* log(87) = */ 4.4659081186545837,
|
||||
/* log(88) = */ 4.4773368144782069,
|
||||
/* log(89) = */ 4.4886363697321396,
|
||||
/* log(90) = */ 4.4998096703302650,
|
||||
/* log(91) = */ 4.5108595065168497,
|
||||
/* log(92) = */ 4.5217885770490405,
|
||||
/* log(93) = */ 4.5325994931532563,
|
||||
/* log(94) = */ 4.5432947822700038,
|
||||
/* log(95) = */ 4.5538768916005408,
|
||||
/* log(96) = */ 4.5643481914678361,
|
||||
/* log(97) = */ 4.5747109785033828,
|
||||
/* log(98) = */ 4.5849674786705723,
|
||||
/* log(99) = */ 4.5951198501345898,
|
||||
/* log( 1) = */ 0.0000000000000000,
|
||||
/* log( 2) = */ 0.6931471805599453,
|
||||
/* log( 3) = */ 1.0986122886681098,
|
||||
/* log( 4) = */ 1.3862943611198906,
|
||||
/* log( 5) = */ 1.6094379124341003,
|
||||
/* log( 6) = */ 1.7917594692280550,
|
||||
/* log( 7) = */ 1.9459101490553132,
|
||||
/* log( 8) = */ 2.0794415416798357,
|
||||
/* log( 9) = */ 2.1972245773362196,
|
||||
/* log(10) = */ 2.3025850929940459,
|
||||
/* log(11) = */ 2.3978952727983707,
|
||||
/* log(12) = */ 2.4849066497880004,
|
||||
/* log(13) = */ 2.5649493574615367,
|
||||
/* log(14) = */ 2.6390573296152584,
|
||||
/* log(15) = */ 2.7080502011022101,
|
||||
/* log(16) = */ 2.7725887222397811,
|
||||
/* log(17) = */ 2.8332133440562162,
|
||||
/* log(18) = */ 2.8903717578961645,
|
||||
/* log(19) = */ 2.9444389791664403,
|
||||
/* log(20) = */ 2.9957322735539909,
|
||||
/* log(21) = */ 3.0445224377234230,
|
||||
/* log(22) = */ 3.0910424533583161,
|
||||
/* log(23) = */ 3.1354942159291497,
|
||||
/* log(24) = */ 3.1780538303479458,
|
||||
/* log(25) = */ 3.2188758248682006,
|
||||
/* log(26) = */ 3.2580965380214821,
|
||||
/* log(27) = */ 3.2958368660043291,
|
||||
/* log(28) = */ 3.3322045101752038,
|
||||
/* log(29) = */ 3.3672958299864741,
|
||||
/* log(30) = */ 3.4011973816621555,
|
||||
/* log(31) = */ 3.4339872044851463,
|
||||
/* log(32) = */ 3.4657359027997265,
|
||||
/* log(33) = */ 3.4965075614664802,
|
||||
/* log(34) = */ 3.5263605246161616,
|
||||
/* log(35) = */ 3.5553480614894135,
|
||||
/* log(36) = */ 3.5835189384561099,
|
||||
/* log(37) = */ 3.6109179126442243,
|
||||
/* log(38) = */ 3.6375861597263857,
|
||||
/* log(39) = */ 3.6635616461296463,
|
||||
/* log(40) = */ 3.6888794541139363,
|
||||
/* log(41) = */ 3.7135720667043080,
|
||||
/* log(42) = */ 3.7376696182833684,
|
||||
/* log(43) = */ 3.7612001156935624,
|
||||
/* log(44) = */ 3.7841896339182610,
|
||||
/* log(45) = */ 3.8066624897703196,
|
||||
/* log(46) = */ 3.8286413964890951,
|
||||
/* log(47) = */ 3.8501476017100584,
|
||||
/* log(48) = */ 3.8712010109078911,
|
||||
/* log(49) = */ 3.8918202981106265,
|
||||
/* log(50) = */ 3.9120230054281460,
|
||||
/* log(51) = */ 3.9318256327243257,
|
||||
/* log(52) = */ 3.9512437185814275,
|
||||
/* log(53) = */ 3.9702919135521220,
|
||||
/* log(54) = */ 3.9889840465642745,
|
||||
/* log(55) = */ 4.0073331852324712,
|
||||
/* log(56) = */ 4.0253516907351496,
|
||||
/* log(57) = */ 4.0430512678345503,
|
||||
/* log(58) = */ 4.0604430105464191,
|
||||
/* log(59) = */ 4.0775374439057197,
|
||||
/* log(60) = */ 4.0943445622221004,
|
||||
/* log(61) = */ 4.1108738641733114,
|
||||
/* log(62) = */ 4.1271343850450917,
|
||||
/* log(63) = */ 4.1431347263915326,
|
||||
/* log(64) = */ 4.1588830833596715,
|
||||
/* log(65) = */ 4.1743872698956368,
|
||||
/* log(66) = */ 4.1896547420264252,
|
||||
/* log(67) = */ 4.2046926193909657,
|
||||
/* log(68) = */ 4.2195077051761070,
|
||||
/* log(69) = */ 4.2341065045972597,
|
||||
/* log(70) = */ 4.2484952420493594,
|
||||
/* log(71) = */ 4.2626798770413155,
|
||||
/* log(72) = */ 4.2766661190160553,
|
||||
/* log(73) = */ 4.2904594411483910,
|
||||
/* log(74) = */ 4.3040650932041702,
|
||||
/* log(75) = */ 4.3174881135363101,
|
||||
/* log(76) = */ 4.3307333402863311,
|
||||
/* log(77) = */ 4.3438054218536841,
|
||||
/* log(78) = */ 4.3567088266895917,
|
||||
/* log(79) = */ 4.3694478524670215,
|
||||
/* log(80) = */ 4.3820266346738812,
|
||||
/* log(81) = */ 4.3944491546724391,
|
||||
/* log(82) = */ 4.4067192472642533,
|
||||
/* log(83) = */ 4.4188406077965983,
|
||||
/* log(84) = */ 4.4308167988433134,
|
||||
/* log(85) = */ 4.4426512564903167,
|
||||
/* log(86) = */ 4.4543472962535073,
|
||||
/* log(87) = */ 4.4659081186545837,
|
||||
/* log(88) = */ 4.4773368144782069,
|
||||
/* log(89) = */ 4.4886363697321396,
|
||||
/* log(90) = */ 4.4998096703302650,
|
||||
/* log(91) = */ 4.5108595065168497,
|
||||
/* log(92) = */ 4.5217885770490405,
|
||||
/* log(93) = */ 4.5325994931532563,
|
||||
/* log(94) = */ 4.5432947822700038,
|
||||
/* log(95) = */ 4.5538768916005408,
|
||||
/* log(96) = */ 4.5643481914678361,
|
||||
/* log(97) = */ 4.5747109785033828,
|
||||
/* log(98) = */ 4.5849674786705723,
|
||||
/* log(99) = */ 4.5951198501345898,
|
||||
};
|
||||
decimal_fp x = to_decimal(v);
|
||||
|
||||
|
||||
@@ -34,17 +34,17 @@ namespace units::detail {
|
||||
* Expression of the dependence of a quantity on the base quantities (and their base dimensions) of a system of
|
||||
* quantities as a product of powers of factors corresponding to the base quantities, omitting any numerical factors.
|
||||
* A power of a factor is the factor raised to an exponent.
|
||||
*
|
||||
* A derived dimension can be formed from multiple exponents (i.e. speed is represented as "exponent<L, 1>, exponent<T, -1>").
|
||||
* It is also possible to form a derived dimension with only one exponent (i.e. frequency is represented as just
|
||||
*
|
||||
* A derived dimension can be formed from multiple exponents (i.e. speed is represented as "exponent<L, 1>, exponent<T,
|
||||
* -1>"). It is also possible to form a derived dimension with only one exponent (i.e. frequency is represented as just
|
||||
* "exponent<T, -1>").
|
||||
*
|
||||
*
|
||||
* @note This class template is used by the library engine and should not be directly instantiated by the user.
|
||||
*
|
||||
*
|
||||
* @tparam Es zero or more exponents of a derived dimension
|
||||
*/
|
||||
template<Exponent... Es>
|
||||
requires (BaseDimension<typename Es::dimension> && ...)
|
||||
requires(BaseDimension<typename Es::dimension> && ...)
|
||||
struct derived_dimension_base : downcast_base<derived_dimension_base<Es...>> {
|
||||
using exponents = exponent_list<Es...>;
|
||||
};
|
||||
|
||||
@@ -32,19 +32,16 @@ namespace units::detail {
|
||||
template<bool Divide, std::size_t NegativeExpCount, std::size_t Idx>
|
||||
constexpr auto operator_text()
|
||||
{
|
||||
if constexpr(Idx == 0) {
|
||||
if constexpr(Divide && NegativeExpCount == 1) {
|
||||
if constexpr (Idx == 0) {
|
||||
if constexpr (Divide && NegativeExpCount == 1) {
|
||||
return basic_fixed_string("1/");
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return basic_fixed_string("");
|
||||
}
|
||||
}
|
||||
else {
|
||||
if constexpr(Divide && NegativeExpCount == 1) {
|
||||
} else {
|
||||
if constexpr (Divide && NegativeExpCount == 1) {
|
||||
return basic_fixed_string("/");
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return basic_symbol_text(" ⋅ ", " ");
|
||||
}
|
||||
}
|
||||
@@ -54,24 +51,21 @@ template<typename E, basic_symbol_text Symbol, std::size_t NegativeExpCount, std
|
||||
constexpr auto exp_text()
|
||||
{
|
||||
// get calculation operator + symbol
|
||||
const auto txt = operator_text<E::num < 0, NegativeExpCount, Idx>() + Symbol;
|
||||
if constexpr(E::den != 1) {
|
||||
const auto txt = operator_text<(E::num < 0), NegativeExpCount, Idx>() + Symbol;
|
||||
if constexpr (E::den != 1) {
|
||||
// add root part
|
||||
return txt + basic_fixed_string("^(") + regular<abs(E::num)>() + basic_fixed_string("/") + regular<E::den>() + basic_fixed_string(")");
|
||||
}
|
||||
else if constexpr(E::num != 1) {
|
||||
return txt + basic_fixed_string("^(") + regular<abs(E::num)>() + basic_fixed_string("/") + regular<E::den>() +
|
||||
basic_fixed_string(")");
|
||||
} else if constexpr (E::num != 1) {
|
||||
// add exponent part
|
||||
if constexpr(NegativeExpCount > 1) { // no '/' sign here (only negative exponents)
|
||||
if constexpr (NegativeExpCount > 1) { // no '/' sign here (only negative exponents)
|
||||
return txt + superscript<E::num>();
|
||||
}
|
||||
else if constexpr(E::num != -1) { // -1 is replaced with '/' sign here
|
||||
} else if constexpr (E::num != -1) { // -1 is replaced with '/' sign here
|
||||
return txt + superscript<abs(E::num)>();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return txt;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return txt;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ inline constexpr bool same_scaled_units<exponent_list<Es...>, Us...> = (UnitOf<U
|
||||
template<Exponent E>
|
||||
constexpr ratio inverse_if_negative(const ratio& r)
|
||||
{
|
||||
if constexpr(E::num * E::den > 0)
|
||||
if constexpr (E::num * E::den > 0)
|
||||
return r;
|
||||
else
|
||||
return inverse(r);
|
||||
@@ -47,7 +47,8 @@ constexpr ratio inverse_if_negative(const ratio& r)
|
||||
template<Unit... Us, typename... Es>
|
||||
constexpr ratio derived_ratio(exponent_list<Es...>)
|
||||
{
|
||||
return (... * inverse_if_negative<Es>(pow<detail::abs(Es::num)>(Us::ratio / dimension_unit<typename Es::dimension>::ratio)));
|
||||
return (... * inverse_if_negative<Es>(
|
||||
pow<detail::abs(Es::num)>(Us::ratio / dimension_unit<typename Es::dimension>::ratio)));
|
||||
}
|
||||
|
||||
template<DerivedDimension D, Unit... Us>
|
||||
|
||||
@@ -54,7 +54,8 @@ struct dim_consolidate<exponent_list<E1, ERest...>> {
|
||||
using type = type_list_push_front<typename dim_consolidate<exponent_list<ERest...>>::type, E1>;
|
||||
};
|
||||
|
||||
template<BaseDimension Dim, std::intmax_t Num1, std::intmax_t Den1, std::intmax_t Num2, std::intmax_t Den2, typename... ERest>
|
||||
template<BaseDimension Dim, std::intmax_t Num1, std::intmax_t Den1, std::intmax_t Num2, std::intmax_t Den2,
|
||||
typename... ERest>
|
||||
struct dim_consolidate<exponent_list<exponent<Dim, Num1, Den1>, exponent<Dim, Num2, Den2>, ERest...>> {
|
||||
using r1 = std::ratio<Num1, Den1>;
|
||||
using r2 = std::ratio<Num2, Den2>;
|
||||
|
||||
@@ -30,8 +30,8 @@ namespace units::detail {
|
||||
|
||||
/**
|
||||
* @brief Unpacks the list of potentially derived dimensions to a list containing only base dimensions
|
||||
*
|
||||
* @tparam Es Exponents of potentially derived dimensions
|
||||
*
|
||||
* @tparam Es Exponents of potentially derived dimensions
|
||||
*/
|
||||
template<Exponent... Es>
|
||||
struct dim_unpack;
|
||||
|
||||
@@ -34,11 +34,11 @@ namespace units {
|
||||
|
||||
/**
|
||||
* @brief Unknown dimension
|
||||
*
|
||||
*
|
||||
* Sometimes a temporary partial result of a complex calculation may not result in a predefined
|
||||
* dimension. In such a case an `unknown_dimension` is created with a coherent unit of `unknown_coherent_unit`
|
||||
* and ratio(1).
|
||||
*
|
||||
*
|
||||
* @tparam Es the list of exponents of ingredient dimensions
|
||||
*/
|
||||
template<Exponent... Es>
|
||||
@@ -70,7 +70,7 @@ struct downcast_dimension_impl<D> {
|
||||
using type = TYPENAME check_unknown<downcast<D>>::type;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace detail
|
||||
|
||||
template<Dimension D>
|
||||
using downcast_dimension = TYPENAME detail::downcast_dimension_impl<D>::type;
|
||||
@@ -97,8 +97,7 @@ struct dim_invert_impl<derived_dimension_base<Es...>> {
|
||||
};
|
||||
|
||||
template<DerivedDimension D>
|
||||
struct dim_invert_impl<D> : dim_invert_impl<downcast_base_t<D>> {
|
||||
};
|
||||
struct dim_invert_impl<D> : dim_invert_impl<downcast_base_t<D>> {};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@@ -123,7 +122,7 @@ struct to_dimension<exponent_list<exponent<D, 1>>> {
|
||||
|
||||
/**
|
||||
* @brief Merges 2 sorted derived dimensions into one units::derived_dimension_base
|
||||
*
|
||||
*
|
||||
* A result of a dimensional calculation may result with many exponents of the same base dimension orginated
|
||||
* from different parts of the equation. As the exponents lists of both operands it is enough to merge them
|
||||
* into one list and consolidate duplicates. Also it is possible that final exponents list will contain only
|
||||
@@ -131,19 +130,22 @@ struct to_dimension<exponent_list<exponent<D, 1>>> {
|
||||
* dimension itself.
|
||||
*/
|
||||
template<Dimension D1, Dimension D2>
|
||||
using merge_dimension = TYPENAME to_dimension<typename dim_consolidate<type_list_merge_sorted<typename D1::exponents, typename D2::exponents, exponent_less>>::type>::type;
|
||||
using merge_dimension = TYPENAME to_dimension<typename dim_consolidate<
|
||||
type_list_merge_sorted<typename D1::exponents, typename D2::exponents, exponent_less>>::type>::type;
|
||||
|
||||
template<Dimension D1, Dimension D2>
|
||||
struct dimension_multiply_impl;
|
||||
|
||||
template<BaseDimension D1, BaseDimension D2>
|
||||
struct dimension_multiply_impl<D1, D2> {
|
||||
using type = downcast_dimension<merge_dimension<derived_dimension_base<exponent<D1, 1>>, derived_dimension_base<exponent<D2, 1>>>>;
|
||||
using type = downcast_dimension<
|
||||
merge_dimension<derived_dimension_base<exponent<D1, 1>>, derived_dimension_base<exponent<D2, 1>>>>;
|
||||
};
|
||||
|
||||
template<BaseDimension D1, DerivedDimension D2>
|
||||
struct dimension_multiply_impl<D1, D2> {
|
||||
using type = downcast_dimension<merge_dimension<derived_dimension_base<exponent<D1, 1>>, typename D2::downcast_base_type>>;
|
||||
using type =
|
||||
downcast_dimension<merge_dimension<derived_dimension_base<exponent<D1, 1>>, typename D2::downcast_base_type>>;
|
||||
};
|
||||
|
||||
template<DerivedDimension D1, BaseDimension D2>
|
||||
|
||||
@@ -30,12 +30,10 @@ namespace units {
|
||||
namespace detail {
|
||||
|
||||
template<typename T, typename U>
|
||||
struct equivalent_impl : std::false_type {
|
||||
};
|
||||
struct equivalent_impl : std::false_type {};
|
||||
|
||||
template<typename T>
|
||||
struct equivalent_impl<T, T> : std::true_type {
|
||||
};
|
||||
struct equivalent_impl<T, T> : std::true_type {};
|
||||
|
||||
|
||||
// units
|
||||
@@ -47,39 +45,35 @@ struct equivalent_impl<U1, U2> : std::disjunction<std::is_base_of<U1, U2>, std::
|
||||
// dimensions
|
||||
|
||||
template<BaseDimension D1, BaseDimension D2>
|
||||
struct equivalent_impl<D1, D2> : std::conjunction<std::bool_constant<D1::symbol == D2::symbol>,
|
||||
same_unit_reference<typename D1::base_unit, typename D2::base_unit>> {
|
||||
};
|
||||
struct equivalent_impl<D1, D2> :
|
||||
std::conjunction<std::bool_constant<D1::symbol == D2::symbol>,
|
||||
same_unit_reference<typename D1::base_unit, typename D2::base_unit>> {};
|
||||
|
||||
template<Exponent E1, Exponent E2>
|
||||
struct equivalent_exp : std::false_type {
|
||||
};
|
||||
struct equivalent_exp : std::false_type {};
|
||||
|
||||
template<BaseDimension Dim1, std::intmax_t Num, std::intmax_t Den, BaseDimension Dim2>
|
||||
struct equivalent_exp<exponent<Dim1, Num, Den>, exponent<Dim2, Num, Den>> : equivalent_impl<Dim1, Dim2> {
|
||||
};
|
||||
struct equivalent_exp<exponent<Dim1, Num, Den>, exponent<Dim2, Num, Den>> : equivalent_impl<Dim1, Dim2> {};
|
||||
|
||||
template<DerivedDimension D1, DerivedDimension D2>
|
||||
struct equivalent_derived_dim : std::false_type {
|
||||
};
|
||||
struct equivalent_derived_dim : std::false_type {};
|
||||
|
||||
template<typename... Es1, typename... Es2>
|
||||
requires(sizeof...(Es1) == sizeof...(Es2))
|
||||
struct equivalent_derived_dim<derived_dimension_base<Es1...>, derived_dimension_base<Es2...>> :
|
||||
std::conjunction<equivalent_exp<Es1, Es2>...> {
|
||||
};
|
||||
std::conjunction<equivalent_exp<Es1, Es2>...> {};
|
||||
|
||||
template<DerivedDimension D1, DerivedDimension D2>
|
||||
struct equivalent_impl<D1, D2> :
|
||||
std::disjunction<std::is_base_of<D1, D2>, std::is_base_of<D2, D1>,
|
||||
equivalent_derived_dim<downcast_base_t<D1>, downcast_base_t<D2>>> {
|
||||
};
|
||||
equivalent_derived_dim<downcast_base_t<D1>, downcast_base_t<D2>>> {};
|
||||
|
||||
|
||||
// additionally accounts for unknown dimensions
|
||||
template<Unit U1, Dimension D1, Unit U2, Dimension D2>
|
||||
struct equivalent_unit : std::disjunction<equivalent_impl<U1, U2>,
|
||||
std::bool_constant<U1::ratio / dimension_unit<D1>::ratio == U2::ratio / dimension_unit<D2>::ratio>> {};
|
||||
struct equivalent_unit :
|
||||
std::disjunction<equivalent_impl<U1, U2>, std::bool_constant<U1::ratio / dimension_unit<D1>::ratio ==
|
||||
U2::ratio / dimension_unit<D2>::ratio>> {};
|
||||
|
||||
// point origins
|
||||
|
||||
@@ -90,41 +84,46 @@ concept EquivalentPointOrigins =
|
||||
std::same_as<U, rebind_point_origin_dimension<T, typename U::dimension>>;
|
||||
|
||||
template<PointOrigin T, PointOrigin U>
|
||||
struct equivalent_impl<T, U> : std::bool_constant<
|
||||
EquivalentPointOrigins<T, U> && equivalent_impl<typename T::dimension, typename U::dimension>::value> {};
|
||||
struct equivalent_impl<T, U> :
|
||||
std::bool_constant<EquivalentPointOrigins<T, U> &&
|
||||
equivalent_impl<typename T::dimension, typename U::dimension>::value> {};
|
||||
|
||||
|
||||
// (point) kinds
|
||||
|
||||
template<Kind T, Kind U>
|
||||
struct equivalent_impl<T, U> :
|
||||
std::conjunction<std::is_same<typename T::base_kind, typename U::base_kind>,
|
||||
equivalent_impl<typename T::dimension, typename U::dimension>> {};
|
||||
std::conjunction<std::is_same<typename T::base_kind, typename U::base_kind>,
|
||||
equivalent_impl<typename T::dimension, typename U::dimension>> {};
|
||||
|
||||
template<PointKind T, PointKind U>
|
||||
struct equivalent_impl<T, U> :
|
||||
std::conjunction<equivalent_impl<typename T::base_kind, typename U::base_kind>,
|
||||
equivalent_impl<typename T::origin, typename U::origin>> {};
|
||||
std::conjunction<equivalent_impl<typename T::base_kind, typename U::base_kind>,
|
||||
equivalent_impl<typename T::origin, typename U::origin>> {};
|
||||
|
||||
|
||||
// quantities, quantity points, quantity (point) kinds
|
||||
|
||||
template<Quantity Q1, Quantity Q2>
|
||||
struct equivalent_impl<Q1, Q2> : std::conjunction<equivalent_impl<typename Q1::dimension, typename Q2::dimension>,
|
||||
equivalent_unit<typename Q1::unit, typename Q1::dimension,
|
||||
typename Q2::unit, typename Q2::dimension>> {};
|
||||
struct equivalent_impl<Q1, Q2> :
|
||||
std::conjunction<
|
||||
equivalent_impl<typename Q1::dimension, typename Q2::dimension>,
|
||||
equivalent_unit<typename Q1::unit, typename Q1::dimension, typename Q2::unit, typename Q2::dimension>> {};
|
||||
|
||||
template<QuantityPoint QP1, QuantityPoint QP2>
|
||||
struct equivalent_impl<QP1, QP2> : std::conjunction<equivalent_impl<typename QP1::quantity_type, typename QP2::quantity_type>,
|
||||
equivalent_impl<typename QP1::origin, typename QP2::origin>> {};
|
||||
struct equivalent_impl<QP1, QP2> :
|
||||
std::conjunction<equivalent_impl<typename QP1::quantity_type, typename QP2::quantity_type>,
|
||||
equivalent_impl<typename QP1::origin, typename QP2::origin>> {};
|
||||
|
||||
template<QuantityKind QK1, QuantityKind QK2>
|
||||
struct equivalent_impl<QK1, QK2> : std::conjunction<equivalent_impl<typename QK1::kind_type, typename QK2::kind_type>,
|
||||
equivalent_impl<typename QK1::quantity_type, typename QK2::quantity_type>> {};
|
||||
struct equivalent_impl<QK1, QK2> :
|
||||
std::conjunction<equivalent_impl<typename QK1::kind_type, typename QK2::kind_type>,
|
||||
equivalent_impl<typename QK1::quantity_type, typename QK2::quantity_type>> {};
|
||||
|
||||
template<QuantityPointKind QPK1, QuantityPointKind QPK2>
|
||||
struct equivalent_impl<QPK1, QPK2> : std::conjunction<equivalent_impl<typename QPK1::quantity_kind_type, typename QPK2::quantity_kind_type>,
|
||||
equivalent_impl<typename QPK1::origin, typename QPK2::origin>> {};
|
||||
struct equivalent_impl<QPK1, QPK2> :
|
||||
std::conjunction<equivalent_impl<typename QPK1::quantity_kind_type, typename QPK2::quantity_kind_type>,
|
||||
equivalent_impl<typename QPK1::origin, typename QPK2::origin>> {};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
||||
+17
-17
@@ -38,17 +38,16 @@ namespace units {
|
||||
template<typename BaseType>
|
||||
struct downcast_base {
|
||||
using downcast_base_type = BaseType;
|
||||
UNITS_DIAGNOSTIC_PUSH
|
||||
UNITS_DIAGNOSTIC_IGNORE_NON_TEMPLATE_FRIEND
|
||||
UNITS_DIAGNOSTIC_PUSH
|
||||
UNITS_DIAGNOSTIC_IGNORE_NON_TEMPLATE_FRIEND
|
||||
friend auto downcast_guide(downcast_base);
|
||||
friend auto downcast_poison_pill(downcast_base);
|
||||
UNITS_DIAGNOSTIC_POP
|
||||
UNITS_DIAGNOSTIC_POP
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
concept Downcastable =
|
||||
requires { typename T::downcast_base_type; } &&
|
||||
std::derived_from<T, downcast_base<typename T::downcast_base_type>>;
|
||||
requires { typename T::downcast_base_type; } && std::derived_from<T, downcast_base<typename T::downcast_base_type>>;
|
||||
|
||||
template<typename T>
|
||||
concept has_downcast_guide = requires(T t) { downcast_guide(t); };
|
||||
@@ -58,30 +57,31 @@ concept has_downcast_poison_pill = requires(T t) { downcast_poison_pill(t); };
|
||||
|
||||
template<typename Target, Downcastable T>
|
||||
struct downcast_child : T {
|
||||
friend auto downcast_guide(typename T::downcast_base)
|
||||
{ return std::type_identity<Target>(); }
|
||||
friend auto downcast_guide(typename T::downcast_base) { return std::type_identity<Target>(); }
|
||||
};
|
||||
|
||||
template<Downcastable T>
|
||||
struct downcast_poison : T {
|
||||
friend auto downcast_poison_pill(typename T::downcast_base)
|
||||
{ return true; }
|
||||
friend auto downcast_poison_pill(typename T::downcast_base) { return true; }
|
||||
};
|
||||
|
||||
enum class downcast_mode {
|
||||
off = 0, // no downcasting at all
|
||||
on = 1, // downcasting always forced -> compile-time errors in case of duplicated definitions
|
||||
automatic = 2 // downcasting automatically enabled if no collisions are present
|
||||
off = 0, // no downcasting at all
|
||||
on = 1, // downcasting always forced -> compile-time errors in case of duplicated definitions
|
||||
automatic = 2 // downcasting automatically enabled if no collisions are present
|
||||
};
|
||||
|
||||
|
||||
template<typename Target, Downcastable T, downcast_mode mode = static_cast<downcast_mode>(UNITS_DOWNCAST_MODE)>
|
||||
struct downcast_dispatch : std::conditional_t<mode == downcast_mode::off, T,
|
||||
struct downcast_dispatch :
|
||||
std::conditional_t<mode == downcast_mode::off, T,
|
||||
#ifdef UNITS_COMP_MSVC
|
||||
downcast_child<Target, T>> {};
|
||||
downcast_child<Target, T>> {
|
||||
};
|
||||
#else
|
||||
std::conditional_t<mode == downcast_mode::automatic && has_downcast_guide<T>,
|
||||
downcast_poison<T>, downcast_child<Target, T>>> {};
|
||||
std::conditional_t<mode == downcast_mode::automatic && has_downcast_guide<T>, downcast_poison<T>,
|
||||
downcast_child<Target, T>>> {
|
||||
};
|
||||
#endif
|
||||
|
||||
namespace detail {
|
||||
@@ -89,7 +89,7 @@ namespace detail {
|
||||
template<typename T>
|
||||
constexpr auto downcast_impl()
|
||||
{
|
||||
if constexpr(has_downcast_guide<downcast_base<T>> && !has_downcast_poison_pill<downcast_base<T>>)
|
||||
if constexpr (has_downcast_guide<downcast_base<T>> && !has_downcast_poison_pill<downcast_base<T>>)
|
||||
return decltype(downcast_guide(std::declval<downcast_base<T>>()))();
|
||||
else
|
||||
return std::type_identity<T>();
|
||||
|
||||
+17
-16
@@ -22,11 +22,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <units/bits/external/hacks.h> // IWYU pragma: keep
|
||||
#include <units/bits/external/hacks.h> // IWYU pragma: keep
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include <cstdlib>
|
||||
#include <compare>
|
||||
#include <cstdlib>
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#include <cstddef>
|
||||
@@ -37,7 +37,7 @@ namespace units {
|
||||
|
||||
/**
|
||||
* @brief A compile-time fixed string
|
||||
*
|
||||
*
|
||||
* @tparam CharT Character type to be used by the string
|
||||
* @tparam N The size of the string
|
||||
*/
|
||||
@@ -70,7 +70,7 @@ struct basic_fixed_string {
|
||||
|
||||
template<std::size_t N2>
|
||||
[[nodiscard]] constexpr friend basic_fixed_string<CharT, N + N2> operator+(
|
||||
const basic_fixed_string& lhs, const basic_fixed_string<CharT, N2>& rhs) noexcept
|
||||
const basic_fixed_string& lhs, const basic_fixed_string<CharT, N2>& rhs) noexcept
|
||||
{
|
||||
CharT txt[N + N2 + 1] = {};
|
||||
|
||||
@@ -82,21 +82,23 @@ struct basic_fixed_string {
|
||||
|
||||
[[nodiscard]] constexpr bool operator==(const basic_fixed_string& other) const
|
||||
{
|
||||
if (size() != other.size())
|
||||
return false;
|
||||
if (size() != other.size()) return false;
|
||||
for (size_t i = 0; i != size(); ++i) {
|
||||
if ((*this)[i] != other[i])
|
||||
return false;
|
||||
if ((*this)[i] != other[i]) return false;
|
||||
}
|
||||
return true;
|
||||
// return std::ranges::equal(*this, other);
|
||||
}
|
||||
|
||||
template<std::size_t N2>
|
||||
[[nodiscard]] friend constexpr bool operator==(const basic_fixed_string&, const basic_fixed_string<CharT, N2>&) { return false; }
|
||||
[[nodiscard]] friend constexpr bool operator==(const basic_fixed_string&, const basic_fixed_string<CharT, N2>&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template<std::size_t N2>
|
||||
[[nodiscard]] friend constexpr auto operator<=>(const basic_fixed_string& lhs, const basic_fixed_string<CharT, N2>& rhs)
|
||||
[[nodiscard]] friend constexpr auto operator<=>(const basic_fixed_string& lhs,
|
||||
const basic_fixed_string<CharT, N2>& rhs)
|
||||
{
|
||||
auto first1 = lhs.begin();
|
||||
const auto last1 = lhs.end();
|
||||
@@ -105,12 +107,11 @@ struct basic_fixed_string {
|
||||
auto comp = std::compare_three_way();
|
||||
|
||||
for (; first1 != last1 && first2 != last2; ++first1, ++first2)
|
||||
if (auto cmp = comp(*first1, *first2); cmp != 0)
|
||||
return cmp;
|
||||
|
||||
return first1 != last1 ? std::strong_ordering::greater :
|
||||
first2 != last2 ? std::strong_ordering::less :
|
||||
std::strong_ordering::equal;
|
||||
if (auto cmp = comp(*first1, *first2); cmp != 0) return cmp;
|
||||
|
||||
return first1 != last1 ? std::strong_ordering::greater
|
||||
: first2 != last2 ? std::strong_ordering::less
|
||||
: std::strong_ordering::equal;
|
||||
// return std::lexicographical_compare_three_way(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
|
||||
}
|
||||
};
|
||||
|
||||
+22
-27
@@ -39,9 +39,9 @@
|
||||
#define UNITS_DIAGNOSTIC_PUSH UNITS_PRAGMA(GCC diagnostic push)
|
||||
#define UNITS_DIAGNOSTIC_POP UNITS_PRAGMA(GCC diagnostic pop)
|
||||
#define UNITS_DIAGNOSTIC_IGNORE_PRAGMAS UNITS_PRAGMA(GCC diagnostic ignored "-Wpragmas")
|
||||
#define UNITS_DIAGNOSTIC_IGNORE(X) \
|
||||
UNITS_DIAGNOSTIC_IGNORE_PRAGMAS \
|
||||
UNITS_PRAGMA(GCC diagnostic ignored "-Wunknown-pragmas") \
|
||||
#define UNITS_DIAGNOSTIC_IGNORE(X) \
|
||||
UNITS_DIAGNOSTIC_IGNORE_PRAGMAS \
|
||||
UNITS_PRAGMA(GCC diagnostic ignored "-Wunknown-pragmas") \
|
||||
UNITS_PRAGMA(GCC diagnostic ignored "-Wunknown-warning-option") \
|
||||
UNITS_PRAGMA(GCC diagnostic ignored X)
|
||||
#define UNITS_DIAGNOSTIC_IGNORE_EXPR_ALWAYS_TF
|
||||
@@ -87,8 +87,8 @@
|
||||
|
||||
#endif
|
||||
|
||||
#include <concepts>
|
||||
#include <compare>
|
||||
#include <concepts>
|
||||
|
||||
#if UNITS_COMP_MSVC || UNITS_COMP_CLANG
|
||||
|
||||
@@ -130,14 +130,14 @@ using concepts::totally_ordered;
|
||||
using ranges::compare_three_way;
|
||||
|
||||
using ranges::input_iterator;
|
||||
using ranges::sentinel_for;
|
||||
using ranges::iter_value_t;
|
||||
using ranges::sentinel_for;
|
||||
|
||||
namespace ranges {
|
||||
|
||||
using ::ranges::begin;
|
||||
using ::ranges::end;
|
||||
using ::ranges::distance;
|
||||
using ::ranges::end;
|
||||
|
||||
using ::ranges::input_range;
|
||||
using ::ranges::range_value_t;
|
||||
@@ -145,7 +145,7 @@ using ::ranges::range_value_t;
|
||||
using ::ranges::lower_bound;
|
||||
using ::ranges::transform;
|
||||
|
||||
}
|
||||
} // namespace ranges
|
||||
|
||||
// missing in Range-v3
|
||||
template<class T>
|
||||
@@ -153,15 +153,10 @@ concept floating_point = std::is_floating_point_v<T>;
|
||||
|
||||
template<class T>
|
||||
concept default_initializable =
|
||||
std::constructible_from<T> &&
|
||||
requires { T{}; } &&
|
||||
requires { ::new (static_cast<void*>(nullptr)) T; };
|
||||
std::constructible_from<T> && requires { T{}; } && requires { ::new (static_cast<void*>(nullptr)) T; };
|
||||
|
||||
template<class F, class... Args>
|
||||
concept invocable =
|
||||
requires(F&& f, Args&&... args) {
|
||||
std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
|
||||
};
|
||||
concept invocable = requires(F&& f, Args&&... args) { std::invoke(std::forward<F>(f), std::forward<Args>(args)...); };
|
||||
|
||||
template<class F, class... Args>
|
||||
concept regular_invocable = invocable<F, Args...>;
|
||||
@@ -172,44 +167,44 @@ constexpr bool cmp_equal(T t, U u) noexcept
|
||||
using UT = std::make_unsigned_t<T>;
|
||||
using UU = std::make_unsigned_t<U>;
|
||||
if constexpr (std::is_signed_v<T> == std::is_signed_v<U>)
|
||||
return t == u;
|
||||
return t == u;
|
||||
else if constexpr (std::is_signed_v<T>)
|
||||
return t < 0 ? false : UT(t) == u;
|
||||
return t < 0 ? false : UT(t) == u;
|
||||
else
|
||||
return u < 0 ? false : t == UU(u);
|
||||
return u < 0 ? false : t == UU(u);
|
||||
}
|
||||
|
||||
|
||||
template<class T, class U>
|
||||
constexpr bool cmp_not_equal(T t, U u) noexcept
|
||||
{
|
||||
return !cmp_equal(t, u);
|
||||
}
|
||||
|
||||
|
||||
template<class T, class U>
|
||||
constexpr bool cmp_less(T t, U u) noexcept
|
||||
{
|
||||
using UT = std::make_unsigned_t<T>;
|
||||
using UU = std::make_unsigned_t<U>;
|
||||
if constexpr (std::is_signed_v<T> == std::is_signed_v<U>)
|
||||
return t < u;
|
||||
return t < u;
|
||||
else if constexpr (std::is_signed_v<T>)
|
||||
return t < 0 ? true : UT(t) < u;
|
||||
return t < 0 ? true : UT(t) < u;
|
||||
else
|
||||
return u < 0 ? false : t < UU(u);
|
||||
return u < 0 ? false : t < UU(u);
|
||||
}
|
||||
|
||||
|
||||
template<class T, class U>
|
||||
constexpr bool cmp_greater(T t, U u) noexcept
|
||||
{
|
||||
return cmp_less(u, t);
|
||||
}
|
||||
|
||||
|
||||
template<class T, class U>
|
||||
constexpr bool cmp_less_equal(T t, U u) noexcept
|
||||
{
|
||||
return !cmp_greater(t, u);
|
||||
}
|
||||
|
||||
|
||||
template<class T, class U>
|
||||
constexpr bool cmp_greater_equal(T t, U u) noexcept
|
||||
{
|
||||
@@ -220,7 +215,7 @@ template<class R, class T>
|
||||
constexpr bool in_range(T t) noexcept
|
||||
{
|
||||
return std::cmp_greater_equal(t, std::numeric_limits<R>::min()) &&
|
||||
std::cmp_less_equal(t, std::numeric_limits<R>::max());
|
||||
std::cmp_less_equal(t, std::numeric_limits<R>::max());
|
||||
}
|
||||
|
||||
#elif UNITS_LIBCXX < 14000
|
||||
@@ -233,4 +228,4 @@ using ::ranges::compare_three_way;
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace std
|
||||
} // namespace std
|
||||
|
||||
+23
-13
@@ -28,19 +28,29 @@
|
||||
namespace units::detail {
|
||||
|
||||
template<std::intmax_t Value>
|
||||
requires (0 <= Value) && (Value < 10)
|
||||
requires(0 <= Value) && (Value < 10)
|
||||
inline constexpr basic_fixed_string superscript_number = "";
|
||||
|
||||
template<> inline constexpr basic_fixed_string superscript_number<0> = "\u2070";
|
||||
template<> inline constexpr basic_fixed_string superscript_number<1> = "\u00b9";
|
||||
template<> inline constexpr basic_fixed_string superscript_number<2> = "\u00b2";
|
||||
template<> inline constexpr basic_fixed_string superscript_number<3> = "\u00b3";
|
||||
template<> inline constexpr basic_fixed_string superscript_number<4> = "\u2074";
|
||||
template<> inline constexpr basic_fixed_string superscript_number<5> = "\u2075";
|
||||
template<> inline constexpr basic_fixed_string superscript_number<6> = "\u2076";
|
||||
template<> inline constexpr basic_fixed_string superscript_number<7> = "\u2077";
|
||||
template<> inline constexpr basic_fixed_string superscript_number<8> = "\u2078";
|
||||
template<> inline constexpr basic_fixed_string superscript_number<9> = "\u2079";
|
||||
template<>
|
||||
inline constexpr basic_fixed_string superscript_number<0> = "\u2070";
|
||||
template<>
|
||||
inline constexpr basic_fixed_string superscript_number<1> = "\u00b9";
|
||||
template<>
|
||||
inline constexpr basic_fixed_string superscript_number<2> = "\u00b2";
|
||||
template<>
|
||||
inline constexpr basic_fixed_string superscript_number<3> = "\u00b3";
|
||||
template<>
|
||||
inline constexpr basic_fixed_string superscript_number<4> = "\u2074";
|
||||
template<>
|
||||
inline constexpr basic_fixed_string superscript_number<5> = "\u2075";
|
||||
template<>
|
||||
inline constexpr basic_fixed_string superscript_number<6> = "\u2076";
|
||||
template<>
|
||||
inline constexpr basic_fixed_string superscript_number<7> = "\u2077";
|
||||
template<>
|
||||
inline constexpr basic_fixed_string superscript_number<8> = "\u2078";
|
||||
template<>
|
||||
inline constexpr basic_fixed_string superscript_number<9> = "\u2079";
|
||||
|
||||
inline constexpr basic_symbol_text superscript_minus("\u207b", "-");
|
||||
|
||||
@@ -49,9 +59,9 @@ inline constexpr basic_symbol_text superscript_prefix("", "^");
|
||||
template<std::intmax_t Value>
|
||||
constexpr auto superscript_helper()
|
||||
{
|
||||
if constexpr(Value < 0)
|
||||
if constexpr (Value < 0)
|
||||
return superscript_minus + superscript_helper<-Value>();
|
||||
else if constexpr(Value < 10)
|
||||
else if constexpr (Value < 10)
|
||||
return basic_symbol_text(superscript_number<Value>, basic_fixed_string(static_cast<char>('0' + Value)));
|
||||
else
|
||||
return superscript_helper<Value / 10>() + superscript_helper<Value % 10>();
|
||||
|
||||
+6
-5
@@ -111,7 +111,7 @@ struct split_impl<List, Idx, N> {
|
||||
};
|
||||
|
||||
template<template<typename...> typename List, std::size_t Idx, std::size_t N, typename T, typename... Rest>
|
||||
requires (Idx < N)
|
||||
requires(Idx < N)
|
||||
struct split_impl<List, Idx, N, T, Rest...> : split_impl<List, Idx + 1, N, Rest...> {
|
||||
using base = split_impl<List, Idx + 1, N, Rest...>;
|
||||
using first_list = TYPENAME type_list_push_front_impl<typename base::first_list, T>::type;
|
||||
@@ -144,8 +144,7 @@ template<TypeList List>
|
||||
struct type_list_split_half;
|
||||
|
||||
template<template<typename...> typename List, typename... Types>
|
||||
struct type_list_split_half<List<Types...>> : type_list_split<List<Types...>, (sizeof...(Types) + 1) / 2> {
|
||||
};
|
||||
struct type_list_split_half<List<Types...>> : type_list_split<List<Types...>, (sizeof...(Types) + 1) / 2> {};
|
||||
|
||||
// merge_sorted
|
||||
|
||||
@@ -174,13 +173,15 @@ template<template<typename...> typename List, typename Lhs1, typename... LhsRest
|
||||
template<typename, typename> typename Pred>
|
||||
requires Pred<Lhs1, Rhs1>::value
|
||||
struct type_list_merge_sorted_impl<List<Lhs1, LhsRest...>, List<Rhs1, RhsRest...>, Pred> {
|
||||
using type = TYPENAME type_list_push_front_impl<typename type_list_merge_sorted_impl<List<LhsRest...>, List<Rhs1, RhsRest...>, Pred>::type, Lhs1>::type;
|
||||
using type = TYPENAME type_list_push_front_impl<
|
||||
typename type_list_merge_sorted_impl<List<LhsRest...>, List<Rhs1, RhsRest...>, Pred>::type, Lhs1>::type;
|
||||
};
|
||||
|
||||
template<template<typename...> typename List, typename Lhs1, typename... LhsRest, typename Rhs1, typename... RhsRest,
|
||||
template<typename, typename> typename Pred>
|
||||
struct type_list_merge_sorted_impl<List<Lhs1, LhsRest...>, List<Rhs1, RhsRest...>, Pred> {
|
||||
using type = TYPENAME type_list_push_front_impl<typename type_list_merge_sorted_impl<List<Lhs1, LhsRest...>, List<RhsRest...>, Pred>::type, Rhs1>::type;
|
||||
using type = TYPENAME type_list_push_front_impl<
|
||||
typename type_list_merge_sorted_impl<List<Lhs1, LhsRest...>, List<RhsRest...>, Pred>::type, Rhs1>::type;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
|
||||
namespace units::detail {
|
||||
|
||||
|
||||
@@ -36,12 +36,16 @@ template<typename Dim, template<typename...> typename DimTemplate>
|
||||
inline constexpr bool same_exponents_of = false;
|
||||
|
||||
template<Exponent... Es, template<typename...> typename DimTemplate>
|
||||
inline constexpr bool same_exponents_of<unknown_dimension<Es...>, DimTemplate> = requires { typename DimTemplate<unknown_dimension<Es...>, unknown_coherent_unit, typename Es::dimension...>; } && std::same_as<exponent_list<Es...>, typename DimTemplate<unknown_dimension<Es...>, unknown_coherent_unit, typename Es::dimension...>::recipe>;
|
||||
inline constexpr bool same_exponents_of<unknown_dimension<Es...>, DimTemplate> =
|
||||
requires { typename DimTemplate<unknown_dimension<Es...>, unknown_coherent_unit, typename Es::dimension...>; } &&
|
||||
std::same_as<exponent_list<Es...>, typename DimTemplate<unknown_dimension<Es...>, unknown_coherent_unit,
|
||||
typename Es::dimension...>::recipe>;
|
||||
|
||||
} // namespace detail
|
||||
} // namespace detail
|
||||
|
||||
template<typename Dim, template<typename...> typename DimTemplate>
|
||||
concept EquivalentUnknownDimensionOfT = Dimension<Dim> && is_derived_from_specialization_of<Dim, unknown_dimension> && detail::same_exponents_of<Dim, DimTemplate>;
|
||||
concept EquivalentUnknownDimensionOfT = Dimension<Dim> && is_derived_from_specialization_of<Dim, unknown_dimension> &&
|
||||
detail::same_exponents_of<Dim, DimTemplate>;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -56,7 +60,7 @@ concept DimensionOfT = Dimension<Dim> && (is_derived_from_specialization_of<Dim,
|
||||
#if UNITS_DOWNCAST_MODE == 0
|
||||
|| EquivalentUnknownDimensionOfT<Dim, DimTemplate>
|
||||
#endif
|
||||
);
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief A concept matching all quantities with provided dimension class template
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gsl/gsl-lite.hpp>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
@@ -29,7 +30,6 @@
|
||||
#include <numeric>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <gsl/gsl-lite.hpp>
|
||||
|
||||
namespace units::detail {
|
||||
|
||||
@@ -106,9 +106,9 @@ template<typename T>
|
||||
// (a 10^e) mod b -> [ (a mod b) (10^e mod b) ] mod b
|
||||
|
||||
return std::gcd(
|
||||
b, static_cast<std::intmax_t>(mulmod(static_cast<std::uint64_t>(a % b),
|
||||
modpow(10, static_cast<std::uint64_t>(e), static_cast<std::uint64_t>(b)),
|
||||
static_cast<std::uint64_t>(b))));
|
||||
b, static_cast<std::intmax_t>(mulmod(static_cast<std::uint64_t>(a % b),
|
||||
modpow(10, static_cast<std::uint64_t>(e), static_cast<std::uint64_t>(b)),
|
||||
static_cast<std::uint64_t>(b))));
|
||||
}
|
||||
|
||||
constexpr void cwap(std::intmax_t& lhs, std::intmax_t& rhs)
|
||||
@@ -119,8 +119,8 @@ constexpr void cwap(std::intmax_t& lhs, std::intmax_t& rhs)
|
||||
}
|
||||
|
||||
// Computes the rational gcd of n1/d1 x 10^e1 and n2/d2 x 10^e2
|
||||
[[nodiscard]] constexpr auto gcd_frac(std::intmax_t n1, std::intmax_t d1, std::intmax_t e1, std::intmax_t n2, std::intmax_t d2,
|
||||
std::intmax_t e2) noexcept
|
||||
[[nodiscard]] constexpr auto gcd_frac(std::intmax_t n1, std::intmax_t d1, std::intmax_t e1, std::intmax_t n2,
|
||||
std::intmax_t d2, std::intmax_t e2) noexcept
|
||||
{
|
||||
// Short cut for equal ratios
|
||||
if (n1 == n2 && d1 == d2 && e1 == e2) {
|
||||
@@ -153,7 +153,7 @@ constexpr void cwap(std::intmax_t& lhs, std::intmax_t& rhs)
|
||||
|
||||
constexpr void normalize(std::intmax_t& num, std::intmax_t& den, std::intmax_t& exp)
|
||||
{
|
||||
if(num == 0) {
|
||||
if (num == 0) {
|
||||
den = 1;
|
||||
exp = 0;
|
||||
return;
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace units::detail {
|
||||
|
||||
template<std::intmax_t N, typename F>
|
||||
requires gt_zero<N>
|
||||
[[nodiscard]] constexpr std::intmax_t iroot_impl(std::intmax_t v, F const& pow_function) noexcept
|
||||
[[nodiscard]] constexpr std::intmax_t iroot_impl(std::intmax_t v, const F& pow_function) noexcept
|
||||
{
|
||||
if constexpr (N == 1) {
|
||||
return v;
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
|
||||
#include <units/bits/derived_symbol_text.h>
|
||||
#include <units/bits/external/text_tools.h>
|
||||
#include <units/prefix.h>
|
||||
#include <units/derived_dimension.h>
|
||||
#include <units/prefix.h>
|
||||
|
||||
namespace units::detail {
|
||||
|
||||
@@ -34,33 +34,25 @@ inline constexpr basic_symbol_text base_multiplier("\u00D7 10", "x 10");
|
||||
template<ratio R>
|
||||
constexpr auto ratio_text()
|
||||
{
|
||||
if constexpr(R.num == 1 && R.den == 1 && R.exp != 0) {
|
||||
if constexpr (R.num == 1 && R.den == 1 && R.exp != 0) {
|
||||
return base_multiplier + superscript<R.exp>();
|
||||
}
|
||||
else if constexpr(R.num != 1 || R.den != 1 || R.exp != 0) {
|
||||
} else if constexpr (R.num != 1 || R.den != 1 || R.exp != 0) {
|
||||
auto txt = basic_fixed_string("[") + regular<R.num>();
|
||||
if constexpr(R.den == 1) {
|
||||
if constexpr(R.exp == 0) {
|
||||
if constexpr (R.den == 1) {
|
||||
if constexpr (R.exp == 0) {
|
||||
return txt + basic_fixed_string("]");
|
||||
} else {
|
||||
return txt + " " + base_multiplier + superscript<R.exp>() + basic_fixed_string("]");
|
||||
}
|
||||
else {
|
||||
return txt + " " + base_multiplier + superscript<R.exp>() +
|
||||
basic_fixed_string("]");
|
||||
} else {
|
||||
if constexpr (R.exp == 0) {
|
||||
return txt + basic_fixed_string("/") + regular<R.den>() + basic_fixed_string("]");
|
||||
} else {
|
||||
return txt + basic_fixed_string("/") + regular<R.den>() + " " + base_multiplier + superscript<R.exp>() +
|
||||
basic_fixed_string("]");
|
||||
}
|
||||
}
|
||||
else {
|
||||
if constexpr(R.exp == 0) {
|
||||
return txt + basic_fixed_string("/") + regular<R.den>() +
|
||||
basic_fixed_string("]");
|
||||
}
|
||||
else {
|
||||
return txt + basic_fixed_string("/") + regular<R.den>() +
|
||||
" " + base_multiplier + superscript<R.exp>() +
|
||||
basic_fixed_string("]");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return basic_fixed_string("");
|
||||
}
|
||||
}
|
||||
@@ -68,32 +60,29 @@ constexpr auto ratio_text()
|
||||
template<ratio R, typename PrefixFamily, std::size_t SymbolLen>
|
||||
constexpr auto prefix_or_ratio_text()
|
||||
{
|
||||
if constexpr(R.num == 1 && R.den == 1 && R.exp == 0) {
|
||||
if constexpr (R.num == 1 && R.den == 1 && R.exp == 0) {
|
||||
// no ratio/prefix
|
||||
return basic_fixed_string("");
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if constexpr (!is_same_v<PrefixFamily, no_prefix>) {
|
||||
// try to form a prefix
|
||||
using prefix = downcast<detail::prefix_base<PrefixFamily, R>>;
|
||||
|
||||
if constexpr(!is_same_v<prefix, prefix_base<PrefixFamily, R>>) {
|
||||
if constexpr (!is_same_v<prefix, prefix_base<PrefixFamily, R>>) {
|
||||
// print as a prefixed unit
|
||||
return prefix::symbol;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// print as a ratio of the coherent unit
|
||||
constexpr auto txt = ratio_text<R>();
|
||||
if constexpr(SymbolLen > 0 && txt.standard().size() > 0)
|
||||
if constexpr (SymbolLen > 0 && txt.standard().size() > 0)
|
||||
return txt + basic_fixed_string(" ");
|
||||
else
|
||||
return txt;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// print as a ratio of the coherent unit
|
||||
constexpr auto txt = ratio_text<R>();
|
||||
if constexpr(SymbolLen > 0 && txt.standard().size() > 0)
|
||||
if constexpr (SymbolLen > 0 && txt.standard().size() > 0)
|
||||
return txt + basic_fixed_string(" ");
|
||||
else
|
||||
return txt;
|
||||
@@ -104,7 +93,8 @@ constexpr auto prefix_or_ratio_text()
|
||||
template<typename... Es, std::size_t... Idxs>
|
||||
constexpr auto derived_dimension_unit_text(exponent_list<Es...>, std::index_sequence<Idxs...>)
|
||||
{
|
||||
return (exp_text<Es, dimension_unit<typename Es::dimension>::symbol, negative_exp_count<Es...>, Idxs>() + ... + basic_symbol_text(basic_fixed_string("")));
|
||||
return (exp_text<Es, dimension_unit<typename Es::dimension>::symbol, negative_exp_count<Es...>, Idxs>() + ... +
|
||||
basic_symbol_text(basic_fixed_string("")));
|
||||
}
|
||||
|
||||
template<typename... Es>
|
||||
@@ -120,10 +110,9 @@ template<Exponent Exp>
|
||||
constexpr auto exponent_list_with_named_units(Exp)
|
||||
{
|
||||
using dim = TYPENAME Exp::dimension;
|
||||
if constexpr(dimension_unit<dim>::is_named) {
|
||||
if constexpr (dimension_unit<dim>::is_named) {
|
||||
return exponent_list<Exp>();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
using recipe = TYPENAME dim::recipe;
|
||||
return exponent_list_with_named_units(recipe());
|
||||
}
|
||||
@@ -135,10 +124,7 @@ constexpr auto exponent_list_with_named_units(exponent_list<Es...>)
|
||||
return type_list_join<decltype(exponent_list_with_named_units(Es()))...>();
|
||||
}
|
||||
|
||||
constexpr auto exponent_list_with_named_units(exponent_list<> empty)
|
||||
{
|
||||
return empty;
|
||||
}
|
||||
constexpr auto exponent_list_with_named_units(exponent_list<> empty) { return empty; }
|
||||
|
||||
template<Dimension Dim>
|
||||
constexpr auto derived_dimension_unit_text()
|
||||
@@ -149,29 +135,31 @@ constexpr auto derived_dimension_unit_text()
|
||||
|
||||
template<typename T>
|
||||
// TODO replace with `inline constexpr bool has_symbol` when MSVC cathes up
|
||||
concept has_symbol = requires{ T::symbol; };
|
||||
concept has_symbol = requires { T::symbol; };
|
||||
|
||||
template<Dimension Dim, Unit U>
|
||||
constexpr auto unit_text()
|
||||
{
|
||||
if constexpr(has_symbol<U>) {
|
||||
if constexpr (has_symbol<U>) {
|
||||
// already has a symbol so print it
|
||||
return U::symbol;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// print as a prefix or ratio of a coherent unit
|
||||
using coherent_unit = dimension_unit<Dim>;
|
||||
|
||||
if constexpr(has_symbol<coherent_unit>) {
|
||||
if constexpr (has_symbol<coherent_unit>) {
|
||||
// use predefined coherent unit symbol
|
||||
constexpr auto symbol_text = coherent_unit::symbol;
|
||||
constexpr auto prefix_txt = prefix_or_ratio_text<U::ratio / coherent_unit::ratio, typename U::reference::prefix_family, symbol_text.standard().size()>();
|
||||
constexpr auto prefix_txt =
|
||||
prefix_or_ratio_text<U::ratio / coherent_unit::ratio, typename U::reference::prefix_family,
|
||||
symbol_text.standard().size()>();
|
||||
return prefix_txt + symbol_text;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// use derived dimension ingredients to create a unit symbol
|
||||
constexpr auto symbol_text = derived_dimension_unit_text<Dim>();
|
||||
constexpr auto prefix_txt = prefix_or_ratio_text<U::ratio / coherent_unit::ratio, typename U::reference::prefix_family, symbol_text.standard().size()>();
|
||||
constexpr auto prefix_txt =
|
||||
prefix_or_ratio_text<U::ratio / coherent_unit::ratio, typename U::reference::prefix_family,
|
||||
symbol_text.standard().size()>();
|
||||
return prefix_txt + symbol_text;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,14 +40,15 @@ struct quantity_like_traits<std::chrono::duration<Rep, Period>> {
|
||||
};
|
||||
|
||||
template<typename C>
|
||||
struct clock_origin : point_origin<isq::si::dim_time> { };
|
||||
struct clock_origin : point_origin<isq::si::dim_time> {};
|
||||
|
||||
template<typename C, typename Rep, typename Period>
|
||||
struct quantity_point_like_traits<std::chrono::time_point<C, std::chrono::duration<Rep, Period>>> {
|
||||
using origin = clock_origin<C>;
|
||||
using unit = downcast_unit<typename origin::dimension, ratio(Period::num, Period::den)>;
|
||||
using rep = Rep;
|
||||
[[nodiscard]] static constexpr auto relative(const std::chrono::time_point<C, std::chrono::duration<Rep, Period>>& qp) {
|
||||
[[nodiscard]] static constexpr auto relative(const std::chrono::time_point<C, std::chrono::duration<Rep, Period>>& qp)
|
||||
{
|
||||
return qp.time_since_epoch();
|
||||
}
|
||||
};
|
||||
@@ -61,17 +62,16 @@ constexpr std::intmax_t pow_10(std::intmax_t v)
|
||||
{
|
||||
gsl_Expects(v > 0);
|
||||
std::intmax_t res = 1;
|
||||
for(std::intmax_t i = 0; i < v; i++)
|
||||
res *= 10;
|
||||
for (std::intmax_t i = 0; i < v; i++) res *= 10;
|
||||
return res;
|
||||
}
|
||||
|
||||
template<ratio R>
|
||||
constexpr auto to_std_ratio_impl()
|
||||
{
|
||||
if constexpr(R.exp == 0)
|
||||
if constexpr (R.exp == 0)
|
||||
return std::ratio<R.num, R.den>{};
|
||||
else if constexpr(R.exp > 0)
|
||||
else if constexpr (R.exp > 0)
|
||||
return std::ratio<R.num * pow_10(R.exp), R.den>{};
|
||||
else
|
||||
return std::ratio<R.num, R.den * pow_10(-R.exp)>{};
|
||||
@@ -96,4 +96,4 @@ template<typename C, typename U, typename Rep>
|
||||
return ret_type(to_std_duration(qp.relative()));
|
||||
}
|
||||
|
||||
} // namespace units
|
||||
} // namespace units
|
||||
|
||||
@@ -30,11 +30,11 @@ namespace units {
|
||||
|
||||
/**
|
||||
* @brief Specifies if a value of a type should be treated as a floating-point value
|
||||
*
|
||||
*
|
||||
* This type trait should be specialized for a custom representation type to specify
|
||||
* that values fo this type should be treated by the library as a floating-point ones
|
||||
* which will enable implicit conversions between quantities.
|
||||
*
|
||||
*
|
||||
* @tparam Rep a representation type for which a type trait is defined
|
||||
*/
|
||||
template<typename Rep>
|
||||
@@ -46,40 +46,56 @@ inline constexpr bool treat_as_floating_point<T> = treat_as_floating_point<typen
|
||||
|
||||
/**
|
||||
* @brief A type trait that defines zero, one, min, and max for a representation type
|
||||
*
|
||||
*
|
||||
* The zero, one, min, and max member functions in units::quantity forward their work to
|
||||
* these methods. This type can be specialized if the representation Rep requires a specific
|
||||
* implementation to return these quantity objects.
|
||||
*
|
||||
*
|
||||
* @tparam Rep a representation type for which a type trait is defined
|
||||
*/
|
||||
template<typename Rep>
|
||||
struct quantity_values {
|
||||
static constexpr Rep zero() noexcept
|
||||
requires std::constructible_from<Rep, int>
|
||||
{ return Rep(0); }
|
||||
{
|
||||
return Rep(0);
|
||||
}
|
||||
|
||||
static constexpr Rep one() noexcept
|
||||
requires std::constructible_from<Rep, int>
|
||||
{ return Rep(1); }
|
||||
{
|
||||
return Rep(1);
|
||||
}
|
||||
|
||||
static constexpr Rep min() noexcept
|
||||
requires requires { { std::numeric_limits<Rep>::lowest() } -> std::same_as<Rep>; }
|
||||
{ return std::numeric_limits<Rep>::lowest(); }
|
||||
requires requires {
|
||||
{
|
||||
std::numeric_limits<Rep>::lowest()
|
||||
} -> std::same_as<Rep>;
|
||||
}
|
||||
{
|
||||
return std::numeric_limits<Rep>::lowest();
|
||||
}
|
||||
|
||||
static constexpr Rep max() noexcept
|
||||
requires requires { { std::numeric_limits<Rep>::max() } -> std::same_as<Rep>; }
|
||||
{ return std::numeric_limits<Rep>::max(); }
|
||||
requires requires {
|
||||
{
|
||||
std::numeric_limits<Rep>::max()
|
||||
} -> std::same_as<Rep>;
|
||||
}
|
||||
{
|
||||
return std::numeric_limits<Rep>::max();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Provides support for external quantity-like types
|
||||
*
|
||||
*
|
||||
* The type trait should provide the following nested type aliases: @c dimension, @c unit, @c rep,
|
||||
* and a static member function @c number(T) that will return the raw value of the quantity.
|
||||
*
|
||||
*
|
||||
* Usage example can be found in @c units/chrono.h header file.
|
||||
*
|
||||
*
|
||||
* @tparam T the type to provide support for
|
||||
*/
|
||||
template<typename T>
|
||||
@@ -87,15 +103,15 @@ struct quantity_like_traits;
|
||||
|
||||
/**
|
||||
* @brief Provides support for external quantity point-like types
|
||||
*
|
||||
*
|
||||
* The type trait should provide the following nested type aliases: @c origin, @c unit, @c rep,
|
||||
* and a static member function @c relative(T) that will return the quantity-like value of the quantity point.
|
||||
*
|
||||
*
|
||||
* Usage example can be found in @c units/chrono.h header file.
|
||||
*
|
||||
*
|
||||
* @tparam T the type to provide support for
|
||||
*/
|
||||
template<typename T>
|
||||
struct quantity_point_like_traits;
|
||||
|
||||
} // namespace units
|
||||
} // namespace units
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace detail {
|
||||
|
||||
/**
|
||||
* @brief Converts user provided derived dimension specification into a valid units::derived_dimension_base definition
|
||||
*
|
||||
*
|
||||
* User provided definition of a derived dimension may contain the same base dimension repeated more than once on the
|
||||
* list possibly hidden in other derived units provided by the user. The process here should:
|
||||
* 1. Extract derived dimensions into exponents of base dimensions.
|
||||
@@ -49,23 +49,24 @@ namespace detail {
|
||||
* this base dimension.
|
||||
*/
|
||||
template<Exponent... Es>
|
||||
using make_dimension = TYPENAME to_derived_dimension_base<typename dim_consolidate<type_list_sort<typename dim_unpack<Es...>::type, exponent_less>>::type>::type;
|
||||
using make_dimension = TYPENAME to_derived_dimension_base<
|
||||
typename dim_consolidate<type_list_sort<typename dim_unpack<Es...>::type, exponent_less>>::type>::type;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* @brief The list of exponents of dimensions (both base and derived) provided by the user
|
||||
*
|
||||
*
|
||||
* This is the user's interface to create derived dimensions. Exponents list can contain powers of factors of both
|
||||
* base and derived dimensions. This is called a "recipe" of the dimension and among others is used to print
|
||||
* unnamed coherent units of this dimension.
|
||||
*
|
||||
*
|
||||
* Coherent unit is a unit that, for a given system of quantities and for a chosen set of base units, is a product
|
||||
* of powers of base units with no other proportionality factor than one.
|
||||
*
|
||||
* The implementation is responsible for unpacking all of the dimensions into a list containing only base dimensions
|
||||
* and their factors and putting them to derived_dimension_base class template.
|
||||
*
|
||||
*
|
||||
* Sometimes units of equivalent quantities in different systems of units do not share the same reference so they
|
||||
* cannot be easily converted to each other. An example can be a pressure for which a coherent unit in SI is pascal
|
||||
* and in CGS barye. Those two units are not directly related with each other with some ratio. As they both are
|
||||
@@ -75,7 +76,7 @@ using make_dimension = TYPENAME to_derived_dimension_base<typename dim_consolida
|
||||
* base_units_ratio of two quantities of equivalent dimensions in two different systems gives a ratio between their
|
||||
* coherent units. Alternatively, the user would always have to directly define a barye in terms of pascal or vice
|
||||
* versa.
|
||||
*
|
||||
*
|
||||
* @tparam Child inherited class type used by the downcasting facility (CRTP Idiom)
|
||||
* @tparam U a coherent unit of a derived dimension
|
||||
* @tparam Es the list of exponents of ingredient dimensions
|
||||
|
||||
@@ -60,7 +60,7 @@ template<std::intmax_t Num, std::intmax_t Den = 1, Quantity Q>
|
||||
using unit = downcast_unit<dim, pow<Num, Den>(Q::unit::ratio)>;
|
||||
using std::pow;
|
||||
return quantity<dim, unit, rep>(
|
||||
static_cast<rep>(pow(q.number(), static_cast<double>(Num) / static_cast<double>(Den))));
|
||||
static_cast<rep>(pow(q.number(), static_cast<double>(Num) / static_cast<double>(Den))));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ template<std::intmax_t Num, std::intmax_t Den = 1, Quantity Q>
|
||||
*/
|
||||
template<Quantity Q>
|
||||
[[nodiscard]] inline Quantity auto sqrt(const Q& q) noexcept
|
||||
requires requires { sqrt(q.number()); } || requires { std::sqrt(q.number()); }
|
||||
requires requires { sqrt(q.number()); } || requires { std::sqrt(q.number()); }
|
||||
{
|
||||
using dim = dimension_pow<typename Q::dimension, 1, 2>;
|
||||
using unit = downcast_unit<dim, sqrt(Q::unit::ratio)>;
|
||||
@@ -126,7 +126,7 @@ template<typename U, typename Rep>
|
||||
*/
|
||||
template<typename D, typename U, typename Rep>
|
||||
[[nodiscard]] inline quantity<D, U, Rep> abs(const quantity<D, U, Rep>& q) noexcept
|
||||
requires requires { abs(q.number()); } || requires { std::abs(q.number()); }
|
||||
requires requires { abs(q.number()); } || requires { std::abs(q.number()); }
|
||||
{
|
||||
using std::abs;
|
||||
return quantity<D, U, Rep>(abs(q.number()));
|
||||
@@ -155,13 +155,12 @@ template<Quantity Q>
|
||||
*/
|
||||
template<Unit To, typename D, typename U, typename Rep>
|
||||
[[nodiscard]] constexpr quantity<D, To, Rep> floor(const quantity<D, U, Rep>& q) noexcept
|
||||
requires ((!treat_as_floating_point<Rep>) ||
|
||||
requires { floor(q.number()); } ||
|
||||
requires { std::floor(q.number()); }) &&
|
||||
(std::same_as<To, U> || requires {
|
||||
::units::quantity_cast<To>(q);
|
||||
quantity<D, To, Rep>::one();
|
||||
})
|
||||
requires((!treat_as_floating_point<Rep>) || requires { floor(q.number()); } ||
|
||||
requires { std::floor(q.number()); }) &&
|
||||
(std::same_as<To, U> || requires {
|
||||
::units::quantity_cast<To>(q);
|
||||
quantity<D, To, Rep>::one();
|
||||
})
|
||||
{
|
||||
const auto handle_signed_results = [&]<typename T>(const T& res) {
|
||||
if (res > q) {
|
||||
@@ -169,20 +168,17 @@ template<Unit To, typename D, typename U, typename Rep>
|
||||
}
|
||||
return res;
|
||||
};
|
||||
if constexpr(treat_as_floating_point<Rep>) {
|
||||
if constexpr (treat_as_floating_point<Rep>) {
|
||||
using std::floor;
|
||||
if constexpr(std::is_same_v<To, U>) {
|
||||
if constexpr (std::is_same_v<To, U>) {
|
||||
return quantity<D, To, Rep>(floor(q.number()));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return handle_signed_results(quantity<D, To, Rep>(floor(quantity_cast<To>(q).number())));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if constexpr(std::is_same_v<To, U>) {
|
||||
} else {
|
||||
if constexpr (std::is_same_v<To, U>) {
|
||||
return q;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return handle_signed_results(quantity_cast<To>(q));
|
||||
}
|
||||
}
|
||||
@@ -209,13 +205,11 @@ template<Quantity To, std::same_as<typename To::dimension> D, typename U, std::s
|
||||
*/
|
||||
template<Unit To, typename D, typename U, typename Rep>
|
||||
[[nodiscard]] constexpr quantity<D, To, Rep> ceil(const quantity<D, U, Rep>& q) noexcept
|
||||
requires ((!treat_as_floating_point<Rep>) ||
|
||||
requires { ceil(q.number()); } ||
|
||||
requires { std::ceil(q.number()); }) &&
|
||||
(std::same_as<To, U> || requires {
|
||||
::units::quantity_cast<To>(q);
|
||||
quantity<D, To, Rep>::one();
|
||||
})
|
||||
requires((!treat_as_floating_point<Rep>) || requires { ceil(q.number()); } || requires { std::ceil(q.number()); }) &&
|
||||
(std::same_as<To, U> || requires {
|
||||
::units::quantity_cast<To>(q);
|
||||
quantity<D, To, Rep>::one();
|
||||
})
|
||||
{
|
||||
const auto handle_signed_results = [&]<typename T>(const T& res) {
|
||||
if (res < q) {
|
||||
@@ -223,20 +217,17 @@ template<Unit To, typename D, typename U, typename Rep>
|
||||
}
|
||||
return res;
|
||||
};
|
||||
if constexpr(treat_as_floating_point<Rep>) {
|
||||
if constexpr (treat_as_floating_point<Rep>) {
|
||||
using std::ceil;
|
||||
if constexpr(std::is_same_v<To, U>) {
|
||||
if constexpr (std::is_same_v<To, U>) {
|
||||
return quantity<D, To, Rep>(ceil(q.number()));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return handle_signed_results(quantity<D, To, Rep>(ceil(quantity_cast<To>(q).number())));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if constexpr(std::is_same_v<To, U>) {
|
||||
} else {
|
||||
if constexpr (std::is_same_v<To, U>) {
|
||||
return q;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return handle_signed_results(quantity_cast<To>(q));
|
||||
}
|
||||
}
|
||||
@@ -265,24 +256,21 @@ template<Quantity To, std::same_as<typename To::dimension> D, typename U, std::s
|
||||
*/
|
||||
template<Unit To, typename D, typename U, typename Rep>
|
||||
[[nodiscard]] constexpr quantity<D, To, Rep> round(const quantity<D, U, Rep>& q) noexcept
|
||||
requires ((!treat_as_floating_point<Rep>) ||
|
||||
requires { round(q.number()); } ||
|
||||
requires { std::round(q.number()); }) &&
|
||||
(std::same_as<To, U> || requires {
|
||||
::units::floor<To>(q);
|
||||
quantity<D, To, Rep>::one();
|
||||
})
|
||||
requires((!treat_as_floating_point<Rep>) || requires { round(q.number()); } ||
|
||||
requires { std::round(q.number()); }) &&
|
||||
(std::same_as<To, U> || requires {
|
||||
::units::floor<To>(q);
|
||||
quantity<D, To, Rep>::one();
|
||||
})
|
||||
{
|
||||
if constexpr(std::is_same_v<To, U>) {
|
||||
if constexpr(treat_as_floating_point<Rep>) {
|
||||
if constexpr (std::is_same_v<To, U>) {
|
||||
if constexpr (treat_as_floating_point<Rep>) {
|
||||
using std::round;
|
||||
return quantity<D, To, Rep>(round(q.number()));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return q;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
const auto res_low = units::floor<To>(q);
|
||||
const auto res_high = res_low + decltype(res_low)::one();
|
||||
const auto diff0 = q - res_low;
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <units/bits/external/downcasting.h>
|
||||
#include <units/bits/basic_concepts.h>
|
||||
#include <units/bits/external/downcasting.h>
|
||||
// IWYU pragma: begin_exports
|
||||
#include <units/ratio.h>
|
||||
#include <units/symbol_text.h>
|
||||
@@ -72,7 +72,7 @@ struct prefix_base : downcast_base<prefix_base<PF, R>> {
|
||||
* @tparam R factor to be used to scale a unit
|
||||
*/
|
||||
template<typename Child, PrefixFamily PF, basic_symbol_text Symbol, ratio R>
|
||||
requires (!std::same_as<PF, no_prefix>)
|
||||
requires(!std::same_as<PF, no_prefix>)
|
||||
struct prefix : downcast_dispatch<Child, detail::prefix_base<PF, R>, downcast_mode::on> {
|
||||
static constexpr auto symbol = Symbol;
|
||||
};
|
||||
|
||||
@@ -48,50 +48,38 @@ inline constexpr auto make_quantity = [](auto&& v) {
|
||||
} // namespace detail
|
||||
|
||||
template<typename T>
|
||||
concept floating_point_ = // exposition only
|
||||
(Quantity<T> && treat_as_floating_point<typename T::rep>) ||
|
||||
(!Quantity<T> && treat_as_floating_point<T>);
|
||||
concept floating_point_ = // exposition only
|
||||
(Quantity<T> && treat_as_floating_point<typename T::rep>) || (!Quantity<T> && treat_as_floating_point<T>);
|
||||
|
||||
template<typename From, typename To>
|
||||
concept safe_convertible_to_ = // exposition only
|
||||
(!Quantity<From>) &&
|
||||
(!Quantity<To>) &&
|
||||
std::convertible_to<From, To> &&
|
||||
(floating_point_<To> || (!floating_point_<From>));
|
||||
concept safe_convertible_to_ = // exposition only
|
||||
(!Quantity<From>) && (!Quantity<To>) && std::convertible_to<From, To> &&
|
||||
(floating_point_<To> || (!floating_point_<From>));
|
||||
|
||||
// QFrom ratio is an exact multiple of QTo
|
||||
template<typename QFrom, typename QTo>
|
||||
concept harmonic_ = // exposition only
|
||||
Quantity<QFrom> &&
|
||||
Quantity<QTo> &&
|
||||
is_integral(detail::quantity_ratio<QFrom> / detail::quantity_ratio<QTo>);
|
||||
concept harmonic_ = // exposition only
|
||||
Quantity<QFrom> && Quantity<QTo> && is_integral(detail::quantity_ratio<QFrom> / detail::quantity_ratio<QTo>);
|
||||
|
||||
template<typename QFrom, typename QTo>
|
||||
concept safe_castable_to_ = // exposition only
|
||||
Quantity<QFrom> &&
|
||||
QuantityOf<QTo, typename QFrom::dimension> &&
|
||||
scalable_with_<typename QFrom::rep, typename QTo::rep> &&
|
||||
(floating_point_<QTo> || (!floating_point_<QFrom> && harmonic_<QFrom, QTo>));
|
||||
concept safe_castable_to_ = // exposition only
|
||||
Quantity<QFrom> && QuantityOf<QTo, typename QFrom::dimension> &&
|
||||
scalable_with_<typename QFrom::rep, typename QTo::rep> &&
|
||||
(floating_point_<QTo> || (!floating_point_<QFrom> && harmonic_<QFrom, QTo>));
|
||||
|
||||
template<typename Func, typename T, typename U>
|
||||
concept quantity_value_for_ =
|
||||
std::regular_invocable<Func, T, U> &&
|
||||
Representation<std::invoke_result_t<Func, T, U>>;
|
||||
concept quantity_value_for_ = std::regular_invocable<Func, T, U> && Representation<std::invoke_result_t<Func, T, U>>;
|
||||
|
||||
template<typename T, typename Func, typename U, typename V>
|
||||
concept invoke_result_convertible_to_ =
|
||||
Representation<T> &&
|
||||
quantity_value_for_<Func, U, V> &&
|
||||
safe_convertible_to_<T, std::invoke_result_t<Func, U, V>>;
|
||||
Representation<T> && quantity_value_for_<Func, U, V> && safe_convertible_to_<T, std::invoke_result_t<Func, U, V>>;
|
||||
|
||||
template<typename Func, typename Q, typename V>
|
||||
concept have_quantity_for_ =
|
||||
Quantity<Q> &&
|
||||
(!Quantity<V>) &&
|
||||
quantity_value_for_<Func, typename Q::rep, V>;
|
||||
concept have_quantity_for_ = Quantity<Q> && (!Quantity<V>) && quantity_value_for_<Func, typename Q::rep, V>;
|
||||
|
||||
template<QuantityLike Q>
|
||||
using quantity_like_type = quantity<typename quantity_like_traits<Q>::dimension, typename quantity_like_traits<Q>::unit, typename quantity_like_traits<Q>::rep>;
|
||||
using quantity_like_type = quantity<typename quantity_like_traits<Q>::dimension, typename quantity_like_traits<Q>::unit,
|
||||
typename quantity_like_traits<Q>::rep>;
|
||||
|
||||
/**
|
||||
* @brief A quantity
|
||||
@@ -144,76 +132,110 @@ public:
|
||||
quantity(quantity&&) = default;
|
||||
|
||||
template<typename Value>
|
||||
requires safe_convertible_to_<std::remove_cvref_t<Value>, rep>
|
||||
constexpr explicit(!(std::same_as<dimension, dim_one> && std::same_as<unit, ::units::one>))
|
||||
quantity(Value&& v) : number_(std::forward<Value>(v)) {}
|
||||
requires(safe_convertible_to_<std::remove_cvref_t<Value>, rep>)
|
||||
constexpr explicit(!(std::same_as<dimension, dim_one> && std::same_as<unit, ::units::one>)) quantity(Value&& v) :
|
||||
number_(std::forward<Value>(v))
|
||||
{
|
||||
}
|
||||
|
||||
template<safe_castable_to_<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<QuantityLike Q>
|
||||
requires safe_castable_to_<quantity_like_type<Q>, quantity>
|
||||
constexpr explicit quantity(const Q& q) : quantity(quantity_like_type<Q>(quantity_like_traits<Q>::number(q))) {}
|
||||
requires(safe_castable_to_<quantity_like_type<Q>, quantity>)
|
||||
constexpr explicit quantity(const Q& q) : quantity(quantity_like_type<Q>(quantity_like_traits<Q>::number(q)))
|
||||
{
|
||||
}
|
||||
|
||||
quantity& operator=(const quantity&) = default;
|
||||
quantity& operator=(quantity&&) = default;
|
||||
|
||||
// data access
|
||||
[[nodiscard]] constexpr rep& number() & noexcept { return number_; }
|
||||
[[nodiscard]] constexpr const rep& number() const & noexcept { return number_; }
|
||||
[[nodiscard]] constexpr const rep& number() const& noexcept { return number_; }
|
||||
[[nodiscard]] constexpr rep&& number() && noexcept { return std::move(number_); }
|
||||
[[nodiscard]] constexpr const rep&& number() const && noexcept { return std::move(number_); }
|
||||
[[nodiscard]] constexpr const rep&& number() const&& noexcept { return std::move(number_); }
|
||||
|
||||
// member unary operators
|
||||
[[nodiscard]] constexpr Quantity auto operator+() const
|
||||
requires requires(rep v) { { +v } -> std::common_with<rep>; }
|
||||
requires requires(rep v) {
|
||||
{
|
||||
+v
|
||||
} -> std::common_with<rep>;
|
||||
}
|
||||
{
|
||||
using ret = quantity<D, U, decltype(+number())>;
|
||||
return ret(+number());
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr Quantity auto operator-() const
|
||||
requires std::regular_invocable<std::negate<>, rep>
|
||||
requires(std::regular_invocable<std::negate<>, rep>)
|
||||
{
|
||||
using ret = quantity<D, U, decltype(-number())>;
|
||||
return ret(-number());
|
||||
}
|
||||
|
||||
constexpr quantity& operator++()
|
||||
requires requires(rep v) { { ++v } -> std::same_as<rep&>; }
|
||||
requires requires(rep v) {
|
||||
{
|
||||
++v
|
||||
} -> std::same_as<rep&>;
|
||||
}
|
||||
{
|
||||
++number_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr quantity operator++(int)
|
||||
requires requires(rep v) { { v++ } -> std::same_as<rep>; }
|
||||
requires requires(rep v) {
|
||||
{
|
||||
v++
|
||||
} -> std::same_as<rep>;
|
||||
}
|
||||
{
|
||||
return quantity(number_++);
|
||||
}
|
||||
|
||||
constexpr quantity& operator--()
|
||||
requires requires(rep v) { { --v } -> std::same_as<rep&>; }
|
||||
requires requires(rep v) {
|
||||
{
|
||||
--v
|
||||
} -> std::same_as<rep&>;
|
||||
}
|
||||
{
|
||||
--number_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr quantity operator--(int)
|
||||
requires requires(rep v) { { v-- } -> std::same_as<rep>; }
|
||||
requires requires(rep v) {
|
||||
{
|
||||
v--
|
||||
} -> std::same_as<rep>;
|
||||
}
|
||||
{
|
||||
return quantity(number_--);
|
||||
}
|
||||
|
||||
constexpr quantity& operator+=(const quantity& q)
|
||||
requires requires(rep a, rep b) { { a += b } -> std::same_as<rep&>; }
|
||||
requires requires(rep a, rep b) {
|
||||
{
|
||||
a += b
|
||||
} -> std::same_as<rep&>;
|
||||
}
|
||||
{
|
||||
number_ += q.number();
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr quantity& operator-=(const quantity& q)
|
||||
requires requires(rep a, rep b) { { a -= b } -> std::same_as<rep&>; }
|
||||
requires requires(rep a, rep b) {
|
||||
{
|
||||
a -= b
|
||||
} -> std::same_as<rep&>;
|
||||
}
|
||||
{
|
||||
number_ -= q.number();
|
||||
return *this;
|
||||
@@ -221,14 +243,22 @@ public:
|
||||
|
||||
template<typename Rep2>
|
||||
constexpr quantity& operator*=(const Rep2& rhs)
|
||||
requires requires(rep a, const Rep2 b) { { a *= b } -> std::same_as<rep&>; }
|
||||
requires requires(rep a, const Rep2 b) {
|
||||
{
|
||||
a *= b
|
||||
} -> std::same_as<rep&>;
|
||||
}
|
||||
{
|
||||
number_ *= rhs;
|
||||
return *this;
|
||||
}
|
||||
template<typename Rep2>
|
||||
constexpr quantity& operator*=(const dimensionless<units::one, Rep2>& rhs)
|
||||
requires requires(rep a, const Rep2 b) { { a *= b } -> std::same_as<rep&>; }
|
||||
requires requires(rep a, const Rep2 b) {
|
||||
{
|
||||
a *= b
|
||||
} -> std::same_as<rep&>;
|
||||
}
|
||||
{
|
||||
number_ *= rhs.number();
|
||||
return *this;
|
||||
@@ -236,7 +266,11 @@ public:
|
||||
|
||||
template<typename Rep2>
|
||||
constexpr quantity& operator/=(const Rep2& rhs)
|
||||
requires requires(rep a, const Rep2 b) { { a /= b } -> std::same_as<rep&>; }
|
||||
requires requires(rep a, const Rep2 b) {
|
||||
{
|
||||
a /= b
|
||||
} -> std::same_as<rep&>;
|
||||
}
|
||||
{
|
||||
gsl_ExpectsAudit(rhs != quantity_values<Rep2>::zero());
|
||||
number_ /= rhs;
|
||||
@@ -244,7 +278,11 @@ public:
|
||||
}
|
||||
template<typename Rep2>
|
||||
constexpr quantity& operator/=(const dimensionless<units::one, Rep2>& rhs)
|
||||
requires requires(rep a, const Rep2 b) { { a /= b } -> std::same_as<rep&>; }
|
||||
requires requires(rep a, const Rep2 b) {
|
||||
{
|
||||
a /= b
|
||||
} -> std::same_as<rep&>;
|
||||
}
|
||||
{
|
||||
gsl_ExpectsAudit(rhs.number() != quantity_values<Rep2>::zero());
|
||||
number_ /= rhs.number();
|
||||
@@ -253,8 +291,11 @@ public:
|
||||
|
||||
template<typename Rep2>
|
||||
constexpr quantity& operator%=(const Rep2& rhs)
|
||||
requires (!floating_point_<rep>) && (!floating_point_<Rep2>) &&
|
||||
requires(rep a, const Rep2 b) { { a %= b } -> std::same_as<rep&>; }
|
||||
requires(!floating_point_<rep>) && (!floating_point_<Rep2>) && requires(rep a, const Rep2 b) {
|
||||
{
|
||||
a %= b
|
||||
} -> std::same_as<rep&>;
|
||||
}
|
||||
{
|
||||
gsl_ExpectsAudit(rhs != quantity_values<Rep2>::zero());
|
||||
number_ %= rhs;
|
||||
@@ -263,8 +304,11 @@ public:
|
||||
|
||||
template<typename Rep2>
|
||||
constexpr quantity& operator%=(const dimensionless<units::one, Rep2>& rhs)
|
||||
requires (!floating_point_<rep>) && (!floating_point_<Rep2>) &&
|
||||
requires(rep a, const Rep2 b) { { a %= b } -> std::same_as<rep&>; }
|
||||
requires(!floating_point_<rep>) && (!floating_point_<Rep2>) && requires(rep a, const Rep2 b) {
|
||||
{
|
||||
a %= b
|
||||
} -> std::same_as<rep&>;
|
||||
}
|
||||
{
|
||||
gsl_ExpectsAudit(rhs.number() != quantity_values<Rep2>::zero());
|
||||
number_ %= rhs.number();
|
||||
@@ -272,8 +316,11 @@ public:
|
||||
}
|
||||
|
||||
constexpr quantity& operator%=(const quantity& q)
|
||||
requires (!floating_point_<rep>) &&
|
||||
requires(rep a, rep b) { { a %= b } -> std::same_as<rep&>; }
|
||||
requires(!floating_point_<rep>) && requires(rep a, rep b) {
|
||||
{
|
||||
a %= b
|
||||
} -> std::same_as<rep&>;
|
||||
}
|
||||
{
|
||||
gsl_ExpectsAudit(q.number() != quantity_values<rep>::zero());
|
||||
number_ %= q.number();
|
||||
@@ -284,36 +331,48 @@ public:
|
||||
// Below friend functions are to be found via argument-dependent lookup only
|
||||
template<typename Value>
|
||||
[[nodiscard]] friend constexpr Quantity auto operator+(const quantity& lhs, const Value& rhs)
|
||||
requires requires { requires !Quantity<Value>; requires is_same_v<unit, units::one>; // TODO: Simplify
|
||||
requires invoke_result_convertible_to_<rep, std::plus<>, rep, Value>; } // when Clang catches up.
|
||||
requires requires { // TODO: Simplify when Clang catches up.
|
||||
requires !Quantity<Value>;
|
||||
requires is_same_v<unit, units::one>;
|
||||
requires invoke_result_convertible_to_<rep, std::plus<>, rep, Value>;
|
||||
}
|
||||
{
|
||||
return units::quantity(lhs.number() + rhs);
|
||||
}
|
||||
template<typename Value>
|
||||
[[nodiscard]] friend constexpr Quantity auto operator+(const Value& lhs, const quantity& rhs)
|
||||
requires requires { requires !Quantity<Value>; requires is_same_v<unit, units::one>; // TODO: Simplify
|
||||
requires invoke_result_convertible_to_<rep, std::plus<>, Value, rep>; } // when Clang catches up.
|
||||
requires requires { // TODO: Simplify when Clang catches up.
|
||||
requires !Quantity<Value>;
|
||||
requires is_same_v<unit, units::one>;
|
||||
requires invoke_result_convertible_to_<rep, std::plus<>, Value, rep>;
|
||||
}
|
||||
{
|
||||
return units::quantity(lhs + rhs.number());
|
||||
}
|
||||
|
||||
template<typename Value>
|
||||
[[nodiscard]] friend constexpr Quantity auto operator-(const quantity& lhs, const Value& rhs)
|
||||
requires requires { requires !Quantity<Value>; requires is_same_v<unit, units::one>; // TODO: Simplify
|
||||
requires invoke_result_convertible_to_<rep, std::minus<>, rep, Value>; } // when Clang catches up.
|
||||
requires requires { // TODO: Simplify when Clang catches up.
|
||||
requires !Quantity<Value>;
|
||||
requires is_same_v<unit, units::one>;
|
||||
requires invoke_result_convertible_to_<rep, std::minus<>, rep, Value>;
|
||||
}
|
||||
{
|
||||
return units::quantity(lhs.number() - rhs);
|
||||
}
|
||||
template<typename Value>
|
||||
[[nodiscard]] friend constexpr Quantity auto operator-(const Value& lhs, const quantity& rhs)
|
||||
requires requires { requires !Quantity<Value>; requires is_same_v<unit, units::one>; // TODO: Simplify
|
||||
requires invoke_result_convertible_to_<rep, std::minus<>, Value, rep>; } // when Clang catches up.
|
||||
requires requires { // TODO: Simplify when Clang catches up.
|
||||
requires !Quantity<Value>;
|
||||
requires is_same_v<unit, units::one>;
|
||||
requires invoke_result_convertible_to_<rep, std::minus<>, Value, rep>;
|
||||
}
|
||||
{
|
||||
return units::quantity(lhs - rhs.number());
|
||||
}
|
||||
|
||||
template<Representation Value>
|
||||
requires invoke_result_convertible_to_<rep, std::multiplies<>, rep, const Value&>
|
||||
requires(invoke_result_convertible_to_<rep, std::multiplies<>, rep, const Value&>)
|
||||
[[nodiscard]] friend constexpr Quantity auto operator*(const quantity& q, const Value& v)
|
||||
{
|
||||
using ret = quantity<D, U, std::invoke_result_t<std::multiplies<>, rep, Value>>;
|
||||
@@ -321,7 +380,7 @@ public:
|
||||
}
|
||||
|
||||
template<Representation Value>
|
||||
requires invoke_result_convertible_to_<rep, std::multiplies<>, const Value&, rep>
|
||||
requires(invoke_result_convertible_to_<rep, std::multiplies<>, const Value&, rep>)
|
||||
[[nodiscard]] friend constexpr Quantity auto operator*(const Value& v, const quantity& q)
|
||||
{
|
||||
using ret = quantity<D, U, std::invoke_result_t<std::multiplies<>, Value, rep>>;
|
||||
@@ -329,8 +388,7 @@ public:
|
||||
}
|
||||
|
||||
template<typename Value>
|
||||
requires (!Quantity<Value>) &&
|
||||
invoke_result_convertible_to_<rep, std::divides<>, rep, const Value&>
|
||||
requires(!Quantity<Value>) && (invoke_result_convertible_to_<rep, std::divides<>, rep, const Value&>)
|
||||
[[nodiscard]] friend constexpr Quantity auto operator/(const quantity& q, const Value& v)
|
||||
{
|
||||
gsl_ExpectsAudit(v != quantity_values<Value>::zero());
|
||||
@@ -339,8 +397,7 @@ public:
|
||||
}
|
||||
|
||||
template<typename Value>
|
||||
requires (!Quantity<Value>) &&
|
||||
invoke_result_convertible_to_<rep, std::divides<>, const Value&, rep>
|
||||
requires(!Quantity<Value>) && (invoke_result_convertible_to_<rep, std::divides<>, const Value&, rep>)
|
||||
[[nodiscard]] friend constexpr Quantity auto operator/(const Value& v, const quantity& q)
|
||||
{
|
||||
gsl_ExpectsAudit(q.number() != quantity_values<rep>::zero());
|
||||
@@ -351,8 +408,8 @@ public:
|
||||
}
|
||||
|
||||
template<typename Value>
|
||||
requires (!Quantity<Value>) && (!floating_point_<rep>) && (!floating_point_<Value>) &&
|
||||
invoke_result_convertible_to_<rep, std::modulus<>, rep, const Value&>
|
||||
requires(!Quantity<Value>) && (!floating_point_<rep>) && (!floating_point_<Value>) &&
|
||||
(invoke_result_convertible_to_<rep, std::modulus<>, rep, const Value&>)
|
||||
[[nodiscard]] friend constexpr Quantity auto operator%(const quantity& q, const Value& v)
|
||||
{
|
||||
gsl_ExpectsAudit(v != quantity_values<Value>::zero());
|
||||
@@ -361,8 +418,7 @@ public:
|
||||
}
|
||||
|
||||
[[nodiscard]] friend constexpr Quantity auto operator%(const quantity& lhs, const quantity& rhs)
|
||||
requires (!floating_point_<rep>) &&
|
||||
invoke_result_convertible_to_<rep, std::modulus<>, rep, rep>
|
||||
requires(!floating_point_<rep>) && (invoke_result_convertible_to_<rep, std::modulus<>, rep, rep>)
|
||||
{
|
||||
gsl_ExpectsAudit(rhs.number() != quantity_values<rep>::zero());
|
||||
using ret = quantity<D, U, std::invoke_result_t<std::modulus<>, rep, rep>>;
|
||||
@@ -385,18 +441,19 @@ public:
|
||||
// CTAD
|
||||
#if !UNITS_COMP_CLANG || UNITS_COMP_CLANG > 15
|
||||
template<typename D, typename U, typename Rep>
|
||||
explicit(false) quantity(Rep&&) -> quantity<D, U, Rep>;
|
||||
explicit(false) quantity(Rep&&)->quantity<D, U, Rep>;
|
||||
#endif
|
||||
|
||||
template<Representation Rep>
|
||||
explicit(false) quantity(Rep) -> quantity<dim_one, one, Rep>;
|
||||
explicit(false) quantity(Rep)->quantity<dim_one, one, Rep>;
|
||||
|
||||
template<QuantityLike Q>
|
||||
explicit quantity(Q) -> quantity<typename quantity_like_traits<Q>::dimension, typename quantity_like_traits<Q>::unit, typename quantity_like_traits<Q>::rep>;
|
||||
explicit quantity(Q) -> quantity<typename quantity_like_traits<Q>::dimension, typename quantity_like_traits<Q>::unit,
|
||||
typename quantity_like_traits<Q>::rep>;
|
||||
|
||||
// non-member binary operators
|
||||
template<Quantity Q1, QuantityEquivalentTo<Q1> Q2>
|
||||
requires quantity_value_for_<std::plus<>, typename Q1::rep, typename Q2::rep>
|
||||
requires(quantity_value_for_<std::plus<>, typename Q1::rep, typename Q2::rep>)
|
||||
[[nodiscard]] constexpr Quantity auto operator+(const Q1& lhs, const Q2& rhs)
|
||||
{
|
||||
using ref = detail::common_quantity_reference<Q1, Q2>;
|
||||
@@ -405,7 +462,7 @@ template<Quantity Q1, QuantityEquivalentTo<Q1> Q2>
|
||||
}
|
||||
|
||||
template<Quantity Q1, QuantityEquivalentTo<Q1> Q2>
|
||||
requires quantity_value_for_<std::minus<>, typename Q1::rep, typename Q2::rep>
|
||||
requires(quantity_value_for_<std::minus<>, typename Q1::rep, typename Q2::rep>)
|
||||
[[nodiscard]] constexpr Quantity auto operator-(const Q1& lhs, const Q2& rhs)
|
||||
{
|
||||
using ref = detail::common_quantity_reference<Q1, Q2>;
|
||||
@@ -414,14 +471,14 @@ template<Quantity Q1, QuantityEquivalentTo<Q1> Q2>
|
||||
}
|
||||
|
||||
template<Quantity Q1, Quantity Q2>
|
||||
requires quantity_value_for_<std::multiplies<>, typename Q1::rep, typename Q2::rep>
|
||||
requires(quantity_value_for_<std::multiplies<>, typename Q1::rep, typename Q2::rep>)
|
||||
[[nodiscard]] constexpr Quantity auto operator*(const Q1& lhs, const Q2& rhs)
|
||||
{
|
||||
return detail::make_quantity<Q1::reference * Q2::reference>(lhs.number() * rhs.number());
|
||||
}
|
||||
|
||||
template<Quantity Q1, Quantity Q2>
|
||||
requires quantity_value_for_<std::divides<>, typename Q1::rep, typename Q2::rep>
|
||||
requires(quantity_value_for_<std::divides<>, typename Q1::rep, typename Q2::rep>)
|
||||
[[nodiscard]] constexpr Quantity auto operator/(const Q1& lhs, const Q2& rhs)
|
||||
{
|
||||
gsl_ExpectsAudit(rhs.number() != quantity_values<typename Q2::rep>::zero());
|
||||
@@ -429,13 +486,14 @@ template<Quantity Q1, Quantity Q2>
|
||||
}
|
||||
|
||||
template<Quantity Q1, Quantity Q2>
|
||||
requires (!floating_point_<typename Q1::rep>) && (!floating_point_<typename Q2::rep>) &&
|
||||
requires(!floating_point_<typename Q1::rep>) && (!floating_point_<typename Q2::rep>) &&
|
||||
(QuantityEquivalentTo<Q2, Q1> || Dimensionless<Q2>) &&
|
||||
quantity_value_for_<std::modulus<>, typename Q1::rep, typename Q2::rep>
|
||||
(quantity_value_for_<std::modulus<>, typename Q1::rep, typename Q2::rep>)
|
||||
[[nodiscard]] constexpr Quantity auto operator%(const Q1& lhs, const Q2& rhs)
|
||||
{
|
||||
gsl_ExpectsAudit(rhs.number() != quantity_values<typename Q2::rep>::zero());
|
||||
using ret = quantity<typename Q1::dimension, typename Q1::unit, std::invoke_result_t<std::modulus<>, typename Q1::rep, typename Q2::rep>>;
|
||||
using ret = quantity<typename Q1::dimension, typename Q1::unit,
|
||||
std::invoke_result_t<std::modulus<>, typename Q1::rep, typename Q2::rep>>;
|
||||
return ret(lhs.number() % rhs.number());
|
||||
}
|
||||
|
||||
@@ -462,7 +520,7 @@ template<typename D, typename U, typename Rep>
|
||||
inline constexpr bool is_quantity<quantity<D, U, Rep>> = true;
|
||||
|
||||
template<typename T>
|
||||
requires units::is_derived_from_specialization_of<T, units::quantity>
|
||||
requires units::is_derived_from_specialization_of<T, units::quantity>
|
||||
inline constexpr bool is_quantity<T> = true;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@@ -22,14 +22,15 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <units/concepts.h>
|
||||
#include <units/customization_points.h>
|
||||
#include <units/bits/dimension_op.h>
|
||||
#include <units/bits/external/type_traits.h>
|
||||
#include <units/bits/pow.h>
|
||||
#include <units/concepts.h>
|
||||
#include <units/customization_points.h>
|
||||
|
||||
UNITS_DIAGNOSTIC_PUSH
|
||||
UNITS_DIAGNOSTIC_IGNORE_LOSS_OF_DATA // warning C4244: 'argument': conversion from 'intmax_t' to 'T', possible loss of data with T=int
|
||||
// warning C4244: 'argument': conversion from 'intmax_t' to 'T', possible loss of data with T=int
|
||||
UNITS_DIAGNOSTIC_IGNORE_LOSS_OF_DATA
|
||||
|
||||
namespace units {
|
||||
|
||||
@@ -48,28 +49,24 @@ class quantity_point_kind;
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
inline constexpr ratio quantity_ratio = std::enable_if_t<!Quantity<T>>{};
|
||||
inline constexpr ratio quantity_ratio = std::enable_if_t<!Quantity<T>>{};
|
||||
|
||||
template<typename D, typename U, typename Rep>
|
||||
inline constexpr ratio quantity_ratio<quantity<D, U, Rep>> = []
|
||||
{
|
||||
if constexpr(BaseDimension<D>) {
|
||||
inline constexpr ratio quantity_ratio<quantity<D, U, Rep>> = [] {
|
||||
if constexpr (BaseDimension<D>) {
|
||||
return U::ratio;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return D::base_units_ratio * U::ratio / D::coherent_unit::ratio;
|
||||
}
|
||||
}();
|
||||
|
||||
template<typename QFrom, typename QTo>
|
||||
inline constexpr ratio cast_ratio = []
|
||||
{
|
||||
inline constexpr ratio cast_ratio = [] {
|
||||
using FromU = TYPENAME QFrom::unit;
|
||||
using ToU = TYPENAME QTo::unit;
|
||||
if constexpr(same_unit_reference<FromU, ToU>::value) {
|
||||
if constexpr (same_unit_reference<FromU, ToU>::value) {
|
||||
return FromU::ratio / ToU::ratio;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return quantity_ratio<QFrom> / quantity_ratio<QTo>;
|
||||
}
|
||||
}();
|
||||
@@ -78,17 +75,17 @@ template<typename From, typename To>
|
||||
struct cast_traits;
|
||||
|
||||
template<typename From, typename To>
|
||||
requires common_type_with_<std::common_type_t<From, To>, std::intmax_t>
|
||||
struct cast_traits<From, To> {
|
||||
requires common_type_with_<std::common_type_t<From, To>,
|
||||
std::intmax_t> struct cast_traits<From, To> {
|
||||
using ratio_type = std::common_type_t<std::common_type_t<From, To>, std::intmax_t>;
|
||||
using rep_type = ratio_type;
|
||||
};
|
||||
|
||||
template<typename From, typename To>
|
||||
requires (!common_type_with_<std::common_type_t<From, To>, std::intmax_t>) &&
|
||||
scalable_number_<std::common_type_t<From, To>, std::intmax_t> &&
|
||||
requires { typename std::common_type_t<From, To>::value_type; } &&
|
||||
common_type_with_<typename std::common_type_t<From, To>::value_type, std::intmax_t>
|
||||
requires(!common_type_with_<std::common_type_t<From, To>, std::intmax_t> &&
|
||||
scalable_number_<std::common_type_t<From, To>, std::intmax_t> &&
|
||||
requires { typename std::common_type_t<From, To>::value_type; } &&
|
||||
common_type_with_<typename std::common_type_t<From, To>::value_type, std::intmax_t>)
|
||||
struct cast_traits<From, To> {
|
||||
using ratio_type = std::common_type_t<typename std::common_type_t<From, To>::value_type, std::intmax_t>;
|
||||
using rep_type = std::common_type_t<From, To>;
|
||||
@@ -109,7 +106,7 @@ struct cast_traits<From, To> {
|
||||
* @tparam To a target quantity type to cast to
|
||||
*/
|
||||
template<Quantity To, typename D, typename U, scalable_with_<typename To::rep> Rep>
|
||||
requires QuantityOf<To, D> && std::constructible_from<typename To::rep, std::common_type_t<typename To::rep, Rep>>
|
||||
requires QuantityOf<To, D> && (std::constructible_from<typename To::rep, std::common_type_t<typename To::rep, Rep>>)
|
||||
[[nodiscard]] constexpr auto quantity_cast(const quantity<D, U, Rep>& q)
|
||||
{
|
||||
using traits = detail::cast_traits<Rep, typename To::rep>;
|
||||
@@ -118,19 +115,20 @@ template<Quantity To, typename D, typename U, scalable_with_<typename To::rep> R
|
||||
constexpr auto c_ratio = detail::cast_ratio<quantity<D, U, Rep>, To>;
|
||||
|
||||
if constexpr (treat_as_floating_point<rep_type>) {
|
||||
return To(static_cast<TYPENAME To::rep>(static_cast<rep_type>(q.number()) *
|
||||
(static_cast<ratio_type>(c_ratio.num) * detail::fpow10<ratio_type>(c_ratio.exp) / static_cast<ratio_type>(c_ratio.den))));
|
||||
}
|
||||
else {
|
||||
return To(
|
||||
static_cast<TYPENAME To::rep>(static_cast<rep_type>(q.number()) *
|
||||
(static_cast<ratio_type>(c_ratio.num) * detail::fpow10<ratio_type>(c_ratio.exp) /
|
||||
static_cast<ratio_type>(c_ratio.den))));
|
||||
} else {
|
||||
if constexpr (c_ratio.exp > 0) {
|
||||
return To(static_cast<TYPENAME To::rep>(static_cast<rep_type>(q.number()) *
|
||||
(static_cast<ratio_type>(c_ratio.num) * static_cast<ratio_type>(detail::ipow10(c_ratio.exp))) /
|
||||
static_cast<ratio_type>(c_ratio.den)));
|
||||
}
|
||||
else {
|
||||
return To(static_cast<TYPENAME To::rep>(static_cast<rep_type>(q.number()) *
|
||||
static_cast<ratio_type>(c_ratio.num) /
|
||||
(static_cast<ratio_type>(c_ratio.den) * static_cast<ratio_type>(detail::ipow10(-c_ratio.exp)))));
|
||||
return To(static_cast<TYPENAME To::rep>(
|
||||
static_cast<rep_type>(q.number()) *
|
||||
(static_cast<ratio_type>(c_ratio.num) * static_cast<ratio_type>(detail::ipow10(c_ratio.exp))) /
|
||||
static_cast<ratio_type>(c_ratio.den)));
|
||||
} else {
|
||||
return To(static_cast<TYPENAME To::rep>(
|
||||
static_cast<rep_type>(q.number()) * static_cast<ratio_type>(c_ratio.num) /
|
||||
(static_cast<ratio_type>(c_ratio.den) * static_cast<ratio_type>(detail::ipow10(-c_ratio.exp)))));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -209,7 +207,7 @@ template<Dimension ToD, Unit ToU, typename D, typename U, typename Rep>
|
||||
* @tparam ToRep a representation type to use for a target quantity
|
||||
*/
|
||||
template<Representation ToRep, typename D, typename U, scalable_with_<ToRep> Rep>
|
||||
requires std::constructible_from<ToRep, std::common_type_t<ToRep, Rep>>
|
||||
requires(std::constructible_from<ToRep, std::common_type_t<ToRep, Rep>>)
|
||||
[[nodiscard]] constexpr auto quantity_cast(const quantity<D, U, Rep>& q)
|
||||
{
|
||||
return quantity_cast<quantity<D, U, ToRep>>(q);
|
||||
@@ -233,9 +231,11 @@ template<Representation ToRep, typename D, typename U, scalable_with_<ToRep> Rep
|
||||
*/
|
||||
template<typename CastSpec, typename O, typename U, typename Rep>
|
||||
[[nodiscard]] constexpr auto quantity_point_cast(const quantity_point<O, U, Rep>& qp)
|
||||
requires requires { requires is_specialization_of<CastSpec, quantity_point>;
|
||||
requires requires { quantity_cast<typename CastSpec::quantity_type>(qp.relative()); };
|
||||
requires equivalent<O, typename CastSpec::origin>; } || // TODO: Simplify when Clang catches up.
|
||||
requires requires {
|
||||
requires is_specialization_of<CastSpec, quantity_point>;
|
||||
requires requires { quantity_cast<typename CastSpec::quantity_type>(qp.relative()); };
|
||||
requires equivalent<O, typename CastSpec::origin>;
|
||||
} || // TODO: Simplify when Clang catches up.
|
||||
requires { quantity_cast<CastSpec>(qp.relative()); }
|
||||
{
|
||||
if constexpr (is_specialization_of<CastSpec, quantity_point>)
|
||||
@@ -286,10 +286,13 @@ template<Dimension ToD, Unit ToU, typename O, typename U, typename Rep>
|
||||
*/
|
||||
template<typename CastSpec, typename K, typename U, typename Rep>
|
||||
[[nodiscard]] constexpr QuantityKind auto quantity_kind_cast(const quantity_kind<K, U, Rep>& qk)
|
||||
requires requires { requires is_specialization_of<CastSpec, quantity_kind>;
|
||||
requires requires { quantity_cast<typename CastSpec::quantity_type>(qk.common()); }; } ||
|
||||
requires { requires Kind<CastSpec>; requires UnitOf<U, typename CastSpec::dimension>; } ||
|
||||
requires { quantity_cast<CastSpec>(qk.common()); } // TODO: Simplify when Clang catches up.
|
||||
requires requires {
|
||||
requires is_specialization_of<CastSpec, quantity_kind>;
|
||||
requires requires { quantity_cast<typename CastSpec::quantity_type>(qk.common()); };
|
||||
} || requires {
|
||||
requires Kind<CastSpec>;
|
||||
requires UnitOf<U, typename CastSpec::dimension>;
|
||||
} || requires { quantity_cast<CastSpec>(qk.common()); } // TODO: Simplify when Clang catches up.
|
||||
{
|
||||
if constexpr (is_specialization_of<CastSpec, quantity_kind>)
|
||||
return CastSpec(quantity_cast<typename CastSpec::quantity_type>(qk.common()));
|
||||
@@ -330,25 +333,27 @@ template<Kind ToK, Unit ToU, typename K, typename U, typename Rep>
|
||||
* Implicit conversions between quantity point kinds of different types are allowed only for "safe"
|
||||
* (i.e. non-truncating) conversion. In other cases an explicit cast has to be used.
|
||||
*
|
||||
* This cast gets the target (quantity) point kind type to cast to or anything that works for quantity_kind_cast. For example:
|
||||
* This cast gets the target (quantity) point kind type to cast to or anything that works for quantity_kind_cast. For
|
||||
* example:
|
||||
*
|
||||
* auto q1 = units::quantity_point_kind_cast<decltype(ns::x_coordinate{1 * m))>(ns::x_coordinate{1 * mm});
|
||||
* auto q1 = units::quantity_point_kind_cast<decltype(ns::width{1 * m})>(ns::x_coordinate{1 * mm});
|
||||
* auto q1 = units::quantity_point_kind_cast<ns::y_coordinate_kind>(ns::x_coordinate{1 * m});
|
||||
* auto q1 = units::quantity_point_kind_cast<ns::height_kind>(ns::x_coordinate{1 * m});
|
||||
* auto q1 = units::quantity_point_kind_cast<units::isq::si::length<units::isq::si::metre>>(ns::x_coordinate{1 * mm});
|
||||
* auto q1 = units::quantity_point_kind_cast<units::isq::si::dim_acceleration>(quantity_point_kind(ns::rate_of_climb{200 * Gal}));
|
||||
* auto q1 = units::quantity_point_kind_cast<units::isq::si::metre>(ns::x_coordinate{1 * mm});
|
||||
* auto q1 = units::quantity_point_kind_cast<int>(ns::x_coordinate{1.0 * mm});
|
||||
* auto q1 = units::quantity_point_kind_cast<units::isq::si::dim_acceleration>(quantity_point_kind(ns::rate_of_climb{200
|
||||
* * Gal})); auto q1 = units::quantity_point_kind_cast<units::isq::si::metre>(ns::x_coordinate{1 * mm}); auto q1 =
|
||||
* units::quantity_point_kind_cast<int>(ns::x_coordinate{1.0 * mm});
|
||||
*
|
||||
* @tparam CastSpec a target (quantity) point kind type to cast to or anything that works for quantity_kind_cast
|
||||
*/
|
||||
template<typename CastSpec, typename PK, typename U, typename Rep>
|
||||
[[nodiscard]] constexpr QuantityPointKind auto quantity_point_kind_cast(const quantity_point_kind<PK, U, Rep>& qpk)
|
||||
requires requires { requires is_specialization_of<CastSpec, quantity_point_kind>;
|
||||
requires requires { quantity_kind_cast<typename CastSpec::quantity_kind_type>(qpk.relative()); };
|
||||
requires equivalent<typename PK::origin, typename CastSpec::point_kind_type::origin>; } ||
|
||||
requires { requires PointKind<CastSpec> && UnitOf<U, typename CastSpec::dimension>; } ||
|
||||
requires requires {
|
||||
requires is_specialization_of<CastSpec, quantity_point_kind>;
|
||||
requires requires { quantity_kind_cast<typename CastSpec::quantity_kind_type>(qpk.relative()); };
|
||||
requires equivalent<typename PK::origin, typename CastSpec::point_kind_type::origin>;
|
||||
} || requires { requires PointKind<CastSpec> && UnitOf<U, typename CastSpec::dimension>; } ||
|
||||
requires { quantity_kind_cast<CastSpec>(qpk.relative()); } // TODO: Simplify when Clang catches up.
|
||||
{
|
||||
if constexpr (is_specialization_of<CastSpec, quantity_point_kind>)
|
||||
|
||||
@@ -63,7 +63,7 @@ inline constexpr auto& downcasted_kind = downcasted_kind_fn<typename QK::kind_ty
|
||||
*/
|
||||
template<typename QK1, typename QK2>
|
||||
concept QuantityKindRelatedTo = QuantityKind<QK1> && QuantityKind<QK2> &&
|
||||
equivalent<typename QK1::kind_type::base_kind, typename QK2::kind_type::base_kind>;
|
||||
equivalent<typename QK1::kind_type::base_kind, typename QK2::kind_type::base_kind>;
|
||||
|
||||
/**
|
||||
* @brief A quantity kind
|
||||
@@ -94,24 +94,26 @@ public:
|
||||
quantity_kind(quantity_kind&&) = default;
|
||||
|
||||
template<typename T>
|
||||
requires
|
||||
(Quantity<std::remove_cvref_t<T>> ||
|
||||
QuantityLike<std::remove_cvref_t<T>> ||
|
||||
(Dimensionless<quantity_type> && !Quantity<std::remove_cvref_t<T>>)) &&
|
||||
std::constructible_from<quantity_type, T>
|
||||
constexpr explicit quantity_kind(T&& t) : q_(std::forward<T>(t)) {}
|
||||
requires(Quantity<std::remove_cvref_t<T>> || QuantityLike<std::remove_cvref_t<T>> ||
|
||||
(Dimensionless<quantity_type> && !Quantity<std::remove_cvref_t<T>>)) &&
|
||||
std::constructible_from<quantity_type, T>
|
||||
constexpr explicit quantity_kind(T&& t) : q_(std::forward<T>(t))
|
||||
{
|
||||
}
|
||||
|
||||
template<QuantityKindEquivalentTo<quantity_kind> QK2>
|
||||
requires std::convertible_to<typename QK2::quantity_type, quantity_type>
|
||||
constexpr explicit(false) quantity_kind(const QK2& qk) : q_(qk.common()) {}
|
||||
constexpr explicit(false) quantity_kind(const QK2& qk) : q_(qk.common())
|
||||
{
|
||||
}
|
||||
|
||||
quantity_kind& operator=(const quantity_kind&) = default;
|
||||
quantity_kind& operator=(quantity_kind&&) = default;
|
||||
|
||||
[[nodiscard]] constexpr quantity_type& common() & noexcept { return q_; }
|
||||
[[nodiscard]] constexpr const quantity_type& common() const & noexcept { return q_; }
|
||||
[[nodiscard]] constexpr const quantity_type& common() const& noexcept { return q_; }
|
||||
[[nodiscard]] constexpr quantity_type&& common() && noexcept { return std::move(q_); }
|
||||
[[nodiscard]] constexpr const quantity_type&& common() const && noexcept { return std::move(q_); }
|
||||
[[nodiscard]] constexpr const quantity_type&& common() const&& noexcept { return std::move(q_); }
|
||||
|
||||
[[nodiscard]] static constexpr quantity_kind zero() noexcept
|
||||
requires requires { quantity_type::zero(); }
|
||||
@@ -222,17 +224,18 @@ public:
|
||||
|
||||
template<typename Rep2>
|
||||
constexpr quantity_kind& operator%=(const Rep2& rhs)
|
||||
requires (!Quantity<Rep2> || Dimensionless<Rep2>) && requires(quantity_type q, const Rep2 r) { q %= r; }
|
||||
requires(!Quantity<Rep2> || Dimensionless<Rep2>) && requires(quantity_type q, const Rep2 r) { q %= r; }
|
||||
{
|
||||
gsl_ExpectsAudit(rhs != quantity_values<Rep2>::zero());
|
||||
q_ %= rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
template<QuantityKind QK>
|
||||
constexpr quantity_kind& operator%=(const QK& rhs)
|
||||
requires (QuantityKindEquivalentTo<QK, quantity_kind> || std::same_as<typename QK::kind_type, downcast_kind<K, dim_one>>) &&
|
||||
requires(quantity_type q) { q %= rhs.common(); }
|
||||
requires(QuantityKindEquivalentTo<QK, quantity_kind> ||
|
||||
std::same_as<typename QK::kind_type, downcast_kind<K, dim_one>>) &&
|
||||
requires(quantity_type q) { q %= rhs.common(); }
|
||||
{
|
||||
gsl_ExpectsAudit(rhs.common().number() != quantity_values<typename QK::rep>::zero());
|
||||
q_ %= rhs.common();
|
||||
@@ -243,21 +246,33 @@ public:
|
||||
// Below friend functions are to be found via argument-dependent lookup only
|
||||
template<Representation Value>
|
||||
[[nodiscard]] friend constexpr QuantityKind auto operator*(const quantity_kind& qk, const Value& v)
|
||||
requires requires(quantity_type q) { { q * v } -> Quantity; }
|
||||
requires requires(quantity_type q) {
|
||||
{
|
||||
q* v
|
||||
} -> Quantity;
|
||||
}
|
||||
{
|
||||
return detail::make_quantity_kind<quantity_kind>(qk.common() * v);
|
||||
}
|
||||
|
||||
template<Representation Value>
|
||||
[[nodiscard]] friend constexpr QuantityKind auto operator*(const Value& v, const quantity_kind& qk)
|
||||
requires requires(quantity_type q) { { v * q } -> Quantity; }
|
||||
requires requires(quantity_type q) {
|
||||
{
|
||||
v* q
|
||||
} -> Quantity;
|
||||
}
|
||||
{
|
||||
return detail::make_quantity_kind<quantity_kind>(v * qk.common());
|
||||
}
|
||||
|
||||
template<Representation Value>
|
||||
[[nodiscard]] friend constexpr QuantityKind auto operator/(const quantity_kind& qk, const Value& v)
|
||||
requires requires(quantity_type q) { { q / v } -> Quantity; }
|
||||
requires requires(quantity_type q) {
|
||||
{
|
||||
q / v
|
||||
} -> Quantity;
|
||||
}
|
||||
{
|
||||
gsl_ExpectsAudit(v != quantity_values<Value>::zero());
|
||||
return detail::make_quantity_kind<quantity_kind>(qk.common() / v);
|
||||
@@ -265,7 +280,11 @@ public:
|
||||
|
||||
template<Representation Value>
|
||||
[[nodiscard]] friend constexpr QuantityKind auto operator/(const Value& v, const quantity_kind& qk)
|
||||
requires requires(quantity_type q) { { v / q } -> Quantity; }
|
||||
requires requires(quantity_type q) {
|
||||
{
|
||||
v / q
|
||||
} -> Quantity;
|
||||
}
|
||||
{
|
||||
gsl_ExpectsAudit(qk.common().number() != quantity_values<rep>::zero());
|
||||
return detail::downcasted_kind<quantity_kind>(v / qk.common());
|
||||
@@ -297,7 +316,7 @@ template<QuantityKind QK1, QuantityKindEquivalentTo<QK1> QK2>
|
||||
|
||||
template<QuantityKind QK1, QuantityKindEquivalentTo<QK1> QK2>
|
||||
[[nodiscard]] constexpr QuantityKind auto operator-(const QK1& lhs, const QK2& rhs)
|
||||
requires requires { lhs.common() - rhs.common(); }
|
||||
requires requires { lhs.common() - rhs.common(); }
|
||||
{
|
||||
return detail::make_quantity_kind<QK1>(lhs.common() - rhs.common());
|
||||
}
|
||||
@@ -311,7 +330,7 @@ template<QuantityKind QK, Quantity Q>
|
||||
|
||||
template<Quantity Q, QuantityKind QK>
|
||||
[[nodiscard]] constexpr QuantityKind auto operator*(const Q& lhs, const QK& rhs)
|
||||
requires requires { lhs * rhs.common(); }
|
||||
requires requires { lhs* rhs.common(); }
|
||||
{
|
||||
return detail::downcasted_kind<QK>(lhs * rhs.common());
|
||||
}
|
||||
|
||||
@@ -76,25 +76,31 @@ public:
|
||||
|
||||
template<typename T>
|
||||
requires std::constructible_from<quantity_type, T>
|
||||
constexpr explicit quantity_point(T&& t) : q_(std::forward<T>(t)) {}
|
||||
constexpr explicit quantity_point(T&& t) : q_(std::forward<T>(t))
|
||||
{
|
||||
}
|
||||
|
||||
template<QuantityPointOf<origin> QP2>
|
||||
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<QuantityPointLike QP>
|
||||
constexpr explicit quantity_point(const QP& qp)
|
||||
requires std::is_constructible_v<quantity_type, decltype(quantity_point_like_traits<QP>::relative(qp))> &&
|
||||
equivalent<origin, typename quantity_point_like_traits<QP>::origin>
|
||||
: q_(quantity_point_like_traits<QP>::relative(qp)) {}
|
||||
equivalent<origin, typename quantity_point_like_traits<QP>::origin>
|
||||
: q_(quantity_point_like_traits<QP>::relative(qp))
|
||||
{
|
||||
}
|
||||
|
||||
quantity_point& operator=(const quantity_point&) = default;
|
||||
quantity_point& operator=(quantity_point&&) = default;
|
||||
|
||||
[[nodiscard]] constexpr quantity_type& relative() & noexcept { return q_; }
|
||||
[[nodiscard]] constexpr const quantity_type& relative() const & noexcept { return q_; }
|
||||
[[nodiscard]] constexpr const quantity_type& relative() const& noexcept { return q_; }
|
||||
[[nodiscard]] constexpr quantity_type&& relative() && noexcept { return std::move(q_); }
|
||||
[[nodiscard]] constexpr const quantity_type&& relative() const && noexcept { return std::move(q_); }
|
||||
[[nodiscard]] constexpr const quantity_type&& relative() const&& noexcept { return std::move(q_); }
|
||||
|
||||
[[nodiscard]] static constexpr quantity_point min() noexcept
|
||||
requires requires { quantity_type::min(); }
|
||||
@@ -207,13 +213,14 @@ template<Quantity Q>
|
||||
explicit quantity_point(Q) -> quantity_point<dynamic_origin<typename Q::dimension>, typename Q::unit, typename Q::rep>;
|
||||
|
||||
template<QuantityLike Q>
|
||||
explicit quantity_point(Q) -> quantity_point<dynamic_origin<typename quantity_like_traits<Q>::dimension>,
|
||||
typename quantity_like_traits<Q>::unit, typename quantity_like_traits<Q>::rep>;
|
||||
explicit quantity_point(Q)
|
||||
-> quantity_point<dynamic_origin<typename quantity_like_traits<Q>::dimension>, typename quantity_like_traits<Q>::unit,
|
||||
typename quantity_like_traits<Q>::rep>;
|
||||
|
||||
template<QuantityPointLike QP>
|
||||
explicit quantity_point(QP) -> quantity_point<typename quantity_point_like_traits<QP>::origin,
|
||||
typename quantity_point_like_traits<QP>::unit,
|
||||
typename quantity_point_like_traits<QP>::rep>;
|
||||
explicit quantity_point(QP)
|
||||
-> quantity_point<typename quantity_point_like_traits<QP>::origin, typename quantity_point_like_traits<QP>::unit,
|
||||
typename quantity_point_like_traits<QP>::rep>;
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
@@ -63,26 +63,32 @@ public:
|
||||
|
||||
template<typename T>
|
||||
requires std::constructible_from<quantity_kind_type, T>
|
||||
constexpr explicit quantity_point_kind(T&& t) : qk_(std::forward<T>(t)) {}
|
||||
constexpr explicit quantity_point_kind(T&& t) : qk_(std::forward<T>(t))
|
||||
{
|
||||
}
|
||||
|
||||
constexpr explicit quantity_point_kind(const quantity_point<origin, U, Rep>& qp) : qk_(qp.relative()) {}
|
||||
constexpr explicit quantity_point_kind(quantity_point<origin, U, Rep>&& qp) : qk_(std::move(qp).relative()) {}
|
||||
|
||||
template<QuantityPointLike QP>
|
||||
requires std::constructible_from<quantity_point<origin, U, Rep>, QP>
|
||||
constexpr explicit quantity_point_kind(const QP& qp) : qk_(quantity_point_like_traits<QP>::relative(qp)) {}
|
||||
requires(std::constructible_from<quantity_point<origin, U, Rep>, QP>)
|
||||
constexpr explicit quantity_point_kind(const QP& qp) : qk_(quantity_point_like_traits<QP>::relative(qp))
|
||||
{
|
||||
}
|
||||
|
||||
template<QuantityPointKindOf<point_kind_type> QPK2>
|
||||
requires std::convertible_to<typename QPK2::quantity_kind_type, quantity_kind_type>
|
||||
constexpr explicit(false) quantity_point_kind(const QPK2& qpk) : qk_(qpk.relative()) {}
|
||||
constexpr explicit(false) quantity_point_kind(const QPK2& qpk) : qk_(qpk.relative())
|
||||
{
|
||||
}
|
||||
|
||||
quantity_point_kind& operator=(const quantity_point_kind&) = default;
|
||||
quantity_point_kind& operator=(quantity_point_kind&&) = default;
|
||||
|
||||
[[nodiscard]] constexpr quantity_kind_type& relative() & noexcept { return qk_; }
|
||||
[[nodiscard]] constexpr const quantity_kind_type& relative() const & noexcept { return qk_; }
|
||||
[[nodiscard]] constexpr const quantity_kind_type& relative() const& noexcept { return qk_; }
|
||||
[[nodiscard]] constexpr quantity_kind_type&& relative() && noexcept { return std::move(qk_); }
|
||||
[[nodiscard]] constexpr const quantity_kind_type&& relative() const && noexcept { return std::move(qk_); }
|
||||
[[nodiscard]] constexpr const quantity_kind_type&& relative() const&& noexcept { return std::move(qk_); }
|
||||
|
||||
[[nodiscard]] static constexpr quantity_point_kind min() noexcept
|
||||
requires requires { quantity_kind_type::min(); }
|
||||
@@ -180,12 +186,11 @@ public:
|
||||
{
|
||||
return lhs.relative() == rhs.relative();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<QuantityKind QK>
|
||||
quantity_point_kind(QK) ->
|
||||
quantity_point_kind<downcast_point_kind<typename QK::kind_type>, typename QK::unit, typename QK::rep>;
|
||||
quantity_point_kind(QK)
|
||||
-> quantity_point_kind<downcast_point_kind<typename QK::kind_type>, typename QK::unit, typename QK::rep>;
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
+451
-377
@@ -23,460 +23,534 @@
|
||||
#pragma once
|
||||
|
||||
#include <units/concepts.h>
|
||||
#include <random>
|
||||
#include <functional>
|
||||
#include <random>
|
||||
|
||||
namespace units {
|
||||
|
||||
namespace detail {
|
||||
template <Quantity Q, typename InputIt>
|
||||
static std::vector<typename Q::rep> i_qty_to_rep(InputIt first, InputIt last)
|
||||
{
|
||||
std::vector<typename Q::rep> intervals_rep;
|
||||
intervals_rep.reserve(static_cast<size_t>(std::distance(first, last)));
|
||||
for (auto itr = first; itr != last; ++itr) { intervals_rep.push_back(itr->number()); }
|
||||
return intervals_rep;
|
||||
}
|
||||
|
||||
template <Quantity Q>
|
||||
static std::vector<typename Q::rep> bl_qty_to_rep(std::initializer_list<Q>& bl)
|
||||
{
|
||||
std::vector<typename Q::rep> bl_rep;
|
||||
bl_rep.reserve(bl.size());
|
||||
for (const Q& qty : bl) { bl_rep.push_back(qty.number()); }
|
||||
return bl_rep;
|
||||
}
|
||||
|
||||
template <Quantity Q, typename UnaryOperation>
|
||||
inline static std::vector<typename Q::rep> fw_bl_pwc(std::initializer_list<Q>& bl, UnaryOperation fw)
|
||||
{
|
||||
using rep = TYPENAME Q::rep;
|
||||
std::vector<rep> w_bl;
|
||||
w_bl.reserve(bl.size());
|
||||
for (const Q& qty : bl) { w_bl.push_back(fw(qty)); }
|
||||
std::vector<rep> weights;
|
||||
weights.reserve(bl.size());
|
||||
for (size_t i = 0; i < bl.size() - 1; ++i) { weights.push_back(w_bl[i] + w_bl[i + 1]); }
|
||||
weights.push_back(0);
|
||||
return weights;
|
||||
}
|
||||
|
||||
template <Quantity Q, typename UnaryOperation>
|
||||
static std::vector<typename Q::rep> fw_bl_pwl(std::initializer_list<Q>& bl, UnaryOperation fw)
|
||||
{
|
||||
std::vector<typename Q::rep> weights;
|
||||
weights.reserve(bl.size());
|
||||
for (const Q& qty : bl) { weights.push_back(fw(qty)); }
|
||||
return weights;
|
||||
}
|
||||
} // namespace detail
|
||||
template<Quantity Q, typename InputIt>
|
||||
static std::vector<typename Q::rep> i_qty_to_rep(InputIt first, InputIt last)
|
||||
{
|
||||
std::vector<typename Q::rep> intervals_rep;
|
||||
intervals_rep.reserve(static_cast<size_t>(std::distance(first, last)));
|
||||
for (auto itr = first; itr != last; ++itr) {
|
||||
intervals_rep.push_back(itr->number());
|
||||
}
|
||||
return intervals_rep;
|
||||
}
|
||||
|
||||
template<Quantity Q>
|
||||
requires std::integral<typename Q::rep>
|
||||
struct uniform_int_distribution : public std::uniform_int_distribution<typename Q::rep>
|
||||
static std::vector<typename Q::rep> bl_qty_to_rep(std::initializer_list<Q>& bl)
|
||||
{
|
||||
using rep = TYPENAME Q::rep;
|
||||
using base = TYPENAME std::uniform_int_distribution<rep>;
|
||||
|
||||
uniform_int_distribution() : base() {}
|
||||
uniform_int_distribution(const Q& a, const Q& b) : base(a.number(), b.number()) {}
|
||||
|
||||
template<typename Generator>
|
||||
Q operator()(Generator& g) { return Q(base::operator()(g)); }
|
||||
|
||||
Q a() const { return Q(base::a()); }
|
||||
Q b() const { return Q(base::b()); }
|
||||
|
||||
Q min() const { return Q(base::min()); }
|
||||
Q max() const { return Q(base::max()); }
|
||||
std::vector<typename Q::rep> bl_rep;
|
||||
bl_rep.reserve(bl.size());
|
||||
for (const Q& qty : bl) {
|
||||
bl_rep.push_back(qty.number());
|
||||
}
|
||||
return bl_rep;
|
||||
}
|
||||
|
||||
template<Quantity Q, typename UnaryOperation>
|
||||
inline static std::vector<typename Q::rep> fw_bl_pwc(std::initializer_list<Q>& bl, UnaryOperation fw)
|
||||
{
|
||||
using rep = TYPENAME Q::rep;
|
||||
std::vector<rep> w_bl;
|
||||
w_bl.reserve(bl.size());
|
||||
for (const Q& qty : bl) {
|
||||
w_bl.push_back(fw(qty));
|
||||
}
|
||||
std::vector<rep> weights;
|
||||
weights.reserve(bl.size());
|
||||
for (size_t i = 0; i < bl.size() - 1; ++i) {
|
||||
weights.push_back(w_bl[i] + w_bl[i + 1]);
|
||||
}
|
||||
weights.push_back(0);
|
||||
return weights;
|
||||
}
|
||||
|
||||
template<Quantity Q, typename UnaryOperation>
|
||||
static std::vector<typename Q::rep> fw_bl_pwl(std::initializer_list<Q>& bl, UnaryOperation fw)
|
||||
{
|
||||
std::vector<typename Q::rep> weights;
|
||||
weights.reserve(bl.size());
|
||||
for (const Q& qty : bl) {
|
||||
weights.push_back(fw(qty));
|
||||
}
|
||||
return weights;
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
template<Quantity Q>
|
||||
requires std::integral<typename Q::rep>
|
||||
struct uniform_int_distribution : public std::uniform_int_distribution<typename Q::rep> {
|
||||
using rep = TYPENAME Q::rep;
|
||||
using base = TYPENAME std::uniform_int_distribution<rep>;
|
||||
|
||||
uniform_int_distribution() : base() {}
|
||||
uniform_int_distribution(const Q& a, const Q& b) : base(a.number(), b.number()) {}
|
||||
|
||||
template<typename Generator>
|
||||
Q operator()(Generator& g)
|
||||
{
|
||||
return Q(base::operator()(g));
|
||||
}
|
||||
|
||||
Q a() const { return Q(base::a()); }
|
||||
Q b() const { return Q(base::b()); }
|
||||
|
||||
Q min() const { return Q(base::min()); }
|
||||
Q max() const { return Q(base::max()); }
|
||||
};
|
||||
|
||||
template<Quantity Q>
|
||||
requires std::floating_point<typename Q::rep>
|
||||
struct uniform_real_distribution : public std::uniform_real_distribution<typename Q::rep>
|
||||
{
|
||||
using rep = TYPENAME Q::rep;
|
||||
using base = TYPENAME std::uniform_real_distribution<rep>;
|
||||
|
||||
uniform_real_distribution() : base() {}
|
||||
uniform_real_distribution(const Q& a, const Q& b) : base(a.number(), b.number()) {}
|
||||
|
||||
template<typename Generator>
|
||||
Q operator()(Generator& g) { return Q(base::operator()(g)); }
|
||||
|
||||
Q a() const { return Q(base::a()); }
|
||||
Q b() const { return Q(base::b()); }
|
||||
|
||||
Q min() const { return Q(base::min()); }
|
||||
Q max() const { return Q(base::max()); }
|
||||
requires std::floating_point<typename Q::rep>
|
||||
struct uniform_real_distribution : public std::uniform_real_distribution<typename Q::rep> {
|
||||
using rep = TYPENAME Q::rep;
|
||||
using base = TYPENAME std::uniform_real_distribution<rep>;
|
||||
|
||||
uniform_real_distribution() : base() {}
|
||||
uniform_real_distribution(const Q& a, const Q& b) : base(a.number(), b.number()) {}
|
||||
|
||||
template<typename Generator>
|
||||
Q operator()(Generator& g)
|
||||
{
|
||||
return Q(base::operator()(g));
|
||||
}
|
||||
|
||||
Q a() const { return Q(base::a()); }
|
||||
Q b() const { return Q(base::b()); }
|
||||
|
||||
Q min() const { return Q(base::min()); }
|
||||
Q max() const { return Q(base::max()); }
|
||||
};
|
||||
|
||||
template<Quantity Q>
|
||||
requires std::integral<typename Q::rep>
|
||||
struct binomial_distribution : public std::binomial_distribution<typename Q::rep>
|
||||
{
|
||||
using rep = TYPENAME Q::rep;
|
||||
using base = TYPENAME std::binomial_distribution<rep>;
|
||||
|
||||
binomial_distribution() : base() {}
|
||||
binomial_distribution(const Q& t, double p) : base(t.number(), p) {}
|
||||
|
||||
template<typename Generator>
|
||||
Q operator()(Generator& g) { return Q(base::operator()(g)); }
|
||||
|
||||
Q t() const { return Q(base::t()); }
|
||||
|
||||
Q min() const { return Q(base::min()); }
|
||||
Q max() const { return Q(base::max()); }
|
||||
requires std::integral<typename Q::rep>
|
||||
struct binomial_distribution : public std::binomial_distribution<typename Q::rep> {
|
||||
using rep = TYPENAME Q::rep;
|
||||
using base = TYPENAME std::binomial_distribution<rep>;
|
||||
|
||||
binomial_distribution() : base() {}
|
||||
binomial_distribution(const Q& t, double p) : base(t.number(), p) {}
|
||||
|
||||
template<typename Generator>
|
||||
Q operator()(Generator& g)
|
||||
{
|
||||
return Q(base::operator()(g));
|
||||
}
|
||||
|
||||
Q t() const { return Q(base::t()); }
|
||||
|
||||
Q min() const { return Q(base::min()); }
|
||||
Q max() const { return Q(base::max()); }
|
||||
};
|
||||
|
||||
template<Quantity Q>
|
||||
requires std::integral<typename Q::rep>
|
||||
struct negative_binomial_distribution : public std::negative_binomial_distribution<typename Q::rep>
|
||||
{
|
||||
using rep = TYPENAME Q::rep;
|
||||
using base = TYPENAME std::negative_binomial_distribution<rep>;
|
||||
|
||||
negative_binomial_distribution() : base() {}
|
||||
negative_binomial_distribution(const Q& k, double p) : base(k.number(), p) {}
|
||||
|
||||
template<typename Generator>
|
||||
Q operator()(Generator& g) { return Q(base::operator()(g)); }
|
||||
|
||||
Q k() const { return Q(base::k()); }
|
||||
|
||||
Q min() const { return Q(base::min()); }
|
||||
Q max() const { return Q(base::max()); }
|
||||
requires std::integral<typename Q::rep>
|
||||
struct negative_binomial_distribution : public std::negative_binomial_distribution<typename Q::rep> {
|
||||
using rep = TYPENAME Q::rep;
|
||||
using base = TYPENAME std::negative_binomial_distribution<rep>;
|
||||
|
||||
negative_binomial_distribution() : base() {}
|
||||
negative_binomial_distribution(const Q& k, double p) : base(k.number(), p) {}
|
||||
|
||||
template<typename Generator>
|
||||
Q operator()(Generator& g)
|
||||
{
|
||||
return Q(base::operator()(g));
|
||||
}
|
||||
|
||||
Q k() const { return Q(base::k()); }
|
||||
|
||||
Q min() const { return Q(base::min()); }
|
||||
Q max() const { return Q(base::max()); }
|
||||
};
|
||||
|
||||
template<Quantity Q>
|
||||
requires std::integral<typename Q::rep>
|
||||
struct geometric_distribution : public std::geometric_distribution<typename Q::rep>
|
||||
{
|
||||
using rep = TYPENAME Q::rep;
|
||||
using base = TYPENAME std::geometric_distribution<rep>;
|
||||
|
||||
geometric_distribution() : base() {}
|
||||
geometric_distribution(double p) : base(p) {}
|
||||
|
||||
template<typename Generator>
|
||||
Q operator()(Generator& g) { return Q(base::operator()(g)); }
|
||||
requires std::integral<typename Q::rep>
|
||||
struct geometric_distribution : public std::geometric_distribution<typename Q::rep> {
|
||||
using rep = TYPENAME Q::rep;
|
||||
using base = TYPENAME std::geometric_distribution<rep>;
|
||||
|
||||
Q min() const { return Q(base::min()); }
|
||||
Q max() const { return Q(base::max()); }
|
||||
geometric_distribution() : base() {}
|
||||
geometric_distribution(double p) : base(p) {}
|
||||
|
||||
template<typename Generator>
|
||||
Q operator()(Generator& g)
|
||||
{
|
||||
return Q(base::operator()(g));
|
||||
}
|
||||
|
||||
Q min() const { return Q(base::min()); }
|
||||
Q max() const { return Q(base::max()); }
|
||||
};
|
||||
|
||||
template<Quantity Q>
|
||||
requires std::integral<typename Q::rep>
|
||||
struct poisson_distribution : public std::poisson_distribution<typename Q::rep>
|
||||
{
|
||||
using rep = TYPENAME Q::rep;
|
||||
using base = TYPENAME std::poisson_distribution<rep>;
|
||||
|
||||
poisson_distribution() : base() {}
|
||||
explicit poisson_distribution(double p) : base(p) {}
|
||||
|
||||
template<typename Generator>
|
||||
Q operator()(Generator& g) { return Q(base::operator()(g)); }
|
||||
|
||||
Q min() const { return Q(base::min()); }
|
||||
Q max() const { return Q(base::max()); }
|
||||
requires std::integral<typename Q::rep>
|
||||
struct poisson_distribution : public std::poisson_distribution<typename Q::rep> {
|
||||
using rep = TYPENAME Q::rep;
|
||||
using base = TYPENAME std::poisson_distribution<rep>;
|
||||
|
||||
poisson_distribution() : base() {}
|
||||
explicit poisson_distribution(double p) : base(p) {}
|
||||
|
||||
template<typename Generator>
|
||||
Q operator()(Generator& g)
|
||||
{
|
||||
return Q(base::operator()(g));
|
||||
}
|
||||
|
||||
Q min() const { return Q(base::min()); }
|
||||
Q max() const { return Q(base::max()); }
|
||||
};
|
||||
|
||||
template<Quantity Q>
|
||||
requires std::floating_point<typename Q::rep>
|
||||
struct exponential_distribution : public std::exponential_distribution<typename Q::rep>
|
||||
{
|
||||
using rep = TYPENAME Q::rep;
|
||||
using base = TYPENAME std::exponential_distribution<rep>;
|
||||
|
||||
exponential_distribution() : base() {}
|
||||
explicit exponential_distribution(const rep& lambda) : base(lambda) {}
|
||||
|
||||
template<typename Generator>
|
||||
Q operator()(Generator& g) { return Q(base::operator()(g)); }
|
||||
|
||||
Q min() const { return Q(base::min()); }
|
||||
Q max() const { return Q(base::max()); }
|
||||
requires std::floating_point<typename Q::rep>
|
||||
struct exponential_distribution : public std::exponential_distribution<typename Q::rep> {
|
||||
using rep = TYPENAME Q::rep;
|
||||
using base = TYPENAME std::exponential_distribution<rep>;
|
||||
|
||||
exponential_distribution() : base() {}
|
||||
explicit exponential_distribution(const rep& lambda) : base(lambda) {}
|
||||
|
||||
template<typename Generator>
|
||||
Q operator()(Generator& g)
|
||||
{
|
||||
return Q(base::operator()(g));
|
||||
}
|
||||
|
||||
Q min() const { return Q(base::min()); }
|
||||
Q max() const { return Q(base::max()); }
|
||||
};
|
||||
|
||||
template<Quantity Q>
|
||||
requires std::floating_point<typename Q::rep>
|
||||
struct gamma_distribution : public std::gamma_distribution<typename Q::rep>
|
||||
{
|
||||
using rep = TYPENAME Q::rep;
|
||||
using base = TYPENAME std::gamma_distribution<rep>;
|
||||
|
||||
gamma_distribution() : base() {}
|
||||
gamma_distribution(const rep& alpha, const rep& beta) : base(alpha, beta) {}
|
||||
|
||||
template<typename Generator>
|
||||
Q operator()(Generator& g) { return Q(base::operator()(g)); }
|
||||
|
||||
Q min() const { return Q(base::min()); }
|
||||
Q max() const { return Q(base::max()); }
|
||||
requires std::floating_point<typename Q::rep>
|
||||
struct gamma_distribution : public std::gamma_distribution<typename Q::rep> {
|
||||
using rep = TYPENAME Q::rep;
|
||||
using base = TYPENAME std::gamma_distribution<rep>;
|
||||
|
||||
gamma_distribution() : base() {}
|
||||
gamma_distribution(const rep& alpha, const rep& beta) : base(alpha, beta) {}
|
||||
|
||||
template<typename Generator>
|
||||
Q operator()(Generator& g)
|
||||
{
|
||||
return Q(base::operator()(g));
|
||||
}
|
||||
|
||||
Q min() const { return Q(base::min()); }
|
||||
Q max() const { return Q(base::max()); }
|
||||
};
|
||||
|
||||
template<Quantity Q>
|
||||
requires std::floating_point<typename Q::rep>
|
||||
struct weibull_distribution : public std::weibull_distribution<typename Q::rep>
|
||||
{
|
||||
using rep = TYPENAME Q::rep;
|
||||
using base = TYPENAME std::weibull_distribution<rep>;
|
||||
|
||||
weibull_distribution() : base() {}
|
||||
weibull_distribution(const rep& a, const rep& b) : base(a, b) {}
|
||||
|
||||
template<typename Generator>
|
||||
Q operator()(Generator& g) { return Q(base::operator()(g)); }
|
||||
|
||||
Q min() const { return Q(base::min()); }
|
||||
Q max() const { return Q(base::max()); }
|
||||
requires std::floating_point<typename Q::rep>
|
||||
struct weibull_distribution : public std::weibull_distribution<typename Q::rep> {
|
||||
using rep = TYPENAME Q::rep;
|
||||
using base = TYPENAME std::weibull_distribution<rep>;
|
||||
|
||||
weibull_distribution() : base() {}
|
||||
weibull_distribution(const rep& a, const rep& b) : base(a, b) {}
|
||||
|
||||
template<typename Generator>
|
||||
Q operator()(Generator& g)
|
||||
{
|
||||
return Q(base::operator()(g));
|
||||
}
|
||||
|
||||
Q min() const { return Q(base::min()); }
|
||||
Q max() const { return Q(base::max()); }
|
||||
};
|
||||
|
||||
template<Quantity Q>
|
||||
requires std::floating_point<typename Q::rep>
|
||||
struct extreme_value_distribution : public std::extreme_value_distribution<typename Q::rep>
|
||||
{
|
||||
using rep = TYPENAME Q::rep;
|
||||
using base = TYPENAME std::extreme_value_distribution<rep>;
|
||||
|
||||
extreme_value_distribution() : base() {}
|
||||
extreme_value_distribution(const Q& a, const rep& b) : base(a.number(), b) {}
|
||||
|
||||
template<typename Generator>
|
||||
Q operator()(Generator& g) { return Q(base::operator()(g)); }
|
||||
requires std::floating_point<typename Q::rep>
|
||||
struct extreme_value_distribution : public std::extreme_value_distribution<typename Q::rep> {
|
||||
using rep = TYPENAME Q::rep;
|
||||
using base = TYPENAME std::extreme_value_distribution<rep>;
|
||||
|
||||
Q a() const { return Q(base::a()); }
|
||||
|
||||
Q min() const { return Q(base::min()); }
|
||||
Q max() const { return Q(base::max()); }
|
||||
extreme_value_distribution() : base() {}
|
||||
extreme_value_distribution(const Q& a, const rep& b) : base(a.number(), b) {}
|
||||
|
||||
template<typename Generator>
|
||||
Q operator()(Generator& g)
|
||||
{
|
||||
return Q(base::operator()(g));
|
||||
}
|
||||
|
||||
Q a() const { return Q(base::a()); }
|
||||
|
||||
Q min() const { return Q(base::min()); }
|
||||
Q max() const { return Q(base::max()); }
|
||||
};
|
||||
|
||||
template<Quantity Q>
|
||||
requires std::floating_point<typename Q::rep>
|
||||
struct normal_distribution : public std::normal_distribution<typename Q::rep>
|
||||
{
|
||||
using rep = TYPENAME Q::rep;
|
||||
using base = TYPENAME std::normal_distribution<rep>;
|
||||
|
||||
normal_distribution() : base() {}
|
||||
normal_distribution(const Q& mean, const Q& stddev) : base(mean.number(), stddev.number()) {}
|
||||
|
||||
template<typename Generator>
|
||||
Q operator()(Generator& g) { return Q(base::operator()(g)); }
|
||||
|
||||
Q mean() const { return Q(base::mean()); }
|
||||
Q stddev() const { return Q(base::stddev()); }
|
||||
|
||||
Q min() const { return Q(base::min()); }
|
||||
Q max() const { return Q(base::max()); }
|
||||
requires std::floating_point<typename Q::rep>
|
||||
struct normal_distribution : public std::normal_distribution<typename Q::rep> {
|
||||
using rep = TYPENAME Q::rep;
|
||||
using base = TYPENAME std::normal_distribution<rep>;
|
||||
|
||||
normal_distribution() : base() {}
|
||||
normal_distribution(const Q& mean, const Q& stddev) : base(mean.number(), stddev.number()) {}
|
||||
|
||||
template<typename Generator>
|
||||
Q operator()(Generator& g)
|
||||
{
|
||||
return Q(base::operator()(g));
|
||||
}
|
||||
|
||||
Q mean() const { return Q(base::mean()); }
|
||||
Q stddev() const { return Q(base::stddev()); }
|
||||
|
||||
Q min() const { return Q(base::min()); }
|
||||
Q max() const { return Q(base::max()); }
|
||||
};
|
||||
|
||||
template<Quantity Q>
|
||||
requires std::floating_point<typename Q::rep>
|
||||
struct lognormal_distribution : public std::lognormal_distribution<typename Q::rep>
|
||||
{
|
||||
using rep = TYPENAME Q::rep;
|
||||
using base = TYPENAME std::lognormal_distribution<rep>;
|
||||
|
||||
lognormal_distribution() : base() {}
|
||||
lognormal_distribution(const Q& m, const Q& s) : base(m.number(), s.number()) {}
|
||||
|
||||
template<typename Generator>
|
||||
Q operator()(Generator& g) { return Q(base::operator()(g)); }
|
||||
|
||||
Q m() const { return Q(base::m()); }
|
||||
Q s() const { return Q(base::s()); }
|
||||
|
||||
Q min() const { return Q(base::min()); }
|
||||
Q max() const { return Q(base::max()); }
|
||||
requires std::floating_point<typename Q::rep>
|
||||
struct lognormal_distribution : public std::lognormal_distribution<typename Q::rep> {
|
||||
using rep = TYPENAME Q::rep;
|
||||
using base = TYPENAME std::lognormal_distribution<rep>;
|
||||
|
||||
lognormal_distribution() : base() {}
|
||||
lognormal_distribution(const Q& m, const Q& s) : base(m.number(), s.number()) {}
|
||||
|
||||
template<typename Generator>
|
||||
Q operator()(Generator& g)
|
||||
{
|
||||
return Q(base::operator()(g));
|
||||
}
|
||||
|
||||
Q m() const { return Q(base::m()); }
|
||||
Q s() const { return Q(base::s()); }
|
||||
|
||||
Q min() const { return Q(base::min()); }
|
||||
Q max() const { return Q(base::max()); }
|
||||
};
|
||||
|
||||
template<Quantity Q>
|
||||
requires std::floating_point<typename Q::rep>
|
||||
struct chi_squared_distribution : public std::chi_squared_distribution<typename Q::rep>
|
||||
{
|
||||
using rep = TYPENAME Q::rep;
|
||||
using base = TYPENAME std::chi_squared_distribution<rep>;
|
||||
|
||||
chi_squared_distribution() : base() {}
|
||||
explicit chi_squared_distribution(const rep& n) : base(n) {}
|
||||
|
||||
template<typename Generator>
|
||||
Q operator()(Generator& g) { return Q(base::operator()(g)); }
|
||||
|
||||
Q min() const { return Q(base::min()); }
|
||||
Q max() const { return Q(base::max()); }
|
||||
requires std::floating_point<typename Q::rep>
|
||||
struct chi_squared_distribution : public std::chi_squared_distribution<typename Q::rep> {
|
||||
using rep = TYPENAME Q::rep;
|
||||
using base = TYPENAME std::chi_squared_distribution<rep>;
|
||||
|
||||
chi_squared_distribution() : base() {}
|
||||
explicit chi_squared_distribution(const rep& n) : base(n) {}
|
||||
|
||||
template<typename Generator>
|
||||
Q operator()(Generator& g)
|
||||
{
|
||||
return Q(base::operator()(g));
|
||||
}
|
||||
|
||||
Q min() const { return Q(base::min()); }
|
||||
Q max() const { return Q(base::max()); }
|
||||
};
|
||||
|
||||
template<Quantity Q>
|
||||
requires std::floating_point<typename Q::rep>
|
||||
struct cauchy_distribution : public std::cauchy_distribution<typename Q::rep>
|
||||
{
|
||||
using rep = TYPENAME Q::rep;
|
||||
using base = TYPENAME std::cauchy_distribution<rep>;
|
||||
|
||||
cauchy_distribution() : base() {}
|
||||
cauchy_distribution(const Q& a, const Q& b) : base(a.number(), b.number()) {}
|
||||
|
||||
template<typename Generator>
|
||||
Q operator()(Generator& g) { return Q(base::operator()(g)); }
|
||||
|
||||
Q a() const { return Q(base::a()); }
|
||||
Q b() const { return Q(base::b()); }
|
||||
|
||||
Q min() const { return Q(base::min()); }
|
||||
Q max() const { return Q(base::max()); }
|
||||
requires std::floating_point<typename Q::rep>
|
||||
struct cauchy_distribution : public std::cauchy_distribution<typename Q::rep> {
|
||||
using rep = TYPENAME Q::rep;
|
||||
using base = TYPENAME std::cauchy_distribution<rep>;
|
||||
|
||||
cauchy_distribution() : base() {}
|
||||
cauchy_distribution(const Q& a, const Q& b) : base(a.number(), b.number()) {}
|
||||
|
||||
template<typename Generator>
|
||||
Q operator()(Generator& g)
|
||||
{
|
||||
return Q(base::operator()(g));
|
||||
}
|
||||
|
||||
Q a() const { return Q(base::a()); }
|
||||
Q b() const { return Q(base::b()); }
|
||||
|
||||
Q min() const { return Q(base::min()); }
|
||||
Q max() const { return Q(base::max()); }
|
||||
};
|
||||
|
||||
template<Quantity Q>
|
||||
requires std::floating_point<typename Q::rep>
|
||||
struct fisher_f_distribution : public std::fisher_f_distribution<typename Q::rep>
|
||||
{
|
||||
using rep = TYPENAME Q::rep;
|
||||
using base = TYPENAME std::fisher_f_distribution<rep>;
|
||||
|
||||
fisher_f_distribution() : base() {}
|
||||
fisher_f_distribution(const rep& m, const rep& n) : base(m, n) {}
|
||||
|
||||
template<typename Generator>
|
||||
Q operator()(Generator& g) { return Q(base::operator()(g)); }
|
||||
|
||||
Q min() const { return Q(base::min()); }
|
||||
Q max() const { return Q(base::max()); }
|
||||
requires std::floating_point<typename Q::rep>
|
||||
struct fisher_f_distribution : public std::fisher_f_distribution<typename Q::rep> {
|
||||
using rep = TYPENAME Q::rep;
|
||||
using base = TYPENAME std::fisher_f_distribution<rep>;
|
||||
|
||||
fisher_f_distribution() : base() {}
|
||||
fisher_f_distribution(const rep& m, const rep& n) : base(m, n) {}
|
||||
|
||||
template<typename Generator>
|
||||
Q operator()(Generator& g)
|
||||
{
|
||||
return Q(base::operator()(g));
|
||||
}
|
||||
|
||||
Q min() const { return Q(base::min()); }
|
||||
Q max() const { return Q(base::max()); }
|
||||
};
|
||||
|
||||
template<Quantity Q>
|
||||
requires std::floating_point<typename Q::rep>
|
||||
struct student_t_distribution : public std::student_t_distribution<typename Q::rep>
|
||||
{
|
||||
using rep = TYPENAME Q::rep;
|
||||
using base = TYPENAME std::student_t_distribution<rep>;
|
||||
|
||||
student_t_distribution() : base() {}
|
||||
explicit student_t_distribution(const rep& n) : base(n) {}
|
||||
|
||||
template<typename Generator>
|
||||
Q operator()(Generator& g) { return Q(base::operator()(g)); }
|
||||
|
||||
Q min() const { return Q(base::min()); }
|
||||
Q max() const { return Q(base::max()); }
|
||||
requires std::floating_point<typename Q::rep>
|
||||
struct student_t_distribution : public std::student_t_distribution<typename Q::rep> {
|
||||
using rep = TYPENAME Q::rep;
|
||||
using base = TYPENAME std::student_t_distribution<rep>;
|
||||
|
||||
student_t_distribution() : base() {}
|
||||
explicit student_t_distribution(const rep& n) : base(n) {}
|
||||
|
||||
template<typename Generator>
|
||||
Q operator()(Generator& g)
|
||||
{
|
||||
return Q(base::operator()(g));
|
||||
}
|
||||
|
||||
Q min() const { return Q(base::min()); }
|
||||
Q max() const { return Q(base::max()); }
|
||||
};
|
||||
|
||||
template<Quantity Q>
|
||||
requires std::integral<typename Q::rep>
|
||||
struct discrete_distribution : public std::discrete_distribution<typename Q::rep>
|
||||
{
|
||||
using rep = TYPENAME Q::rep;
|
||||
using base = TYPENAME std::discrete_distribution<rep>;
|
||||
|
||||
discrete_distribution() : base() {}
|
||||
|
||||
template <typename InputIt>
|
||||
discrete_distribution(InputIt first, InputIt last) : base(first, last) {}
|
||||
requires std::integral<typename Q::rep>
|
||||
struct discrete_distribution : public std::discrete_distribution<typename Q::rep> {
|
||||
using rep = TYPENAME Q::rep;
|
||||
using base = TYPENAME std::discrete_distribution<rep>;
|
||||
|
||||
discrete_distribution(std::initializer_list<double> weights) : base(weights) {}
|
||||
discrete_distribution() : base() {}
|
||||
|
||||
template <typename UnaryOperation>
|
||||
discrete_distribution(std::size_t count, double xmin, double xmax, UnaryOperation unary_op) :
|
||||
base(count, xmin, xmax, unary_op) {}
|
||||
|
||||
template<typename Generator>
|
||||
Q operator()(Generator& g) { return Q(base::operator()(g)); }
|
||||
|
||||
Q min() const { return Q(base::min()); }
|
||||
Q max() const { return Q(base::max()); }
|
||||
template<typename InputIt>
|
||||
discrete_distribution(InputIt first, InputIt last) : base(first, last)
|
||||
{
|
||||
}
|
||||
|
||||
discrete_distribution(std::initializer_list<double> weights) : base(weights) {}
|
||||
|
||||
template<typename UnaryOperation>
|
||||
discrete_distribution(std::size_t count, double xmin, double xmax, UnaryOperation unary_op) :
|
||||
base(count, xmin, xmax, unary_op)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Generator>
|
||||
Q operator()(Generator& g)
|
||||
{
|
||||
return Q(base::operator()(g));
|
||||
}
|
||||
|
||||
Q min() const { return Q(base::min()); }
|
||||
Q max() const { return Q(base::max()); }
|
||||
};
|
||||
|
||||
template<Quantity Q>
|
||||
requires std::floating_point<typename Q::rep>
|
||||
class piecewise_constant_distribution : public std::piecewise_constant_distribution<typename Q::rep>
|
||||
{
|
||||
using rep = TYPENAME Q::rep;
|
||||
using base = TYPENAME std::piecewise_constant_distribution<rep>;
|
||||
|
||||
template <typename InputIt>
|
||||
piecewise_constant_distribution(const std::vector<rep>& i, InputIt first_w) :
|
||||
base(i.cbegin(), i.cend(), first_w) {}
|
||||
|
||||
piecewise_constant_distribution(const std::vector<rep>& bl, const std::vector<rep>& weights) :
|
||||
base(bl.cbegin(), bl.cend(), weights.cbegin()) {}
|
||||
requires std::floating_point<typename Q::rep>
|
||||
class piecewise_constant_distribution : public std::piecewise_constant_distribution<typename Q::rep> {
|
||||
using rep = TYPENAME Q::rep;
|
||||
using base = TYPENAME std::piecewise_constant_distribution<rep>;
|
||||
|
||||
template<typename InputIt>
|
||||
piecewise_constant_distribution(const std::vector<rep>& i, InputIt first_w) : base(i.cbegin(), i.cend(), first_w)
|
||||
{
|
||||
}
|
||||
|
||||
piecewise_constant_distribution(const std::vector<rep>& bl, const std::vector<rep>& weights) :
|
||||
base(bl.cbegin(), bl.cend(), weights.cbegin())
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
piecewise_constant_distribution() : base() {}
|
||||
|
||||
template <typename InputIt1, typename InputIt2>
|
||||
piecewise_constant_distribution(InputIt1 first_i, InputIt1 last_i, InputIt2 first_w) :
|
||||
piecewise_constant_distribution(detail::i_qty_to_rep<Q>(first_i, last_i), first_w) {}
|
||||
piecewise_constant_distribution() : base() {}
|
||||
|
||||
template <typename UnaryOperation>
|
||||
piecewise_constant_distribution(std::initializer_list<Q> bl, UnaryOperation fw) :
|
||||
piecewise_constant_distribution(detail::bl_qty_to_rep(bl), detail::fw_bl_pwc(bl, fw)) {}
|
||||
template<typename InputIt1, typename InputIt2>
|
||||
piecewise_constant_distribution(InputIt1 first_i, InputIt1 last_i, InputIt2 first_w) :
|
||||
piecewise_constant_distribution(detail::i_qty_to_rep<Q>(first_i, last_i), first_w)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename UnaryOperation>
|
||||
piecewise_constant_distribution(std::size_t nw, const Q& xmin, const Q& xmax, UnaryOperation fw) :
|
||||
base(nw, xmin.number(), xmax.number(), [fw](rep val) { return fw(Q(val)); }) {}
|
||||
|
||||
template<typename Generator>
|
||||
Q operator()(Generator& g) { return Q(base::operator()(g)); }
|
||||
template<typename UnaryOperation>
|
||||
piecewise_constant_distribution(std::initializer_list<Q> bl, UnaryOperation fw) :
|
||||
piecewise_constant_distribution(detail::bl_qty_to_rep(bl), detail::fw_bl_pwc(bl, fw))
|
||||
{
|
||||
}
|
||||
|
||||
std::vector<Q> intervals() const
|
||||
{
|
||||
std::vector<rep> intervals_rep = base::intervals();
|
||||
std::vector<Q> intervals_qty;
|
||||
intervals_qty.reserve(intervals_rep.size());
|
||||
for (const rep& val : intervals_rep) { intervals_qty.push_back(Q(val)); }
|
||||
return intervals_qty;
|
||||
template<typename UnaryOperation>
|
||||
piecewise_constant_distribution(std::size_t nw, const Q& xmin, const Q& xmax, UnaryOperation fw) :
|
||||
base(nw, xmin.number(), xmax.number(), [fw](rep val) { return fw(Q(val)); })
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Generator>
|
||||
Q operator()(Generator& g)
|
||||
{
|
||||
return Q(base::operator()(g));
|
||||
}
|
||||
|
||||
std::vector<Q> intervals() const
|
||||
{
|
||||
std::vector<rep> intervals_rep = base::intervals();
|
||||
std::vector<Q> intervals_qty;
|
||||
intervals_qty.reserve(intervals_rep.size());
|
||||
for (const rep& val : intervals_rep) {
|
||||
intervals_qty.push_back(Q(val));
|
||||
}
|
||||
|
||||
Q min() const { return Q(base::min()); }
|
||||
Q max() const { return Q(base::max()); }
|
||||
return intervals_qty;
|
||||
}
|
||||
|
||||
Q min() const { return Q(base::min()); }
|
||||
Q max() const { return Q(base::max()); }
|
||||
};
|
||||
|
||||
template<Quantity Q>
|
||||
requires std::floating_point<typename Q::rep>
|
||||
class piecewise_linear_distribution : public std::piecewise_linear_distribution<typename Q::rep>
|
||||
{
|
||||
using rep = TYPENAME Q::rep;
|
||||
using base = TYPENAME std::piecewise_linear_distribution<rep>;
|
||||
|
||||
template <typename InputIt>
|
||||
piecewise_linear_distribution(const std::vector<rep>& i, InputIt first_w) :
|
||||
base(i.cbegin(), i.cend(), first_w) {}
|
||||
|
||||
piecewise_linear_distribution(const std::vector<rep>& bl, const std::vector<rep>& weights) :
|
||||
base(bl.cbegin(), bl.cend(), weights.cbegin()) {}
|
||||
requires std::floating_point<typename Q::rep>
|
||||
class piecewise_linear_distribution : public std::piecewise_linear_distribution<typename Q::rep> {
|
||||
using rep = TYPENAME Q::rep;
|
||||
using base = TYPENAME std::piecewise_linear_distribution<rep>;
|
||||
|
||||
template<typename InputIt>
|
||||
piecewise_linear_distribution(const std::vector<rep>& i, InputIt first_w) : base(i.cbegin(), i.cend(), first_w)
|
||||
{
|
||||
}
|
||||
|
||||
piecewise_linear_distribution(const std::vector<rep>& bl, const std::vector<rep>& weights) :
|
||||
base(bl.cbegin(), bl.cend(), weights.cbegin())
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
piecewise_linear_distribution() : base() {}
|
||||
|
||||
template <typename InputIt1, typename InputIt2>
|
||||
piecewise_linear_distribution(InputIt1 first_i, InputIt1 last_i, InputIt2 first_w) :
|
||||
piecewise_linear_distribution(detail::i_qty_to_rep<Q>(first_i, last_i), first_w) {}
|
||||
piecewise_linear_distribution() : base() {}
|
||||
|
||||
template <typename UnaryOperation>
|
||||
piecewise_linear_distribution(std::initializer_list<Q> bl, UnaryOperation fw) :
|
||||
piecewise_linear_distribution(detail::bl_qty_to_rep(bl), detail::fw_bl_pwl(bl, fw)) {}
|
||||
template<typename InputIt1, typename InputIt2>
|
||||
piecewise_linear_distribution(InputIt1 first_i, InputIt1 last_i, InputIt2 first_w) :
|
||||
piecewise_linear_distribution(detail::i_qty_to_rep<Q>(first_i, last_i), first_w)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename UnaryOperation>
|
||||
piecewise_linear_distribution(std::size_t nw, const Q& xmin, const Q& xmax, UnaryOperation fw) :
|
||||
base(nw, xmin.number(), xmax.number(), [fw](rep val) { return fw(Q(val)); }) {}
|
||||
|
||||
template<typename Generator>
|
||||
Q operator()(Generator& g) { return Q(base::operator()(g)); }
|
||||
template<typename UnaryOperation>
|
||||
piecewise_linear_distribution(std::initializer_list<Q> bl, UnaryOperation fw) :
|
||||
piecewise_linear_distribution(detail::bl_qty_to_rep(bl), detail::fw_bl_pwl(bl, fw))
|
||||
{
|
||||
}
|
||||
|
||||
std::vector<Q> intervals() const
|
||||
{
|
||||
std::vector<rep> intervals_rep = base::intervals();
|
||||
std::vector<Q> intervals_qty;
|
||||
intervals_qty.reserve(intervals_rep.size());
|
||||
for (const rep& val : intervals_rep) { intervals_qty.push_back(Q(val)); }
|
||||
return intervals_qty;
|
||||
template<typename UnaryOperation>
|
||||
piecewise_linear_distribution(std::size_t nw, const Q& xmin, const Q& xmax, UnaryOperation fw) :
|
||||
base(nw, xmin.number(), xmax.number(), [fw](rep val) { return fw(Q(val)); })
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Generator>
|
||||
Q operator()(Generator& g)
|
||||
{
|
||||
return Q(base::operator()(g));
|
||||
}
|
||||
|
||||
std::vector<Q> intervals() const
|
||||
{
|
||||
std::vector<rep> intervals_rep = base::intervals();
|
||||
std::vector<Q> intervals_qty;
|
||||
intervals_qty.reserve(intervals_rep.size());
|
||||
for (const rep& val : intervals_rep) {
|
||||
intervals_qty.push_back(Q(val));
|
||||
}
|
||||
|
||||
Q min() const { return Q(base::min()); }
|
||||
Q max() const { return Q(base::max()); }
|
||||
return intervals_qty;
|
||||
}
|
||||
|
||||
Q min() const { return Q(base::min()); }
|
||||
Q max() const { return Q(base::max()); }
|
||||
};
|
||||
|
||||
} // namespace units
|
||||
} // namespace units
|
||||
|
||||
@@ -30,9 +30,9 @@
|
||||
#include <cstdint>
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#include <gsl/gsl-lite.hpp>
|
||||
#include <array>
|
||||
#include <numeric>
|
||||
#include <gsl/gsl-lite.hpp>
|
||||
|
||||
namespace units {
|
||||
|
||||
@@ -52,7 +52,7 @@ struct ratio {
|
||||
std::intmax_t den;
|
||||
std::intmax_t exp;
|
||||
|
||||
constexpr explicit(false) ratio(std::intmax_t n, std::intmax_t d = 1, std::intmax_t e = 0): num(n), den(d), exp(e)
|
||||
constexpr explicit(false) ratio(std::intmax_t n, std::intmax_t d = 1, std::intmax_t e = 0) : num(n), den(d), exp(e)
|
||||
{
|
||||
gsl_Expects(den != 0);
|
||||
detail::normalize(num, den, exp);
|
||||
@@ -60,16 +60,13 @@ struct ratio {
|
||||
|
||||
[[nodiscard]] friend constexpr bool operator==(const ratio&, const ratio&) = default;
|
||||
|
||||
[[nodiscard]] friend constexpr ratio operator-(const ratio& r)
|
||||
{
|
||||
return ratio(-r.num, r.den, r.exp);
|
||||
}
|
||||
[[nodiscard]] friend constexpr ratio operator-(const ratio& r) { return ratio(-r.num, r.den, r.exp); }
|
||||
|
||||
[[nodiscard]] friend constexpr ratio operator+(ratio lhs, ratio rhs)
|
||||
{
|
||||
// First, get the inputs into a common exponent.
|
||||
const auto common_exp = std::min(lhs.exp, rhs.exp);
|
||||
auto commonify = [common_exp](ratio &r) {
|
||||
auto commonify = [common_exp](ratio& r) {
|
||||
while (r.exp > common_exp) {
|
||||
r.num *= 10;
|
||||
--r.exp;
|
||||
@@ -86,24 +83,17 @@ struct ratio {
|
||||
const std::intmax_t gcd1 = std::gcd(lhs.num, rhs.den);
|
||||
const std::intmax_t gcd2 = std::gcd(rhs.num, lhs.den);
|
||||
return ratio(detail::safe_multiply(lhs.num / gcd1, rhs.num / gcd2),
|
||||
detail::safe_multiply(lhs.den / gcd2, rhs.den / gcd1),
|
||||
lhs.exp + rhs.exp);
|
||||
detail::safe_multiply(lhs.den / gcd2, rhs.den / gcd1), lhs.exp + rhs.exp);
|
||||
}
|
||||
|
||||
[[nodiscard]] friend constexpr ratio operator/(const ratio& lhs, const ratio& rhs)
|
||||
{
|
||||
return lhs * inverse(rhs);
|
||||
}
|
||||
[[nodiscard]] friend constexpr ratio operator/(const ratio& lhs, const ratio& rhs) { return lhs * inverse(rhs); }
|
||||
};
|
||||
|
||||
[[nodiscard]] constexpr ratio inverse(const ratio& r)
|
||||
{
|
||||
return ratio(r.den, r.num, -r.exp);
|
||||
}
|
||||
[[nodiscard]] constexpr ratio inverse(const ratio& r) { return ratio(r.den, r.num, -r.exp); }
|
||||
|
||||
[[nodiscard]] constexpr bool is_integral(const ratio& r)
|
||||
{
|
||||
if(r.exp < 0) {
|
||||
if (r.exp < 0) {
|
||||
return false;
|
||||
} else {
|
||||
return detail::gcdpow(r.num, r.exp, r.den) == r.den;
|
||||
|
||||
@@ -36,24 +36,26 @@ struct reference;
|
||||
namespace detail {
|
||||
|
||||
template<typename D, typename D1, typename U1, typename D2, typename U2>
|
||||
using reference_multiply_impl = reference<D, downcast_unit<D,
|
||||
(U1::ratio / dimension_unit<D1>::ratio) * (U2::ratio / dimension_unit<D2>::ratio) * dimension_unit<D>::ratio>>;
|
||||
using reference_multiply_impl =
|
||||
reference<D, downcast_unit<D, (U1::ratio / dimension_unit<D1>::ratio) * (U2::ratio / dimension_unit<D2>::ratio) *
|
||||
dimension_unit<D>::ratio>>;
|
||||
|
||||
template<typename D, typename D1, typename U1, typename D2, typename U2>
|
||||
using reference_divide_impl = reference<D, downcast_unit<D,
|
||||
(U1::ratio / dimension_unit<D1>::ratio) / (U2::ratio / dimension_unit<D2>::ratio) * dimension_unit<D>::ratio>>;
|
||||
using reference_divide_impl =
|
||||
reference<D, downcast_unit<D, (U1::ratio / dimension_unit<D1>::ratio) / (U2::ratio / dimension_unit<D2>::ratio) *
|
||||
dimension_unit<D>::ratio>>;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<Reference R1, Reference R2>
|
||||
using reference_multiply = detail::reference_multiply_impl<
|
||||
dimension_multiply<typename R1::dimension, typename R2::dimension>,
|
||||
typename R1::dimension, typename R1::unit, typename R2::dimension, typename R2::unit>;
|
||||
using reference_multiply =
|
||||
detail::reference_multiply_impl<dimension_multiply<typename R1::dimension, typename R2::dimension>,
|
||||
typename R1::dimension, typename R1::unit, typename R2::dimension, typename R2::unit>;
|
||||
|
||||
template<Reference R1, Reference R2>
|
||||
using reference_divide = detail::reference_divide_impl<
|
||||
dimension_divide<typename R1::dimension, typename R2::dimension>,
|
||||
typename R1::dimension, typename R1::unit, typename R2::dimension, typename R2::unit>;
|
||||
using reference_divide =
|
||||
detail::reference_divide_impl<dimension_divide<typename R1::dimension, typename R2::dimension>,
|
||||
typename R1::dimension, typename R1::unit, typename R2::dimension, typename R2::unit>;
|
||||
|
||||
/**
|
||||
* @brief The type for quantity references
|
||||
@@ -62,21 +64,21 @@ using reference_divide = detail::reference_divide_impl<
|
||||
*
|
||||
* @code{.cpp}
|
||||
* namespace length_references {
|
||||
*
|
||||
*
|
||||
* inline constexpr auto m = reference<dim_length, metre>{};
|
||||
* inline constexpr auto km = reference<dim_length, kilometre>{};
|
||||
*
|
||||
*
|
||||
* }
|
||||
*
|
||||
*
|
||||
* namespace references {
|
||||
*
|
||||
*
|
||||
* using namespace length_references;
|
||||
*
|
||||
*
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
*
|
||||
* Quantity references simplify quantity creation:
|
||||
*
|
||||
*
|
||||
* @code{.cpp}
|
||||
* using namespace units::isq::si::references;
|
||||
*
|
||||
@@ -85,12 +87,12 @@ using reference_divide = detail::reference_divide_impl<
|
||||
* @endcode
|
||||
*
|
||||
* Also, it is allowed to define custom quantity references from existing ones:
|
||||
*
|
||||
*
|
||||
* @code{.cpp}
|
||||
* constexpr auto Nm = N * m;
|
||||
* constexpr auto mph = mi / h;
|
||||
* @endcode
|
||||
*
|
||||
*
|
||||
* The following syntaxes are not allowed:
|
||||
* `2 / s`, `km * 3`, `s / 4`, `70 * km / h`.
|
||||
*/
|
||||
@@ -103,10 +105,16 @@ struct reference {
|
||||
// Below friend functions are to be found via argument-dependent lookup only
|
||||
|
||||
template<Reference R2>
|
||||
[[nodiscard]] friend constexpr reference_multiply<reference, R2> operator*(reference, R2) { return {}; }
|
||||
[[nodiscard]] friend constexpr reference_multiply<reference, R2> operator*(reference, R2)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
template<Reference R2>
|
||||
[[nodiscard]] friend constexpr reference_divide<reference, R2> operator/(reference, R2) { return {}; }
|
||||
[[nodiscard]] friend constexpr reference_divide<reference, R2> operator/(reference, R2)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
template<Representation Rep>
|
||||
[[nodiscard]] friend constexpr Quantity auto operator*(const Rep& lhs, reference)
|
||||
@@ -117,7 +125,10 @@ struct reference {
|
||||
friend void /*Use `q * (1 * r)` rather than `q * r`.*/ operator*(Quantity auto, reference) = delete;
|
||||
|
||||
template<Reference R2>
|
||||
[[nodiscard]] friend constexpr bool operator==(reference, R2) { return false; }
|
||||
[[nodiscard]] friend constexpr bool operator==(reference, R2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] friend constexpr bool operator==(reference, reference) { return true; }
|
||||
};
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
// IWYU pragma: begin_exports
|
||||
#include <units/bits/external/fixed_string.h>
|
||||
#include <compare>
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#include <gsl/gsl-lite.hpp>
|
||||
@@ -42,8 +42,7 @@ constexpr void validate_ascii_string([[maybe_unused]] const char (&s)[N + 1]) no
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
if constexpr (N != 0)
|
||||
for (size_t i = 0; i < N; ++i)
|
||||
validate_ascii_char(s[i]);
|
||||
for (size_t i = 0; i < N; ++i) validate_ascii_char(s[i]);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -52,11 +51,11 @@ constexpr void validate_ascii_string([[maybe_unused]] const char (&s)[N + 1]) no
|
||||
|
||||
/**
|
||||
* @brief A symbol text representation
|
||||
*
|
||||
*
|
||||
* This class template is responsible for definition and handling of a symbol text
|
||||
* representation. In the libary it is used to define symbols of units and prefixes.
|
||||
* Each symbol can have two versions: Unicode and ASCI-only.
|
||||
*
|
||||
*
|
||||
* @tparam StandardCharT Character type to be used for a Unicode representation
|
||||
* @tparam N The size of a Unicode symbol
|
||||
* @tparam M The size of the ASCII-only symbol
|
||||
@@ -66,12 +65,30 @@ struct basic_symbol_text {
|
||||
basic_fixed_string<StandardCharT, N> standard_;
|
||||
basic_fixed_string<char, M> ascii_;
|
||||
|
||||
constexpr basic_symbol_text(char std) noexcept: standard_(std), ascii_(std) { detail::validate_ascii_char(std); }
|
||||
constexpr basic_symbol_text(StandardCharT std, char a) noexcept: standard_(std), ascii_(a) { detail::validate_ascii_char(a); }
|
||||
constexpr basic_symbol_text(const char (&std)[N + 1]) noexcept: standard_(std), ascii_(std) { detail::validate_ascii_string<N>(std); }
|
||||
constexpr basic_symbol_text(const basic_fixed_string<char, N>& std) noexcept: standard_(std), ascii_(std) { detail::validate_ascii_string<N>(std.data_); }
|
||||
constexpr basic_symbol_text(const StandardCharT (&std)[N + 1], const char (&a)[M + 1]) noexcept: standard_(std), ascii_(a) { detail::validate_ascii_string<M>(a); }
|
||||
constexpr basic_symbol_text(const basic_fixed_string<StandardCharT, N>& std, const basic_fixed_string<char, M>& a) noexcept: standard_(std), ascii_(a) { detail::validate_ascii_string<M>(a.data_); }
|
||||
constexpr basic_symbol_text(char std) noexcept : standard_(std), ascii_(std) { detail::validate_ascii_char(std); }
|
||||
constexpr basic_symbol_text(StandardCharT std, char a) noexcept : standard_(std), ascii_(a)
|
||||
{
|
||||
detail::validate_ascii_char(a);
|
||||
}
|
||||
constexpr basic_symbol_text(const char (&std)[N + 1]) noexcept : standard_(std), ascii_(std)
|
||||
{
|
||||
detail::validate_ascii_string<N>(std);
|
||||
}
|
||||
constexpr basic_symbol_text(const basic_fixed_string<char, N>& std) noexcept : standard_(std), ascii_(std)
|
||||
{
|
||||
detail::validate_ascii_string<N>(std.data_);
|
||||
}
|
||||
constexpr basic_symbol_text(const StandardCharT (&std)[N + 1], const char (&a)[M + 1]) noexcept :
|
||||
standard_(std), ascii_(a)
|
||||
{
|
||||
detail::validate_ascii_string<M>(a);
|
||||
}
|
||||
constexpr basic_symbol_text(const basic_fixed_string<StandardCharT, N>& std,
|
||||
const basic_fixed_string<char, M>& a) noexcept :
|
||||
standard_(std), ascii_(a)
|
||||
{
|
||||
detail::validate_ascii_string<M>(a.data_);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr auto& standard() { return standard_; }
|
||||
[[nodiscard]] constexpr const auto& standard() const { return standard_; }
|
||||
@@ -80,48 +97,47 @@ struct basic_symbol_text {
|
||||
|
||||
template<std::size_t N2, std::size_t M2>
|
||||
[[nodiscard]] constexpr friend basic_symbol_text<StandardCharT, N + N2, M + M2> operator+(
|
||||
const basic_symbol_text& lhs, const basic_symbol_text<StandardCharT, N2, M2>& rhs) noexcept
|
||||
const basic_symbol_text& lhs, const basic_symbol_text<StandardCharT, N2, M2>& rhs) noexcept
|
||||
{
|
||||
return basic_symbol_text<StandardCharT, N + N2, M + M2>(
|
||||
lhs.standard() + rhs.standard(), lhs.ascii() + rhs.ascii());
|
||||
return basic_symbol_text<StandardCharT, N + N2, M + M2>(lhs.standard() + rhs.standard(), lhs.ascii() + rhs.ascii());
|
||||
}
|
||||
|
||||
template<std::size_t N2>
|
||||
[[nodiscard]] constexpr friend basic_symbol_text<StandardCharT, N + N2, M + N2> operator+(
|
||||
const basic_symbol_text& lhs, const basic_fixed_string<StandardCharT, N2>& rhs) noexcept
|
||||
const basic_symbol_text& lhs, const basic_fixed_string<StandardCharT, N2>& rhs) noexcept
|
||||
{
|
||||
return lhs + basic_symbol_text<StandardCharT, N2, N2>(rhs);
|
||||
}
|
||||
|
||||
|
||||
template<std::size_t N2>
|
||||
[[nodiscard]] constexpr friend basic_symbol_text<StandardCharT, N + N2, M + N2> operator+(
|
||||
const basic_fixed_string<StandardCharT, N2>& lhs, const basic_symbol_text& rhs) noexcept
|
||||
const basic_fixed_string<StandardCharT, N2>& lhs, const basic_symbol_text& rhs) noexcept
|
||||
{
|
||||
return basic_symbol_text<StandardCharT, N2, N2>(lhs) + rhs;
|
||||
}
|
||||
|
||||
template<std::size_t N2>
|
||||
[[nodiscard]] constexpr friend basic_symbol_text<StandardCharT, N + N2 - 1, M + N2 - 1> operator+(
|
||||
const basic_symbol_text& lhs, const StandardCharT (&rhs)[N2]) noexcept
|
||||
const basic_symbol_text& lhs, const StandardCharT (&rhs)[N2]) noexcept
|
||||
{
|
||||
return lhs + basic_symbol_text<StandardCharT, N2 - 1, N2 - 1>(rhs);
|
||||
}
|
||||
|
||||
|
||||
template<std::size_t N2>
|
||||
[[nodiscard]] constexpr friend basic_symbol_text<StandardCharT, N + N2 - 1, M + N2 - 1> operator+(
|
||||
const StandardCharT (&lhs)[N2], const basic_symbol_text& rhs) noexcept
|
||||
const StandardCharT (&lhs)[N2], const basic_symbol_text& rhs) noexcept
|
||||
{
|
||||
return basic_symbol_text<StandardCharT, N2 - 1, N2 - 1>(lhs) + rhs;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr friend basic_symbol_text<StandardCharT, N + 1, M + 1> operator+(
|
||||
const basic_symbol_text& lhs, StandardCharT rhs) noexcept
|
||||
[[nodiscard]] constexpr friend basic_symbol_text<StandardCharT, N + 1, M + 1> operator+(const basic_symbol_text& lhs,
|
||||
StandardCharT rhs) noexcept
|
||||
{
|
||||
return lhs + basic_symbol_text<StandardCharT, 1, 1>(rhs);
|
||||
}
|
||||
|
||||
|
||||
[[nodiscard]] constexpr friend basic_symbol_text<StandardCharT, N + 1, M + 1> operator+(
|
||||
StandardCharT lhs, const basic_symbol_text& rhs) noexcept
|
||||
StandardCharT lhs, const basic_symbol_text& rhs) noexcept
|
||||
{
|
||||
return basic_symbol_text<StandardCharT, 1, 1>(lhs) + rhs;
|
||||
}
|
||||
@@ -142,7 +158,7 @@ struct basic_symbol_text {
|
||||
}
|
||||
};
|
||||
|
||||
basic_symbol_text(char) -> basic_symbol_text<char, 1, 1>;
|
||||
basic_symbol_text(char)->basic_symbol_text<char, 1, 1>;
|
||||
|
||||
template<typename StandardCharT>
|
||||
basic_symbol_text(StandardCharT, char) -> basic_symbol_text<StandardCharT, 1, 1>;
|
||||
@@ -157,7 +173,7 @@ template<typename StandardCharT, std::size_t N, std::size_t M>
|
||||
basic_symbol_text(const StandardCharT (&)[N], const char (&)[M]) -> basic_symbol_text<StandardCharT, N - 1, M - 1>;
|
||||
|
||||
template<typename StandardCharT, std::size_t N, std::size_t M>
|
||||
basic_symbol_text(const basic_fixed_string<StandardCharT, N>&,
|
||||
const basic_fixed_string<char, M>&) -> basic_symbol_text<StandardCharT, N, M>;
|
||||
basic_symbol_text(const basic_fixed_string<StandardCharT, N>&, const basic_fixed_string<char, M>&)
|
||||
-> basic_symbol_text<StandardCharT, N, M>;
|
||||
|
||||
} // namespace units
|
||||
|
||||
@@ -26,9 +26,9 @@
|
||||
#include <units/bits/external/downcasting.h>
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include <units/bits/derived_unit.h>
|
||||
#include <units/bits/derived_unit.h>
|
||||
#include <units/bits/external/fixed_string.h>
|
||||
#include <units/prefix.h>
|
||||
#include <units/prefix.h>
|
||||
#include <units/ratio.h>
|
||||
#include <units/symbol_text.h>
|
||||
// IWYU pragma: end_exports
|
||||
@@ -41,7 +41,7 @@ namespace units {
|
||||
* A unit is an entity defined and adopted by convention, with which any other quantity of
|
||||
* the same kind can be compared to express the ratio of the second quantity to the first
|
||||
* one as a number.
|
||||
*
|
||||
*
|
||||
* All units of the same dimension can be convereted between each other. To allow this all of
|
||||
* them are expressed as different ratios of the same one proprietary chosen reference unit
|
||||
* (i.e. all length units are expressed in terms of meter, all mass units are expressed in
|
||||
@@ -162,7 +162,7 @@ struct derived_unit : downcast_dispatch<Child, detail::derived_unit<Dim, U, URes
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A named unit with a deduced ratio
|
||||
* @brief A named unit with a deduced ratio
|
||||
*
|
||||
* Defines a new unit with a deduced ratio and the given symbol based on the recipe from the provided
|
||||
* derived dimension. The number and order of provided units should match the recipe of the
|
||||
@@ -229,7 +229,7 @@ struct prefixed_alias_unit : U {
|
||||
|
||||
/**
|
||||
* @brief Unknown unit
|
||||
*
|
||||
*
|
||||
* Used as a coherent unit of an unknown dimension.
|
||||
*/
|
||||
struct unknown_coherent_unit : unit<unknown_coherent_unit> {};
|
||||
|
||||
Reference in New Issue
Block a user