Library refactoring based on Walter Brown's feedback

This commit is contained in:
Mateusz Pusz
2018-09-29 18:08:02 -07:00
parent 2514b669c9
commit 4409fa01ca
17 changed files with 384 additions and 346 deletions

View File

@ -43,4 +43,4 @@ enable_testing()
add_subdirectory(test)
# add usage example
#add_subdirectory(example)
add_subdirectory(example)

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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> {};

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
View 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

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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