mirror of
https://github.com/mpusz/mp-units.git
synced 2025-07-31 02:47:16 +02:00
Library refactoring based on Walter Brown's feedback
This commit is contained in:
@ -43,4 +43,4 @@ enable_testing()
|
||||
add_subdirectory(test)
|
||||
|
||||
# add usage example
|
||||
#add_subdirectory(example)
|
||||
add_subdirectory(example)
|
||||
|
@ -23,18 +23,21 @@
|
||||
#include "units/si/velocity.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace units;
|
||||
|
||||
template<Unit U1, typename Rep1, Unit U2, typename Rep2>
|
||||
void foo(velocity<U1, Rep1> v, time<U2, Rep2> t)
|
||||
{
|
||||
const auto distance = v * t;
|
||||
|
||||
std::cout << "A car driving " << v.count() << " km/h in a time of " << t.count() << " minutes will pass "
|
||||
<< quantity_cast<length<meter, int>>(distance).count() << " meters.\n";
|
||||
}
|
||||
|
||||
void foo()
|
||||
{
|
||||
using namespace units;
|
||||
using namespace units::literals;
|
||||
|
||||
const auto speed = 60_kmph;
|
||||
const auto time = 10.0_min;
|
||||
const auto distance = speed * time;
|
||||
|
||||
std::cout << "A car driving " << speed.count() << " km/h in a time of " << time.count() << " minutes will pass "
|
||||
<< quantity_cast<meters<int>>(distance).count() << " meters.\n";
|
||||
foo(60_kmph, 10.0_min);
|
||||
}
|
||||
|
||||
int main()
|
||||
|
@ -27,6 +27,8 @@
|
||||
|
||||
namespace mp {
|
||||
|
||||
namespace std_concepts {
|
||||
|
||||
namespace detail {
|
||||
template<class T, class U>
|
||||
concept bool SameHelper = std::is_same_v<T, U>;
|
||||
@ -36,9 +38,10 @@ namespace mp {
|
||||
concept bool Same = detail::SameHelper<T, U>&& detail::SameHelper<U, T>;
|
||||
|
||||
template<class From, class To>
|
||||
concept bool ConvertibleTo = std::is_convertible_v<From, To> &&
|
||||
requires(From (&f)()) {
|
||||
concept bool ConvertibleTo = std::is_convertible_v<From, To>&& requires(From (&f)())
|
||||
{
|
||||
static_cast<To>(f());
|
||||
};
|
||||
|
||||
} // namespace std_concepts
|
||||
} // namespace mp
|
||||
|
@ -26,7 +26,9 @@
|
||||
#include <ratio>
|
||||
#include <type_traits>
|
||||
|
||||
namespace mp {
|
||||
namespace units {
|
||||
|
||||
using namespace mp::std_concepts; // todo Remove when std::concepts will arrive
|
||||
|
||||
// static_sign
|
||||
|
||||
@ -66,7 +68,7 @@ namespace mp {
|
||||
struct is_ratio<std::ratio<Num, Den>> : std::true_type {
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
template<typename T>
|
||||
concept bool Ratio = detail::is_ratio<T>::value;
|
||||
@ -84,4 +86,4 @@ namespace mp {
|
||||
template<Ratio Ratio1, Ratio Ratio2>
|
||||
using common_ratio_t = typename common_ratio<Ratio1, Ratio2>::type;
|
||||
|
||||
} // namespace mp
|
||||
} // namespace units
|
||||
|
@ -30,12 +30,14 @@ namespace mp {
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
struct is_type_list : std::false_type {};
|
||||
struct is_type_list : std::false_type {
|
||||
};
|
||||
|
||||
template<template<typename...> typename T, typename... Types>
|
||||
struct is_type_list<T<Types...>> : std::true_type {};
|
||||
struct is_type_list<T<Types...>> : std::true_type {
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
template<typename T>
|
||||
concept bool TypeList = detail::is_type_list<T>::value;
|
||||
@ -133,10 +135,8 @@ namespace mp {
|
||||
struct type_list_merge_sorted<List<Lhs1, LhsRest...>, List<Rhs1, RhsRest...>, Pred> {
|
||||
using type = std::conditional_t<
|
||||
Pred<Lhs1, Rhs1>::value,
|
||||
type_list_push_front_t<type_list_merge_sorted_t<List<LhsRest...>, List<Rhs1, RhsRest...>, Pred>,
|
||||
Lhs1>,
|
||||
type_list_push_front_t<type_list_merge_sorted_t<List<Lhs1, LhsRest...>, List<RhsRest...>, Pred>,
|
||||
Rhs1>>;
|
||||
type_list_push_front_t<type_list_merge_sorted_t<List<LhsRest...>, List<Rhs1, RhsRest...>, Pred>, Lhs1>,
|
||||
type_list_push_front_t<type_list_merge_sorted_t<List<Lhs1, LhsRest...>, List<RhsRest...>, Pred>, Rhs1>>;
|
||||
};
|
||||
|
||||
// sort
|
||||
|
@ -40,7 +40,8 @@ namespace units {
|
||||
|
||||
// exp
|
||||
|
||||
template<typename BaseDimension, int Value>
|
||||
template<typename BaseDimension, int Value> // todo: to be replaced with fixed_string when supported by the compilers
|
||||
// template<fixed_string BaseDimension, int Value>
|
||||
struct exp {
|
||||
using dimension = BaseDimension;
|
||||
static constexpr int value = Value;
|
||||
@ -55,12 +56,11 @@ namespace units {
|
||||
template<typename BaseDim, int Value>
|
||||
struct is_exp<exp<BaseDim, Value>> : std::true_type {
|
||||
};
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
template<typename T>
|
||||
concept bool Exponent = detail::is_exp<T>::value;
|
||||
|
||||
|
||||
// exp_less
|
||||
|
||||
template<Exponent E1, Exponent E2>
|
||||
@ -88,16 +88,17 @@ namespace units {
|
||||
// is_dimension
|
||||
namespace detail {
|
||||
template<typename T>
|
||||
struct is_dimension : std::false_type {};
|
||||
struct is_dimension : std::false_type {
|
||||
};
|
||||
|
||||
template<Exponent... Es>
|
||||
struct is_dimension<dimension<Es...>> : std::bool_constant<(is_exp<Es>::value && ...)> {};
|
||||
}
|
||||
struct is_dimension<dimension<Es...>> : std::bool_constant<(is_exp<Es>::value && ...)> {
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
template<typename T>
|
||||
concept bool Dimension = detail::is_dimension<T>::value;
|
||||
|
||||
|
||||
// make_dimension
|
||||
|
||||
namespace detail {
|
||||
@ -121,8 +122,8 @@ namespace units {
|
||||
template<Exponent E1, Exponent... ERest>
|
||||
struct dim_consolidate<dimension<E1, ERest...>> {
|
||||
using rest = dim_consolidate_t<dimension<ERest...>>;
|
||||
using type = std::conditional_t<std::is_same_v<rest, dimension<>>, dimension<E1>,
|
||||
mp::type_list_push_front_t<rest, E1>>;
|
||||
using type =
|
||||
std::conditional_t<std::is_same_v<rest, dimension<>>, dimension<E1>, mp::type_list_push_front_t<rest, E1>>;
|
||||
};
|
||||
|
||||
template<typename D, int V1, int V2, Exponent... ERest>
|
||||
@ -141,8 +142,6 @@ namespace units {
|
||||
template<Exponent... Es>
|
||||
using make_dimension_t = typename make_dimension<Es...>::type;
|
||||
|
||||
|
||||
|
||||
// dimension_multiply
|
||||
|
||||
template<Dimension D1, Dimension D2>
|
||||
|
@ -22,16 +22,15 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "bits/tools.h"
|
||||
#include "dimension.h"
|
||||
#include "unit.h"
|
||||
#include <limits>
|
||||
|
||||
namespace units {
|
||||
|
||||
// is_quantity
|
||||
|
||||
template<Dimension D, typename Rep, mp::Ratio R>
|
||||
class quantity;
|
||||
template<Dimension D, Unit U, typename Rep>
|
||||
requires Same<D, typename U::dimension> class quantity;
|
||||
|
||||
namespace detail {
|
||||
|
||||
@ -39,11 +38,11 @@ namespace units {
|
||||
struct is_quantity : std::false_type {
|
||||
};
|
||||
|
||||
template<Dimension D, typename Rep, mp::Ratio R>
|
||||
struct is_quantity<quantity<D, Rep, R>> : std::true_type {
|
||||
template<Dimension D, Unit U, typename Rep>
|
||||
struct is_quantity<quantity<D, U, Rep>> : std::true_type {
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
template<typename T>
|
||||
concept bool Quantity = detail::is_quantity<T>::value;
|
||||
@ -51,7 +50,8 @@ namespace units {
|
||||
// treat_as_floating_point
|
||||
|
||||
template<class Rep>
|
||||
struct treat_as_floating_point : std::is_floating_point<Rep> {};
|
||||
struct treat_as_floating_point : std::is_floating_point<Rep> {
|
||||
};
|
||||
|
||||
template<class Rep>
|
||||
inline constexpr bool treat_as_floating_point_v = treat_as_floating_point<Rep>::value;
|
||||
@ -60,38 +60,38 @@ namespace units {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<Quantity To, mp::Ratio CR, typename CRep, bool NumIsOne = false, bool DenIsOne = false>
|
||||
template<Quantity To, Ratio CR, typename CRep, bool NumIsOne = false, bool DenIsOne = false>
|
||||
struct quantity_cast_impl {
|
||||
template<Dimension D, typename Rep, mp::Ratio R>
|
||||
static constexpr To cast(const quantity<D, Rep, R>& q)
|
||||
template<Dimension D, Ratio R, typename Rep>
|
||||
static constexpr To cast(const quantity<D, unit<D, R>, Rep>& q)
|
||||
{
|
||||
return To(static_cast<typename To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(CR::num) /
|
||||
static_cast<CRep>(CR::den)));
|
||||
}
|
||||
};
|
||||
|
||||
template<Quantity To, mp::Ratio CR, typename CRep>
|
||||
template<Quantity To, Ratio CR, typename CRep>
|
||||
struct quantity_cast_impl<To, CR, CRep, true, true> {
|
||||
template<Dimension D, typename Rep, mp::Ratio R>
|
||||
static constexpr To cast(const quantity<D, Rep, R>& q)
|
||||
template<Dimension D, Ratio R, typename Rep>
|
||||
static constexpr To cast(const quantity<D, unit<D, R>, Rep>& q)
|
||||
{
|
||||
return To(static_cast<typename To::rep>(q.count()));
|
||||
}
|
||||
};
|
||||
|
||||
template<Quantity To, mp::Ratio CR, typename CRep>
|
||||
template<Quantity To, Ratio CR, typename CRep>
|
||||
struct quantity_cast_impl<To, CR, CRep, true, false> {
|
||||
template<Dimension D, typename Rep, mp::Ratio R>
|
||||
static constexpr To cast(const quantity<D, Rep, R>& q)
|
||||
template<Dimension D, Ratio R, typename Rep>
|
||||
static constexpr To cast(const quantity<D, unit<D, R>, Rep>& q)
|
||||
{
|
||||
return To(static_cast<typename To::rep>(static_cast<CRep>(q.count()) / static_cast<CRep>(CR::den)));
|
||||
}
|
||||
};
|
||||
|
||||
template<Quantity To, mp::Ratio CR, typename CRep>
|
||||
template<Quantity To, Ratio CR, typename CRep>
|
||||
struct quantity_cast_impl<To, CR, CRep, false, true> {
|
||||
template<Dimension D, typename Rep, mp::Ratio R>
|
||||
static constexpr To cast(const quantity<D, Rep, R>& q)
|
||||
template<Dimension D, Ratio R, typename Rep>
|
||||
static constexpr To cast(const quantity<D, unit<D, R>, Rep>& q)
|
||||
{
|
||||
return To(static_cast<typename To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(CR::num)));
|
||||
}
|
||||
@ -99,11 +99,10 @@ namespace units {
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<Quantity To, Dimension D, typename Rep, mp::Ratio R>
|
||||
requires mp::Same<typename To::dimension, D>
|
||||
constexpr To quantity_cast(const quantity<D, Rep, R>& q)
|
||||
template<Quantity To, Dimension D, Unit U, typename Rep>
|
||||
requires Same<typename To::dimension, D> constexpr To quantity_cast(const quantity<D, U, Rep>& q)
|
||||
{
|
||||
using c_ratio = std::ratio_divide<R, typename To::ratio>;
|
||||
using c_ratio = std::ratio_divide<typename U::ratio, typename To::unit::ratio>;
|
||||
using c_rep = std::common_type_t<typename To::rep, Rep, intmax_t>;
|
||||
using cast = detail::quantity_cast_impl<To, c_ratio, c_rep, c_ratio::num == 1, c_ratio::den == 1>;
|
||||
return cast::cast(q);
|
||||
@ -120,30 +119,33 @@ namespace units {
|
||||
|
||||
// quantity
|
||||
|
||||
template<Dimension D, typename Rep, mp::Ratio R = std::ratio<1>>
|
||||
class quantity {
|
||||
template<Dimension D, Unit U, typename Rep>
|
||||
requires Same<D, typename U::dimension> class quantity {
|
||||
Rep value_;
|
||||
|
||||
public:
|
||||
using dimension = D;
|
||||
using unit = U;
|
||||
using rep = Rep;
|
||||
using ratio = R;
|
||||
|
||||
static_assert(!detail::is_quantity<Rep>::value, "rep cannot be a quantity");
|
||||
static_assert(ratio::num > 0, "ratio must be positive");
|
||||
|
||||
quantity() = default;
|
||||
quantity(const quantity&) = default;
|
||||
|
||||
template<class Rep2>
|
||||
requires mp::ConvertibleTo<Rep2, rep> && (treat_as_floating_point_v<rep> || !treat_as_floating_point_v<Rep2>)
|
||||
constexpr explicit quantity(const Rep2& r) : value_{static_cast<rep>(r)}
|
||||
requires ConvertibleTo<Rep2, rep> &&
|
||||
(treat_as_floating_point_v<rep> || !treat_as_floating_point_v<Rep2>)constexpr explicit quantity(const Rep2& r)
|
||||
: value_{static_cast<rep>(r)}
|
||||
{
|
||||
}
|
||||
|
||||
template<class Rep2, mp::Ratio Ratio2>
|
||||
requires mp::ConvertibleTo<Rep2, rep> && (treat_as_floating_point_v<rep> ||
|
||||
(std::ratio_divide<Ratio2, ratio>::den == 1 && !treat_as_floating_point_v<Rep2>))
|
||||
constexpr quantity(const quantity<Dimension, Rep2, Ratio2>& q) : value_{quantity_cast<quantity>(q).count()}
|
||||
template<Quantity Q2>
|
||||
requires Same<dimension, typename Q2::dimension>&& ConvertibleTo<typename Q2::rep, rep> &&
|
||||
(treat_as_floating_point_v<rep> ||
|
||||
(std::ratio_divide<typename Q2::unit::ratio, typename unit::ratio>::den == 1 &&
|
||||
!treat_as_floating_point_v<typename Q2::rep>)) constexpr quantity(const Q2& q)
|
||||
: value_{quantity_cast<quantity>(q).count()}
|
||||
{
|
||||
}
|
||||
|
||||
@ -210,149 +212,146 @@ namespace units {
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
template<Dimension D, typename Rep1, mp::Ratio R1, typename Rep2, mp::Ratio R2>
|
||||
std::common_type_t<quantity<D, Rep1, R1>, quantity<D, Rep2, R2>>
|
||||
constexpr operator+(const quantity<D, Rep1, R1>& lhs,
|
||||
const quantity<D, Rep2, R2>& rhs)
|
||||
template<Dimension D, Unit U1, typename Rep1, Unit U2, typename Rep2>
|
||||
std::common_type_t<quantity<D, U1, Rep1>, quantity<D, U2, Rep2>>
|
||||
constexpr operator+(const quantity<D, U1, Rep1>& lhs,
|
||||
const quantity<D, U2, Rep2>& rhs)
|
||||
{
|
||||
using ret = std::common_type_t<quantity<D, Rep1, R1>, quantity<D, Rep2, R2>>;
|
||||
using ret = std::common_type_t<quantity<D, U1, Rep1>, quantity<D, U2, Rep2>>;
|
||||
return ret(ret(lhs).count() + ret(rhs).count());
|
||||
}
|
||||
|
||||
template<Dimension D, typename Rep1, mp::Ratio R1, typename Rep2, mp::Ratio R2>
|
||||
std::common_type_t<quantity<D, Rep1, R1>, quantity<D, Rep2, R2>>
|
||||
constexpr operator-(const quantity<D, Rep1, R1>& lhs,
|
||||
const quantity<D, Rep2, R2>& rhs)
|
||||
template<Dimension D, Unit U1, typename Rep1, Unit U2, typename Rep2>
|
||||
std::common_type_t<quantity<D, U1, Rep1>, quantity<D, U2, Rep2>>
|
||||
constexpr operator-(const quantity<D, U1, Rep1>& lhs,
|
||||
const quantity<D, U2, Rep2>& rhs)
|
||||
{
|
||||
using ret = std::common_type_t<quantity<D, Rep1, R1>, quantity<D, Rep2, R2>>;
|
||||
using ret = std::common_type_t<quantity<D, U1, Rep1>, quantity<D, U2, Rep2>>;
|
||||
return ret(ret(lhs).count() - ret(rhs).count());
|
||||
}
|
||||
|
||||
template<Dimension D, typename Rep1, mp::Ratio R, typename Rep2>
|
||||
quantity<D, std::common_type_t<Rep1, Rep2>, R>
|
||||
constexpr operator*(const quantity<D, Rep1, R>& q,
|
||||
template<Dimension D, Unit U, typename Rep1, typename Rep2>
|
||||
quantity<D, U, std::common_type_t<Rep1, Rep2>>
|
||||
constexpr operator*(const quantity<D, U, Rep1>& q,
|
||||
const Rep2& v)
|
||||
{
|
||||
using ret = quantity<D, std::common_type_t<Rep1, Rep2>, R>;
|
||||
using ret = quantity<D, U, std::common_type_t<Rep1, Rep2>>;
|
||||
return ret(ret(q).count() * v);
|
||||
}
|
||||
|
||||
template<typename Rep1, Dimension D, typename Rep2, mp::Ratio R>
|
||||
quantity<D, std::common_type_t<Rep1, Rep2>, R>
|
||||
template<typename Rep1, Dimension D, Unit U, typename Rep2>
|
||||
quantity<D, U, std::common_type_t<Rep1, Rep2>>
|
||||
constexpr operator*(const Rep1& v,
|
||||
const quantity<D, Rep2, R>& q)
|
||||
const quantity<D, U, Rep2>& q)
|
||||
{
|
||||
return q * v;
|
||||
}
|
||||
|
||||
template<Dimension D1, typename Rep1, mp::Ratio R1, Dimension D2, typename Rep2, mp::Ratio R2>
|
||||
requires treat_as_floating_point_v<std::common_type_t<Rep1, Rep2>> || std::ratio_multiply<R1, R2>::den == 1
|
||||
quantity<dimension_multiply_t<D1, D2>, std::common_type_t<Rep1, Rep2>, std::ratio_multiply<R1, R2>>
|
||||
constexpr operator*(const quantity<D1, Rep1, R1>& lhs,
|
||||
const quantity<D2, Rep2, R2>& rhs)
|
||||
template<Dimension D1, Unit U1, typename Rep1, Dimension D2, Unit U2, typename Rep2>
|
||||
requires treat_as_floating_point_v<std::common_type_t<Rep1, Rep2>> || std::ratio_multiply<typename U1::ratio, typename U2::ratio>::den == 1
|
||||
quantity<dimension_multiply_t<D1, D2>, unit<dimension_multiply_t<D1, D2>, std::ratio_multiply<typename U1::ratio, typename U2::ratio>>, std::common_type_t<Rep1, Rep2>>
|
||||
constexpr operator*(const quantity<D1, U1, Rep1>& lhs,
|
||||
const quantity<D2, U2, Rep2>& rhs)
|
||||
{
|
||||
using ret = quantity<dimension_multiply_t<D1, D2>, std::common_type_t<Rep1, Rep2>, std::ratio_multiply<R1, R2>>;
|
||||
using dim = dimension_multiply_t<D1, D2>;
|
||||
using ret = quantity<dim, unit<dim, std::ratio_multiply<typename U1::ratio, typename U2::ratio>>, std::common_type_t<Rep1, Rep2>>;
|
||||
return ret(lhs.count() * rhs.count());
|
||||
}
|
||||
|
||||
template<typename Rep1, Exponent E, mp::Ratio R, typename Rep2>
|
||||
quantity<dimension<exp_invert_t<E>>, std::common_type_t<Rep1, Rep2>, R>
|
||||
template<typename Rep1, Exponent... E, Unit U, typename Rep2>
|
||||
quantity<dimension<exp_invert_t<E>...>, unit<dimension<exp_invert_t<E>...>, std::ratio<U::ratio::den, U::ratio::num>>, std::common_type_t<Rep1, Rep2>>
|
||||
constexpr operator/(const Rep1& v,
|
||||
const quantity<dimension<E>, Rep2, R>& q)
|
||||
const quantity<dimension<E...>, U, Rep2>& q)
|
||||
{
|
||||
using ret = quantity<dimension<exp_invert_t<E>>, std::common_type_t<Rep1, Rep2>, R>;
|
||||
using den = quantity<dimension<E>, std::common_type_t<Rep1, Rep2>, R>;
|
||||
using dim = dimension<exp_invert_t<E>...>;
|
||||
using ret = quantity<dim, unit<dim, std::ratio<U::ratio::den, U::ratio::num>>, std::common_type_t<Rep1, Rep2>>;
|
||||
using den = quantity<dimension<E...>, U, std::common_type_t<Rep1, Rep2>>;
|
||||
return ret(v / den(q).count());
|
||||
}
|
||||
|
||||
template<Dimension D, typename Rep1, mp::Ratio R, typename Rep2>
|
||||
quantity<D, std::common_type_t<Rep1, Rep2>, R>
|
||||
constexpr operator/(const quantity<D, Rep1, R>& q,
|
||||
template<Dimension D, Unit U, typename Rep1, typename Rep2>
|
||||
quantity<D, U, std::common_type_t<Rep1, Rep2>>
|
||||
constexpr operator/(const quantity<D, U, Rep1>& q,
|
||||
const Rep2& v)
|
||||
{
|
||||
using ret = quantity<D, std::common_type_t<Rep1, Rep2>, R>;
|
||||
using ret = quantity<D, U, std::common_type_t<Rep1, Rep2>>;
|
||||
return ret(ret(q).count() / v);
|
||||
}
|
||||
|
||||
template<Dimension D, typename Rep1, mp::Ratio R1, typename Rep2, mp::Ratio R2>
|
||||
template<Dimension D, Unit U1, typename Rep1, Unit U2, typename Rep2>
|
||||
std::common_type_t<Rep1, Rep2>
|
||||
constexpr operator/(const quantity<D, Rep1, R1>& lhs,
|
||||
const quantity<D, Rep2, R2>& rhs)
|
||||
constexpr operator/(const quantity<D, U1, Rep1>& lhs,
|
||||
const quantity<D, U2, Rep2>& rhs)
|
||||
{
|
||||
using cq = std::common_type_t<quantity<D, Rep1, R1>, quantity<D, Rep2, R2>>;
|
||||
using cq = std::common_type_t<quantity<D, U1, Rep1>, quantity<D, U2, Rep2>>;
|
||||
return cq(lhs).count() / cq(rhs).count();
|
||||
}
|
||||
|
||||
template<Dimension D1, typename Rep1, mp::Ratio R1, Dimension D2, typename Rep2, mp::Ratio R2>
|
||||
requires treat_as_floating_point_v<std::common_type_t<Rep1, Rep2>> || std::ratio_divide<R1, R2>::den == 1
|
||||
quantity<dimension_divide_t<D1, D2>, std::common_type_t<Rep1, Rep2>, std::ratio_divide<R1, R2>>
|
||||
constexpr operator/(const quantity<D1, Rep1, R1>& lhs,
|
||||
const quantity<D2, Rep2, R2>& rhs)
|
||||
template<Dimension D1, Unit U1, typename Rep1, Dimension D2, Unit U2, typename Rep2>
|
||||
requires treat_as_floating_point_v<std::common_type_t<Rep1, Rep2>> || std::ratio_divide<typename U1::ratio, typename U2::ratio>::den == 1
|
||||
quantity<dimension_divide_t<D1, D2>, unit<dimension_divide_t<D1, D2>, std::ratio_divide<typename U1::ratio, typename U2::ratio>>, std::common_type_t<Rep1, Rep2>>
|
||||
constexpr operator/(const quantity<D1, U1, Rep1>& lhs,
|
||||
const quantity<D2, U2, Rep2>& rhs)
|
||||
{
|
||||
using ret = quantity<dimension_divide_t<D1, D2>, std::common_type_t<Rep1, Rep2>, std::ratio_divide<R1, R2>>;
|
||||
using dim = dimension_divide_t<D1, D2>;
|
||||
using ret = quantity<dim, unit<dim, std::ratio_divide<typename U1::ratio, typename U2::ratio>>, std::common_type_t<Rep1, Rep2>>;
|
||||
return ret(lhs.count() / rhs.count());
|
||||
}
|
||||
|
||||
template<Dimension D, typename Rep1, mp::Ratio R, typename Rep2>
|
||||
quantity<D, std::common_type_t<Rep1, Rep2>, R>
|
||||
constexpr operator%(const quantity<D, Rep1, R>& q,
|
||||
template<Dimension D, Unit U, typename Rep1, typename Rep2>
|
||||
quantity<D, U, std::common_type_t<Rep1, Rep2>>
|
||||
constexpr operator%(const quantity<D, U, Rep1>& q,
|
||||
const Rep2& v)
|
||||
{
|
||||
using ret = quantity<D, std::common_type_t<Rep1, Rep2>, R>;
|
||||
using ret = quantity<D, U, std::common_type_t<Rep1, Rep2>>;
|
||||
return ret(ret(q).count() % v);
|
||||
}
|
||||
|
||||
template<Dimension D, typename Rep1, mp::Ratio R1, typename Rep2, mp::Ratio R2>
|
||||
std::common_type_t<quantity<D, Rep1, R1>, quantity<D, Rep2, R2>>
|
||||
constexpr operator%(const quantity<D, Rep1, R1>& lhs,
|
||||
const quantity<D, Rep2, R2>& rhs)
|
||||
template<Dimension D, Unit U1, typename Rep1, Unit U2, typename Rep2>
|
||||
std::common_type_t<quantity<D, U1, Rep1>, quantity<D, U2, Rep2>>
|
||||
constexpr operator%(const quantity<D, U1, Rep1>& lhs,
|
||||
const quantity<D, U2, Rep2>& rhs)
|
||||
{
|
||||
using ret = std::common_type_t<quantity<D, Rep1, R1>, quantity<D, Rep2, R2>>;
|
||||
using ret = std::common_type_t<quantity<D, U1, Rep1>, quantity<D, U2, Rep2>>;
|
||||
return ret(ret(lhs).count() % ret(rhs).count());
|
||||
}
|
||||
|
||||
// clang-format on
|
||||
|
||||
template<Dimension D, typename Rep1, mp::Ratio R1, typename Rep2, mp::Ratio R2>
|
||||
constexpr bool operator==(const quantity<D, Rep1, R1>& lhs,
|
||||
const quantity<D, Rep2, R2>& rhs)
|
||||
template<Dimension D, Unit U1, typename Rep1, Unit U2, typename Rep2>
|
||||
constexpr bool operator==(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs)
|
||||
{
|
||||
using ct = std::common_type_t<quantity<D, Rep1, R1>, quantity<D, Rep2, R2>>;
|
||||
using ct = std::common_type_t<quantity<D, U1, Rep1>, quantity<D, U2, Rep2>>;
|
||||
return ct(lhs).count() == ct(rhs).count();
|
||||
}
|
||||
|
||||
template<Dimension D, typename Rep1, mp::Ratio R1, typename Rep2, mp::Ratio R2>
|
||||
constexpr bool operator!=(const quantity<D, Rep1, R1>& lhs,
|
||||
const quantity<D, Rep2, R2>& rhs)
|
||||
template<Dimension D, Unit U1, typename Rep1, Unit U2, typename Rep2>
|
||||
constexpr bool operator!=(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
template<Dimension D, typename Rep1, mp::Ratio R1, typename Rep2, mp::Ratio R2>
|
||||
constexpr bool operator<(const quantity<D, Rep1, R1>& lhs,
|
||||
const quantity<D, Rep2, R2>& rhs)
|
||||
template<Dimension D, Unit U1, typename Rep1, Unit U2, typename Rep2>
|
||||
constexpr bool operator<(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs)
|
||||
{
|
||||
using ct = std::common_type_t<quantity<D, Rep1, R1>, quantity<D, Rep2, R2>>;
|
||||
using ct = std::common_type_t<quantity<D, U1, Rep1>, quantity<D, U2, Rep2>>;
|
||||
return ct(lhs).count() < ct(rhs).count();
|
||||
}
|
||||
|
||||
template<Dimension D, typename Rep1, mp::Ratio R1, typename Rep2, mp::Ratio R2>
|
||||
constexpr bool operator<=(const quantity<D, Rep1, R1>& lhs,
|
||||
const quantity<D, Rep2, R2>& rhs)
|
||||
template<Dimension D, Unit U1, typename Rep1, Unit U2, typename Rep2>
|
||||
constexpr bool operator<=(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs)
|
||||
{
|
||||
return !(rhs < lhs);
|
||||
}
|
||||
|
||||
template<Dimension D, typename Rep1, mp::Ratio R1, typename Rep2, mp::Ratio R2>
|
||||
constexpr bool operator>(const quantity<D, Rep1, R1>& lhs,
|
||||
const quantity<D, Rep2, R2>& rhs)
|
||||
template<Dimension D, Unit U1, typename Rep1, Unit U2, typename Rep2>
|
||||
constexpr bool operator>(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs)
|
||||
{
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
template<Dimension D, typename Rep1, mp::Ratio R1, typename Rep2, mp::Ratio R2>
|
||||
constexpr bool operator>=(const quantity<D, Rep1, R1>& lhs,
|
||||
const quantity<D, Rep2, R2>& rhs)
|
||||
template<Dimension D, Unit U1, typename Rep1, Unit U2, typename Rep2>
|
||||
constexpr bool operator>=(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs)
|
||||
{
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
@ -362,10 +361,10 @@ namespace units {
|
||||
namespace std {
|
||||
|
||||
// todo: simplified
|
||||
template<units::Dimension D, typename Rep1, mp::Ratio R1, typename Rep2, mp::Ratio R2>
|
||||
struct common_type<units::quantity<D, Rep1, R1>, units::quantity<D, Rep2, R2>> {
|
||||
using type =
|
||||
units::quantity<D, std::common_type_t<Rep1, Rep2>, mp::common_ratio_t<R1, R2>>;
|
||||
template<units::Dimension D, units::Unit U1, typename Rep1, units::Unit U2, typename Rep2>
|
||||
struct common_type<units::quantity<D, U1, Rep1>, units::quantity<D, U2, Rep2>> {
|
||||
using type = units::quantity<D, units::unit<D, units::common_ratio_t<typename U1::ratio, typename U2::ratio>>,
|
||||
std::common_type_t<Rep1, Rep2>>;
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
@ -26,6 +26,8 @@
|
||||
|
||||
namespace units {
|
||||
|
||||
// todo: to be replaced with fixed_string when supported by the compilers
|
||||
|
||||
struct base_dim_length : dim_id<0> {};
|
||||
struct base_dim_mass : dim_id<1> {};
|
||||
struct base_dim_time : dim_id<2> {};
|
||||
|
@ -29,54 +29,43 @@ namespace units {
|
||||
|
||||
using dimension_frequency = make_dimension_t<exp<base_dim_time, -1>>;
|
||||
|
||||
template<typename Rep, class Ratio = std::ratio<1>>
|
||||
using frequency = quantity<dimension_frequency, Rep, Ratio>;
|
||||
using millihertz = unit<dimension_frequency, std::milli>;
|
||||
using hertz = unit<dimension_frequency, std::ratio<1>>;
|
||||
using kilohertz = unit<dimension_frequency, std::kilo>;
|
||||
using megahertz = unit<dimension_frequency, std::mega>;
|
||||
using gigahertz = unit<dimension_frequency, std::giga>;
|
||||
using terahertz = unit<dimension_frequency, std::tera>;
|
||||
|
||||
template<typename Rep>
|
||||
using millihertzs = frequency<Rep, std::milli>;
|
||||
|
||||
template<typename Rep>
|
||||
using hertzs = frequency<Rep>;
|
||||
|
||||
template<typename Rep>
|
||||
using kilohertzs = frequency<Rep, std::kilo>;
|
||||
|
||||
template<typename Rep>
|
||||
using megahertzs = frequency<Rep, std::mega>;
|
||||
|
||||
template<typename Rep>
|
||||
using gigahertzs = frequency<Rep, std::giga>;
|
||||
|
||||
template<typename Rep>
|
||||
using terahertzs = frequency<Rep, std::tera>;
|
||||
template<Unit U = hertz, typename Rep = std::intmax_t>
|
||||
using frequency = quantity<dimension_frequency, U, Rep>;
|
||||
|
||||
// ...
|
||||
|
||||
namespace literals {
|
||||
|
||||
// mHz
|
||||
constexpr auto operator""_mHz(unsigned long long l) { return millihertzs<std::int64_t>(l); }
|
||||
constexpr auto operator""_mHz(long double l) { return millihertzs<long double>(l); }
|
||||
constexpr auto operator""_mHz(unsigned long long l) { return frequency<millihertz, std::int64_t>(l); }
|
||||
constexpr auto operator""_mHz(long double l) { return frequency<millihertz, long double>(l); }
|
||||
|
||||
// Hz
|
||||
constexpr auto operator""_Hz(unsigned long long l) { return hertzs<std::int64_t>(l); }
|
||||
constexpr auto operator""_Hz(long double l) { return hertzs<long double>(l); }
|
||||
constexpr auto operator""_Hz(unsigned long long l) { return frequency<hertz, std::int64_t>(l); }
|
||||
constexpr auto operator""_Hz(long double l) { return frequency<hertz, long double>(l); }
|
||||
|
||||
// kHz
|
||||
constexpr auto operator""_kHz(unsigned long long l) { return kilohertzs<std::int64_t>(l); }
|
||||
constexpr auto operator""_kHz(long double l) { return kilohertzs<long double>(l); }
|
||||
constexpr auto operator""_kHz(unsigned long long l) { return frequency<kilohertz, std::int64_t>(l); }
|
||||
constexpr auto operator""_kHz(long double l) { return frequency<kilohertz, long double>(l); }
|
||||
|
||||
// MHz
|
||||
constexpr auto operator""_MHz(unsigned long long l) { return megahertzs<std::int64_t>(l); }
|
||||
constexpr auto operator""_MHz(long double l) { return megahertzs<long double>(l); }
|
||||
constexpr auto operator""_MHz(unsigned long long l) { return frequency<megahertz, std::int64_t>(l); }
|
||||
constexpr auto operator""_MHz(long double l) { return frequency<megahertz, long double>(l); }
|
||||
|
||||
// GHz
|
||||
constexpr auto operator""_GHz(unsigned long long l) { return gigahertzs<std::int64_t>(l); }
|
||||
constexpr auto operator""_GHz(long double l) { return gigahertzs<long double>(l); }
|
||||
constexpr auto operator""_GHz(unsigned long long l) { return frequency<gigahertz, std::int64_t>(l); }
|
||||
constexpr auto operator""_GHz(long double l) { return frequency<gigahertz, long double>(l); }
|
||||
|
||||
// THz
|
||||
constexpr auto operator""_THz(unsigned long long l) { return terahertzs<std::int64_t>(l); }
|
||||
constexpr auto operator""_THz(long double l) { return terahertzs<long double>(l); }
|
||||
constexpr auto operator""_THz(unsigned long long l) { return frequency<terahertz, std::int64_t>(l); }
|
||||
constexpr auto operator""_THz(long double l) { return frequency<terahertz, long double>(l); }
|
||||
|
||||
} // namespace literals
|
||||
|
||||
|
@ -29,33 +29,26 @@ namespace units {
|
||||
|
||||
using dimension_length = make_dimension_t<exp<base_dim_length, 1>>;
|
||||
|
||||
template<typename Rep, class Ratio = std::ratio<1>>
|
||||
using length = quantity<dimension_length, Rep, Ratio>;
|
||||
using millimeter = unit<dimension_length, std::milli>;
|
||||
using meter = unit<dimension_length, std::ratio<1>>;
|
||||
using kilometer = unit<dimension_length, std::kilo>;
|
||||
|
||||
template<typename Rep>
|
||||
using millimeters = length<Rep, std::milli>;
|
||||
|
||||
template<typename Rep>
|
||||
using meters = length<Rep>;
|
||||
|
||||
template<typename Rep>
|
||||
using kilometers = length<Rep, std::kilo>;
|
||||
|
||||
// ...
|
||||
template<Unit U = meter, typename Rep = std::intmax_t>
|
||||
using length = quantity<dimension_length, U, Rep>;
|
||||
|
||||
namespace literals {
|
||||
|
||||
// mm
|
||||
constexpr auto operator""_mm(unsigned long long l) { return millimeters<std::int64_t>(l); }
|
||||
constexpr auto operator""_mm(long double l) { return millimeters<long double>(l); }
|
||||
constexpr auto operator""_mm(unsigned long long l) { return length<millimeter, std::int64_t>(l); }
|
||||
constexpr auto operator""_mm(long double l) { return length<millimeter, long double>(l); }
|
||||
|
||||
// m
|
||||
constexpr auto operator""_m(unsigned long long l) { return meters<std::int64_t>(l); }
|
||||
constexpr auto operator""_m(long double l) { return meters<long double>(l); }
|
||||
constexpr auto operator""_m(unsigned long long l) { return length<meter, std::int64_t>(l); }
|
||||
constexpr auto operator""_m(long double l) { return length<meter, long double>(l); }
|
||||
|
||||
// km
|
||||
constexpr auto operator""_km(unsigned long long l) { return kilometers<std::int64_t>(l); }
|
||||
constexpr auto operator""_km(long double l) { return kilometers<long double>(l); }
|
||||
constexpr auto operator""_km(unsigned long long l) { return length<kilometer, std::int64_t>(l); }
|
||||
constexpr auto operator""_km(long double l) { return length<kilometer, long double>(l); }
|
||||
|
||||
} // namespace literals
|
||||
|
||||
|
@ -29,54 +29,43 @@ namespace units {
|
||||
|
||||
using dimension_time = make_dimension_t<exp<base_dim_time, 1>>;
|
||||
|
||||
template<typename Rep, class Ratio = std::ratio<1>>
|
||||
using time = quantity<dimension_time, Rep, Ratio>;
|
||||
using nanosecond = unit<dimension_time, std::nano>;
|
||||
using microsecond = unit<dimension_time, std::micro>;
|
||||
using millisecond = unit<dimension_time, std::milli>;
|
||||
using second = unit<dimension_time, std::ratio<1>>;
|
||||
using minute = unit<dimension_time, std::ratio<60>>;
|
||||
using hour = unit<dimension_time, std::ratio<3600>>;
|
||||
|
||||
template<typename Rep>
|
||||
using nanoseconds = time<Rep, std::nano>;
|
||||
|
||||
template<typename Rep>
|
||||
using microseconds = time<Rep, std::micro>;
|
||||
|
||||
template<typename Rep>
|
||||
using milliseconds = time<Rep, std::milli>;
|
||||
|
||||
template<typename Rep>
|
||||
using seconds = time<Rep>;
|
||||
|
||||
template<typename Rep>
|
||||
using minutes = time<Rep, std::ratio<60>>;
|
||||
|
||||
template<typename Rep>
|
||||
using hours = time<Rep, std::ratio<3600>>;
|
||||
template<Unit U = second, typename Rep = std::intmax_t>
|
||||
using time = quantity<dimension_time, U, Rep>;
|
||||
|
||||
// ...
|
||||
|
||||
namespace literals {
|
||||
|
||||
// ns
|
||||
constexpr auto operator""_ns(unsigned long long l) { return nanoseconds<std::int64_t>(l); }
|
||||
constexpr auto operator""_ns(long double l) { return nanoseconds<long double>(l); }
|
||||
constexpr auto operator""_ns(unsigned long long l) { return time<nanosecond, std::int64_t>(l); }
|
||||
constexpr auto operator""_ns(long double l) { return time<nanosecond, long double>(l); }
|
||||
|
||||
// us
|
||||
constexpr auto operator""_us(unsigned long long l) { return microseconds<std::int64_t>(l); }
|
||||
constexpr auto operator""_us(long double l) { return microseconds<long double>(l); }
|
||||
constexpr auto operator""_us(unsigned long long l) { return time<microsecond, std::int64_t>(l); }
|
||||
constexpr auto operator""_us(long double l) { return time<microsecond, long double>(l); }
|
||||
|
||||
// ms
|
||||
constexpr auto operator""_ms(unsigned long long l) { return milliseconds<std::int64_t>(l); }
|
||||
constexpr auto operator""_ms(long double l) { return milliseconds<long double>(l); }
|
||||
constexpr auto operator""_ms(unsigned long long l) { return time<millisecond, std::int64_t>(l); }
|
||||
constexpr auto operator""_ms(long double l) { return time<millisecond, long double>(l); }
|
||||
|
||||
// s
|
||||
constexpr auto operator""_s(unsigned long long l) { return seconds<std::int64_t>(l); }
|
||||
constexpr auto operator""_s(long double l) { return seconds<long double>(l); }
|
||||
constexpr auto operator""_s(unsigned long long l) { return time<second, std::int64_t>(l); }
|
||||
constexpr auto operator""_s(long double l) { return time<second, long double>(l); }
|
||||
|
||||
// min
|
||||
constexpr auto operator""_min(unsigned long long l) { return minutes<std::int64_t>(l); }
|
||||
constexpr auto operator""_min(long double l) { return minutes<long double>(l); }
|
||||
constexpr auto operator""_min(unsigned long long l) { return time<minute, std::int64_t>(l); }
|
||||
constexpr auto operator""_min(long double l) { return time<minute, long double>(l); }
|
||||
|
||||
// h
|
||||
constexpr auto operator""_h(unsigned long long l) { return hours<std::int64_t>(l); }
|
||||
constexpr auto operator""_h(long double l) { return hours<long double>(l); }
|
||||
constexpr auto operator""_h(unsigned long long l) { return time<hour, std::int64_t>(l); }
|
||||
constexpr auto operator""_h(long double l) { return time<hour, long double>(l); }
|
||||
|
||||
} // namespace literals
|
||||
|
||||
|
@ -30,33 +30,28 @@ namespace units {
|
||||
|
||||
using dimension_velocity = make_dimension_t<exp<base_dim_length, 1>, exp<base_dim_time, -1>>;
|
||||
|
||||
template<typename Rep, class Ratio = std::ratio<1>>
|
||||
using velocity = quantity<dimension_velocity, Rep, Ratio>;
|
||||
using meter_per_second = unit<dimension_velocity, std::ratio<1>>;
|
||||
using kilometer_per_hour = unit<dimension_velocity, std::ratio<1000, 3600>>;
|
||||
using mile_per_hour = unit<dimension_velocity, std::ratio<44'704, 100'000>>;
|
||||
|
||||
template<typename Rep>
|
||||
using meters_per_second = velocity<Rep>;
|
||||
|
||||
template<typename Rep>
|
||||
using kilometers_per_hour = velocity<Rep, std::ratio<1000, 3600>>;
|
||||
|
||||
template<typename Rep>
|
||||
using miles_per_hour = velocity<Rep, std::ratio<44'704, 100'000>>;
|
||||
template<Unit U = meter_per_second, typename Rep = std::intmax_t>
|
||||
using velocity = quantity<dimension_velocity, U, Rep>;
|
||||
|
||||
// ...
|
||||
|
||||
namespace literals {
|
||||
|
||||
// mps
|
||||
constexpr auto operator""_mps(unsigned long long l) { return meters_per_second<std::int64_t>(l); }
|
||||
constexpr auto operator""_mps(long double l) { return meters_per_second<long double>(l); }
|
||||
constexpr auto operator""_mps(unsigned long long l) { return velocity<meter_per_second, std::int64_t>(l); }
|
||||
constexpr auto operator""_mps(long double l) { return velocity<meter_per_second, long double>(l); }
|
||||
|
||||
// kmph
|
||||
constexpr auto operator""_kmph(unsigned long long l) { return kilometers_per_hour<std::int64_t>(l); }
|
||||
constexpr auto operator""_kmph(long double l) { return kilometers_per_hour<long double>(l); }
|
||||
constexpr auto operator""_kmph(unsigned long long l) { return velocity<kilometer_per_hour, std::int64_t>(l); }
|
||||
constexpr auto operator""_kmph(long double l) { return velocity<kilometer_per_hour, long double>(l); }
|
||||
|
||||
// mph
|
||||
constexpr auto operator""_mph(unsigned long long l) { return miles_per_hour<std::int64_t>(l); }
|
||||
constexpr auto operator""_mph(long double l) { return miles_per_hour<long double>(l); }
|
||||
constexpr auto operator""_mph(unsigned long long l) { return velocity<mile_per_hour, std::int64_t>(l); }
|
||||
constexpr auto operator""_mph(long double l) { return velocity<mile_per_hour, long double>(l); }
|
||||
|
||||
} // namespace literals
|
||||
|
||||
|
62
src/include/units/unit.h
Normal file
62
src/include/units/unit.h
Normal file
@ -0,0 +1,62 @@
|
||||
// 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 "bits/tools.h"
|
||||
#include "dimension.h"
|
||||
|
||||
namespace units {
|
||||
|
||||
template<Dimension D, Ratio R>
|
||||
struct unit {
|
||||
using dimension = D;
|
||||
using ratio = R;
|
||||
static_assert(ratio::num > 0, "ratio must be positive");
|
||||
};
|
||||
|
||||
// is_unit
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
struct is_unit : std::false_type {
|
||||
};
|
||||
|
||||
template<Dimension D, Ratio R>
|
||||
struct is_unit<unit<D, R>> : std::true_type {
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
concept bool Unit = detail::is_unit<T>::value;
|
||||
|
||||
// template<Unit U1, Unit U2>
|
||||
// auto operator/(U1, U2)
|
||||
// {
|
||||
// return ;
|
||||
// }
|
||||
//
|
||||
// unit<dimension_divide_t<D1, D2>, std::ratio_divide<typename U1::ratio, typename::U2::ratio>>
|
||||
|
||||
} // namespace units
|
@ -31,7 +31,6 @@ include(tools)
|
||||
|
||||
# add dependencies
|
||||
enable_testing()
|
||||
find_package(GTest MODULE REQUIRED)
|
||||
if(NOT TARGET mp::units)
|
||||
find_package(units CONFIG REQUIRED)
|
||||
endif()
|
||||
|
@ -74,102 +74,103 @@ namespace {
|
||||
|
||||
// class invariants
|
||||
|
||||
// constexpr quantity<meters<int>> error(0_m); // should trigger a static_assert
|
||||
// constexpr quantity<dimension_length, second> q; // should a static_assert
|
||||
// constexpr quantity<length<meter, int>> error(0_m); // should trigger a static_assert
|
||||
// constexpr quantity<int, float> error(0); // should trigger a static_assert
|
||||
// constexpr quantity<int, std::ratio<-1, 1>> error(0); // should trigger a static_assert
|
||||
|
||||
// member types
|
||||
|
||||
static_assert(std::is_same_v<meters<int>::rep, int>);
|
||||
static_assert(std::is_same_v<meters<float>::rep, float>);
|
||||
static_assert(std::is_same_v<meters<int>::ratio, std::ratio<1, 1>>);
|
||||
static_assert(std::is_same_v<kilometers<int>::ratio, std::ratio<1000, 1>>);
|
||||
static_assert(std::is_same_v<length<meter, int>::rep, int>);
|
||||
static_assert(std::is_same_v<length<meter, float>::rep, float>);
|
||||
static_assert(std::is_same_v<length<meter, int>::unit, meter>);
|
||||
static_assert(std::is_same_v<length<kilometer, int>::unit, kilometer>);
|
||||
|
||||
// constructors
|
||||
|
||||
static_assert(meters<int>().count() == 0);
|
||||
constexpr meters<int> kilometer{1000};
|
||||
static_assert(kilometer.count() == 1000);
|
||||
static_assert(meters<int>(kilometer).count() == kilometer.count());
|
||||
static_assert(length<meter, int>().count() == 0);
|
||||
constexpr length<meter, int> km{1000};
|
||||
static_assert(km.count() == 1000);
|
||||
static_assert(length<meter, int>(km).count() == km.count());
|
||||
|
||||
static_assert(meters<int>(1).count() == 1);
|
||||
static_assert(meters<int>(my_value<int>(1)).count() == 1);
|
||||
static_assert(meters<my_value<int>>(1).count() == 1);
|
||||
// static_assert(meters<int>(1.0).count() == 1); // should not compile
|
||||
// static_assert(meters<int>(my_value<float>(1.0)).count() == 1); // should not compile
|
||||
// static_assert(meters<my_value<int>>(1.0).count() == 1); // should not compile
|
||||
static_assert(meters<float>(1.0).count() == 1.0);
|
||||
static_assert(meters<float>(my_value<float>(1.0)).count() == 1.0);
|
||||
static_assert(meters<float>(1).count() == 1.0);
|
||||
static_assert(meters<float>(my_value<int>(1)).count() == 1.0);
|
||||
static_assert(meters<float>(3.14f).count() == 3.14f);
|
||||
static_assert(meters<my_value<float>>(1.0).count() == 1.0);
|
||||
static_assert(meters<my_value<float>>(1).count() == 1.0);
|
||||
static_assert(meters<my_value<float>>(3.14f).count() == 3.14f);
|
||||
static_assert(length<meter, int>(1).count() == 1);
|
||||
static_assert(length<meter, int>(my_value<int>(1)).count() == 1);
|
||||
static_assert(length<meter, my_value<int>>(1).count() == 1);
|
||||
// static_assert(length<meter, int>(1.0).count() == 1); // should not compile
|
||||
// static_assert(length<meter, int>(my_value<float>(1.0)).count() == 1); // should not compile
|
||||
// static_assert(length<meter, my_value<int>>(1.0).count() == 1); // should not compile
|
||||
static_assert(length<meter, float>(1.0).count() == 1.0);
|
||||
static_assert(length<meter, float>(my_value<float>(1.0)).count() == 1.0);
|
||||
static_assert(length<meter, float>(1).count() == 1.0);
|
||||
static_assert(length<meter, float>(my_value<int>(1)).count() == 1.0);
|
||||
static_assert(length<meter, float>(3.14f).count() == 3.14f);
|
||||
static_assert(length<meter, my_value<float>>(1.0).count() == 1.0);
|
||||
static_assert(length<meter, my_value<float>>(1).count() == 1.0);
|
||||
static_assert(length<meter, my_value<float>>(3.14f).count() == 3.14f);
|
||||
|
||||
static_assert(meters<int>(kilometer).count() == 1000);
|
||||
// static_assert(meters<int>(meters<float>(3.14)).count() == 3); // should not compile
|
||||
static_assert(meters<int>(quantity_cast<meters<int>>(3.14_m)).count() == 3);
|
||||
// static_assert(meters<int>(meters<my_value<float>>(1000.0)).count() == 1000); // should not compile
|
||||
// static_assert(meters<my_value<int>>(1000.0_m).count() == 1000); // should not compile
|
||||
static_assert(meters<float>(1000.0_m).count() == 1000.0);
|
||||
static_assert(meters<float>(meters<my_value<float>>(1000.0)).count() == 1000.0);
|
||||
static_assert(meters<my_value<float>>(1000.0_m).count() == 1000.0);
|
||||
static_assert(meters<float>(kilometer).count() == 1000.0);
|
||||
static_assert(meters<my_value<float>>(kilometer).count() == 1000.0);
|
||||
static_assert(meters<int>(1_km).count() == 1000);
|
||||
// static_assert(meters<int>(1_s).count() == 1); // should not compile
|
||||
// static_assert(kilometers<int>(1010_m).count() == 1); // should not compile
|
||||
static_assert(kilometers<int>(quantity_cast<kilometers<int>>(1010_m)).count() == 1);
|
||||
static_assert(length<meter, int>(km).count() == 1000);
|
||||
// static_assert(length<meter, int>(length<meter, float>(3.14)).count() == 3); // should not compile
|
||||
static_assert(length<meter, int>(quantity_cast<length<meter, int>>(3.14_m)).count() == 3);
|
||||
// static_assert(length<meter, int>(length<meter, my_value<float>>(1000.0)).count() == 1000); // should not compile
|
||||
// static_assert(length<meter, my_value<int>>(1000.0_m).count() == 1000); // should not compile
|
||||
static_assert(length<meter, float>(1000.0_m).count() == 1000.0);
|
||||
static_assert(length<meter, float>(length<meter, my_value<float>>(1000.0)).count() == 1000.0);
|
||||
static_assert(length<meter, my_value<float>>(1000.0_m).count() == 1000.0);
|
||||
static_assert(length<meter, float>(km).count() == 1000.0);
|
||||
static_assert(length<meter, my_value<float>>(km).count() == 1000.0);
|
||||
static_assert(length<meter, int>(1_km).count() == 1000);
|
||||
// static_assert(length<meter, int>(1_s).count() == 1); // should not compile
|
||||
// static_assert(length<kilometer, int>(1010_m).count() == 1); // should not compile
|
||||
static_assert(length<kilometer, int>(quantity_cast<length<kilometer, int>>(1010_m)).count() == 1);
|
||||
|
||||
// assignment operator
|
||||
|
||||
static_assert([]() {
|
||||
meters<int> l1(1), l2(2);
|
||||
length<meter, int> l1(1), l2(2);
|
||||
return l2 = l1;
|
||||
}()
|
||||
.count() == 1);
|
||||
|
||||
// static member functions
|
||||
|
||||
static_assert(meters<int>::zero().count() == 0);
|
||||
static_assert(meters<int>::min().count() == std::numeric_limits<int>::lowest());
|
||||
static_assert(meters<int>::max().count() == std::numeric_limits<int>::max());
|
||||
static_assert(meters<float>::zero().count() == 0.0);
|
||||
static_assert(meters<float>::min().count() == std::numeric_limits<float>::lowest());
|
||||
static_assert(meters<float>::max().count() == std::numeric_limits<float>::max());
|
||||
static_assert(meters<my_value<int>>::zero().count() == 0);
|
||||
static_assert(meters<my_value<int>>::min().count() == std::numeric_limits<int>::lowest());
|
||||
static_assert(meters<my_value<int>>::max().count() == std::numeric_limits<int>::max());
|
||||
static_assert(meters<my_value<float>>::zero().count() == 0.0);
|
||||
static_assert(meters<my_value<float>>::min().count() == std::numeric_limits<float>::lowest());
|
||||
static_assert(meters<my_value<float>>::max().count() == std::numeric_limits<float>::max());
|
||||
static_assert(length<meter, int>::zero().count() == 0);
|
||||
static_assert(length<meter, int>::min().count() == std::numeric_limits<int>::lowest());
|
||||
static_assert(length<meter, int>::max().count() == std::numeric_limits<int>::max());
|
||||
static_assert(length<meter, float>::zero().count() == 0.0);
|
||||
static_assert(length<meter, float>::min().count() == std::numeric_limits<float>::lowest());
|
||||
static_assert(length<meter, float>::max().count() == std::numeric_limits<float>::max());
|
||||
static_assert(length<meter, my_value<int>>::zero().count() == 0);
|
||||
static_assert(length<meter, my_value<int>>::min().count() == std::numeric_limits<int>::lowest());
|
||||
static_assert(length<meter, my_value<int>>::max().count() == std::numeric_limits<int>::max());
|
||||
static_assert(length<meter, my_value<float>>::zero().count() == 0.0);
|
||||
static_assert(length<meter, my_value<float>>::min().count() == std::numeric_limits<float>::lowest());
|
||||
static_assert(length<meter, my_value<float>>::max().count() == std::numeric_limits<float>::max());
|
||||
|
||||
// unary member operators
|
||||
|
||||
static_assert((+kilometer).count() == 1000);
|
||||
static_assert((-kilometer).count() == -1000);
|
||||
static_assert((+(-kilometer)).count() == -1000);
|
||||
static_assert((-(-kilometer)).count() == 1000);
|
||||
static_assert((+km).count() == 1000);
|
||||
static_assert((-km).count() == -1000);
|
||||
static_assert((+(-km)).count() == -1000);
|
||||
static_assert((-(-km)).count() == 1000);
|
||||
|
||||
// binary member operators
|
||||
|
||||
static_assert([](auto v) {
|
||||
auto vv = v++;
|
||||
return std::make_pair(v, vv);
|
||||
}(kilometer) == std::make_pair(meters<int>(1001), meters<int>(1000)));
|
||||
}(km) == std::make_pair(length<meter, int>(1001), length<meter, int>(1000)));
|
||||
static_assert([](auto v) {
|
||||
auto vv = ++v;
|
||||
return std::make_pair(v, vv);
|
||||
}(kilometer) == std::make_pair(meters<int>(1001), meters<int>(1001)));
|
||||
}(km) == std::make_pair(length<meter, int>(1001), length<meter, int>(1001)));
|
||||
static_assert([](auto v) {
|
||||
auto vv = v--;
|
||||
return std::make_pair(v, vv);
|
||||
}(kilometer) == std::make_pair(meters<int>(999), meters<int>(1000)));
|
||||
}(km) == std::make_pair(length<meter, int>(999), length<meter, int>(1000)));
|
||||
static_assert([](auto v) {
|
||||
auto vv = --v;
|
||||
return std::make_pair(v, vv);
|
||||
}(kilometer) == std::make_pair(meters<int>(999), meters<int>(999)));
|
||||
}(km) == std::make_pair(length<meter, int>(999), length<meter, int>(999)));
|
||||
|
||||
// compound assignment
|
||||
|
||||
@ -182,18 +183,18 @@ namespace {
|
||||
|
||||
// non-member arithmetic operators
|
||||
|
||||
static_assert(std::is_same_v<decltype(meters<int>() + meters<float>()), meters<float>>);
|
||||
static_assert(std::is_same_v<decltype(meters<float>() - meters<int>()), meters<float>>);
|
||||
static_assert(std::is_same_v<decltype(meters<int>() * 1.0f), meters<float>>);
|
||||
static_assert(std::is_same_v<decltype(1.0f * meters<int>()), meters<float>>);
|
||||
static_assert(std::is_same_v<decltype(meters<int>() / 1.0f), meters<float>>);
|
||||
static_assert(std::is_same_v<decltype(meters<int>() / meters<float>()), float>);
|
||||
static_assert(std::is_same_v<decltype(meters<int>() % short(1)), meters<int>>);
|
||||
static_assert(std::is_same_v<decltype(meters<int>() % meters<short>(1)), meters<int>>);
|
||||
static_assert(std::is_same_v<decltype(length<meter, int>() + length<meter, float>()), length<meter, float>>);
|
||||
static_assert(std::is_same_v<decltype(length<meter, float>() - length<meter, int>()), length<meter, float>>);
|
||||
static_assert(std::is_same_v<decltype(length<meter, int>() * 1.0f), length<meter, float>>);
|
||||
static_assert(std::is_same_v<decltype(1.0f * length<meter, int>()), length<meter, float>>);
|
||||
static_assert(std::is_same_v<decltype(length<meter, int>() / 1.0f), length<meter, float>>);
|
||||
static_assert(std::is_same_v<decltype(length<meter, int>() / length<meter, float>()), float>);
|
||||
static_assert(std::is_same_v<decltype(length<meter, int>() % short(1)), length<meter, int>>);
|
||||
static_assert(std::is_same_v<decltype(length<meter, int>() % length<meter, short>(1)), length<meter, int>>);
|
||||
|
||||
static_assert((1_m + kilometer).count() == 1001);
|
||||
static_assert((1_m + km).count() == 1001);
|
||||
static_assert((1_m + 1_km).count() == 1001);
|
||||
static_assert((kilometer - 1_m).count() == 999);
|
||||
static_assert((km - 1_m).count() == 999);
|
||||
static_assert((1_km - 1_m).count() == 999);
|
||||
static_assert((2_m * 2).count() == 4);
|
||||
static_assert((3 * 3_m).count() == 9);
|
||||
@ -237,19 +238,19 @@ namespace {
|
||||
|
||||
// is_quantity
|
||||
|
||||
static_assert(units::detail::is_quantity<millimeters<int>>::value);
|
||||
static_assert(units::detail::is_quantity<length<millimeter, int>>::value);
|
||||
|
||||
// common_type
|
||||
|
||||
static_assert(std::is_same_v<std::common_type_t<meters<int>, kilometers<int>>, meters<int>>);
|
||||
static_assert(std::is_same_v<std::common_type_t<kilometers<long long>, meters<int>>, meters<long long>>);
|
||||
static_assert(std::is_same_v<std::common_type_t<kilometers<long long>, millimeters<float>>, millimeters<float>>);
|
||||
static_assert(std::is_same_v<std::common_type_t<length<meter, int>, length<kilometer, int>>, length<meter, int>>);
|
||||
static_assert(std::is_same_v<std::common_type_t<length<kilometer, long long>, length<meter, int>>, length<meter, long long>>);
|
||||
static_assert(std::is_same_v<std::common_type_t<length<kilometer, long long>, length<millimeter, float>>, length<millimeter, float>>);
|
||||
|
||||
// quantity_cast
|
||||
|
||||
// static_assert(quantity_cast<int>(2_km).count() == 2000); // should not compile
|
||||
static_assert(quantity_cast<meters<int>>(2_km).count() == 2000);
|
||||
static_assert(quantity_cast<kilometers<int>>(2000_m).count() == 2);
|
||||
static_assert(quantity_cast<length<meter, int>>(2_km).count() == 2000);
|
||||
static_assert(quantity_cast<length<kilometer, int>>(2000_m).count() == 2);
|
||||
|
||||
// time
|
||||
|
||||
|
@ -20,28 +20,29 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#include "units/si/velocity.h"
|
||||
#include <utility>
|
||||
#include "units/bits/tools.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace units;
|
||||
|
||||
// static_sign
|
||||
|
||||
static_assert(mp::static_sign<2>::value == 1);
|
||||
static_assert(mp::static_sign<-3>::value == -1);
|
||||
static_assert(mp::static_sign<0>::value == 1);
|
||||
static_assert(static_sign<2>::value == 1);
|
||||
static_assert(static_sign<-3>::value == -1);
|
||||
static_assert(static_sign<0>::value == 1);
|
||||
|
||||
// static_abs
|
||||
|
||||
static_assert(mp::static_abs<2>::value == 2);
|
||||
static_assert(mp::static_abs<-3>::value == 3);
|
||||
static_assert(mp::static_abs<0>::value == 0);
|
||||
static_assert(static_abs<2>::value == 2);
|
||||
static_assert(static_abs<-3>::value == 3);
|
||||
static_assert(static_abs<0>::value == 0);
|
||||
|
||||
// common_ratio
|
||||
|
||||
static_assert(std::is_same_v<mp::common_ratio_t<std::ratio<1>, std::kilo>, std::ratio<1>>);
|
||||
static_assert(std::is_same_v<mp::common_ratio_t<std::kilo, std::ratio<1>>, std::ratio<1>>);
|
||||
static_assert(std::is_same_v<mp::common_ratio_t<std::ratio<1>, std::milli>, std::milli>);
|
||||
static_assert(std::is_same_v<mp::common_ratio_t<std::milli, std::ratio<1>>, std::milli>);
|
||||
static_assert(std::is_same_v<common_ratio_t<std::ratio<1>, std::kilo>, std::ratio<1>>);
|
||||
static_assert(std::is_same_v<common_ratio_t<std::kilo, std::ratio<1>>, std::ratio<1>>);
|
||||
static_assert(std::is_same_v<common_ratio_t<std::ratio<1>, std::milli>, std::milli>);
|
||||
static_assert(std::is_same_v<common_ratio_t<std::milli, std::ratio<1>>, std::milli>);
|
||||
|
||||
} // namespace
|
@ -34,6 +34,7 @@ namespace {
|
||||
|
||||
static_assert(2 / 1_s == 2_Hz);
|
||||
static_assert(1000 / 1_s == 1_kHz);
|
||||
static_assert(1 / 1_ms == 1_kHz);
|
||||
static_assert(3.2_GHz == 3'200'000'000_Hz);
|
||||
|
||||
// time
|
||||
@ -49,7 +50,7 @@ namespace {
|
||||
|
||||
// velocity
|
||||
|
||||
static_assert(std::is_same_v<decltype(1_km / 1_s), velocity<long long int, std::ratio<1000, 1>>>);
|
||||
static_assert(std::is_same_v<decltype(1_km / 1_s), velocity<unit<dimension_velocity, std::ratio<1000, 1>>, long long int>>);
|
||||
|
||||
static_assert(10_m / 5_s == 2_mps);
|
||||
static_assert(10 / 5_s * 1_m == 2_mps);
|
||||
@ -65,6 +66,6 @@ namespace {
|
||||
|
||||
static_assert(2_km / 2_kmph == 1_h);
|
||||
// static_assert(2000_m / 2_kmph == 1_h); // should not compile
|
||||
static_assert(quantity_cast<kilometers<int>>(2000_m) / 2_kmph == 1_h);
|
||||
static_assert(quantity_cast<length<kilometer, int>>(2000_m) / 2_kmph == 1_h);
|
||||
|
||||
} // namespace
|
||||
|
Reference in New Issue
Block a user