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

File diff suppressed because it is too large Load Diff

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,299 +20,319 @@
// 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;
namespace {
template<typename T>
class my_value {
T value_{};
public:
my_value() = default;
constexpr my_value(T v) : value_(std::move(v)) {}
[[nodiscard]] constexpr my_value operator-() const { return my_value(-value_); }
template<typename T>
class my_value {
T 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_); }
public:
my_value() = default;
constexpr my_value(T v) : value_(std::move(v)) {}
[[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); }
[[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 rhs < lhs; }
[[nodiscard]] friend constexpr bool operator<=(my_value lhs, my_value rhs) { return !(rhs < lhs); }
[[nodiscard]] friend constexpr bool operator>=(my_value lhs, my_value rhs) { return !(lhs < rhs); }
// 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; }
constexpr operator const T&() const & { return value_; }
};
[[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 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); }
[[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 rhs < lhs; }
[[nodiscard]] friend constexpr bool operator<=(my_value lhs, my_value rhs) { return !(rhs < lhs); }
[[nodiscard]] friend constexpr bool operator>=(my_value lhs, my_value rhs) { return !(lhs < rhs); }
constexpr operator const T&() const& { return value_; }
};
} // namespace
namespace units {
template<typename T>
inline constexpr bool treat_as_floating_point<my_value<T>> = std::is_floating_point_v<T>;
template<typename T>
inline constexpr bool treat_as_floating_point<my_value<T>> = std::is_floating_point_v<T>;
template<typename T>
struct quantity_values<my_value<T>> {
static constexpr my_value<T> zero() { return my_value<T>(0); }
static constexpr my_value<T> max() { return std::numeric_limits<T>::max(); }
static constexpr my_value<T> min() { return std::numeric_limits<T>::lowest(); }
};
template<typename T>
struct quantity_values<my_value<T>> {
static constexpr my_value<T> zero() { return my_value<T>(0); }
static constexpr my_value<T> max() { return std::numeric_limits<T>::max(); }
static constexpr my_value<T> min() { return std::numeric_limits<T>::lowest(); }
};
} // 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>>> {
};
template<typename T, typename 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> {
};
template<typename T, typename 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> {
};
template<typename T, typename U>
struct common_type<T, my_value<U>> : common_type<T, U> {};
} // namespace std
namespace {
static_assert(units::Scalar<my_value<float>>);
static_assert(std::convertible_to<my_value<float>, float>);
static_assert(std::convertible_to<float, my_value<float>>);
static_assert(units::Scalar<my_value<float>>);
static_assert(std::convertible_to<my_value<float>, float>);
static_assert(std::convertible_to<float, my_value<float>>);
using namespace units;
using namespace units;
using namespace units::si;
// class invariants
// class invariants
// constexpr quantity<length, second, int> q; // should a static_assert
// 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
// 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
// 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
// constructors
using my_int = my_value<int>;
using my_double = my_value<double>;
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(km.count() == 1000);
static_assert(quantity<metre, int>(km).count() == km.count());
static_assert(length<metre, int>().count() == 0);
constexpr length<metre, int> km{1000};
static_assert(km.count() == 1000);
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
// assignment operator
static_assert([]() {
quantity<metre, int> l1(1), l2(2);
return l2 = l1;
}().count() == 1);
static_assert([]() {
length<metre, int> l1(1), l2(2);
return l2 = l1;
}()
.count() == 1);
// static member functions
// 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
// unary member operators
static_assert((+km).count() == 1000);
static_assert((-km).count() == -1000);
static_assert((+(-km)).count() == -1000);
static_assert((-(-km)).count() == 1000);
static_assert((+km).count() == 1000);
static_assert((-km).count() == -1000);
static_assert((+(-km)).count() == -1000);
static_assert((-(-km)).count() == 1000);
// binary member operators
// binary member operators
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)));
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)));
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)));
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)));
static_assert([](auto v) {
auto vv = v++;
return std::make_pair(v, vv);
}(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(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(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(length<metre, int>(999), length<metre, int>(999)));
// compound assignment
// compound assignment
static_assert((1m += 1m).count() == 2);
static_assert((2m -= 1m).count() == 1);
static_assert((1m *= 2).count() == 2);
static_assert((2m /= 2).count() == 1);
static_assert((7m %= 2).count() == 1);
static_assert((7m %= 2m).count() == 1);
static_assert((1m += 1m).count() == 2);
static_assert((2m -= 1m).count() == 1);
static_assert((1m *= 2).count() == 2);
static_assert((2m /= 2).count() == 1);
static_assert((7m %= 2).count() == 1);
static_assert((7m %= 2m).count() == 1);
// static_assert((7.m %= 2.).count() == 1); // should not compile
// static_assert((7.m %= 2).count() == 1); // should not compile
// static_assert((7m %= 2.).count() == 1); // should not compile
static_assert((7m %= 2m).count() == 1);
static_assert((7m %= 2m).count() == 1);
// static_assert((7.m %= 2.m).count() == 1); // should not compile
// static_assert((7.m %= 2m).count() == 1); // should not compile
// static_assert((7m %= 2.m).count() == 1); // should not compile
// non-member arithmetic operators
// 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);
static_assert((km - 1m).count() == 999);
static_assert((1km - 1m).count() == 999);
static_assert((2m * 2).count() == 4);
static_assert((3 * 3m).count() == 9);
static_assert((4m / 2).count() == 2);
static_assert(4m / 2m == 2);
static_assert(4km / 2000m == 2);
static_assert((7m % 2).count() == 1);
static_assert((7m % 2m).count() == 1);
static_assert((7km % 2000m).count() == 1000);
static_assert((1m + km).count() == 1001);
static_assert((1m + 1km).count() == 1001);
static_assert((km - 1m).count() == 999);
static_assert((1km - 1m).count() == 999);
static_assert((2m * 2).count() == 4);
static_assert((3 * 3m).count() == 9);
static_assert((4m / 2).count() == 2);
static_assert(4m / 2m == 2);
static_assert(4km / 2000m == 2);
static_assert((7m % 2).count() == 1);
static_assert((7m % 2m).count() == 1);
static_assert((7km % 2000m).count() == 1000);
// comparators
// comparators
static_assert(2m + 1m == 3m);
static_assert(!(2m + 2m == 3m));
static_assert(2m + 2m != 3m);
static_assert(!(2m + 2m != 4m));
static_assert(2m > 1m);
static_assert(!(1m > 1m));
static_assert(1m < 2m);
static_assert(!(2m < 2m));
static_assert(2m >= 1m);
static_assert(2m >= 2m);
static_assert(!(2m >= 3m));
static_assert(1m <= 2m);
static_assert(2m <= 2m);
static_assert(!(3m <= 2m));
static_assert(2m + 1m == 3m);
static_assert(!(2m + 2m == 3m));
static_assert(2m + 2m != 3m);
static_assert(!(2m + 2m != 4m));
static_assert(2m > 1m);
static_assert(!(1m > 1m));
static_assert(1m < 2m);
static_assert(!(2m < 2m));
static_assert(2m >= 1m);
static_assert(2m >= 2m);
static_assert(!(2m >= 3m));
static_assert(1m <= 2m);
static_assert(2m <= 2m);
static_assert(!(3m <= 2m));
static_assert(3m == 3.0m);
static_assert(3m != 3.14m);
static_assert(2m > 1.0m);
static_assert(1.0m < 2m);
static_assert(2.0m >= 1m);
static_assert(1m <= 2.0m);
static_assert(3m == 3.0m);
static_assert(3m != 3.14m);
static_assert(2m > 1.0m);
static_assert(1.0m < 2m);
static_assert(2.0m >= 1m);
static_assert(1m <= 2.0m);
static_assert(1000m == 1km);
static_assert(1001m != 1km);
static_assert(1001m > 1km);
static_assert(999m < 1km);
static_assert(1000m >= 1km);
static_assert(1000m <= 1km);
static_assert(1000m == 1km);
static_assert(1001m != 1km);
static_assert(1001m > 1km);
static_assert(999m < 1km);
static_assert(1000m >= 1km);
static_assert(1000m <= 1km);
// is_quantity
// is_quantity
static_assert(Quantity<quantity<millimetre, int>>);
static_assert(Quantity<length<millimetre, int>>);
// common_quantity
// 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
// 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<int>(2km).count() == 2000); // should not compile
static_assert(quantity_cast<length<metre, int>>(2km).count() == 2000);
static_assert(quantity_cast<length<kilometre, int>>(2000m).count() == 2);
// time
// time
// static_assert(1s == 1m); // should not compile
static_assert(1h == 3600s);
// static_assert(1s == 1m); // should not compile
static_assert(1h == 3600s);
// length
// length
static_assert(1km == 1000m);
static_assert(1km + 1m == 1001m);
static_assert(10km / 5km == 2);
static_assert(10km / 2 == 5km);
static_assert(1km == 1000m);
static_assert(1km + 1m == 1001m);
static_assert(10km / 5km == 2);
static_assert(10km / 2 == 5km);
// velocity
// velocity
static_assert(10m / 5s == 2mps);
static_assert(10 / 5s * 1m == 2mps);
static_assert(1km / 1s == 1000mps);
static_assert(2kmph * 2h == 4km);
static_assert(2km / 2kmph == 1h);
static_assert(10m / 5s == 2mps);
static_assert(10 / 5s * 1m == 2mps);
static_assert(1km / 1s == 1000mps);
static_assert(2kmph * 2h == 4km);
static_assert(2km / 2kmph == 1h);
static_assert(std::is_same_v<decltype(pow<2>(2m)), decltype(4sq_m)>);
static_assert(std::is_same_v<decltype(pow<2>(2m)), decltype(4sq_m)>);
} // namespace