quantity refactored and quantity_test enabled

This commit is contained in:
Mateusz Pusz
2019-12-04 17:46:19 +01:00
parent 0986d1e812
commit c48bfe2098
23 changed files with 1499 additions and 1174 deletions

View File

@@ -24,7 +24,6 @@
#include <units/bits/fixed_string.h>
#include <units/bits/unit_concept.h>
#include <units/unit.h>
#include <type_traits>
namespace units {
@@ -46,7 +45,7 @@ namespace units {
*/
template<basic_fixed_string Name, Unit U>
struct base_dimension {
using base_type = base_dimension;
using base_type_workaround = base_dimension; // TODO Replace with is_derived_from_instantiation when fixed
static constexpr auto name = Name;
using coherent_unit = U;
};
@@ -63,7 +62,7 @@ inline constexpr bool is_base_dimension<base_dimension<Name, Params...>> = true;
} // namespace detail
template<typename T>
concept BaseDimension = detail::is_base_dimension<typename T::base_type>;
concept BaseDimension = detail::is_base_dimension<typename T::base_type_workaround>;
// base_dimension_less
// TODO Remove the below when https://bugs.llvm.org/show_bug.cgi?id=32208 is fixed

View File

@@ -1,115 +0,0 @@
// 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 <type_traits>
#include <cmath>
namespace units {
// treat_as_floating_point
template<typename Rep> // TODO Conceptify that
inline constexpr bool treat_as_floating_point = std::is_floating_point_v<Rep>;
// isnan
namespace isnan_impl {
// non-ADL lookup block
void isnan(); // undefined
template<typename>
inline constexpr bool has_customization = false;
template<typename T>
requires requires(const T& t) {
{ isnan(t) } -> bool;
}
inline constexpr bool has_customization<T> = true;
struct fn {
template<typename T>
constexpr bool operator()(const T&) const
{
return false;
}
template<typename T>
requires treat_as_floating_point<T>
constexpr bool operator()(const T& value) const
{
return std::isnan(value);
}
template<typename T>
requires treat_as_floating_point<T> && has_customization<T>
constexpr bool operator()(const T& value) const
{
return isnan(value); // uses ADL
}
};
}
inline constexpr isnan_impl::fn isnan{};
// isfinite
namespace isfinite_impl {
// non-ADL lookup block
void isfinite(); // undefined
template<typename>
inline constexpr bool has_customization = false;
template<typename T>
requires requires(const T& t) {
{ isfinite(t) } -> bool;
}
inline constexpr bool has_customization<T> = true;
struct fn {
template<typename T>
constexpr bool operator()(const T&) const
{
return true;
}
template<typename T>
requires treat_as_floating_point<T>
constexpr bool operator()(const T& value) const
{
return std::isfinite(value);
}
template<typename T>
requires treat_as_floating_point<T> && has_customization<T>
constexpr bool operator()(const T& value) const
{
return isfinite(value); // uses ADL
}
};
}
inline constexpr isfinite_impl::fn isfinite{};
}

View File

@@ -24,7 +24,7 @@
#include <units/bits/hacks.h>
#include <units/bits/numeric_concepts.h>
#include <units/bits/customization_points.h>
#include <units/customization_points.h>
#include <units/ratio.h>
namespace units {

View File

@@ -0,0 +1,115 @@
// 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 <type_traits>
#include <cmath>
namespace units {
// treat_as_floating_point
template<typename Rep> // TODO Conceptify that
inline constexpr bool treat_as_floating_point = std::is_floating_point_v<Rep>;
// // isnan
// namespace isnan_impl {
// // non-ADL lookup block
// void isnan(); // undefined
// template<typename>
// inline constexpr bool has_customization = false;
// template<typename T>
// requires requires(const T& t) {
// { isnan(t) } -> bool;
// }
// inline constexpr bool has_customization<T> = true;
// struct fn {
// template<typename T>
// constexpr bool operator()(const T&) const
// {
// return false;
// }
// template<typename T>
// requires treat_as_floating_point<T>
// constexpr bool operator()(const T& value) const
// {
// return std::isnan(value);
// }
// template<typename T>
// requires treat_as_floating_point<T> && has_customization<T>
// constexpr bool operator()(const T& value) const
// {
// return isnan(value); // uses ADL
// }
// };
// }
// inline constexpr isnan_impl::fn isnan{};
// // isfinite
// namespace isfinite_impl {
// // non-ADL lookup block
// void isfinite(); // undefined
// template<typename>
// inline constexpr bool has_customization = false;
// template<typename T>
// requires requires(const T& t) {
// { isfinite(t) } -> bool;
// }
// inline constexpr bool has_customization<T> = true;
// struct fn {
// template<typename T>
// constexpr bool operator()(const T&) const
// {
// return true;
// }
// template<typename T>
// requires treat_as_floating_point<T>
// constexpr bool operator()(const T& value) const
// {
// return std::isfinite(value);
// }
// template<typename T>
// requires treat_as_floating_point<T> && has_customization<T>
// constexpr bool operator()(const T& value) const
// {
// return isfinite(value); // uses ADL
// }
// };
// }
// inline constexpr isfinite_impl::fn isfinite{};
}

View File

@@ -277,10 +277,14 @@ struct dim_invert_impl<derived_dimension<Es...>> {
using type = downcast<derived_dimension<exp_invert<Es>...>>;
};
template<DerivedDimension D>
struct dim_invert_impl<D> : dim_invert_impl<downcast_base_t<D>> {
};
} // namespace detail
template<Dimension D>
using dim_invert = detail::dim_invert_impl<downcast_base_t<D>>::type;
using dim_invert = detail::dim_invert_impl<D>::type;
// dimension_multiply
namespace detail {
@@ -377,7 +381,7 @@ struct dimension_pow_impl;
template<BaseDimension D, std::size_t N>
struct dimension_pow_impl<D, N> {
using type = derived_dimension<exp<D, N>>;
using type = downcast<derived_dimension<exp<D, N>>>;
};
template<BaseDimension D, std::size_t N>
@@ -387,7 +391,7 @@ struct dimension_pow_impl<exp<D, 1, N>, N> {
template<DerivedDimension D, std::size_t N>
struct dimension_pow_impl<D, N> {
using type = dimension_pow_impl<typename D::base_type, N>;
using type = dimension_pow_impl<downcast_base<D>, N>;
};
template<typename... Es, std::size_t N>

View File

@@ -1,64 +0,0 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/dimensions/length.h>
namespace units {
struct area : derived_dimension<area, exp<length, 2>> {};
template<typename T>
concept Area = QuantityOf<T, area>;
struct square_metre : coherent_derived_unit<square_metre, area> {};
struct square_millimetre : deduced_derived_unit<square_millimetre, area, millimetre> {};
struct square_centimetre : deduced_derived_unit<square_centimetre, area, centimetre> {};
struct square_kilometre : deduced_derived_unit<square_kilometre, area, kilometre> {};
struct square_foot : deduced_derived_unit<square_foot, area, foot> {};
inline namespace literals {
// sq_m
constexpr auto operator""sq_m(unsigned long long l) { return quantity<square_metre, std::int64_t>(l); }
constexpr auto operator""sq_m(long double l) { return quantity<square_metre, long double>(l); }
// sq_mm
constexpr auto operator""sq_mm(unsigned long long l) { return quantity<square_millimetre, std::int64_t>(l); }
constexpr auto operator""sq_mm(long double l) { return quantity<square_millimetre, long double>(l); }
// sq_cm
constexpr auto operator""sq_cm(unsigned long long l) { return quantity<square_centimetre, std::int64_t>(l); }
constexpr auto operator""sq_cm(long double l) { return quantity<square_centimetre, long double>(l); }
// sq_km
constexpr auto operator""sq_km(unsigned long long l) { return quantity<square_kilometre, std::int64_t>(l); }
constexpr auto operator""sq_km(long double l) { return quantity<square_kilometre, long double>(l); }
// sq_ft
constexpr auto operator""sq_ft(unsigned long long l) { return quantity<square_foot, std::int64_t>(l); }
constexpr auto operator""sq_ft(long double l) { return quantity<square_foot, long double>(l); }
} // namespace literals
} // namespace units

View File

@@ -1,71 +0,0 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/dimensions/si_base_dimensions.h>
#include <units/dimensions/si_prefixes.h>
#include <units/dimensions/time.h>
namespace units {
struct frequency : derived_dimension<frequency, exp<time, -1>> {};
template<typename T>
concept Frequency = QuantityOf<T, frequency>;
struct hertz : named_coherent_derived_unit<hertz, frequency, "Hz", si_prefix> {};
struct millihertz : prefixed_derived_unit<millihertz, milli, hertz> {};
struct kilohertz : prefixed_derived_unit<kilohertz, kilo, hertz> {};
struct megahertz : prefixed_derived_unit<megahertz, mega, hertz> {};
struct gigahertz : prefixed_derived_unit<gigahertz, giga, hertz> {};
struct terahertz : prefixed_derived_unit<terahertz, tera, hertz> {};
inline namespace literals {
// Hz
constexpr auto operator""Hz(unsigned long long l) { return quantity<hertz, std::int64_t>(l); }
constexpr auto operator""Hz(long double l) { return quantity<hertz, long double>(l); }
// mHz
constexpr auto operator""mHz(unsigned long long l) { return quantity<millihertz, std::int64_t>(l); }
constexpr auto operator""mHz(long double l) { return quantity<millihertz, long double>(l); }
// kHz
constexpr auto operator""kHz(unsigned long long l) { return quantity<kilohertz, std::int64_t>(l); }
constexpr auto operator""kHz(long double l) { return quantity<kilohertz, long double>(l); }
// MHz
constexpr auto operator""MHz(unsigned long long l) { return quantity<megahertz, std::int64_t>(l); }
constexpr auto operator""MHz(long double l) { return quantity<megahertz, long double>(l); }
// GHz
constexpr auto operator""GHz(unsigned long long l) { return quantity<gigahertz, std::int64_t>(l); }
constexpr auto operator""GHz(long double l) { return quantity<gigahertz, long double>(l); }
// THz
constexpr auto operator""THz(unsigned long long l) { return quantity<terahertz, std::int64_t>(l); }
constexpr auto operator""THz(long double l) { return quantity<terahertz, long double>(l); }
} // namespace literals
} // namespace units

View File

@@ -1,88 +0,0 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/dimensions/si_base_dimensions.h>
#include <units/dimensions/si_prefixes.h>
#include <units/quantity.h>
namespace units {
struct length : derived_dimension<length, exp<base_dim_length, 1>> {};
template<typename T>
concept Length = QuantityOf<T, length>;
// SI units
struct metre : named_coherent_derived_unit<metre, length, "m", si_prefix> {};
struct millimetre : prefixed_derived_unit<millimetre, milli, metre> {};
struct centimetre : prefixed_derived_unit<centimetre, centi, metre> {};
struct kilometre : prefixed_derived_unit<kilometre, kilo, metre> {};
inline namespace literals {
// m
constexpr auto operator""m(unsigned long long l) { return quantity<metre, std::int64_t>(l); }
constexpr auto operator""m(long double l) { return quantity<metre, long double>(l); }
// mm
constexpr auto operator""mm(unsigned long long l) { return quantity<millimetre, std::int64_t>(l); }
constexpr auto operator""mm(long double l) { return quantity<millimetre, long double>(l); }
// cm
constexpr auto operator""cm(unsigned long long l) { return quantity<centimetre, std::int64_t>(l); }
constexpr auto operator""cm(long double l) { return quantity<centimetre, long double>(l); }
// km
constexpr auto operator""km(unsigned long long l) { return quantity<kilometre, std::int64_t>(l); }
constexpr auto operator""km(long double l) { return quantity<kilometre, long double>(l); }
} // namespace literals
// US customary units
struct yard : named_scaled_derived_unit<yard, length, "yd", ratio<9'144, 10'000>> {};
struct foot : named_scaled_derived_unit<foot, length, "ft", ratio_divide<yard::ratio, ratio<3>>> {};
struct inch : named_scaled_derived_unit<inch, length, "in", ratio_divide<foot::ratio, ratio<12>>> {};
struct mile : named_scaled_derived_unit<mile, length, "mi", ratio_multiply<ratio<1'760>, yard::ratio>> {};
inline namespace literals {
// yd
constexpr auto operator""yd(unsigned long long l) { return quantity<yard, std::int64_t>(l); }
constexpr auto operator""yd(long double l) { return quantity<yard, long double>(l); }
// ft
constexpr auto operator""ft(unsigned long long l) { return quantity<foot, std::int64_t>(l); }
constexpr auto operator""ft(long double l) { return quantity<foot, long double>(l); }
// in
constexpr auto operator""in(unsigned long long l) { return quantity<inch, std::int64_t>(l); }
constexpr auto operator""in(long double l) { return quantity<inch, long double>(l); }
// mi
constexpr auto operator""mi(unsigned long long l) { return quantity<mile, std::int64_t>(l); }
constexpr auto operator""mi(long double l) { return quantity<mile, long double>(l); }
} // namespace literals
} // namespace units

View File

@@ -0,0 +1,124 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/dimensions/si_base_dimensions.h>
#include <units/dimensions/si_prefixes.h>
namespace units {
// base dimension
template<basic_fixed_string Name>
struct base_dimension {
static constexpr auto name = Name;
};
template<typename T>
concept BaseDimension = true;
// base dimension
template<basic_fixed_string Symbol, BaseDimension Dim, PrefixType PT, Ratio R = ratio<1>>
struct base_unit {
static constexpr auto symbol = Symbol;
using dimension = Dim;
using prefix_type = PT;
using ratio = R;
};
template<typename T>
concept BaseUnit = true;
template<typename T, typename Dim>
concept BaseUnitOf = BaseUnit<T> && BaseDimension<Dim> && std::same_as<typename T::dimension, Dim>;
namespace physical {
// base dimensions
struct base_dim_length : base_dimension<"length"> {};
struct base_dim_mass : base_dimension<"mass"> {};
struct base_dim_time : base_dimension<"time"> {};
struct base_dim_current : base_dimension<"current"> {};
struct base_dim_temperature : base_dimension<"temperature"> {};
struct base_dim_substance : base_dimension<"substance"> {};
struct base_dim_luminous_intensity : base_dimension<"luminous intensity"> {};
// dimensions
template<UnitOf<base_dim_length> L>
struct length : derived_dimension<length, exp<L, 1>> {};
template<UnitOf<base_dim_mass> M>
struct mass : derived_dimension<mass, exp<M, 1>> {};
template<UnitOf<base_dim_time> T>
struct time : derived_dimension<time, exp<T, 1>> {};
template<UnitOf<base_dim_length> L, UnitOf<base_dim_time> T>
struct velocity : derived_dimension<velocity, exp<L, 1>, exp<T, -1>> {};
template<UnitOf<base_dim_length> L, UnitOf<base_dim_time> T>
struct acceleration : derived_dimension<acceleration, exp<L, 1>, exp<T, -2>> {};
template<UnitOf<base_dim_mass> M, UnitOf<acceleration> A>
struct force : derived_dimension<force, exp<M, 1>, exp<A, 1>> {};
} // physical
// SI
namespace si {
struct si_prefix;
// length
struct metre : base_unit<"m", base_dim_length, si_prefix> {};
struct length : physical::length<metre> {};
// mass
struct kilogram : base_unit<"kg", base_dim_mass, si_prefix> {};
struct mass : physical::mass<kilogram> {};
// time
struct second : base_unit<"s", base_dim_time, si_prefix> {};
struct time : physical::time<second> {};
struct nanosecond : prefixed_derived_unit<nanosecond, nano, second> {};
struct microsecond : prefixed_derived_unit<microsecond, micro, second> {};
struct millisecond : prefixed_derived_unit<millisecond, milli, second> {};
struct minute : named_derived_unit<minute, time, "min", ratio<60>> {};
struct hour : named_derived_unit<hour, time, "h", ratio<3600>> {};
// velocity
struct velocity : physical::velocity<metre, second>;
// acceleration
struct acceleration : physical::acceleration<metre, second>;
// acceleration
struct acceleration : physical::acceleration<metre, second>;
}
} // namespace units

View File

@@ -1,37 +0,0 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/dimension.h>
namespace units {
struct base_dim_length : base_dimension<"length", "m"> {};
struct base_dim_mass : base_dimension<"mass", "kg"> {};
struct base_dim_time : base_dimension<"time", "s"> {};
struct base_dim_current : base_dimension<"current", "A"> {};
struct base_dim_temperature : base_dimension<"temperature", "K"> {};
struct base_dim_substance : base_dimension<"substance", "mol"> {};
struct base_dim_luminous_intensity : base_dimension<"luminous intensity", "cd"> {};
} // namespace units

View File

@@ -1,71 +0,0 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/dimensions/si_base_dimensions.h>
#include <units/dimensions/si_prefixes.h>
#include <units/quantity.h>
namespace units {
struct time : derived_dimension<time, exp<base_dim_time, 1>> {};
template<typename T>
concept Time = QuantityOf<T, time>;
struct second : named_coherent_derived_unit<second, time, "s", si_prefix> {};
struct nanosecond : prefixed_derived_unit<nanosecond, nano, second> {};
struct microsecond : prefixed_derived_unit<microsecond, micro, second> {};
struct millisecond : prefixed_derived_unit<millisecond, milli, second> {};
struct minute : named_scaled_derived_unit<minute, time, "min", ratio<60>> {};
struct hour : named_scaled_derived_unit<hour, time, "h", ratio<3600>> {};
inline namespace literals {
// ns
constexpr auto operator""ns(unsigned long long l) { return quantity<nanosecond, std::int64_t>(l); }
constexpr auto operator""ns(long double l) { return quantity<nanosecond, long double>(l); }
// us
constexpr auto operator""us(unsigned long long l) { return quantity<microsecond, std::int64_t>(l); }
constexpr auto operator""us(long double l) { return quantity<microsecond, long double>(l); }
// ms
constexpr auto operator""ms(unsigned long long l) { return quantity<millisecond, std::int64_t>(l); }
constexpr auto operator""ms(long double l) { return quantity<millisecond, long double>(l); }
// s
constexpr auto operator""s(unsigned long long l) { return quantity<second, std::int64_t>(l); }
constexpr auto operator""s(long double l) { return quantity<second, long double>(l); }
// min
constexpr auto operator""min(unsigned long long l) { return quantity<minute, std::int64_t>(l); }
constexpr auto operator""min(long double l) { return quantity<minute, long double>(l); }
// h
constexpr auto operator""h(unsigned long long l) { return quantity<hour, std::int64_t>(l); }
constexpr auto operator""h(long double l) { return quantity<hour, long double>(l); }
} // namespace literals
} // namespace units

View File

@@ -1,55 +0,0 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/dimensions/length.h>
#include <units/dimensions/time.h>
namespace units {
struct velocity : derived_dimension<velocity, exp<length, 1>, exp<time, -1>> {};
template<typename T>
concept Velocity = QuantityOf<T, velocity>;
struct metre_per_second : coherent_derived_unit<metre_per_second, velocity> {};
struct kilometre_per_hour : deduced_derived_unit<kilometre_per_hour, velocity, kilometre, hour> {};
struct mile_per_hour : deduced_derived_unit<mile_per_hour, velocity, mile, hour> {};
inline namespace literals {
// mps
constexpr auto operator""mps(unsigned long long l) { return quantity<metre_per_second, std::int64_t>(l); }
constexpr auto operator""mps(long double l) { return quantity<metre_per_second, long double>(l); }
// kmph
constexpr auto operator""kmph(unsigned long long l) { return quantity<kilometre_per_hour, std::int64_t>(l); }
constexpr auto operator""kmph(long double l) { return quantity<kilometre_per_hour, long double>(l); }
// mph
constexpr auto operator""mph(unsigned long long l) { return quantity<mile_per_hour, std::int64_t>(l); }
constexpr auto operator""mph(long double l) { return quantity<mile_per_hour, long double>(l); }
} // namespace literals
} // namespace units

View File

@@ -27,27 +27,27 @@
namespace units {
template<std::size_t N, typename U, typename Rep>
template<std::size_t N, typename D, typename U, typename Rep>
requires N == 0
inline Rep AUTO pow(const quantity<U, Rep>&) noexcept
inline Rep AUTO pow(const quantity<D, U, Rep>&) noexcept
{
return 1;
}
template<std::size_t N, typename U, typename Rep>
inline Quantity AUTO pow(const quantity<U, Rep>& q) noexcept
template<std::size_t N, typename D, typename U, typename Rep>
inline Quantity AUTO pow(const quantity<D, U, Rep>& q) noexcept
{
using dim = dimension_pow<typename U::dimension, N>;
using dim = dimension_pow<D, N>;
using r = ratio_pow<typename U::ratio, N>;
return quantity<downcast<unit<dim, r>>, Rep>(static_cast<Rep>(std::pow(q.count(), N)));
return quantity<dim, downcast<detail::reference_unit<typename dim::coherent_unit::reference, r>>, Rep>(static_cast<Rep>(std::pow(q.count(), N)));
}
template<typename U, typename Rep>
inline Quantity AUTO sqrt(const quantity<U, Rep>& q) noexcept
template<typename D, typename U, typename Rep>
inline Quantity AUTO sqrt(const quantity<D, U, Rep>& q) noexcept
{
using dim = dimension_sqrt<typename U::dimension>;
using r = ratio_sqrt<typename U::ratio>;
return quantity<downcast<unit<dim, r>>, Rep>(static_cast<Rep>(std::sqrt(q.count())));
return quantity<dim, downcast<detail::reference_unit<typename dim::coherent_unit::reference, r>>, Rep>(static_cast<Rep>(std::sqrt(q.count())));
}
} // namespace units

View File

@@ -0,0 +1,151 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/base_dimension.h>
#include <units/bits/type_traits.h>
#include <units/quantity.h>
#include <units/unit.h>
namespace units {
inline namespace physical {
template<typename Dim, template<typename...> typename DimTemplate>
concept DimensionOf = (Dimension<Dim> || BaseDimension<Dim>) && is_derived_from_instantiation<Dim, DimTemplate>;
template<typename Q, template<typename...> typename DimTemplate>
concept QuantityOf = Quantity<Q> && is_derived_from_instantiation<Q::dimension, DimTemplate>;
// ------------------------ base dimensions -----------------------------
// length
template<Unit U>
struct dim_length : base_dimension<"length", U> {};
template<typename T>
concept Length = QuantityOf<T, dim_length>;
// mass
template<Unit U>
struct dim_mass : base_dimension<"mass", U> {};
template<typename T>
concept Mass = QuantityOf<T, dim_mass>;
// time
template<Unit U>
struct dim_time : base_dimension<"time", U> {};
template<typename T>
concept Time = QuantityOf<T, dim_time>;
// current
template<Unit U>
struct dim_current : base_dimension<"current", U> {};
template<typename T>
concept Current = QuantityOf<T, dim_current>;
// temperature
template<Unit U>
struct dim_temperature : base_dimension<"temperature", U> {};
template<typename T>
concept Temperature = QuantityOf<T, dim_temperature>;
// substance
template<Unit U>
struct dim_substance : base_dimension<"substance", U> {};
template<typename T>
concept Substance = QuantityOf<T, dim_substance>;
// luminous intensity
template<Unit U>
struct dim_luminous_intensity : base_dimension<"luminous intensity", U> {};
template<typename T>
concept LuminousIntensity = QuantityOf<T, dim_luminous_intensity>;
// ------------------------ derived dimensions -----------------------------
// frequency
template<typename Child, Unit U, DimensionOf<dim_time> T>
struct dim_frequency : derived_dimension<Child, U, exp<T, -1>> {};
template<typename T>
concept Frequency = QuantityOf<T, dim_frequency>;
// area
template<typename Child, Unit U, DimensionOf<dim_length> L>
struct dim_area : derived_dimension<Child, U, exp<L, 2>> {};
template<typename T>
concept Area = QuantityOf<T, dim_area>;
// velocity
template<typename Child, Unit U, DimensionOf<dim_length> L, DimensionOf<dim_time> T>
struct dim_velocity : derived_dimension<Child, U, exp<L, 1>, exp<T, -1>> {};
template<typename T>
concept Velocity = QuantityOf<T, dim_velocity>;
// acceleration
template<typename Child, Unit U, DimensionOf<dim_length> L, DimensionOf<dim_time> T>
struct dim_acceleration : derived_dimension<Child, U, exp<L, 1>, exp<T, -2>> {};
template<typename T>
concept Acceleration = QuantityOf<T, dim_acceleration>;
// force
template<typename Child, Unit U, DimensionOf<dim_mass> M, DimensionOf<dim_acceleration> A>
struct dim_force : derived_dimension<Child, U, exp<M, 1>, exp<A, 1>> {};
template<typename T>
concept Force = QuantityOf<T, dim_force>;
// energy
template<typename Child, Unit U, DimensionOf<dim_force> F, DimensionOf<dim_length> L>
struct dim_energy : derived_dimension<Child, U, exp<F, 1>, exp<L, 1>> {};
template<typename T>
concept Energy = QuantityOf<T, dim_energy>;
// power
template<typename Child, Unit U, DimensionOf<dim_energy> E, DimensionOf<dim_time> T>
struct dim_power : derived_dimension<Child, U, exp<E, 1>, exp<T, -1>> {};
template<typename T>
concept Power = QuantityOf<T, dim_power>;
// pressure
template<typename Child, Unit U, DimensionOf<dim_force> F, DimensionOf<dim_area> A>
struct dim_pressure : derived_dimension<Child, U, exp<F, 1>, exp<A, -1>> {};
template<typename T>
concept Pressure = QuantityOf<T, dim_pressure>;
} // namespace physical
} // namespace units

View File

@@ -0,0 +1,65 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/physical/dimensions.h>
#include <units/physical/si/length.h>
namespace units::si {
struct square_metre : unit<square_metre> {};
struct dim_area : physical::dim_area<dim_area, square_metre, dim_length> {};
struct square_millimetre : deduced_unit<square_millimetre, dim_area, millimetre> {};
struct square_centimetre : deduced_unit<square_centimetre, dim_area, centimetre> {};
struct square_kilometre : deduced_unit<square_kilometre, dim_area, kilometre> {};
struct square_foot : deduced_unit<square_foot, dim_area, foot> {};
template<Unit U, Scalar Rep = double>
using area = quantity<dim_area, U, Rep>;
inline namespace literals {
// sq_m
constexpr auto operator"" sq_m(unsigned long long l) { return area<square_metre, std::int64_t>(l); }
constexpr auto operator"" sq_m(long double l) { return area<square_metre, long double>(l); }
// sq_mm
constexpr auto operator"" sq_mm(unsigned long long l) { return area<square_millimetre, std::int64_t>(l); }
constexpr auto operator"" sq_mm(long double l) { return area<square_millimetre, long double>(l); }
// sq_cm
constexpr auto operator"" sq_cm(unsigned long long l) { return area<square_centimetre, std::int64_t>(l); }
constexpr auto operator"" sq_cm(long double l) { return area<square_centimetre, long double>(l); }
// sq_km
constexpr auto operator"" sq_km(unsigned long long l) { return area<square_kilometre, std::int64_t>(l); }
constexpr auto operator"" sq_km(long double l) { return area<square_kilometre, long double>(l); }
// sq_ft
constexpr auto operator"" sq_ft(unsigned long long l) { return area<square_foot, std::int64_t>(l); }
constexpr auto operator"" sq_ft(long double l) { return area<square_foot, long double>(l); }
} // namespace literals
} // namespace units::si

View File

@@ -0,0 +1,70 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/physical/dimensions.h>
#include <units/physical/si/time.h>
namespace units::si {
struct hertz : named_unit<hertz, "Hz", prefix> {};
struct millihertz : prefixed_unit<millihertz, milli, hertz> {};
struct kilohertz : prefixed_unit<kilohertz, kilo, hertz> {};
struct megahertz : prefixed_unit<megahertz, mega, hertz> {};
struct gigahertz : prefixed_unit<gigahertz, giga, hertz> {};
struct terahertz : prefixed_unit<terahertz, tera, hertz> {};
struct dim_frequency : physical::dim_frequency<dim_frequency, hertz, dim_time> {};
template<Unit U, Scalar Rep = double>
using frequency = quantity<dim_frequency, U, Rep>;
inline namespace literals {
// Hz
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); }
// mHz
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); }
// kHz
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 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 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 frequency<terahertz, std::int64_t>(l); }
constexpr auto operator"" THz(long double l) { return frequency<terahertz, long double>(l); }
} // namespace literals
} // namespace units::si

View File

@@ -0,0 +1,86 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/physical/dimensions.h>
#include <units/physical/si/prefixes.h>
namespace units::si {
struct metre : named_unit<metre, "m", prefix> {};
struct millimetre : prefixed_unit<millimetre, milli, metre> {};
struct centimetre : prefixed_unit<centimetre, centi, metre> {};
struct kilometre : prefixed_unit<kilometre, kilo, metre> {};
struct dim_length : physical::dim_length<metre> {};
template<Unit U, Scalar Rep = double>
using length = quantity<dim_length, U, Rep>;
inline namespace literals {
// m
constexpr auto operator"" m(unsigned long long l) { return length<metre, std::int64_t>(l); }
constexpr auto operator"" m(long double l) { return length<metre, long double>(l); }
// mm
constexpr auto operator"" mm(unsigned long long l) { return length<millimetre, std::int64_t>(l); }
constexpr auto operator"" mm(long double l) { return length<millimetre, long double>(l); }
// cm
constexpr auto operator"" cm(unsigned long long l) { return length<centimetre, std::int64_t>(l); }
constexpr auto operator"" cm(long double l) { return length<centimetre, long double>(l); }
// km
constexpr auto operator"" km(unsigned long long l) { return length<kilometre, std::int64_t>(l); }
constexpr auto operator"" km(long double l) { return length<kilometre, long double>(l); }
} // namespace literals
// US customary units
struct yard : scaled_unit<yard, "yd", no_prefix, ratio<9'144, 10'000>, metre> {};
struct foot : scaled_unit<foot, "ft", no_prefix, ratio<1, 3>, yard> {};
struct inch : scaled_unit<inch, "in", no_prefix, ratio<1, 12>, foot> {};
struct mile : scaled_unit<mile, "mi", no_prefix, ratio<1'760>, yard> {};
inline namespace literals {
// yd
constexpr auto operator"" yd(unsigned long long l) { return length<yard, std::int64_t>(l); }
constexpr auto operator"" yd(long double l) { return length<yard, long double>(l); }
// ft
constexpr auto operator"" ft(unsigned long long l) { return length<foot, std::int64_t>(l); }
constexpr auto operator"" ft(long double l) { return length<foot, long double>(l); }
// in
constexpr auto operator"" in(unsigned long long l) { return length<inch, std::int64_t>(l); }
constexpr auto operator"" in(long double l) { return length<inch, long double>(l); }
// mi
constexpr auto operator"" mi(unsigned long long l) { return length<mile, std::int64_t>(l); }
constexpr auto operator"" mi(long double l) { return length<mile, long double>(l); }
} // namespace literals
} // namespace units::si

View File

@@ -0,0 +1,70 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/physical/dimensions.h>
#include <units/physical/si/prefixes.h>
namespace units::si {
struct second : named_unit<second, "s", prefix> {};
struct nanosecond : prefixed_unit<nanosecond, nano, second> {};
struct microsecond : prefixed_unit<microsecond, micro, second> {};
struct millisecond : prefixed_unit<millisecond, milli, second> {};
struct minute : scaled_unit<minute, "min", no_prefix, ratio<60>, second> {};
struct hour : scaled_unit<hour, "h", no_prefix, ratio<3600>, second> {};
struct dim_time : physical::dim_time<second> {};
template<Unit U, Scalar Rep = double>
using time = quantity<dim_time, U, Rep>;
inline namespace literals {
// ns
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 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 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 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 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 time<hour, std::int64_t>(l); }
constexpr auto operator""h(long double l) { return time<hour, long double>(l); }
} // namespace literals
} // namespace units::si

View File

@@ -0,0 +1,56 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#include <units/physical/dimensions.h>
#include <units/physical/si/length.h>
#include <units/physical/si/time.h>
namespace units::si {
struct metre_per_second : unit<metre_per_second> {};
struct dim_velocity : physical::dim_velocity<dim_velocity, metre_per_second, dim_length, dim_time> {};
struct kilometre_per_hour : deduced_unit<kilometre_per_hour, dim_velocity, kilometre, hour> {};
struct mile_per_hour : deduced_unit<mile_per_hour, dim_velocity, mile, hour> {};
template<Unit U, Scalar Rep = double>
using velocity = quantity<dim_velocity, U, Rep>;
inline namespace literals {
// mps
constexpr auto operator"" mps(unsigned long long l) { return velocity<metre_per_second, std::int64_t>(l); }
constexpr auto operator"" mps(long double l) { return velocity<metre_per_second, long double>(l); }
// kmph
constexpr auto operator"" kmph(unsigned long long l) { return velocity<kilometre_per_hour, std::int64_t>(l); }
constexpr auto operator"" kmph(long double l) { return velocity<kilometre_per_hour, long double>(l); }
// mph
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
} // namespace units::si

View File

@@ -22,14 +22,14 @@
#pragma once
#include <units/bits/concepts.h>
#include <units/concepts.h>
#include <units/unit.h>
#include <limits>
#include <ostream>
namespace units {
// is_quantity
// Quantity
namespace detail {
template<typename T>
@@ -42,24 +42,21 @@ namespace units {
template<typename T>
concept Quantity = detail::is_quantity<T>;
// QuantityOf
template<typename T, typename Dim>
concept QuantityOf = Quantity<T> && Dimension<Dim> && same_dim<typename T::dimension, Dim>;
// Scalar
template<typename T>
concept Scalar =
(!Quantity<T>) &&
std::regular<T> &&
std::totally_ordered<T> &&
detail::basic_arithmetic<T>;
concept Scalar = (!Quantity<T>) && std::regular<T> && std::totally_ordered<T> && detail::basic_arithmetic<T>;
template<Unit U, Scalar Rep>
template<Dimension D, UnitOf<D> U, Scalar Rep>
class quantity;
namespace detail {
template<typename U, typename Rep>
inline constexpr bool is_quantity<quantity<U, Rep>> = true;
template<typename D, typename U, typename Rep>
inline constexpr bool is_quantity<quantity<D, U, Rep>> = true;
} // namespace detail
@@ -69,16 +66,15 @@ namespace units {
template<typename Q1, typename Q2, typename Rep>
struct common_quantity_impl;
template<typename U, typename Rep1, typename Rep2, typename Rep>
struct common_quantity_impl<quantity<U, Rep1>, quantity<U, Rep2>, Rep> {
using type = quantity<U, Rep>;
template<typename D, typename U, typename Rep1, typename Rep2, typename Rep>
struct common_quantity_impl<quantity<D, U, Rep1>, quantity<D, U, Rep2>, Rep> {
using type = quantity<D, U, Rep>;
};
template<typename U1, typename Rep1, typename U2, typename Rep2, typename Rep>
requires same_dim<typename U1::dimension, typename U2::dimension>
struct common_quantity_impl<quantity<U1, Rep1>, quantity<U2, Rep2>, Rep> {
using type =
quantity<downcast<unit<typename U1::dimension, common_ratio<typename U1::ratio, typename U2::ratio>>>,
template<typename D, typename U1, typename Rep1, typename U2, typename Rep2, typename Rep>
struct common_quantity_impl<quantity<D, U1, Rep1>, quantity<D, U2, Rep2>, Rep> {
using type = quantity<
D, downcast<detail::reference_unit<typename U1::reference, common_ratio<typename U1::ratio, typename U2::ratio>>>,
Rep>;
};
@@ -88,7 +84,6 @@ namespace units {
using common_quantity = detail::common_quantity_impl<Q1, Q2, Rep>::type;
// quantity_cast
namespace detail {
template<typename To, typename CRatio, typename CRep, bool NumIsOne = false, bool DenIsOne = false>
@@ -99,10 +94,9 @@ namespace units {
if constexpr (treat_as_floating_point<CRep>) {
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) *
(static_cast<CRep>(CRatio::num) / static_cast<CRep>(CRatio::den))));
}
else {
return To(
static_cast<To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(CRatio::num) / static_cast<CRep>(CRatio::den)));
} else {
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(CRatio::num) /
static_cast<CRep>(CRatio::den)));
}
}
};
@@ -123,8 +117,7 @@ namespace units {
{
if constexpr (treat_as_floating_point<CRep>) {
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) * (CRep{1} / static_cast<CRep>(CRatio::den))));
}
else {
} else {
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) / static_cast<CRep>(CRatio::den)));
}
}
@@ -141,63 +134,126 @@ namespace units {
} // namespace detail
template<Quantity To, typename U, typename Rep>
[[nodiscard]] constexpr auto quantity_cast(const quantity<U, Rep>& q)
requires same_dim<typename To::dimension, typename U::dimension> &&
/**
* @brief Explcit cast of a quantity
*
* Implicit conversions between quantities of different types are allowed only for "safe"
* (i.e. non-truncating) conversion. In such cases an explicit cast have to be used.
*
* This cast gets the target quantity type to cast to. For example:
*
* using seconds = units::time<units::si::second, double>;
* auto q1 = units::quantity_cast<seconds>(1ms);
*
* @tparam To a target quantity type to cast to
*/
template<Quantity To, typename D, typename U, typename Rep>
[[nodiscard]] constexpr auto quantity_cast(const quantity<D, U, Rep>& q)
requires QuantityOf<To, D> &&
detail::basic_arithmetic<std::common_type_t<typename To::rep, Rep, intmax_t>>
{
using c_ratio = ratio_divide<typename U::ratio, typename To::unit::ratio>;
using c_rep = std::common_type_t<typename To::rep, Rep, intmax_t>;
using ret_dim = downcast<typename To::unit::dimension>;
using ret_unit = downcast<unit<ret_dim, typename To::unit::ratio>>;
using ret = quantity<ret_unit, typename To::rep>;
using ret_unit = downcast<detail::reference_unit<typename U::reference, typename To::unit::ratio>>;
using ret = quantity<D, ret_unit, typename To::rep>;
using cast = detail::quantity_cast_impl<ret, c_ratio, c_rep, c_ratio::num == 1, c_ratio::den == 1>;
return cast::cast(q);
}
template<Unit ToU, Scalar ToRep, typename U, typename Rep>
[[nodiscard]] constexpr auto quantity_cast(const quantity<U, Rep>& q)
requires same_dim<typename ToU::dimension, typename U::dimension> &&
/**
* @brief Explcit cast of a quantity
*
* Implicit conversions between quantities of different types are allowed only for "safe"
* (i.e. non-truncating) conversion. In such cases an explicit cast have to be used.
*
* This cast gets both the target unit and representation to cast to. For example:
*
* auto q1 = units::quantity_cast<units::second, int>(1ms);
*
* @tparam ToU a unit type to use for a target quantity
* @tparam ToRep a representation type to use for a target quantity
*/
template<Unit ToU, Scalar ToRep, typename D, typename U, typename Rep>
[[nodiscard]] constexpr auto quantity_cast(const quantity<D, U, Rep>& q)
requires UnitOf<ToU, D> &&
detail::basic_arithmetic<std::common_type_t<ToRep, Rep, intmax_t>>
{
return quantity_cast<quantity<ToU, ToRep>>(q);
return quantity_cast<quantity<D, ToU, ToRep>>(q);
}
template<Unit ToU, typename U, typename Rep>
[[nodiscard]] constexpr auto quantity_cast(const quantity<U, Rep>& q)
requires same_dim<typename ToU::dimension, typename U::dimension>
/**
* @brief Explcit cast of a quantity
*
* Implicit conversions between quantities of different types are allowed only for "safe"
* (i.e. non-truncating) conversion. In such cases an explicit cast have to be used.
*
* This cast gets only the target unit to cast to. For example:
*
* auto q1 = units::quantity_cast<units::second>(1ms);
*
* @tparam ToU a unit type to use for a target quantity
*/
template<Unit ToU, typename D, typename U, typename Rep>
[[nodiscard]] constexpr auto quantity_cast(const quantity<D, U, Rep>& q)
requires UnitOf<ToU, D>
{
return quantity_cast<quantity<ToU, Rep>>(q);
return quantity_cast<quantity<D, ToU, Rep>>(q);
}
template<Scalar ToRep, typename U, typename Rep>
[[nodiscard]] constexpr auto quantity_cast(const quantity<U, Rep>& q)
/**
* @brief Explcit cast of a quantity
*
* Implicit conversions between quantities of different types are allowed only for "safe"
* (i.e. non-truncating) conversion. In such cases an explicit cast have to be used.
*
* This cast gets only representation to cast to. For example:
*
* auto q1 = units::quantity_cast<int>(1ms);
*
* @tparam ToRep a representation type to use for a target quantity
*/
template<Scalar ToRep, typename D, typename U, typename Rep>
[[nodiscard]] constexpr auto quantity_cast(const quantity<D, U, Rep>& q)
requires detail::basic_arithmetic<std::common_type_t<ToRep, Rep, intmax_t>>
{
return quantity_cast<quantity<U, ToRep>>(q);
return quantity_cast<quantity<D, U, ToRep>>(q);
}
// quantity_values
/**
* @brief A type trait that defines zero, one, min, and max for a representation type
*
* The zero, one, min, and max member functions in units::quantity forward their work to
* these methods. This type can be specialized if the representation Rep requires a specific
* implementation to return these quantity objects.
*
* @tparam Rep a representation type for which a type trait is defined
*/
template<Scalar Rep>
struct quantity_values {
static constexpr Rep zero() noexcept { return Rep(0); }
static constexpr Rep one() noexcept { return Rep(1); }
static constexpr Rep max() noexcept { return std::numeric_limits<Rep>::max(); }
static constexpr Rep min() noexcept { return std::numeric_limits<Rep>::lowest(); }
static constexpr Rep max() noexcept { return std::numeric_limits<Rep>::max(); }
};
// quantity
template<Unit U, Scalar Rep = double>
/**
* @brief A quantity
*
* Property of a phenomenon, body, or substance, where the property has a magnitude that can be
* expressed by means of a number and a measurement unit.
*
* @tparam D a dimension of the quantity (can be either a BaseDimension or a DerivedDimension)
* @tparam U a measurement unit of the quantity
* @tparam Rep a type to be used to represent values of a quantity
*/
template<Dimension D, UnitOf<D> U, Scalar Rep = double>
class quantity {
Rep value_;
public:
using dimension = D;
using unit = U;
using rep = Rep;
using dimension = U::dimension;
quantity() = default;
quantity(const quantity&) = default;
@@ -205,17 +261,13 @@ namespace units {
template<Scalar Value>
requires detail::safe_convertible<Value, rep>
constexpr explicit quantity(const Value& v): value_{static_cast<rep>(v)}
{
}
constexpr explicit quantity(const Value& v) : value_{static_cast<rep>(v)} {}
template<Quantity Q2>
requires same_dim<dimension, typename Q2::dimension> &&
detail::safe_convertible<typename Q2::rep, rep> &&
detail::safe_divisible<rep, typename Q2::unit, unit>
constexpr quantity(const Q2& q): value_{quantity_cast<quantity>(q).count()}
{
}
constexpr quantity(const Q2& q) : value_{quantity_cast<quantity>(q).count()} {}
quantity& operator=(const quantity&) = default;
quantity& operator=(quantity&&) = default;
@@ -277,7 +329,9 @@ namespace units {
requires requires(T v) { { v++ } -> SAME_AS(T); }
constexpr quantity operator++(int)
// requires requires(rep v) { { v++ } -> std::same_as<rep>; } // TODO gated by gcc-9 (fixed in gcc-10)
{ return quantity(value_++); }
{
return quantity(value_++);
}
template<typename T = Rep>
requires requires(T v) { { --v } -> SAME_AS(T&); }
@@ -292,7 +346,9 @@ namespace units {
requires requires(T v) { { v-- } -> SAME_AS(T); }
constexpr quantity operator--(int)
// requires requires(rep v) { { v-- } -> std::same_as<rep>; } // TODO gated by gcc-9 (fixed in gcc-10)
{ return quantity(value_--); }
{
return quantity(value_--);
}
template<typename T = Rep>
requires requires(T v1, T v2) { { v1 += v2 } -> SAME_AS(T&); }
@@ -354,184 +410,188 @@ namespace units {
template<class CharT, class Traits>
friend std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const quantity& q)
{
return os << q.count() << " " << detail::unit_text<quantity::unit>();
return os; // << q.count() << " " << detail::unit_text<quantity::unit>();
}
};
template<typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr Quantity AUTO operator+(const quantity<U1, Rep1>& lhs, const quantity<U2, Rep2>& rhs)
requires same_dim<typename U1::dimension, typename U2::dimension> && detail::basic_arithmetic<Rep1, Rep2>
template<typename D, typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr Quantity AUTO operator+(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs)
requires detail::basic_arithmetic<Rep1, Rep2>
{
using common_rep = decltype(lhs.count() + rhs.count());
using ret = common_quantity<quantity<U1, Rep1>, quantity<U2, Rep2>, common_rep>;
using ret = common_quantity<quantity<D, U1, Rep1>, quantity<D, U2, Rep2>, common_rep>;
return ret(ret(lhs).count() + ret(rhs).count());
}
template<typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr Quantity AUTO operator-(const quantity<U1, Rep1>& lhs, const quantity<U2, Rep2>& rhs)
requires same_dim<typename U1::dimension, typename U2::dimension> &&
detail::basic_arithmetic<Rep1, Rep2>
template<typename D, typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr Quantity AUTO operator-(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs)
requires detail::basic_arithmetic<Rep1, Rep2>
{
using common_rep = decltype(lhs.count() - rhs.count());
using ret = common_quantity<quantity<U1, Rep1>, quantity<U2, Rep2>, common_rep>;
using ret = common_quantity<quantity<D, U1, Rep1>, quantity<D, U2, Rep2>, common_rep>;
return ret(ret(lhs).count() - ret(rhs).count());
}
template<typename U, typename Rep, Scalar Value>
[[nodiscard]] constexpr Quantity AUTO operator*(const quantity<U, Rep>& q, const Value& v)
template<typename D, typename U, typename Rep, Scalar Value>
[[nodiscard]] constexpr Quantity AUTO operator*(const quantity<D, U, Rep>& q, const Value& v)
requires std::magma<std::ranges::times, Rep, Value>
{
using common_rep = decltype(q.count() * v);
using ret = quantity<U, common_rep>;
using ret = quantity<D, U, common_rep>;
return ret(q.count() * v);
}
template<Scalar Value, typename U, typename Rep>
[[nodiscard]] constexpr Quantity AUTO operator*(const Value& v, const quantity<U, Rep>& q)
template<Scalar Value, typename D, typename U, typename Rep>
[[nodiscard]] constexpr Quantity AUTO operator*(const Value& v, const quantity<D, U, Rep>& q)
requires std::magma<std::ranges::times, Value, Rep>
{
return q * v;
}
template<typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr Scalar AUTO operator*(const quantity<U1, Rep1>& lhs, const quantity<U2, Rep2>& rhs)
requires same_dim<typename U1::dimension, dim_invert<typename U2::dimension>> &&
detail::basic_arithmetic<Rep1, Rep2>
template<typename D1, typename U1, typename Rep1, typename D2, typename U2, typename Rep2>
[[nodiscard]] constexpr Scalar AUTO operator*(const quantity<D1, U1, Rep1>& lhs, const quantity<D2, U2, Rep2>& rhs)
requires same_dim<D1, dim_invert<D2>>&& detail::basic_arithmetic<Rep1, Rep2>
{
using common_rep = decltype(lhs.count() * rhs.count());
using ratio = ratio_multiply<typename U1::ratio, typename U2::ratio>;
return common_rep(lhs.count()) * common_rep(rhs.count()) * common_rep(ratio::num) / common_rep(ratio::den);
}
template<typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr Quantity AUTO operator*(const quantity<U1, Rep1>& lhs, const quantity<U2, Rep2>& rhs)
requires (!same_dim<typename U1::dimension, dim_invert<typename U2::dimension>>) &&
template<typename D1, typename U1, typename Rep1, typename D2, typename U2, typename Rep2>
[[nodiscard]] constexpr Quantity AUTO operator*(const quantity<D1, U1, Rep1>& lhs, const quantity<D2, U2, Rep2>& rhs)
requires (!same_dim<D1, dim_invert<D2>>) &&
(treat_as_floating_point<decltype(lhs.count() * rhs.count())> ||
(std::ratio_multiply<typename U1::ratio, typename U2::ratio>::den == 1)) &&
detail::basic_arithmetic<Rep1, Rep2>
{
using dim = dimension_multiply<typename U1::dimension, typename U2::dimension>;
using dim = dimension_multiply<D1, D2>;
using ratio = ratio_multiply<typename U1::ratio, typename U2::ratio>;
using unit = downcast<detail::reference_unit<typename dim::coherent_unit::reference, ratio>>;
using common_rep = decltype(lhs.count() * rhs.count());
using ret = quantity<downcast<unit<dim, ratio_multiply<typename U1::ratio, typename U2::ratio>>>, common_rep>;
using ret = quantity<dim, unit, common_rep>;
return ret(lhs.count() * rhs.count());
}
template<Scalar Value, typename U, typename Rep>
[[nodiscard]] constexpr Quantity AUTO operator/(const Value& v, const quantity<U, Rep>& q)
template<typename D, Scalar Value, typename U, typename Rep>
[[nodiscard]] constexpr Quantity AUTO operator/(const Value& v, const quantity<D, U, Rep>& q)
requires std::magma<std::ranges::divided_by, Value, Rep>
{
Expects(q != std::remove_cvref_t<decltype(q)>(0));
using dim = dim_invert<typename U::dimension>;
using dim = dim_invert<D>;
using ratio = ratio<U::ratio::den, U::ratio::num>;
using unit = downcast<detail::reference_unit<typename dim::coherent_unit::reference, ratio>>;
using common_rep = decltype(v / q.count());
using ret = quantity<downcast<unit<dim, ratio<U::ratio::den, U::ratio::num>>>, common_rep>;
using ret = quantity<dim, unit, common_rep>;
return ret(v / q.count());
}
template<typename U, typename Rep, Scalar Value>
[[nodiscard]] constexpr Quantity AUTO operator/(const quantity<U, Rep>& q, const Value& v)
template<typename D, typename U, typename Rep, Scalar Value>
[[nodiscard]] constexpr Quantity AUTO operator/(const quantity<D, U, Rep>& q, const Value& v)
requires std::magma<std::ranges::divided_by, Rep, Value>
{
Expects(v != Value{0});
using common_rep = decltype(q.count() / v);
using ret = quantity<U, common_rep>;
using ret = quantity<D, U, common_rep>;
return ret(q.count() / v);
}
template<typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr Scalar AUTO operator/(const quantity<U1, Rep1>& lhs, const quantity<U2, Rep2>& rhs)
requires same_dim<typename U1::dimension, typename U2::dimension> &&
detail::basic_arithmetic<Rep1, Rep2>
template<typename D, typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr Scalar AUTO operator/(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs)
requires detail::basic_arithmetic<Rep1, Rep2>
{
Expects(rhs != std::remove_cvref_t<decltype(rhs)>(0));
using common_rep = decltype(lhs.count() / rhs.count());
using cq = common_quantity<quantity<U1, Rep1>, quantity<U2, Rep2>, common_rep>;
using cq = common_quantity<quantity<D, U1, Rep1>, quantity<D, U2, Rep2>, common_rep>;
return cq(lhs).count() / cq(rhs).count();
}
template<typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr Quantity AUTO operator/(const quantity<U1, Rep1>& lhs, const quantity<U2, Rep2>& rhs)
requires (!same_dim<typename U1::dimension, typename U2::dimension>) &&
(treat_as_floating_point<decltype(lhs.count() / rhs.count())> ||
template<typename D1, typename U1, typename Rep1, typename D2, typename U2, typename Rep2>
[[nodiscard]] constexpr Quantity AUTO operator/(const quantity<D1, U1, Rep1>& lhs, const quantity<D2, U2, Rep2>& rhs)
requires (treat_as_floating_point<decltype(lhs.count() / rhs.count())> ||
(ratio_divide<typename U1::ratio, typename U2::ratio>::den == 1)) &&
detail::basic_arithmetic<Rep1, Rep2>
{
Expects(rhs != std::remove_cvref_t<decltype(rhs)>(0));
using common_rep = decltype(lhs.count() / rhs.count());
using dim = dimension_divide<typename U1::dimension, typename U2::dimension>;
using ret = quantity<downcast<unit<dim, ratio_divide<typename U1::ratio, typename U2::ratio>>>, common_rep>;
using dim = dimension_divide<D1, D2>;
using unit = downcast<detail::reference_unit<typename dim::coherent_unit::reference,
ratio_divide<typename U1::ratio, typename U2::ratio>>>;
using ret = quantity<dim, unit, common_rep>;
return ret(lhs.count() / rhs.count());
}
template<typename U, typename Rep, Scalar Value>
[[nodiscard]] constexpr Quantity AUTO operator%(const quantity<U, Rep>& q, const Value& v)
requires (!treat_as_floating_point<Rep>) && (!treat_as_floating_point<Value>) &&
template<typename D, typename U, typename Rep, Scalar Value>
[[nodiscard]] constexpr Quantity AUTO operator%(const quantity<D, U, Rep>& q, const Value& v)
requires (!treat_as_floating_point<Rep>) &&
(!treat_as_floating_point<Value>) &&
std::magma<std::ranges::modulus, Rep, Value>
{
using common_rep = decltype(q.count() % v);
using ret = quantity<U, common_rep>;
using ret = quantity<D, U, common_rep>;
return ret(q.count() % v);
}
template<typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr Quantity AUTO operator%(const quantity<U1, Rep1>& lhs, const quantity<U2, Rep2>& rhs)
requires (!treat_as_floating_point<Rep1>) && (!treat_as_floating_point<Rep2>) &&
template<typename D, typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr Quantity AUTO operator%(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs)
requires (!treat_as_floating_point<Rep1>) &&
(!treat_as_floating_point<Rep2>) &&
std::magma<std::ranges::modulus, Rep1, Rep2>
{
using common_rep = decltype(lhs.count() % rhs.count());
using ret = common_quantity<quantity<U1, Rep1>, quantity<U2, Rep2>, common_rep>;
using ret = common_quantity<quantity<D, U1, Rep1>, quantity<D, U2, Rep2>, common_rep>;
return ret(ret(lhs).count() % ret(rhs).count());
}
template<typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr bool operator==(const quantity<U1, Rep1>& lhs, const quantity<U2, Rep2>& rhs)
requires same_dim<typename U1::dimension, typename U2::dimension> &&
detail::basic_arithmetic<Rep1, Rep2> && std::equality_comparable_with<Rep1, Rep2>
template<typename D, typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr bool operator==(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs)
requires detail::basic_arithmetic<Rep1, Rep2> &&
std::equality_comparable_with<Rep1, Rep2>
{
using cq = common_quantity<quantity<U1, Rep1>, quantity<U2, Rep2>>;
using cq = common_quantity<quantity<D, U1, Rep1>, quantity<D, U2, Rep2>>;
return cq(lhs).count() == cq(rhs).count();
}
template<typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr bool operator!=(const quantity<U1, Rep1>& lhs, const quantity<U2, Rep2>& rhs)
requires same_dim<typename U1::dimension, typename U2::dimension> &&
detail::basic_arithmetic<Rep1, Rep2> && std::equality_comparable_with<Rep1, Rep2>
template<typename D, typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr bool operator!=(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs)
requires detail::basic_arithmetic<Rep1, Rep2> &&
std::equality_comparable_with<Rep1, Rep2>
{
return !(lhs == rhs);
}
template<typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr bool operator<(const quantity<U1, Rep1>& lhs, const quantity<U2, Rep2>& rhs)
requires same_dim<typename U1::dimension, typename U2::dimension> &&
detail::basic_arithmetic<Rep1, Rep2> && std::totally_ordered_with<Rep1, Rep2>
template<typename D, typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr bool operator<(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs)
requires detail::basic_arithmetic<Rep1, Rep2> &&
std::totally_ordered_with<Rep1, Rep2>
{
using cq = common_quantity<quantity<U1, Rep1>, quantity<U2, Rep2>>;
using cq = common_quantity<quantity<D, U1, Rep1>, quantity<D, U2, Rep2>>;
return cq(lhs).count() < cq(rhs).count();
}
template<typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr bool operator<=(const quantity<U1, Rep1>& lhs, const quantity<U2, Rep2>& rhs)
requires same_dim<typename U1::dimension, typename U2::dimension> &&
detail::basic_arithmetic<Rep1, Rep2> && std::totally_ordered_with<Rep1, Rep2>
template<typename D, typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr bool operator<=(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs)
requires detail::basic_arithmetic<Rep1, Rep2> &&
std::totally_ordered_with<Rep1, Rep2>
{
return !(rhs < lhs);
}
template<typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr bool operator>(const quantity<U1, Rep1>& lhs, const quantity<U2, Rep2>& rhs)
requires same_dim<typename U1::dimension, typename U2::dimension> &&
detail::basic_arithmetic<Rep1, Rep2> && std::totally_ordered_with<Rep1, Rep2>
template<typename D, typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr bool operator>(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs)
requires detail::basic_arithmetic<Rep1, Rep2> &&
std::totally_ordered_with<Rep1, Rep2>
{
return rhs < lhs;
}
template<typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr bool operator>=(const quantity<U1, Rep1>& lhs, const quantity<U2, Rep2>& rhs)
requires same_dim<typename U1::dimension, typename U2::dimension> &&
detail::basic_arithmetic<Rep1, Rep2> && std::totally_ordered_with<Rep1, Rep2>
template<typename D, typename U1, typename Rep1, typename U2, typename Rep2>
[[nodiscard]] constexpr bool operator>=(const quantity<D, U1, Rep1>& lhs, const quantity<D, U2, Rep2>& rhs)
requires detail::basic_arithmetic<Rep1, Rep2> &&
std::totally_ordered_with<Rep1, Rep2>
{
return !(lhs < rhs);
}

View File

@@ -42,6 +42,13 @@ struct reference_unit : downcast_base<reference_unit<U, R>> {
} // namespace detail
// UnitOf
template<typename U, typename D>
concept UnitOf =
Unit<U> &&
Dimension<D> &&
std::same_as<typename U::reference, typename D::coherent_unit::reference>;
namespace detail {
// same_reference_units
@@ -49,8 +56,7 @@ template<DerivedDimension D, Unit... Us>
inline constexpr bool same_reference_units = false;
template<typename... Es, Unit... Us>
inline constexpr bool same_reference_units<derived_dimension<Es...>, Us...> =
(std::same_as<typename Es::dimension::coherent_unit::reference, typename Us::reference> && ...);
inline constexpr bool same_reference_units<derived_dimension<Es...>, Us...> = (UnitOf<Us, typename Es::dimension> && ...);
// deduced_unit
template<typename Result, int UnitExpNum, int UnitExpDen, typename UnitRatio>

View File

@@ -27,7 +27,7 @@ add_library(unit_tests_static
# fixed_string_test.cpp
# math_test.cpp
# new_design.cpp
# quantity_test.cpp
quantity_test.cpp
ratio_test.cpp
# si_test.cpp
type_list_test.cpp

View File

@@ -20,12 +20,12 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include "units/dimensions/velocity.h"
#include "units/dimensions/frequency.h"
#include "units/dimensions/area.h"
#include "units/math.h"
#include <utility>
#include "units/physical/si/area.h"
#include "units/physical/si/frequency.h"
#include "units/physical/si/velocity.h"
#include <chrono>
#include <utility>
using namespace units;
@@ -34,15 +34,30 @@ namespace {
template<typename T>
class my_value {
T value_{};
public:
my_value() = default;
constexpr my_value(T v) : value_(std::move(v)) {}
// constexpr my_value& operator+=(my_value other) { value_ += other.value_; return *this; }
// constexpr my_value& operator-=(my_value other) { value_ -= other.value_; return *this; }
// constexpr my_value& operator*=(my_value other) { value_ *= other.value_; return *this; }
// constexpr my_value& operator/=(my_value other) { value_ /= other.value_; return *this; }
[[nodiscard]] constexpr my_value operator-() const { return my_value(-value_); }
[[nodiscard]] friend constexpr my_value operator+(my_value lhs, my_value rhs) { return my_value(lhs.value_ + rhs.value_); }
[[nodiscard]] friend constexpr my_value operator-(my_value lhs, my_value rhs) { return my_value(lhs.value_ - rhs.value_); }
[[nodiscard]] friend constexpr my_value operator*(my_value lhs, my_value rhs) { return my_value(lhs.value_ * rhs.value_); }
[[nodiscard]] friend constexpr my_value operator/(my_value lhs, my_value rhs) { return my_value(lhs.value_ / rhs.value_); }
[[nodiscard]] friend constexpr my_value operator+(my_value lhs, my_value rhs) {
return my_value(lhs.value_ + rhs.value_);
}
[[nodiscard]] friend constexpr my_value operator-(my_value lhs, my_value rhs) {
return my_value(lhs.value_ - rhs.value_);
}
[[nodiscard]] friend constexpr my_value operator*(my_value lhs, my_value rhs) {
return my_value(lhs.value_ * rhs.value_);
}
[[nodiscard]] friend constexpr my_value operator/(my_value lhs, my_value rhs) {
return my_value(lhs.value_ / rhs.value_);
}
[[nodiscard]] friend constexpr bool operator==(my_value lhs, my_value rhs) { return lhs.value_ == rhs.value_; }
[[nodiscard]] friend constexpr bool operator!=(my_value lhs, my_value rhs) { return !(lhs == rhs); }
@@ -73,16 +88,13 @@ namespace units {
namespace std {
template<typename T, typename U>
struct common_type<my_value<T>, my_value<U>> : std::type_identity<my_value<common_type_t<T, U>>> {
};
struct common_type<my_value<T>, my_value<U>> : std::type_identity<my_value<common_type_t<T, U>>> {};
template<typename T, typename U>
struct common_type<my_value<T>, U> : common_type<T, U> {
};
struct common_type<my_value<T>, U> : common_type<T, U> {};
template<typename T, typename U>
struct common_type<T, my_value<U>> : common_type<T, U> {
};
struct common_type<T, my_value<U>> : common_type<T, U> {};
} // namespace std
@@ -93,82 +105,84 @@ namespace {
static_assert(std::convertible_to<float, my_value<float>>);
using namespace units;
using namespace units::si;
// class invariants
// constexpr quantity<length, second, int> q; // should a static_assert
// constexpr quantity<dim_length, metre, int> q(1); // should not compile
// constexpr quantity<length, metre, quantity<metre, int>> error(0m); // should trigger a static_assert
// constexpr quantity<int, int, double> error(0); // should trigger a static_assert
// constexpr quantity<length, unit<length, std::ratio<-1, 1>>, int> error(0); // should trigger a static_assert
// member types
static_assert(std::is_same_v<quantity<metre, int>::rep, int>);
static_assert(std::is_same_v<quantity<metre, double>::rep, double>);
static_assert(std::is_same_v<quantity<metre, int>::unit, metre>);
static_assert(std::is_same_v<quantity<kilometre, int>::unit, kilometre>);
static_assert(std::is_same_v<length<metre, int>::rep, int>);
static_assert(std::is_same_v<length<metre, double>::rep, double>);
static_assert(std::is_same_v<length<metre, int>::unit, metre>);
static_assert(std::is_same_v<length<kilometre, int>::unit, kilometre>);
// constructors
using my_int = my_value<int>;
using my_double = my_value<double>;
static_assert(quantity<metre, int>().count() == 0);
constexpr quantity<metre, int> km{1000};
static_assert(length<metre, int>().count() == 0);
constexpr length<metre, int> km{1000};
static_assert(km.count() == 1000);
static_assert(quantity<metre, int>(km).count() == km.count());
static_assert(length<metre, int>(km).count() == km.count());
static_assert(quantity<metre, int>(1).count() == 1);
static_assert(quantity<metre, int>(my_value(1)).count() == 1);
static_assert(quantity<metre, my_int>(1).count() == my_int{1});
// static_assert(quantity<metre, int>(1.0).count() == 1); // should not compile
// static_assert(quantity<metre, int>(my_value(1.0)).count() == 1); // should not compile
// static_assert(quantity<metre, my_value>(1.0).count() == 1); // should not compile
static_assert(quantity<metre, double>(1.0).count() == 1.0);
static_assert(quantity<metre, double>(my_value(1.0)).count() == 1.0);
static_assert(quantity<metre, double>(1).count() == 1.0);
static_assert(quantity<metre, double>(my_value(1)).count() == 1.0);
static_assert(quantity<metre, double>(3.14).count() == 3.14);
static_assert(quantity<metre, my_double>(1.0).count() == my_double{1.0});
static_assert(quantity<metre, my_double>(1).count() == my_double{1.0});
static_assert(quantity<metre, my_double>(3.14).count() == my_double{3.14});
static_assert(length<metre, int>(1).count() == 1);
static_assert(length<metre, int>(my_value(1)).count() == 1);
static_assert(length<metre, my_int>(1).count() == my_int{1});
// static_assert(length<metre, int>(1.0).count() == 1); // should not compile
// static_assert(length<metre, int>(my_value(1.0)).count() == 1); // should not compile
// static_assert(length<metre, my_value>(1.0).count() == 1); // should not compile
static_assert(length<metre, double>(1.0).count() == 1.0);
static_assert(length<metre, double>(my_value(1.0)).count() == 1.0);
static_assert(length<metre, double>(1).count() == 1.0);
static_assert(length<metre, double>(my_value(1)).count() == 1.0);
static_assert(length<metre, double>(3.14).count() == 3.14);
static_assert(length<metre, my_double>(1.0).count() == my_double{1.0});
static_assert(length<metre, my_double>(1).count() == my_double{1.0});
static_assert(length<metre, my_double>(3.14).count() == my_double{3.14});
static_assert(quantity<metre, int>(km).count() == 1000);
// static_assert(quantity<metre, int>(quantity<metre, double>(3.14)).count() == 3); // should not compile
static_assert(quantity<metre, int>(quantity_cast<quantity<metre, my_int>>(3.14m)).count() == 3);
// static_assert(quantity<metre, int>(quantity<metre, my_double>(1000.0)).count() == 1000); // should not compile
// static_assert(quantity<metre, my_value>(1000.0m).count() == 1000); // should not compile
static_assert(quantity<metre, double>(1000.0m).count() == 1000.0);
static_assert(quantity<metre, double>(quantity<metre, my_double>(1000.0)).count() == 1000.0);
static_assert(quantity<metre, my_double>(1000.0m).count() == my_double{1000.0});
static_assert(quantity<metre, double>(km).count() == 1000.0);
static_assert(quantity<metre, my_double>(km).count() == my_double{1000.0});
static_assert(quantity<metre, int>(1km).count() == 1000);
// static_assert(quantity<metre, int>(1_s).count() == 1); // should not compile
// static_assert(quantity<kilometre, int>(1010m).count() == 1); // should not compile
static_assert(quantity<kilometre, int>(quantity_cast<quantity<kilometre, my_int>>(1010m)).count() == 1);
static_assert(length<metre, int>(km).count() == 1000);
// static_assert(length<metre, int>(length<metre, double>(3.14)).count() == 3); // should not compile
static_assert(length<metre, int>(quantity_cast<length<metre, my_int>>(3.14m)).count() == 3);
// static_assert(length<metre, int>(length<metre, my_double>(1000.0)).count() == 1000); // should not compile
// static_assert(length<metre, my_value>(1000.0m).count() == 1000); // should not compile
static_assert(length<metre, double>(1000.0m).count() == 1000.0);
static_assert(length<metre, double>(length<metre, my_double>(1000.0)).count() == 1000.0);
static_assert(length<metre, my_double>(1000.0m).count() == my_double{1000.0});
static_assert(length<metre, double>(km).count() == 1000.0);
static_assert(length<metre, my_double>(km).count() == my_double{1000.0});
static_assert(length<metre, int>(1km).count() == 1000);
// static_assert(length<metre, int>(1_s).count() == 1); // should not compile
// static_assert(length<kilometre, int>(1010m).count() == 1); // should not compile
static_assert(length<kilometre, int>(quantity_cast<length<kilometre, my_int>>(1010m)).count() == 1);
// assignment operator
static_assert([]() {
quantity<metre, int> l1(1), l2(2);
length<metre, int> l1(1), l2(2);
return l2 = l1;
}().count() == 1);
}()
.count() == 1);
// static member functions
static_assert(quantity<metre, int>::zero().count() == 0);
static_assert(quantity<metre, int>::min().count() == std::numeric_limits<int>::lowest());
static_assert(quantity<metre, int>::max().count() == std::numeric_limits<int>::max());
static_assert(quantity<metre, double>::zero().count() == 0.0);
static_assert(quantity<metre, double>::min().count() == std::numeric_limits<double>::lowest());
static_assert(quantity<metre, double>::max().count() == std::numeric_limits<double>::max());
static_assert(quantity<metre, my_int>::zero().count() == my_int{0});
static_assert(quantity<metre, my_int>::min().count() == my_int{std::numeric_limits<int>::lowest()});
static_assert(quantity<metre, my_int>::max().count() == my_int{std::numeric_limits<int>::max()});
static_assert(quantity<metre, my_double>::zero().count() == my_double{0.0});
static_assert(quantity<metre, my_double>::min().count() == my_double{std::numeric_limits<double>::lowest()});
static_assert(quantity<metre, my_double>::max().count() == my_double{std::numeric_limits<double>::max()});
static_assert(length<metre, int>::zero().count() == 0);
static_assert(length<metre, int>::min().count() == std::numeric_limits<int>::lowest());
static_assert(length<metre, int>::max().count() == std::numeric_limits<int>::max());
static_assert(length<metre, double>::zero().count() == 0.0);
static_assert(length<metre, double>::min().count() == std::numeric_limits<double>::lowest());
static_assert(length<metre, double>::max().count() == std::numeric_limits<double>::max());
static_assert(length<metre, my_int>::zero().count() == my_int{0});
static_assert(length<metre, my_int>::min().count() == my_int{std::numeric_limits<int>::lowest()});
static_assert(length<metre, my_int>::max().count() == my_int{std::numeric_limits<int>::max()});
static_assert(length<metre, my_double>::zero().count() == my_double{0.0});
static_assert(length<metre, my_double>::min().count() == my_double{std::numeric_limits<double>::lowest()});
static_assert(length<metre, my_double>::max().count() == my_double{std::numeric_limits<double>::max()});
// unary member operators
@@ -182,19 +196,19 @@ namespace {
static_assert([](auto v) {
auto vv = v++;
return std::make_pair(v, vv);
}(km) == std::make_pair(quantity<metre, int>(1001), quantity<metre, int>(1000)));
}(km) == std::make_pair(length<metre, int>(1001), length<metre, int>(1000)));
static_assert([](auto v) {
auto vv = ++v;
return std::make_pair(v, vv);
}(km) == std::make_pair(quantity<metre, int>(1001), quantity<metre, int>(1001)));
}(km) == std::make_pair(length<metre, int>(1001), length<metre, int>(1001)));
static_assert([](auto v) {
auto vv = v--;
return std::make_pair(v, vv);
}(km) == std::make_pair(quantity<metre, int>(999), quantity<metre, int>(1000)));
}(km) == std::make_pair(length<metre, int>(999), length<metre, int>(1000)));
static_assert([](auto v) {
auto vv = --v;
return std::make_pair(v, vv);
}(km) == std::make_pair(quantity<metre, int>(999), quantity<metre, int>(999)));
}(km) == std::make_pair(length<metre, int>(999), length<metre, int>(999)));
// compound assignment
@@ -214,21 +228,26 @@ namespace {
// non-member arithmetic operators
static_assert(std::is_same_v<decltype(quantity<metre, int>() + quantity<metre, double>()), quantity<metre, double>>);
static_assert(std::is_same_v<decltype(quantity<metre, int>() + quantity<metre, double>()), quantity<metre, double>>);
static_assert(std::is_same_v<decltype(quantity<kilometre, int>() + quantity<metre, double>()), quantity<metre, double>>);
static_assert(std::is_same_v<decltype(quantity<metre, double>() - quantity<metre, int>()), quantity<metre, double>>);
static_assert(std::is_same_v<decltype(quantity<kilometre, double>() - quantity<metre, int>()), quantity<metre, double>>);
static_assert(std::is_same_v<decltype(quantity<metre, int>() * 1.0), quantity<metre, double>>);
static_assert(std::is_same_v<decltype(1.0 * quantity<metre, int>()), quantity<metre, double>>);
static_assert(std::is_same_v<decltype(quantity<metre_per_second, int>() * quantity<second, int>()), quantity<metre, int>>);
static_assert(std::is_same_v<decltype(1 / quantity<second, int>()), quantity<hertz, int>>);
static_assert(std::is_same_v<decltype(quantity<metre, int>() / 1.0), quantity<metre, double>>);
static_assert(std::is_same_v<decltype(quantity<metre, int>() / quantity<metre, double>()), double>);
static_assert(std::is_same_v<decltype(quantity<kilometre, int>() / quantity<metre, double>()), double>);
static_assert(std::is_same_v<decltype(quantity<metre, int>() / quantity<second, int>()), quantity<metre_per_second, int>>);
static_assert(std::is_same_v<decltype(quantity<metre, int>() % short(1)), quantity<metre, int>>);
static_assert(std::is_same_v<decltype(quantity<metre, int>() % quantity<metre, short>(1)), quantity<metre, int>>);
static_assert(std::is_same_v<decltype(length<metre, int>() + length<metre, double>()), length<metre, double>>);
static_assert(std::is_same_v<decltype(length<metre, int>() + length<metre, double>()), length<metre, double>>);
static_assert(
std::is_same_v<decltype(length<kilometre, int>() + length<metre, double>()), length<metre, double>>);
static_assert(std::is_same_v<decltype(length<metre, double>() - length<metre, int>()), length<metre, double>>);
static_assert(
std::is_same_v<decltype(length<kilometre, double>() - length<metre, int>()), length<metre, double>>);
static_assert(std::is_same_v<decltype(length<metre, int>() * 1.0), length<metre, double>>);
static_assert(std::is_same_v<decltype(1.0 * length<metre, int>()), length<metre, double>>);
static_assert(
std::is_same_v<decltype(velocity<metre_per_second, int>() * si::time<second, int>()), length<metre, int>>);
static_assert(std::is_same_v<decltype(1 / si::time<second, int>()), frequency<hertz, int>>);
static_assert(std::is_same_v<decltype(1 / frequency<hertz, int>()), si::time<second, int>>);
static_assert(std::is_same_v<decltype(length<metre, int>() / 1.0), length<metre, double>>);
static_assert(std::is_same_v<decltype(length<metre, int>() / length<metre, double>()), double>);
static_assert(std::is_same_v<decltype(length<kilometre, int>() / length<metre, double>()), double>);
static_assert(
std::is_same_v<decltype(length<metre, int>() / si::time<second, int>()), velocity<metre_per_second, int>>);
static_assert(std::is_same_v<decltype(length<metre, int>() % short(1)), length<metre, int>>);
static_assert(std::is_same_v<decltype(length<metre, int>() % length<metre, short>(1)), length<metre, int>>);
static_assert((1m + km).count() == 1001);
static_assert((1m + 1km).count() == 1001);
@@ -276,22 +295,23 @@ namespace {
// is_quantity
static_assert(Quantity<quantity<millimetre, int>>);
static_assert(Quantity<length<millimetre, int>>);
// common_quantity
static_assert(std::is_same_v<common_quantity<quantity<metre, int>, quantity<kilometre, int>>, quantity<metre, int>>);
static_assert(std::is_same_v<common_quantity<quantity<kilometre, long long>, quantity<metre, int>>, quantity<metre, long long>>);
static_assert(std::is_same_v<common_quantity<quantity<kilometre, long long>, quantity<millimetre, double>>, quantity<millimetre, double>>);
static_assert(std::is_same_v<common_quantity<length<metre, int>, length<kilometre, int>>, length<metre, int>>);
static_assert(
std::is_same_v<common_quantity<length<kilometre, long long>, length<metre, int>>, length<metre, long long>>);
static_assert(std::is_same_v<common_quantity<length<kilometre, long long>, length<millimetre, double>>,
length<millimetre, double>>);
// quantity_cast
static_assert(std::is_same_v<decltype(quantity_cast<unit<length, ratio<1>>>(2km))::unit, metre>);
static_assert(std::is_same_v<decltype(quantity_cast<unit<dimension<units::exp<base_dim_length, 1>>, ratio<1>>>(2km))::unit, metre>);
static_assert(std::is_same_v<decltype(quantity_cast<detail::reference_unit<metre, ratio<1>>>(2km))::unit, metre>);
// static_assert(quantity_cast<int>(2km).count() == 2000); // should not compile
static_assert(quantity_cast<quantity<metre, int>>(2km).count() == 2000);
static_assert(quantity_cast<quantity<kilometre, int>>(2000m).count() == 2);
static_assert(quantity_cast<length<metre, int>>(2km).count() == 2000);
static_assert(quantity_cast<length<kilometre, int>>(2000m).count() == 2);
// time