Merge branch 'master' into chiphogg/prime-wheel

This commit is contained in:
Chip Hogg
2022-03-19 16:01:32 +00:00
145 changed files with 5823 additions and 3539 deletions
+3 -4
View File
@@ -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;
+61 -73
View File
@@ -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
+18 -14
View File
@@ -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
+99 -99
View File
@@ -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;
}
}
+3 -2
View File
@@ -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>;
+2 -2
View File
@@ -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;
+11 -9
View File
@@ -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>
+33 -34
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+1 -1
View File
@@ -22,8 +22,8 @@
#pragma once
#include <cstdint>
#include <cassert>
#include <cstdint>
namespace units::detail {
+8 -4
View File
@@ -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
+7 -7
View File
@@ -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;
+1 -1
View File
@@ -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;
+37 -49
View File
@@ -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;
}
}
+7 -7
View File
@@ -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
+33 -17
View File
@@ -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
+7 -6
View File
@@ -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
+36 -48
View File
@@ -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;
+2 -2
View File
@@ -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;
};
+141 -83
View File
@@ -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
+54 -49
View File
@@ -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>)
+39 -20
View File
@@ -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());
}
+18 -11
View File
@@ -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 {
+14 -9
View File
@@ -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
View File
@@ -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
+8 -18
View File
@@ -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;
+33 -22
View File
@@ -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; }
};
+43 -27
View File
@@ -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
+5 -5
View File
@@ -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> {};