forked from mpusz/mp-units
build: core library and each system separated to dedicated CMake targets
Refers to #249
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2018 Mateusz Pusz
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <units/base_dimension.h>
|
||||
#include <units/exponent.h>
|
||||
#include <units/ratio.h>
|
||||
|
||||
namespace units::detail {
|
||||
|
||||
template<Exponent E>
|
||||
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 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates the common ratio of all the references of base units in the derived dimension
|
||||
*/
|
||||
template<typename... Es>
|
||||
constexpr ratio base_units_ratio(exponent_list<Es...>)
|
||||
{
|
||||
return (exp_ratio<Es>() * ... * ratio(1));
|
||||
}
|
||||
|
||||
} // namespace units::detail
|
||||
@@ -0,0 +1,419 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2018 Mateusz Pusz
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <units/bits/external/downcasting.h>
|
||||
#include <units/bits/external/fixed_string.h>
|
||||
#include <units/bits/external/hacks.h>
|
||||
#include <units/customization_points.h>
|
||||
#include <units/ratio.h>
|
||||
#include <units/bits/external/type_traits.h>
|
||||
#include <functional>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
|
||||
namespace units {
|
||||
|
||||
// PrefixFamily
|
||||
struct prefix_family;
|
||||
|
||||
/**
|
||||
* @brief A concept matching a prefix family
|
||||
*
|
||||
* Satisfied by all types derived from `prefix_family`
|
||||
*/
|
||||
template<typename T>
|
||||
concept PrefixFamily = std::derived_from<T, prefix_family>;
|
||||
|
||||
// Prefix
|
||||
namespace detail {
|
||||
|
||||
template<PrefixFamily PF, ratio R>
|
||||
struct prefix_base;
|
||||
|
||||
template<PrefixFamily PF, ratio R>
|
||||
void to_prefix_base(const volatile prefix_base<PF, R>*);
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* @brief A concept matching a symbol prefix
|
||||
*
|
||||
* Satisfied by all specializations of `prefix`.
|
||||
*/
|
||||
template<typename T>
|
||||
concept Prefix = requires(T* t) { detail::to_prefix_base(t); };
|
||||
|
||||
/**
|
||||
* @brief A concept matching unit's ratio
|
||||
*
|
||||
* 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;
|
||||
|
||||
// Unit
|
||||
template<ratio R, typename U>
|
||||
requires UnitRatio<R>
|
||||
struct scaled_unit;
|
||||
|
||||
// TODO: Remove when P1985 accepted
|
||||
namespace detail {
|
||||
|
||||
template<ratio R, typename U>
|
||||
void to_base_scaled_unit(const volatile scaled_unit<R, U>*);
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* @brief A concept matching all unit types in the library
|
||||
*
|
||||
* Satisfied by all unit types derived from an specialization of :class:`scaled_unit`.
|
||||
*/
|
||||
template<typename T>
|
||||
concept Unit = requires(T* t) { detail::to_base_scaled_unit(t); };
|
||||
|
||||
// BaseDimension
|
||||
template<basic_fixed_string Symbol, Unit U>
|
||||
requires U::is_named
|
||||
struct base_dimension;
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<basic_fixed_string Symbol, typename U>
|
||||
void to_base_base_dimension(const volatile base_dimension<Symbol, U>*);
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* @brief A concept matching all base dimensions in the library.
|
||||
*
|
||||
* Satisfied by all dimension types derived from an specialization of `base_dimension`.
|
||||
*/
|
||||
template<typename T>
|
||||
concept BaseDimension = requires(T* t) { detail::to_base_base_dimension(t); };
|
||||
|
||||
// Exponent
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_exponent = false;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* @brief A concept matching dimension's exponents.
|
||||
*
|
||||
* Satisfied by all specializations of :class:`exponent`.
|
||||
*/
|
||||
template<typename T>
|
||||
concept Exponent = detail::is_exponent<T>;
|
||||
|
||||
// DerivedDimension
|
||||
namespace detail {
|
||||
|
||||
template<Exponent... Es>
|
||||
requires (BaseDimension<typename Es::dimension> && ...)
|
||||
struct derived_dimension_base;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* @brief A concept matching all derived dimensions in the library.
|
||||
*
|
||||
* Satisfied by all dimension types derived from an specialization of `detail::derived_dimension_base`.
|
||||
*/
|
||||
template<typename T>
|
||||
concept DerivedDimension = is_derived_from_specialization_of<T, detail::derived_dimension_base>;
|
||||
|
||||
// Dimension
|
||||
/**
|
||||
* @brief A concept matching all dimensions in the library.
|
||||
*
|
||||
* Satisfied by all dimension types for which either `BaseDimension<T>` or `DerivedDimension<T>` is `true`.
|
||||
*/
|
||||
template<typename T>
|
||||
concept Dimension = BaseDimension<T> || DerivedDimension<T>;
|
||||
|
||||
// UnitOf
|
||||
namespace detail {
|
||||
|
||||
template<Dimension D>
|
||||
auto default_unit()
|
||||
{
|
||||
if constexpr (BaseDimension<D>)
|
||||
return typename D::base_unit{};
|
||||
else
|
||||
return typename D::coherent_unit{};
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* @brief Returns a 'default' unit of the dimension
|
||||
*
|
||||
* Depending on the dimension type it returns a base unit (for base dimensions)
|
||||
* or a coherent unit (in case of derived dimensions).
|
||||
*
|
||||
* @tparam D Dimension type to get the unit from.
|
||||
*/
|
||||
template<Dimension D>
|
||||
using dimension_unit = decltype(detail::default_unit<D>());
|
||||
// TODO: replace with the below code when VS catches up
|
||||
// decltype([]{
|
||||
// if constexpr (BaseDimension<D>)
|
||||
// return TYPENAME D::base_unit{};
|
||||
// else
|
||||
// return TYPENAME D::coherent_unit{};
|
||||
// }());
|
||||
|
||||
/**
|
||||
* @brief A concept matching only units of a specified dimension.
|
||||
*
|
||||
* Satisfied by all unit types that satisfy `Unit<U>`, `Dimension<D>`, and for which
|
||||
* `U::reference` and @c dimension_unit<D>::reference denote the same unit type.
|
||||
*
|
||||
* @tparam U Type to verify.
|
||||
* @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>;
|
||||
|
||||
// Kind
|
||||
namespace detail {
|
||||
|
||||
template<typename, Dimension>
|
||||
struct _kind_base;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename T, template<typename...> typename Base>
|
||||
concept kind_impl_ =
|
||||
is_derived_from_specialization_of<T, Base> &&
|
||||
requires(T* t) {
|
||||
typename T::base_kind;
|
||||
typename T::dimension;
|
||||
requires Dimension<typename T::dimension>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A concept matching all kind types
|
||||
*
|
||||
* 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>;
|
||||
|
||||
// PointKind
|
||||
namespace detail {
|
||||
|
||||
template<Kind>
|
||||
struct _point_kind_base;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* @brief A concept matching all point kind types
|
||||
*
|
||||
* Satisfied by all point kind types derived from an specialization of @c point_kind.
|
||||
*/
|
||||
template<typename T>
|
||||
concept PointKind = kind_impl_<T, detail::_point_kind_base>;
|
||||
|
||||
// Quantity, QuantityPoint, QuantityKind, QuantityPointKind
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_quantity = false;
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_quantity_point = false;
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_quantity_kind = false;
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_quantity_point_kind = false;
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_quantity_like = false;
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_quantity_point_like = false;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* @brief A concept matching all quantities in the library.
|
||||
*
|
||||
* Satisfied by all specializations of @c quantity.
|
||||
*/
|
||||
template<typename T>
|
||||
concept Quantity = detail::is_quantity<T>;
|
||||
|
||||
/**
|
||||
* @brief A concept matching all quantity points in the library.
|
||||
*
|
||||
* Satisfied by all specializations of @c quantity_point.
|
||||
*/
|
||||
template<typename T>
|
||||
concept QuantityPoint = detail::is_quantity_point<T>;
|
||||
|
||||
/**
|
||||
* @brief A concept matching all quantity kinds in the library.
|
||||
*
|
||||
* Satisfied by all specializations of @c quantity_kind.
|
||||
*/
|
||||
template<typename T>
|
||||
concept QuantityKind = detail::is_quantity_kind<T>;
|
||||
|
||||
/**
|
||||
* @brief A concept matching all quantity point kinds in the library.
|
||||
*
|
||||
* Satisfied by all specializations of @c quantity_point_kind.
|
||||
*/
|
||||
template<typename T>
|
||||
concept QuantityPointKind = detail::is_quantity_point_kind<T>;
|
||||
|
||||
// QuantityLike, QuantityPointLike
|
||||
|
||||
/**
|
||||
* @brief A concept matching all quantity-like types (other than specialization of @c quantity)
|
||||
*
|
||||
* Satisfied by all types for which a correct specialization of `quantity_like_traits`
|
||||
* type trait is provided.
|
||||
*/
|
||||
template<typename T>
|
||||
concept QuantityLike = detail::is_quantity_like<T>;
|
||||
|
||||
/**
|
||||
* @brief A concept matching all quantity point-like types (other than specialization of @c quantity_point)
|
||||
*
|
||||
* Satisfied by all types for which a correct specialization of `quantity_point_like_traits`
|
||||
* type trait is provided.
|
||||
*/
|
||||
template<typename T>
|
||||
concept QuantityPointLike = detail::is_quantity_point_like<T>;
|
||||
|
||||
// QuantityValue
|
||||
|
||||
template<typename T, typename U>
|
||||
concept common_type_with_ = // exposition only
|
||||
std::same_as<std::common_type_t<T, U>, std::common_type_t<U, T>> &&
|
||||
std::constructible_from<std::common_type_t<T, U>, T> &&
|
||||
std::constructible_from<std::common_type_t<T, U>, U>;
|
||||
|
||||
template<typename T, typename U = T>
|
||||
concept scalable_number_ = // exposition only
|
||||
std::regular_invocable<std::multiplies<>, T, U> &&
|
||||
std::regular_invocable<std::divides<>, T, U>;
|
||||
|
||||
template<typename T>
|
||||
concept castable_number_ = // exposition only
|
||||
common_type_with_<T, std::intmax_t> &&
|
||||
scalable_number_<std::common_type_t<T, std::intmax_t>>;
|
||||
|
||||
template<typename T>
|
||||
concept scalable_ = // exposition only
|
||||
castable_number_<T> ||
|
||||
(requires { typename T::value_type; } && castable_number_<typename T::value_type> && scalable_number_<T, std::common_type_t<typename T::value_type, std::intmax_t>>);
|
||||
|
||||
template<typename T, typename U>
|
||||
concept scalable_with_ = // exposition only
|
||||
common_type_with_<T, U> &&
|
||||
scalable_<std::common_type_t<T, U>>;
|
||||
|
||||
// WrappedQuantity
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
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>;
|
||||
|
||||
template<typename T>
|
||||
requires requires { typename T::quantity_type; }
|
||||
inline constexpr bool is_wrapped_quantity<T> = Quantity<typename T::quantity_type>;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* @brief A concept matching types that wrap quantity objects.
|
||||
*
|
||||
* Satisfied by all wrapper types that satisfy `Quantity<typename T::value_type>`
|
||||
* recursively (i.e. `std::optional<si::length<si::metre>>`).
|
||||
*/
|
||||
template<typename T>
|
||||
concept wrapped_quantity_ = // exposition only
|
||||
detail::is_wrapped_quantity<T>;
|
||||
|
||||
/**
|
||||
* @brief A concept matching non-Quantity types.
|
||||
*
|
||||
* Satisfied by types that satisfy `(!Quantity<T>) && (!WrappedQuantity<T>) && std::regular<T>`.
|
||||
*/
|
||||
template<typename T>
|
||||
concept QuantityValue =
|
||||
(!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 QuantityValue<typename quantity_like_traits<T>::rep>;
|
||||
{ quantity_like_traits<T>::count(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 QuantityValue<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 units
|
||||
@@ -0,0 +1,123 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2018 Mateusz Pusz
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <units/bits/dimension_op.h>
|
||||
#include <units/bits/equivalent.h>
|
||||
#include <units/quantity_cast.h>
|
||||
|
||||
namespace units {
|
||||
|
||||
template<Dimension D, UnitOf<D> U, QuantityValue Rep>
|
||||
class quantity;
|
||||
|
||||
template<Dimension D, UnitOf<D> U, QuantityValue Rep>
|
||||
class quantity_point;
|
||||
|
||||
template<Kind K, UnitOf<typename K::dimension> U, QuantityValue Rep>
|
||||
class quantity_kind;
|
||||
|
||||
template<PointKind PK, UnitOf<typename PK::dimension> U, QuantityValue Rep>
|
||||
class quantity_point_kind;
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename Q1, typename Q2, typename Rep>
|
||||
struct common_quantity_impl;
|
||||
|
||||
template<typename D, typename U, typename Rep1, typename Rep2, typename Rep>
|
||||
struct common_quantity_impl<quantity<D, U, Rep1>, quantity<D, U, Rep2>, Rep> {
|
||||
using type = quantity<D, U, Rep>;
|
||||
};
|
||||
|
||||
template<typename D, typename U1, typename Rep1, typename U2, typename Rep2, typename Rep>
|
||||
struct common_quantity_impl<quantity<D, U1, Rep1>, quantity<D, U2, Rep2>, Rep> {
|
||||
using type = quantity<D, downcast_unit<D, common_ratio(U1::ratio, U2::ratio)>, Rep>;
|
||||
};
|
||||
|
||||
template<typename D1, typename U1, typename Rep1, typename D2, typename U2, typename Rep2, typename Rep>
|
||||
requires same_unit_reference<dimension_unit<D1>, dimension_unit<D2>>::value
|
||||
struct common_quantity_impl<quantity<D1, U1, Rep1>, quantity<D2, U2, Rep2>, Rep> {
|
||||
using type = quantity<D1, downcast_unit<D1, common_ratio(U1::ratio, U2::ratio)>, Rep>;
|
||||
};
|
||||
|
||||
template<typename D1, typename U1, typename Rep1, typename D2, typename U2, typename Rep2, typename Rep>
|
||||
struct common_quantity_impl<quantity<D1, U1, Rep1>, quantity<D2, U2, Rep2>, Rep> {
|
||||
using dimension = conditional<is_specialization_of<D1, unknown_dimension>, D2, D1>;
|
||||
static constexpr ratio r1 = D1::base_units_ratio * U1::ratio;
|
||||
static constexpr ratio r2 = D2::base_units_ratio * U2::ratio;
|
||||
static constexpr ratio cr = common_ratio(r1, r2);
|
||||
using unit = downcast_unit<dimension, cr / dimension::base_units_ratio>;
|
||||
using type = quantity<dimension, unit, Rep>;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<Quantity Q1, QuantityEquivalentTo<Q1> Q2, QuantityValue Rep = std::common_type_t<typename Q1::rep, typename Q2::rep>>
|
||||
using common_quantity = TYPENAME detail::common_quantity_impl<Q1, Q2, Rep>::type;
|
||||
|
||||
template<QuantityPoint QP1, QuantityPointEquivalentTo<QP1> QP2>
|
||||
using common_quantity_point = std::common_type_t<QP1, QP2>;
|
||||
|
||||
template<QuantityKind QK1, QuantityKindEquivalentTo<QK1> QK2>
|
||||
using common_quantity_kind = std::common_type_t<QK1, QK2>;
|
||||
|
||||
template<QuantityPointKind QPK1, QuantityPointKindEquivalentTo<QPK1> QPK2>
|
||||
using common_quantity_point_kind = std::common_type_t<QPK1, QPK2>;
|
||||
|
||||
} // namespace units
|
||||
|
||||
namespace std {
|
||||
|
||||
template<units::Quantity Q1, units::QuantityEquivalentTo<Q1> Q2>
|
||||
requires requires { typename common_type_t<typename Q1::rep, typename Q2::rep>; }
|
||||
struct common_type<Q1, Q2> {
|
||||
using type = units::common_quantity<Q1, Q2>;
|
||||
};
|
||||
|
||||
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<
|
||||
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>;
|
||||
};
|
||||
|
||||
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,
|
||||
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>;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2018 Mateusz Pusz
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gsl/gsl-lite.hpp>
|
||||
#include <units/bits/math_concepts.h>
|
||||
#include <units/bits/pow.h>
|
||||
#include <units/bits/ratio_maths.h>
|
||||
|
||||
namespace units::detail {
|
||||
|
||||
struct decimal_fp {
|
||||
double significant;
|
||||
std::intmax_t exponent;
|
||||
};
|
||||
|
||||
[[nodiscard]] constexpr decimal_fp to_decimal(double v) noexcept
|
||||
{
|
||||
if (v == 0) {
|
||||
return {.significant = 0.0, .exponent = 0};
|
||||
}
|
||||
|
||||
double significant = abs(v);
|
||||
std::intmax_t exponent = 0;
|
||||
|
||||
while (significant < 1) {
|
||||
significant *= 10.0;
|
||||
--exponent;
|
||||
}
|
||||
|
||||
while (significant >= 10) {
|
||||
significant /= 10.0;
|
||||
++exponent;
|
||||
}
|
||||
|
||||
if (v < 0) {
|
||||
significant = -significant;
|
||||
}
|
||||
|
||||
return {.significant = significant, .exponent = exponent};
|
||||
}
|
||||
|
||||
/* approximate natural log as https://math.stackexchange.com/a/977836
|
||||
far slower than std::log but works at compile time with similar accuracy
|
||||
*/
|
||||
[[nodiscard]] constexpr double constexpr_log(double v) noexcept
|
||||
{
|
||||
gsl_Expects(v > 0);
|
||||
|
||||
// lookup table to speed up convergence for all significant values
|
||||
// significant values of 7 and greater benefit mostly as they now converge in 5 terms compared to O(10)-O(100)
|
||||
// required without the table
|
||||
//
|
||||
// using python:
|
||||
// >>> import math
|
||||
// >>> 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,
|
||||
};
|
||||
decimal_fp x = to_decimal(v);
|
||||
|
||||
// dividing the significant by nearest lower value in [1.0, 1.1, 1.2, ..., 9.9] will greatly improve convergence
|
||||
x.significant *= 10;
|
||||
const auto isignificant = static_cast<std::size_t>(x.significant);
|
||||
x.significant /= static_cast<double>(isignificant);
|
||||
const double result = static_cast<double>(x.exponent - 1) * log_table[9] + log_table[isignificant - 1];
|
||||
|
||||
// 1.0 <= significant < 1.1 converges rapidly
|
||||
const double y = (x.significant - 1) / (x.significant + 1);
|
||||
const double y_squared = y * y;
|
||||
double sum = 0;
|
||||
// 5 terms are needed for convergence to machine precision in the worst case scenario
|
||||
for (int k = 4; k > 0; --k) {
|
||||
sum = y_squared * (1 / (2 * static_cast<double>(k) + 1) + sum);
|
||||
}
|
||||
sum = 2 * y * (1 + sum); // k = 0 term
|
||||
return result + sum;
|
||||
}
|
||||
|
||||
/* approximate e^x as Taylor series e^x = 1 + x/1! + x^2/2! + x^3/3! +... where N is the order of the Taylor series
|
||||
use https://math.stackexchange.com/a/1988927 to improve convergence for large values
|
||||
|
||||
larger Factor values improve convergence for all values but reduce the precision
|
||||
*/
|
||||
template<std::size_t N, std::intmax_t Factor = 256>
|
||||
requires gt_zero<Factor>
|
||||
[[nodiscard]] constexpr double constexpr_exp(double v) noexcept
|
||||
{
|
||||
if constexpr (N == 0) {
|
||||
return 1.0;
|
||||
} else {
|
||||
constexpr auto coefficients = []() {
|
||||
std::array<double, N> coeffs;
|
||||
std::size_t factorial = 1;
|
||||
for (std::size_t i = 0; i < N; ++i) {
|
||||
factorial *= i + 1;
|
||||
coeffs[i] = 1.0 / static_cast<double>(factorial);
|
||||
}
|
||||
return coeffs;
|
||||
}();
|
||||
|
||||
const double x = v / static_cast<double>(Factor);
|
||||
double result = 0;
|
||||
for (auto i = static_cast<std::intmax_t>(N - 1); i >= 0; --i) {
|
||||
result = x * (coefficients[static_cast<std::size_t>(i)] + result);
|
||||
}
|
||||
|
||||
// for factors of power of 2 this should be replaced by log2(Factor) multiplications by the compiler
|
||||
return pow_impl<Factor>(1 + result);
|
||||
}
|
||||
}
|
||||
|
||||
// default template arguments provide reasonable precision even for fairly large exponents
|
||||
// see constexpr_exp for template arguments
|
||||
template<std::size_t ExpOrder = 10, std::intmax_t Factor = 128>
|
||||
[[nodiscard]] constexpr double constexpr_pow(double v, double exponent) noexcept
|
||||
{
|
||||
const double x = exponent * constexpr_log(v);
|
||||
return constexpr_exp<ExpOrder, Factor>(x);
|
||||
}
|
||||
|
||||
} // namespace units::detail
|
||||
@@ -0,0 +1,95 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2018 Mateusz Pusz
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <units/bits/external/fixed_string.h>
|
||||
#include <units/bits/external/text_tools.h>
|
||||
#include <units/derived_dimension.h>
|
||||
#include <units/symbol_text.h>
|
||||
|
||||
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) {
|
||||
return basic_fixed_string("1/");
|
||||
}
|
||||
else {
|
||||
return basic_fixed_string("");
|
||||
}
|
||||
}
|
||||
else {
|
||||
if constexpr(Divide && NegativeExpCount == 1) {
|
||||
return basic_fixed_string("/");
|
||||
}
|
||||
else {
|
||||
return basic_symbol_text(" ⋅ ", " ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename E, basic_symbol_text Symbol, std::size_t NegativeExpCount, std::size_t Idx>
|
||||
constexpr auto exp_text()
|
||||
{
|
||||
// get calculation operator + symbol
|
||||
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) {
|
||||
// add exponent part
|
||||
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
|
||||
return txt + superscript<abs(E::num)>();
|
||||
}
|
||||
else {
|
||||
return txt;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return txt;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename... Es>
|
||||
inline constexpr int negative_exp_count = ((Es::num < 0 ? 1 : 0) + ... + 0);
|
||||
|
||||
template<typename... Us, typename... Es, std::size_t... Idxs>
|
||||
constexpr auto deduced_symbol_text(exponent_list<Es...>, std::index_sequence<Idxs...>)
|
||||
{
|
||||
constexpr auto neg_exp = negative_exp_count<Es...>;
|
||||
return (exp_text<Es, Us::symbol, neg_exp, Idxs>() + ...);
|
||||
}
|
||||
|
||||
template<DerivedDimension Dim, Unit... Us>
|
||||
constexpr auto deduced_symbol_text()
|
||||
{
|
||||
return deduced_symbol_text<Us...>(typename Dim::recipe(), std::index_sequence_for<Us...>());
|
||||
}
|
||||
|
||||
} // namespace units::detail
|
||||
@@ -0,0 +1,56 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2018 Mateusz Pusz
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <units/derived_dimension.h>
|
||||
|
||||
namespace units::detail {
|
||||
|
||||
// same_scaled_units
|
||||
template<typename ExpList, Unit... Us>
|
||||
inline constexpr bool same_scaled_units = false;
|
||||
|
||||
template<typename... Es, Unit... Us>
|
||||
inline constexpr bool same_scaled_units<exponent_list<Es...>, Us...> = (UnitOf<Us, typename Es::dimension> && ...);
|
||||
|
||||
// deduced_unit
|
||||
|
||||
template<Exponent E>
|
||||
constexpr ratio inverse_if_negative(const ratio& r)
|
||||
{
|
||||
if constexpr(E::num * E::den > 0)
|
||||
return r;
|
||||
else
|
||||
return inverse(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));
|
||||
}
|
||||
|
||||
template<DerivedDimension D, Unit... Us>
|
||||
using deduced_unit = scaled_unit<derived_ratio<Us...>(typename D::recipe()), typename D::coherent_unit::reference>;
|
||||
|
||||
} // namespace units::detail
|
||||
@@ -0,0 +1,60 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2018 Mateusz Pusz
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <units/base_dimension.h>
|
||||
#include <units/bits/external/downcasting.h>
|
||||
#include <units/exponent.h>
|
||||
|
||||
namespace units::detail {
|
||||
|
||||
/**
|
||||
* @brief A dimension of a derived quantity
|
||||
*
|
||||
* 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
|
||||
* "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> && ...)
|
||||
struct derived_dimension_base : downcast_base<derived_dimension_base<Es...>> {
|
||||
using exponents = exponent_list<Es...>;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct to_derived_dimension_base;
|
||||
|
||||
template<Exponent... Es>
|
||||
struct to_derived_dimension_base<exponent_list<Es...>> {
|
||||
using type = derived_dimension_base<Es...>;
|
||||
};
|
||||
|
||||
} // namespace units::detail
|
||||
@@ -0,0 +1,67 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2018 Mateusz Pusz
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <units/bits/external/type_list.h>
|
||||
#include <units/exponent.h>
|
||||
#include <ratio> // TODO remove this dependency with #11
|
||||
|
||||
namespace units::detail {
|
||||
|
||||
/**
|
||||
* @brief Consolidates contiguous ranges of exponents of the same dimension
|
||||
*
|
||||
* If there is more than one exponent with the same dimension they are aggregated into one exponent by adding
|
||||
* their exponents. If this accumulation will result with 0, such a dimension is removed from the list.
|
||||
*
|
||||
* @tparam D derived dimension to consolidate
|
||||
*/
|
||||
template<typename ExpList>
|
||||
struct dim_consolidate;
|
||||
|
||||
template<>
|
||||
struct dim_consolidate<exponent_list<>> {
|
||||
using type = exponent_list<>;
|
||||
};
|
||||
|
||||
template<typename E>
|
||||
struct dim_consolidate<exponent_list<E>> {
|
||||
using type = exponent_list<E>;
|
||||
};
|
||||
|
||||
template<typename E1, typename... ERest>
|
||||
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>
|
||||
struct dim_consolidate<exponent_list<exponent<Dim, Num1, Den1>, exponent<Dim, Num2, Den2>, ERest...>> {
|
||||
// TODO: we have ration_add now, but dim_consolidate etc, now need to cope with our new ratio
|
||||
using r1 = std::ratio<Num1, Den1>;
|
||||
using r2 = std::ratio<Num2, Den2>;
|
||||
using r = std::ratio_add<r1, r2>;
|
||||
using type = conditional<r::num == 0, typename dim_consolidate<exponent_list<ERest...>>::type,
|
||||
typename dim_consolidate<exponent_list<exponent<Dim, r::num, r::den>, ERest...>>::type>;
|
||||
};
|
||||
|
||||
} // namespace units::detail
|
||||
@@ -0,0 +1,59 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2018 Mateusz Pusz
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <units/bits/derived_dimension_base.h>
|
||||
#include <units/bits/external/type_list.h>
|
||||
#include <units/exponent.h>
|
||||
|
||||
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
|
||||
*/
|
||||
template<Exponent... Es>
|
||||
struct dim_unpack;
|
||||
|
||||
template<>
|
||||
struct dim_unpack<> {
|
||||
using type = exponent_list<>;
|
||||
};
|
||||
|
||||
template<BaseDimension Dim, std::intmax_t Num, std::intmax_t Den, Exponent... ERest>
|
||||
struct dim_unpack<exponent<Dim, Num, Den>, ERest...> {
|
||||
using type = type_list_push_front<typename dim_unpack<ERest...>::type, exponent<Dim, Num, Den>>;
|
||||
};
|
||||
|
||||
template<DerivedDimension Dim, std::intmax_t Num, std::intmax_t Den, Exponent... ERest>
|
||||
struct dim_unpack<exponent<Dim, Num, Den>, ERest...> {
|
||||
using type = TYPENAME dim_unpack<exponent<downcast_base_t<Dim>, Num, Den>, ERest...>::type;
|
||||
};
|
||||
|
||||
template<Exponent... Es, std::intmax_t Num, std::intmax_t Den, Exponent... ERest>
|
||||
struct dim_unpack<exponent<derived_dimension_base<Es...>, Num, Den>, ERest...> {
|
||||
using type = type_list_push_front<typename dim_unpack<ERest...>::type, exponent_multiply<Es, Num, Den>...>;
|
||||
};
|
||||
|
||||
} // namespace units::detail
|
||||
@@ -0,0 +1,201 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2018 Mateusz Pusz
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <units/derived_dimension.h>
|
||||
#include <units/unit.h>
|
||||
|
||||
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>
|
||||
struct unknown_dimension : derived_dimension<unknown_dimension<Es...>, unknown_coherent_unit, Es...> {};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<DerivedDimension D>
|
||||
struct check_unknown {
|
||||
using type = D;
|
||||
};
|
||||
|
||||
// downcast did not find a user predefined type
|
||||
template<typename... Es>
|
||||
struct check_unknown<derived_dimension_base<Es...>> {
|
||||
using type = unknown_dimension<Es...>;
|
||||
};
|
||||
|
||||
template<Dimension D>
|
||||
struct downcast_dimension_impl;
|
||||
|
||||
template<BaseDimension D>
|
||||
struct downcast_dimension_impl<D> {
|
||||
using type = D;
|
||||
};
|
||||
|
||||
template<DerivedDimension D>
|
||||
struct downcast_dimension_impl<D> {
|
||||
using type = TYPENAME check_unknown<downcast<D>>::type;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<Dimension D>
|
||||
using downcast_dimension = TYPENAME detail::downcast_dimension_impl<D>::type;
|
||||
|
||||
// dim_invert
|
||||
namespace detail {
|
||||
|
||||
template<Dimension D>
|
||||
struct dim_invert_impl;
|
||||
|
||||
template<BaseDimension D>
|
||||
struct dim_invert_impl<D> {
|
||||
using type = downcast_dimension<derived_dimension_base<exponent<D, -1>>>;
|
||||
};
|
||||
|
||||
template<BaseDimension D>
|
||||
struct dim_invert_impl<derived_dimension_base<exponent<D, -1>>> {
|
||||
using type = D;
|
||||
};
|
||||
|
||||
template<typename... Es>
|
||||
struct dim_invert_impl<derived_dimension_base<Es...>> {
|
||||
using type = downcast_dimension<derived_dimension_base<exponent_invert<Es>...>>;
|
||||
};
|
||||
|
||||
template<DerivedDimension D>
|
||||
struct dim_invert_impl<D> : dim_invert_impl<downcast_base_t<D>> {
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<Dimension D>
|
||||
using dim_invert = TYPENAME detail::dim_invert_impl<D>::type;
|
||||
|
||||
// dimension_multiply
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
struct to_dimension;
|
||||
|
||||
template<Exponent... Es>
|
||||
struct to_dimension<exponent_list<Es...>> {
|
||||
using type = derived_dimension_base<Es...>;
|
||||
};
|
||||
|
||||
template<BaseDimension D>
|
||||
struct to_dimension<exponent_list<exponent<D, 1>>> {
|
||||
using type = D;
|
||||
};
|
||||
|
||||
/**
|
||||
* @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
|
||||
* one element being a base dimension with exponent 1. In such a case the final dimension should be the base
|
||||
* 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;
|
||||
|
||||
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>>>>;
|
||||
};
|
||||
|
||||
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>>;
|
||||
};
|
||||
|
||||
template<DerivedDimension D1, BaseDimension D2>
|
||||
struct dimension_multiply_impl<D1, D2> {
|
||||
using type = TYPENAME dimension_multiply_impl<D2, D1>::type;
|
||||
};
|
||||
|
||||
template<DerivedDimension D1, DerivedDimension D2>
|
||||
struct dimension_multiply_impl<D1, D2> {
|
||||
using type = downcast_dimension<merge_dimension<typename D1::downcast_base_type, typename D2::downcast_base_type>>;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<Dimension D1, Dimension D2>
|
||||
using dimension_multiply = TYPENAME detail::dimension_multiply_impl<D1, D2>::type;
|
||||
|
||||
template<Dimension D1, Dimension D2>
|
||||
using dimension_divide = TYPENAME detail::dimension_multiply_impl<D1, dim_invert<D2>>::type;
|
||||
|
||||
// dimension_pow
|
||||
namespace detail {
|
||||
|
||||
template<Dimension D, std::intmax_t Num, std::intmax_t Den = 1>
|
||||
struct dimension_pow_impl;
|
||||
|
||||
template<BaseDimension D, std::intmax_t Num, std::intmax_t Den>
|
||||
struct dimension_pow_impl<D, Num, Den> {
|
||||
using type = downcast_dimension<derived_dimension_base<exponent<D, Num, Den>>>;
|
||||
};
|
||||
|
||||
template<BaseDimension D>
|
||||
struct dimension_pow_impl<D, 1, 1> {
|
||||
using type = D;
|
||||
};
|
||||
|
||||
template<BaseDimension D, std::intmax_t Num, std::intmax_t Den>
|
||||
struct dimension_pow_impl<derived_dimension_base<exponent<D, Den, Num>>, Num, Den> {
|
||||
using type = D;
|
||||
};
|
||||
|
||||
template<DerivedDimension D, std::intmax_t Num, std::intmax_t Den>
|
||||
struct dimension_pow_impl<D, Num, Den> {
|
||||
using type = TYPENAME dimension_pow_impl<downcast_base_t<D>, Num, Den>::type;
|
||||
};
|
||||
|
||||
template<typename... Es, std::intmax_t Num, std::intmax_t Den>
|
||||
struct dimension_pow_impl<derived_dimension_base<Es...>, Num, Den> {
|
||||
using type = downcast_dimension<derived_dimension_base<exponent_multiply<Es, Num, Den>...>>;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<Dimension D, std::intmax_t Num, std::intmax_t Den = 1>
|
||||
using dimension_pow = TYPENAME detail::dimension_pow_impl<D, Num, Den>::type;
|
||||
|
||||
template<Dimension D>
|
||||
using dimension_sqrt = TYPENAME detail::dimension_pow_impl<D, 1, 2>::type;
|
||||
|
||||
} // namespace units
|
||||
@@ -0,0 +1,112 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2018 Mateusz Pusz
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <units/bits/basic_concepts.h>
|
||||
#include <units/unit.h>
|
||||
|
||||
namespace units {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename T, typename U>
|
||||
struct equivalent_impl : std::false_type {
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct equivalent_impl<T, T> : std::true_type {
|
||||
};
|
||||
|
||||
|
||||
// units
|
||||
|
||||
template<Unit U1, Unit U2>
|
||||
struct equivalent_impl<U1, U2> : std::disjunction<std::is_base_of<U1, U2>, std::is_base_of<U2, U1>> {};
|
||||
|
||||
|
||||
// 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>> {
|
||||
};
|
||||
|
||||
template<Exponent E1, Exponent E2>
|
||||
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> {
|
||||
};
|
||||
|
||||
template<DerivedDimension D1, DerivedDimension D2>
|
||||
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>...> {
|
||||
};
|
||||
|
||||
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>>> {
|
||||
};
|
||||
|
||||
|
||||
// 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>> {};
|
||||
|
||||
|
||||
// (point) kinds
|
||||
|
||||
template<typename T, typename U>
|
||||
requires (Kind<T> && Kind<U>) || (PointKind<T> && PointKind<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>> {};
|
||||
|
||||
|
||||
// quantities, quantity points, quantity (point) kinds
|
||||
|
||||
template<typename Q1, typename Q2>
|
||||
requires (Quantity<Q1> && Quantity<Q2>) || (QuantityPoint<Q1> && QuantityPoint<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>> {};
|
||||
|
||||
template<typename QK1, typename QK2>
|
||||
requires (QuantityKind<QK1> && QuantityKind<QK2>) || (QuantityPointKind<QK1> && QuantityPointKind<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>> {};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename T, typename U>
|
||||
inline constexpr bool equivalent = detail::equivalent_impl<T, U>::value;
|
||||
|
||||
} // namespace units
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2018 Mateusz Pusz
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <units/bits/external/hacks.h>
|
||||
#include <type_traits>
|
||||
|
||||
#ifdef UNITS_DOWNCAST_MODE
|
||||
#if UNITS_DOWNCAST_MODE < 0 || UNITS_DOWNCAST_MODE > 2
|
||||
#error "Invalid UNITS_DOWNCAST_MODE value"
|
||||
#endif
|
||||
#else
|
||||
#define UNITS_DOWNCAST_MODE 1
|
||||
#endif
|
||||
|
||||
namespace units {
|
||||
|
||||
template<typename BaseType>
|
||||
struct downcast_base {
|
||||
using downcast_base_type = BaseType;
|
||||
friend auto downcast_guide(downcast_base);
|
||||
friend auto downcast_poison_pill(downcast_base);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
concept Downcastable =
|
||||
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); };
|
||||
|
||||
template<typename T>
|
||||
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>(); }
|
||||
};
|
||||
|
||||
template<Downcastable T>
|
||||
struct downcast_poison : T {
|
||||
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
|
||||
};
|
||||
|
||||
|
||||
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,
|
||||
#ifdef UNITS_COMP_MSVC
|
||||
downcast_child<Target, T>> {};
|
||||
#else
|
||||
std::conditional_t<mode == downcast_mode::automatic && has_downcast_guide<T>,
|
||||
downcast_poison<T>, downcast_child<Target, T>>> {};
|
||||
#endif
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
constexpr auto downcast_impl()
|
||||
{
|
||||
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>();
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<Downcastable T>
|
||||
using downcast = TYPENAME decltype(detail::downcast_impl<T>())::type;
|
||||
|
||||
template<Downcastable T>
|
||||
using downcast_base_t = TYPENAME T::downcast_base_type;
|
||||
|
||||
} // namespace units
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2018 Mateusz Pusz
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <units/bits/external/hacks.h>
|
||||
#include <cstdlib>
|
||||
#include <compare>
|
||||
|
||||
// TODO use <algorithm> when moved to C++20 modules (parsing takes too long for each translation unit)
|
||||
|
||||
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
|
||||
*/
|
||||
template<typename CharT, std::size_t N>
|
||||
struct basic_fixed_string {
|
||||
CharT data_[N + 1] = {};
|
||||
|
||||
using iterator = CharT*;
|
||||
using const_iterator = const CharT*;
|
||||
|
||||
constexpr explicit(false) basic_fixed_string(CharT ch) noexcept { data_[0] = ch; }
|
||||
|
||||
constexpr explicit(false) basic_fixed_string(const CharT (&txt)[N + 1]) noexcept
|
||||
{
|
||||
if constexpr (N != 0)
|
||||
for (std::size_t i = 0; i < N; ++i) data_[i] = txt[i];
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool empty() const noexcept { return N == 0; }
|
||||
[[nodiscard]] constexpr std::size_t size() const noexcept { return N; }
|
||||
[[nodiscard]] constexpr const CharT* data() const noexcept { return data_; }
|
||||
[[nodiscard]] constexpr const CharT* c_str() const noexcept { return data(); }
|
||||
[[nodiscard]] constexpr const CharT& operator[](std::size_t index) const noexcept { return data()[index]; }
|
||||
[[nodiscard]] constexpr CharT operator[](std::size_t index) noexcept { return data()[index]; }
|
||||
|
||||
[[nodiscard]] constexpr iterator begin() noexcept { return data(); }
|
||||
[[nodiscard]] constexpr const_iterator begin() const noexcept { return data(); }
|
||||
[[nodiscard]] constexpr iterator end() noexcept { return data() + size(); }
|
||||
[[nodiscard]] constexpr const_iterator end() const noexcept { return data() + size(); }
|
||||
|
||||
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
|
||||
{
|
||||
CharT txt[N + N2 + 1] = {};
|
||||
|
||||
for (size_t i = 0; i != N; ++i) txt[i] = lhs[i];
|
||||
for (size_t i = 0; i != N2; ++i) txt[N + i] = rhs[i];
|
||||
|
||||
return basic_fixed_string<CharT, N + N2>(txt);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool operator==(const basic_fixed_string& other) const
|
||||
{
|
||||
if (size() != other.size())
|
||||
return false;
|
||||
for (size_t i = 0; i != size(); ++i) {
|
||||
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; }
|
||||
|
||||
template<std::size_t N2>
|
||||
[[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();
|
||||
auto first2 = rhs.begin();
|
||||
const auto last2 = rhs.end();
|
||||
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;
|
||||
// return std::lexicographical_compare_three_way(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename CharT, std::size_t N>
|
||||
basic_fixed_string(const CharT (&str)[N]) -> basic_fixed_string<CharT, N - 1>;
|
||||
|
||||
template<typename CharT>
|
||||
basic_fixed_string(CharT) -> basic_fixed_string<CharT, 1>;
|
||||
|
||||
template<std::size_t N>
|
||||
using fixed_string = basic_fixed_string<char, N>;
|
||||
|
||||
} // namespace units
|
||||
@@ -0,0 +1,36 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2018 Mateusz Pusz
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <units/bits/external/fixed_string.h>
|
||||
#include <ostream>
|
||||
|
||||
namespace units {
|
||||
|
||||
template<typename CharT, class Traits, std::size_t N>
|
||||
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const basic_fixed_string<CharT, N>& txt)
|
||||
{
|
||||
return os << txt.c_str();
|
||||
}
|
||||
|
||||
} // namespace units
|
||||
+188
@@ -0,0 +1,188 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2018 Mateusz Pusz
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if __clang__
|
||||
#define UNITS_COMP_CLANG __clang_major__
|
||||
#elif __GNUC__
|
||||
#define UNITS_COMP_GCC __GNUC__
|
||||
#define UNITS_COMP_GCC_MINOR __GNUC_MINOR__
|
||||
#elif _MSC_VER
|
||||
#define UNITS_COMP_MSVC _MSC_VER
|
||||
#endif
|
||||
|
||||
#if UNITS_COMP_CLANG
|
||||
|
||||
#include <ciso646>
|
||||
#if _LIBCPP_VERSION
|
||||
#define UNITS_LIBCXX _LIBCPP_VERSION
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if UNITS_COMP_CLANG == 12 && UNITS_LIBCXX
|
||||
|
||||
#include <concepts/compare.hpp>
|
||||
#include <concepts/concepts.hpp>
|
||||
#include <range/v3/functional/comparisons.hpp>
|
||||
#include <range/v3/iterator.hpp>
|
||||
#include <range/v3/range/concepts.hpp>
|
||||
#include <range/v3/algorithm/lower_bound.hpp>
|
||||
#include <range/v3/algorithm/transform.hpp>
|
||||
|
||||
#endif
|
||||
|
||||
#include <concepts>
|
||||
#include <compare>
|
||||
|
||||
#if UNITS_COMP_MSVC || UNITS_COMP_CLANG
|
||||
|
||||
#define TYPENAME typename
|
||||
|
||||
#else
|
||||
|
||||
#define TYPENAME
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
namespace std {
|
||||
|
||||
#if UNITS_COMP_GCC
|
||||
|
||||
template<class T>
|
||||
concept default_constructible = constructible_from<T>;
|
||||
|
||||
#elif UNITS_COMP_CLANG && UNITS_LIBCXX
|
||||
|
||||
// concepts
|
||||
using concepts::common_with;
|
||||
using concepts::constructible_from;
|
||||
using concepts::convertible_to;
|
||||
using concepts::copy_constructible;
|
||||
using concepts::derived_from;
|
||||
using concepts::equality_comparable;
|
||||
using concepts::equality_comparable_with;
|
||||
using concepts::integral;
|
||||
using concepts::move_constructible;
|
||||
using concepts::regular;
|
||||
using concepts::three_way_comparable;
|
||||
using concepts::three_way_comparable_with;
|
||||
using concepts::totally_ordered;
|
||||
|
||||
using ranges::compare_three_way;
|
||||
|
||||
namespace ranges {
|
||||
|
||||
using ::ranges::begin;
|
||||
using ::ranges::end;
|
||||
using ::ranges::distance;
|
||||
|
||||
using ::ranges::forward_range;
|
||||
using ::ranges::input_range;
|
||||
using ::ranges::range_value_t;
|
||||
|
||||
using ::ranges::lower_bound;
|
||||
using ::ranges::transform;
|
||||
|
||||
}
|
||||
|
||||
// missing in Range-v3
|
||||
template<class T>
|
||||
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; };
|
||||
|
||||
template<class F, class... 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...>;
|
||||
|
||||
template<class T, class U>
|
||||
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;
|
||||
else if constexpr (std::is_signed_v<T>)
|
||||
return t < 0 ? false : UT(t) == u;
|
||||
else
|
||||
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;
|
||||
else if constexpr (std::is_signed_v<T>)
|
||||
return t < 0 ? true : UT(t) < u;
|
||||
else
|
||||
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
|
||||
{
|
||||
return !cmp_less(t, u);
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace std
|
||||
@@ -0,0 +1,77 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2018 Mateusz Pusz
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <units/bits/external/fixed_string.h>
|
||||
#include <units/symbol_text.h>
|
||||
|
||||
namespace units::detail {
|
||||
|
||||
template<std::intmax_t Value>
|
||||
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";
|
||||
|
||||
inline constexpr basic_symbol_text superscript_minus("\u207b", "-");
|
||||
|
||||
inline constexpr basic_symbol_text superscript_prefix("", "^");
|
||||
|
||||
template<std::intmax_t Value>
|
||||
constexpr auto superscript_helper()
|
||||
{
|
||||
if constexpr(Value < 0)
|
||||
return superscript_minus + superscript_helper<-Value>();
|
||||
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>();
|
||||
}
|
||||
|
||||
template<std::intmax_t Value>
|
||||
constexpr auto superscript()
|
||||
{
|
||||
return superscript_prefix + superscript_helper<Value>();
|
||||
}
|
||||
|
||||
template<std::intmax_t Value>
|
||||
constexpr auto regular()
|
||||
{
|
||||
if constexpr (Value < 0)
|
||||
return basic_fixed_string("-") + superscript_helper<-Value>();
|
||||
else if constexpr (Value < 10)
|
||||
return basic_symbol_text(static_cast<char>('0' + Value));
|
||||
else
|
||||
return regular<Value / 10>() + regular<Value % 10>();
|
||||
}
|
||||
|
||||
} // namespace units::detail
|
||||
+226
@@ -0,0 +1,226 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2018 Mateusz Pusz
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <units/bits/external/type_traits.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable:4296) // warning C4296: '<': expression is always false
|
||||
#endif //_MSC_VER
|
||||
|
||||
namespace units {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_type_list = false;
|
||||
|
||||
template<template<typename...> typename T, typename... Types>
|
||||
inline constexpr bool is_type_list<T<Types...>> = true;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename T>
|
||||
concept TypeList = detail::is_type_list<T>;
|
||||
|
||||
// push_front
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename List, typename... Types>
|
||||
struct type_list_push_front_impl;
|
||||
|
||||
template<template<typename...> typename List, typename... OldTypes, typename... NewTypes>
|
||||
struct type_list_push_front_impl<List<OldTypes...>, NewTypes...> {
|
||||
using type = List<NewTypes..., OldTypes...>;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<TypeList List, typename... Types>
|
||||
using type_list_push_front = TYPENAME detail::type_list_push_front_impl<List, Types...>::type;
|
||||
|
||||
// push_back
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename List, typename... Types>
|
||||
struct type_list_push_back_impl;
|
||||
|
||||
template<template<typename...> typename List, typename... OldTypes, typename... NewTypes>
|
||||
struct type_list_push_back_impl<List<OldTypes...>, NewTypes...> {
|
||||
using type = List<OldTypes..., NewTypes...>;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<TypeList List, typename... Types>
|
||||
using type_list_push_back = TYPENAME detail::type_list_push_back_impl<List, Types...>::type;
|
||||
|
||||
// join
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename List, typename... Rest>
|
||||
struct type_list_join_impl {
|
||||
using type = List;
|
||||
};
|
||||
|
||||
template<template<typename...> typename List, typename... First, typename... Second, typename... Rest>
|
||||
struct type_list_join_impl<List<First...>, List<Second...>, Rest...> {
|
||||
using type = TYPENAME type_list_join_impl<List<First..., Second...>, Rest...>::type;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<TypeList... Lists>
|
||||
using type_list_join = TYPENAME detail::type_list_join_impl<Lists...>::type;
|
||||
|
||||
// split
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<template<typename...> typename List, std::size_t Idx, std::size_t N, typename... Types>
|
||||
struct split_impl;
|
||||
|
||||
template<template<typename...> typename List, std::size_t Idx, std::size_t N>
|
||||
struct split_impl<List, Idx, N> {
|
||||
using first_list = List<>;
|
||||
using second_list = List<>;
|
||||
};
|
||||
|
||||
template<template<typename...> typename List, std::size_t Idx, std::size_t N, typename T, typename... Rest>
|
||||
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;
|
||||
using second_list = TYPENAME base::second_list;
|
||||
};
|
||||
|
||||
template<template<typename...> typename List, std::size_t Idx, std::size_t N, typename T, typename... Rest>
|
||||
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 base::first_list;
|
||||
using second_list = TYPENAME type_list_push_front_impl<typename base::second_list, T>::type;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<TypeList List, std::size_t N>
|
||||
struct type_list_split;
|
||||
|
||||
template<template<typename...> typename List, std::size_t N, typename... Types>
|
||||
struct type_list_split<List<Types...>, N> {
|
||||
static_assert(N <= sizeof...(Types), "Invalid index provided");
|
||||
using split = detail::split_impl<List, 0, N, Types...>;
|
||||
using first_list = TYPENAME split::first_list;
|
||||
using second_list = TYPENAME split::second_list;
|
||||
};
|
||||
|
||||
// split_half
|
||||
|
||||
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> {
|
||||
};
|
||||
|
||||
// merge_sorted
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename SortedList1, typename SortedList2, template<typename, typename> typename Pred>
|
||||
struct type_list_merge_sorted_impl;
|
||||
|
||||
template<template<typename...> typename List, template<typename, typename> typename Pred>
|
||||
struct type_list_merge_sorted_impl<List<>, List<>, Pred> {
|
||||
using type = List<>;
|
||||
};
|
||||
|
||||
template<template<typename...> typename List, typename... Lhs, template<typename, typename> typename Pred>
|
||||
struct type_list_merge_sorted_impl<List<Lhs...>, List<>, Pred> {
|
||||
using type = List<Lhs...>;
|
||||
};
|
||||
|
||||
template<template<typename...> typename List, typename... Rhs, template<typename, typename> typename Pred>
|
||||
struct type_list_merge_sorted_impl<List<>, List<Rhs...>, Pred> {
|
||||
using type = List<Rhs...>;
|
||||
};
|
||||
|
||||
|
||||
template<template<typename...> typename List, typename Lhs1, typename... LhsRest, typename Rhs1, typename... RhsRest,
|
||||
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;
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<TypeList SortedList1, TypeList SortedList2, template<typename, typename> typename Pred>
|
||||
using type_list_merge_sorted = TYPENAME detail::type_list_merge_sorted_impl<SortedList1, SortedList2, Pred>::type;
|
||||
|
||||
// sort
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename List, template<typename, typename> typename Pred>
|
||||
struct type_list_sort_impl;
|
||||
|
||||
template<template<typename...> typename List, template<typename, typename> typename Pred>
|
||||
struct type_list_sort_impl<List<>, Pred> {
|
||||
using type = List<>;
|
||||
};
|
||||
|
||||
template<template<typename...> typename List, typename T, template<typename, typename> typename Pred>
|
||||
struct type_list_sort_impl<List<T>, Pred> {
|
||||
using type = List<T>;
|
||||
};
|
||||
|
||||
template<template<typename...> typename List, typename... Types, template<typename, typename> typename Pred>
|
||||
struct type_list_sort_impl<List<Types...>, Pred> {
|
||||
using types = List<Types...>;
|
||||
using split = type_list_split_half<List<Types...>>;
|
||||
using sorted_left = TYPENAME type_list_sort_impl<typename split::first_list, Pred>::type;
|
||||
using sorted_right = TYPENAME type_list_sort_impl<typename split::second_list, Pred>::type;
|
||||
using type = TYPENAME type_list_merge_sorted_impl<sorted_left, sorted_right, Pred>::type;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<TypeList List, template<typename, typename> typename Pred>
|
||||
using type_list_sort = TYPENAME detail::type_list_sort_impl<List, Pred>::type;
|
||||
|
||||
} // namespace units
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (pop)
|
||||
#endif //_MSC_VER
|
||||
@@ -0,0 +1,80 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2018 Mateusz Pusz
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <units/bits/external/hacks.h>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace units {
|
||||
|
||||
// conditional
|
||||
namespace detail {
|
||||
|
||||
template<bool>
|
||||
struct conditional_impl {
|
||||
template<typename T, typename F>
|
||||
using type = F;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct conditional_impl<true> {
|
||||
template<typename T, typename F>
|
||||
using type = T;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<bool B, typename T, typename F>
|
||||
using conditional = TYPENAME detail::conditional_impl<B>::template type<T, F>;
|
||||
|
||||
// is_same
|
||||
template<class T, class U>
|
||||
inline constexpr bool is_same_v = false;
|
||||
|
||||
template<class T>
|
||||
inline constexpr bool is_same_v<T, T> = true;
|
||||
|
||||
template<class T, class U>
|
||||
using is_same = std::bool_constant<is_same_v<T, U>>;
|
||||
|
||||
// is_specialization_of
|
||||
template<typename T, template<typename...> typename Type>
|
||||
inline constexpr bool is_specialization_of = false;
|
||||
|
||||
template<typename... Params, template<typename...> typename Type>
|
||||
inline constexpr bool is_specialization_of<Type<Params...>, Type> = true;
|
||||
|
||||
// is_derived_from_specialization_of
|
||||
namespace detail {
|
||||
|
||||
template<template<typename...> typename Type, typename... Params>
|
||||
void to_base_specialization_of(const volatile Type<Params...>*);
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename T, template<typename...> typename Type>
|
||||
// inline constexpr bool // TODO: Replace with concept when it works with MSVC
|
||||
concept is_derived_from_specialization_of = requires(T* t) { detail::to_base_specialization_of<Type>(t); };
|
||||
|
||||
} // namespace units
|
||||
@@ -0,0 +1,35 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2018 Mateusz Pusz
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace units::detail {
|
||||
|
||||
template<std::intmax_t N>
|
||||
concept gt_zero = (N > 0);
|
||||
|
||||
template<std::intmax_t N>
|
||||
concept non_zero = (N != 0);
|
||||
|
||||
} // namespace units::detail
|
||||
@@ -0,0 +1,77 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2018 Mateusz Pusz
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cassert>
|
||||
|
||||
namespace units::detail {
|
||||
|
||||
constexpr std::intmax_t ipow10(std::intmax_t exp)
|
||||
{
|
||||
assert(exp >= 0);
|
||||
if (exp == 0) return 1;
|
||||
std::intmax_t result = 1;
|
||||
while (exp > 0) {
|
||||
result *= 10;
|
||||
--exp;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename Rep>
|
||||
constexpr Rep fpow10(std::intmax_t exp)
|
||||
{
|
||||
if (exp == 0) return Rep(1.0);
|
||||
Rep result = Rep(1.0);
|
||||
if (exp < 0) {
|
||||
while (exp < 0) {
|
||||
result = result / Rep(10.0);
|
||||
++exp;
|
||||
}
|
||||
} else {
|
||||
while (exp > 0) {
|
||||
result = result * Rep(10.0);
|
||||
--exp;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<std::intmax_t N, typename T>
|
||||
constexpr T pow_impl(const T& v) noexcept
|
||||
{
|
||||
if constexpr (N == 0) {
|
||||
return T(1);
|
||||
} else if constexpr (N == 1) {
|
||||
return v;
|
||||
} else if constexpr (N < 0) {
|
||||
return 1 / pow_impl<-N>(v);
|
||||
} else if constexpr (N % 2 == 0) { // even
|
||||
return pow_impl<N / 2>(v * v);
|
||||
} else { // odd
|
||||
return v * pow_impl<(N - 1) / 2>(v * v);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace units::detail
|
||||
@@ -0,0 +1,139 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2018 Mateusz Pusz
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <units/bits/dimension_op.h>
|
||||
#include <units/bits/equivalent.h>
|
||||
|
||||
namespace units {
|
||||
|
||||
// DimensionOfT
|
||||
#if UNITS_DOWNCAST_MODE == 0
|
||||
|
||||
namespace detail {
|
||||
|
||||
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>;
|
||||
|
||||
} // 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>;
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief A concept matching all dimensions matching provided dimension class template
|
||||
*
|
||||
* Satisfied by all dimensions being the instantiations derived from the provided dimension
|
||||
* class template.
|
||||
*/
|
||||
template<typename Dim, template<typename...> typename DimTemplate>
|
||||
concept DimensionOfT = Dimension<Dim> && (is_derived_from_specialization_of<Dim, DimTemplate>
|
||||
#if UNITS_DOWNCAST_MODE == 0
|
||||
|| EquivalentUnknownDimensionOfT<Dim, DimTemplate>
|
||||
#endif
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief A concept matching all quantities with provided dimension class template
|
||||
*
|
||||
* Satisfied by all quantities with a dimension being the instantiation derived from
|
||||
* the provided dimension class template.
|
||||
*/
|
||||
template<typename Q, template<typename...> typename DimTemplate>
|
||||
concept QuantityOfT = Quantity<Q> && DimensionOfT<typename Q::dimension, DimTemplate>;
|
||||
|
||||
/**
|
||||
* @brief A concept matching all quantities with provided dimension
|
||||
*
|
||||
* Satisfied by all quantities with a dimension being the instantiation derived from
|
||||
* the provided dimension type.
|
||||
*/
|
||||
template<typename Q, typename Dim>
|
||||
concept QuantityOf = Quantity<Q> && Dimension<Dim> && equivalent<typename Q::dimension, Dim>;
|
||||
|
||||
/**
|
||||
* @brief A concept matching two equivalent quantities
|
||||
*
|
||||
* Satisfied by quantities having equivalent dimensions.
|
||||
*/
|
||||
template<typename Q1, typename Q2>
|
||||
concept QuantityEquivalentTo = Quantity<Q1> && QuantityOf<Q2, typename Q1::dimension>;
|
||||
|
||||
/**
|
||||
* @brief A concept matching all quantity points with provided dimension
|
||||
*
|
||||
* Satisfied by all quantity points with a dimension being the instantiation derived from
|
||||
* the provided dimension type.
|
||||
*/
|
||||
template<typename QP, typename Dim>
|
||||
concept QuantityPointOf = QuantityPoint<QP> && Dimension<Dim> && equivalent<typename QP::dimension, Dim>;
|
||||
|
||||
/**
|
||||
* @brief A concept matching two equivalent quantity points
|
||||
*
|
||||
* Satisfied by quantity points having equivalent dimensions.
|
||||
*/
|
||||
template<typename QP1, typename QP2>
|
||||
concept QuantityPointEquivalentTo = QuantityPoint<QP1> && QuantityPointOf<QP2, typename QP1::dimension>;
|
||||
|
||||
/**
|
||||
* @brief A concept matching only quantity kinds of a specific kind.
|
||||
*
|
||||
* @tparam QK Quantity kind to verify.
|
||||
* @tparam K Kind type to use for verification.
|
||||
*/
|
||||
template<typename QK, typename K>
|
||||
concept QuantityKindOf = QuantityKind<QK> && Kind<K> && equivalent<typename QK::kind_type, K>;
|
||||
|
||||
/**
|
||||
* @brief A concept matching two equivalent quantity kinds
|
||||
*
|
||||
* Satisfied by quantity kinds having equivalent kinds.
|
||||
*/
|
||||
template<typename QK1, typename QK2>
|
||||
concept QuantityKindEquivalentTo = QuantityKind<QK1> && QuantityKindOf<QK2, typename QK1::kind_type>;
|
||||
|
||||
/**
|
||||
* @brief A concept matching only quantity point kinds of a specific point kind.
|
||||
*
|
||||
* @tparam QPK Quantity point kind to verify.
|
||||
* @tparam PK Point kind type to use for verification.
|
||||
*/
|
||||
template<typename QPK, typename PK>
|
||||
concept QuantityPointKindOf = QuantityPointKind<QPK> && PointKind<PK> && equivalent<typename QPK::point_kind_type, PK>;
|
||||
|
||||
/**
|
||||
* @brief A concept matching two equivalent quantity point kinds
|
||||
*
|
||||
* Satisfied by quantity point kinds having equivalent kinds.
|
||||
*/
|
||||
template<typename QPK1, typename QPK2>
|
||||
concept QuantityPointKindEquivalentTo =
|
||||
QuantityPointKind<QPK1> && QuantityPointKindOf<QPK2, typename QPK1::point_kind_type>;
|
||||
|
||||
} // namespace units
|
||||
@@ -0,0 +1,194 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2018 Mateusz Pusz, Conor Williams, Oliver Schonrock
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <units/bits/external/hacks.h>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <numeric>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <gsl/gsl-lite.hpp>
|
||||
|
||||
namespace units::detail {
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] constexpr T abs(T v) noexcept
|
||||
{
|
||||
return v < 0 ? -v : v;
|
||||
}
|
||||
|
||||
// the following functions enable gcd and related computations on ratios
|
||||
// with exponents. They avoid overflow. Further information here:
|
||||
// https://github.com/mpusz/units/issues/62#issuecomment-588152833
|
||||
|
||||
// Computes (a * b) mod m relies on unsigned integer arithmetic, should not
|
||||
// overflow
|
||||
[[nodiscard]] constexpr std::uint64_t mulmod(std::uint64_t a, std::uint64_t b, std::uint64_t m)
|
||||
{
|
||||
std::uint64_t res = 0;
|
||||
|
||||
if (b >= m) {
|
||||
if (m > UINT64_MAX / 2u) {
|
||||
b -= m;
|
||||
} else {
|
||||
b %= m;
|
||||
}
|
||||
}
|
||||
|
||||
while (a != 0) {
|
||||
if (a & 1) {
|
||||
if (b >= m - res) {
|
||||
res -= m;
|
||||
}
|
||||
res += b;
|
||||
}
|
||||
a >>= 1;
|
||||
|
||||
std::uint64_t temp_b = b;
|
||||
if (b >= m - b) {
|
||||
temp_b -= m;
|
||||
}
|
||||
b += temp_b;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// Calculates (a ^ e) mod m , should not overflow.
|
||||
[[nodiscard]] constexpr std::uint64_t modpow(std::uint64_t a, std::uint64_t e, std::uint64_t m)
|
||||
{
|
||||
a %= m;
|
||||
std::uint64_t result = 1;
|
||||
|
||||
while (e > 0) {
|
||||
if (e & 1) {
|
||||
result = mulmod(result, a, m);
|
||||
}
|
||||
a = mulmod(a, a, m);
|
||||
e >>= 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// gcd(a * 10 ^ e, b), should not overflow
|
||||
[[nodiscard]] constexpr std::intmax_t gcdpow(std::intmax_t a, std::intmax_t e, std::intmax_t b) noexcept
|
||||
{
|
||||
assert(a > 0);
|
||||
assert(e >= 0);
|
||||
assert(b > 0);
|
||||
|
||||
// gcd(i, j) = gcd(j, i mod j) for j != 0 Euclid;
|
||||
//
|
||||
// gcd(a 10^e, b) = gcd(b, a 10^e mod b)
|
||||
//
|
||||
// (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))));
|
||||
}
|
||||
|
||||
constexpr void cwap(std::intmax_t& lhs, std::intmax_t& rhs)
|
||||
{
|
||||
std::intmax_t tmp = lhs;
|
||||
lhs = rhs;
|
||||
rhs = tmp;
|
||||
}
|
||||
|
||||
// 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
|
||||
{
|
||||
// Short cut for equal ratios
|
||||
if (n1 == n2 && d1 == d2 && e1 == e2) {
|
||||
return std::array{n1, d1, e1};
|
||||
}
|
||||
|
||||
if (e2 > e1) {
|
||||
detail::cwap(n1, n2);
|
||||
detail::cwap(d1, d2);
|
||||
detail::cwap(e1, e2);
|
||||
}
|
||||
|
||||
std::intmax_t exp = e2; // minimum
|
||||
|
||||
// gcd(a/b,c/d) = gcd(a⋅d, c⋅b) / b⋅d
|
||||
|
||||
assert(std::numeric_limits<std::intmax_t>::max() / n1 > d2);
|
||||
assert(std::numeric_limits<std::intmax_t>::max() / n2 > d1);
|
||||
|
||||
std::intmax_t num = detail::gcdpow(n1 * d2, e1 - e2, n2 * d1);
|
||||
|
||||
assert(std::numeric_limits<std::intmax_t>::max() / d1 > d2);
|
||||
|
||||
std::intmax_t den = d1 * d2;
|
||||
|
||||
std::intmax_t gcd = std::gcd(num, den);
|
||||
|
||||
return std::array{num / gcd, den / gcd, exp};
|
||||
}
|
||||
|
||||
constexpr void normalize(std::intmax_t& num, std::intmax_t& den, std::intmax_t& exp)
|
||||
{
|
||||
if(num == 0) {
|
||||
den = 1;
|
||||
exp = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
std::intmax_t gcd = std::gcd(num, den);
|
||||
num = num * (den < 0 ? -1 : 1) / gcd;
|
||||
den = detail::abs(den) / gcd;
|
||||
|
||||
while (num % 10 == 0) {
|
||||
num /= 10;
|
||||
++exp;
|
||||
}
|
||||
while (den % 10 == 0) {
|
||||
den /= 10;
|
||||
--exp;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] static constexpr std::intmax_t safe_multiply(std::intmax_t lhs, std::intmax_t rhs)
|
||||
{
|
||||
constexpr std::intmax_t c = std::uintmax_t(1) << (sizeof(std::intmax_t) * 4);
|
||||
|
||||
const std::intmax_t a0 = detail::abs(lhs) % c;
|
||||
const std::intmax_t a1 = detail::abs(lhs) / c;
|
||||
const std::intmax_t b0 = detail::abs(rhs) % c;
|
||||
const std::intmax_t b1 = detail::abs(rhs) / c;
|
||||
|
||||
gsl_Expects(a1 == 0 || b1 == 0); // overflow in multiplication
|
||||
gsl_Expects(a0 * b1 + b0 * a1 < (c >> 1)); // overflow in multiplication
|
||||
gsl_Expects(b0 * a0 <= INTMAX_MAX); // overflow in multiplication
|
||||
gsl_Expects((a0 * b1 + b0 * a1) * c <= INTMAX_MAX - b0 * a0); // overflow in multiplication
|
||||
|
||||
return lhs * rhs;
|
||||
}
|
||||
|
||||
} // namespace units::detail
|
||||
@@ -0,0 +1,99 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2018 Mateusz Pusz
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gsl/gsl-lite.hpp>
|
||||
#include <units/bits/constexpr_math.h>
|
||||
#include <units/bits/math_concepts.h>
|
||||
#include <units/bits/pow.h>
|
||||
#include <units/bits/ratio_maths.h>
|
||||
#include <cmath>
|
||||
|
||||
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
|
||||
{
|
||||
if constexpr (N == 1) {
|
||||
return v;
|
||||
} else {
|
||||
gsl_Expects(v >= 0);
|
||||
if (v == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
constexpr double exponent = 1.0 / static_cast<double>(N);
|
||||
const auto root = static_cast<std::intmax_t>(pow_function(static_cast<double>(v), exponent));
|
||||
|
||||
// integer roots may be truncated down by 1 or in even rarer cases up by 1 due to finite precision of pow and
|
||||
// exponent, check both cases
|
||||
if (v == pow_impl<N>(root + 1)) {
|
||||
return root + 1;
|
||||
}
|
||||
if (v < pow_impl<N>(root)) {
|
||||
return root - 1;
|
||||
}
|
||||
return root;
|
||||
}
|
||||
}
|
||||
|
||||
// maximum v is std::numeric_limits<std::intmax_t>::max() which is the worst case for exp convergence
|
||||
// ExpOrder = 12 and Factor = 64 give a precision of about O(1e-15) for a wide range of 1 / N exponents
|
||||
// Factor = 32 needs quite a few more terms to converge
|
||||
// https://godbolt.org/z/odWq1o
|
||||
template<std::intmax_t N, std::size_t ExpOrder = 12, std::intmax_t Factor = 64>
|
||||
requires gt_zero<N>
|
||||
[[nodiscard]] constexpr std::intmax_t iroot_compile(std::intmax_t v) noexcept
|
||||
{
|
||||
return iroot_impl<N>(v, [](double x, double exponent) { return constexpr_pow<ExpOrder, Factor>(x, exponent); });
|
||||
}
|
||||
|
||||
template<std::intmax_t N>
|
||||
requires gt_zero<N>
|
||||
[[nodiscard]] std::intmax_t iroot_runtime(std::intmax_t v) noexcept
|
||||
{
|
||||
return iroot_impl<N>(v, [](double x, [[maybe_unused]] double exponent) {
|
||||
if constexpr (N == 2) {
|
||||
return std::sqrt(x);
|
||||
} else if constexpr (N == 3) {
|
||||
return std::cbrt(x);
|
||||
} else {
|
||||
return std::pow(x, exponent);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template<std::intmax_t N>
|
||||
requires gt_zero<N>
|
||||
[[nodiscard]] constexpr std::intmax_t iroot(std::intmax_t v) noexcept
|
||||
{
|
||||
// compile time version is much slower, use faster version at runtime
|
||||
if (std::is_constant_evaluated()) {
|
||||
return iroot_compile<N>(v);
|
||||
}
|
||||
|
||||
return iroot_runtime<N>(v);
|
||||
}
|
||||
|
||||
} // namespace units::detail
|
||||
@@ -0,0 +1,180 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2018 Mateusz Pusz
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <units/bits/deduced_symbol_text.h>
|
||||
#include <units/bits/external/text_tools.h>
|
||||
#include <units/prefix.h>
|
||||
#include <units/derived_dimension.h>
|
||||
|
||||
namespace units::detail {
|
||||
|
||||
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) {
|
||||
return base_multiplier + superscript<R.exp>();
|
||||
}
|
||||
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) {
|
||||
return txt + 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 {
|
||||
return basic_fixed_string("");
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
// no ratio/prefix
|
||||
return basic_fixed_string("");
|
||||
}
|
||||
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>>) {
|
||||
// print as a prefixed unit
|
||||
return prefix::symbol;
|
||||
}
|
||||
else {
|
||||
// print as a ratio of the coherent unit
|
||||
constexpr auto txt = ratio_text<R>();
|
||||
if constexpr(SymbolLen > 0 && txt.standard().size() > 0)
|
||||
return txt + basic_fixed_string(" ");
|
||||
else
|
||||
return txt;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// print as a ratio of the coherent unit
|
||||
constexpr auto txt = ratio_text<R>();
|
||||
if constexpr(SymbolLen > 0 && txt.standard().size() > 0)
|
||||
return txt + basic_fixed_string(" ");
|
||||
else
|
||||
return txt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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("")));
|
||||
}
|
||||
|
||||
template<typename... Es>
|
||||
constexpr auto derived_dimension_unit_text(exponent_list<Es...> list)
|
||||
{
|
||||
return derived_dimension_unit_text(list, std::index_sequence_for<Es...>());
|
||||
}
|
||||
|
||||
template<Exponent... Es>
|
||||
constexpr auto exponent_list_with_named_units(exponent_list<Es...>);
|
||||
|
||||
template<Exponent Exp>
|
||||
constexpr auto exponent_list_with_named_units(Exp)
|
||||
{
|
||||
using dim = TYPENAME Exp::dimension;
|
||||
if constexpr(dimension_unit<dim>::is_named) {
|
||||
return exponent_list<Exp>();
|
||||
}
|
||||
else {
|
||||
using recipe = TYPENAME dim::recipe;
|
||||
return exponent_list_with_named_units(recipe());
|
||||
}
|
||||
}
|
||||
|
||||
template<Exponent... Es>
|
||||
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;
|
||||
}
|
||||
|
||||
template<Dimension Dim>
|
||||
constexpr auto derived_dimension_unit_text()
|
||||
{
|
||||
using recipe = TYPENAME Dim::recipe;
|
||||
return derived_dimension_unit_text(exponent_list_with_named_units(recipe()));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
// TODO replace with `inline constexpr bool has_symbol` when MSVC cathes up
|
||||
concept has_symbol = requires{ T::symbol; };
|
||||
|
||||
template<Dimension Dim, Unit U>
|
||||
constexpr auto unit_text()
|
||||
{
|
||||
if constexpr(has_symbol<U>) {
|
||||
// already has a symbol so print it
|
||||
return U::symbol;
|
||||
}
|
||||
else {
|
||||
// print as a prefix or ratio of a coherent unit
|
||||
using coherent_unit = dimension_unit<Dim>;
|
||||
|
||||
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()>();
|
||||
return prefix_txt + symbol_text;
|
||||
}
|
||||
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()>();
|
||||
return prefix_txt + symbol_text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace units::detail
|
||||
Reference in New Issue
Block a user