#pragma once
#ifdef _MSC_VER
# pragma push_macro("pascal")
# undef pascal
# if _MSC_VER <= 1800
# define _ALLOW_KEYWORD_MACROS
# pragma warning(push)
# pragma warning(disable : 4520)
# pragma push_macro("constexpr")
# define constexpr
# pragma push_macro("noexcept")
# define noexcept throw()
# endif #endif
#if !defined(_MSC_VER) || _MSC_VER > 1800
# define UNIT_HAS_LITERAL_SUPPORT
#endif
#ifndef UNIT_LIB_DEFAULT_TYPE
# define UNIT_LIB_DEFAULT_TYPE double
#endif
#include <chrono>
#include <ratio>
#include <type_traits>
#include <cstdint>
#include <cmath>
#include <limits>
#if defined(UNIT_LIB_ENABLE_IOSTREAM)
#include <iostream>
#include <locale>
#include <string>
#endif
#if __has_include(<fmt/format.h>) && !defined(UNIT_LIB_DISABLE_FMT)
#include <locale>
#include <string>
#include <fmt/format.h>
#endif
#include <gcem.hpp>
namespace units
{
namespace detail
{
template <typename T> std::string to_string(const T& t)
{
std::string str{ std::to_string(t) };
int offset{ 1 };
struct lconv * lc;
lc = localeconv();
char decimalPoint = *lc->decimal_point;
if (str.find_last_not_of('0') == str.find(decimalPoint)) { offset = 0; }
str.erase(str.find_last_not_of('0') + offset, std::string::npos);
return str;
}
}
}
namespace units
{
template<typename T> constexpr const char* name(const T&);
template<typename T> constexpr const char* abbreviation(const T&);
}
#define UNIT_ADD_UNIT_TAGS(namespaceName,nameSingular, namePlural, abbreviation, ...)\
namespace namespaceName\
{\
typedef __VA_ARGS__ namePlural; \
typedef namePlural nameSingular; \
typedef namePlural abbreviation; \
}
#define UNIT_ADD_UNIT_DEFINITION(namespaceName,nameSingular)\
namespace namespaceName\
{\
typedef unit_t<nameSingular> nameSingular ## _t; \
}
#define UNIT_ADD_CUSTOM_TYPE_UNIT_DEFINITION(namespaceName,nameSingular, underlyingType)\
namespace namespaceName\
{\
typedef unit_t<nameSingular,underlyingType> nameSingular ## _t; \
}
#if __has_include(<fmt/format.h>) && !defined(UNIT_LIB_DISABLE_FMT)
#define UNIT_ADD_IO(namespaceName, nameSingular, abbrev)\
}\
template <>\
struct fmt::formatter<units::namespaceName::nameSingular ## _t> \
: fmt::formatter<double> \
{\
template <typename FmtContext>\
auto format(\
const units::namespaceName::nameSingular ## _t& obj,\
FmtContext& ctx) const\
{\
auto out = ctx.out();\
out = fmt::formatter<double>::format(obj(), ctx);\
return fmt::format_to(out, " " #abbrev);\
}\
};\
namespace units\
{\
namespace namespaceName\
{\
inline std::string to_string(const nameSingular ## _t& obj)\
{\
return units::detail::to_string(obj()) + std::string(" "#abbrev);\
}\
}
#elif defined(UNIT_LIB_ENABLE_IOSTREAM)
#define UNIT_ADD_IO(namespaceName, nameSingular, abbrev)\
namespace namespaceName\
{\
inline std::ostream& operator<<(std::ostream& os, const nameSingular ## _t& obj) \
{\
os << obj() << " "#abbrev; return os; \
}\
inline std::string to_string(const nameSingular ## _t& obj)\
{\
return units::detail::to_string(obj()) + std::string(" "#abbrev);\
}\
}
#else
#define UNIT_ADD_IO(namespaceName, nameSingular, abbrev)
#endif
#define UNIT_ADD_NAME(namespaceName, nameSingular, abbrev)\
template<> constexpr const char* name(const namespaceName::nameSingular ## _t&)\
{\
return #nameSingular;\
}\
template<> constexpr const char* abbreviation(const namespaceName::nameSingular ## _t&)\
{\
return #abbrev;\
}
#if defined(UNIT_HAS_LITERAL_SUPPORT)
#define UNIT_ADD_LITERALS(namespaceName, nameSingular, abbreviation)\
namespace literals\
{\
constexpr namespaceName::nameSingular ## _t operator""_ ## abbreviation(long double d)\
{\
return namespaceName::nameSingular ## _t(static_cast<namespaceName::nameSingular ## _t::underlying_type>(d));\
}\
constexpr namespaceName::nameSingular ## _t operator""_ ## abbreviation (unsigned long long d)\
{\
return namespaceName::nameSingular ## _t(static_cast<namespaceName::nameSingular ## _t::underlying_type>(d));\
}\
}
#else
#define UNIT_ADD_LITERALS(namespaceName, nameSingular, abbreviation)
#endif
#define UNIT_ADD(namespaceName, nameSingular, namePlural, abbreviation, ...)\
UNIT_ADD_UNIT_TAGS(namespaceName,nameSingular, namePlural, abbreviation, __VA_ARGS__)\
UNIT_ADD_UNIT_DEFINITION(namespaceName,nameSingular)\
UNIT_ADD_NAME(namespaceName,nameSingular, abbreviation)\
UNIT_ADD_IO(namespaceName,nameSingular, abbreviation)\
UNIT_ADD_LITERALS(namespaceName,nameSingular, abbreviation)
#define UNIT_ADD_WITH_CUSTOM_TYPE(namespaceName, nameSingular, namePlural, abbreviation, underlyingType, ...)\
UNIT_ADD_UNIT_TAGS(namespaceName,nameSingular, namePlural, abbreviation, __VA_ARGS__)\
UNIT_ADD_CUSTOM_TYPE_UNIT_DEFINITION(namespaceName,nameSingular,underlyingType)\
UNIT_ADD_IO(namespaceName,nameSingular, abbreviation)\
UNIT_ADD_LITERALS(namespaceName,nameSingular, abbreviation)
#define UNIT_ADD_DECIBEL(namespaceName, nameSingular, abbreviation)\
namespace namespaceName\
{\
typedef unit_t<nameSingular, UNIT_LIB_DEFAULT_TYPE, units::decibel_scale> abbreviation ## _t; \
}\
UNIT_ADD_IO(namespaceName, abbreviation, abbreviation)\
UNIT_ADD_LITERALS(namespaceName, abbreviation, abbreviation)
#define UNIT_ADD_CATEGORY_TRAIT_DETAIL(unitCategory)\
namespace traits\
{\
\
namespace detail\
{\
template<typename T> struct is_ ## unitCategory ## _unit_impl : std::false_type {};\
template<typename C, typename U, typename P, typename T>\
struct is_ ## unitCategory ## _unit_impl<units::unit<C, U, P, T>> : std::is_same<units::traits::base_unit_of<typename units::traits::unit_traits<units::unit<C, U, P, T>>::base_unit_type>, units::category::unitCategory ## _unit>::type {};\
template<typename U, typename S, template<typename> class N>\
struct is_ ## unitCategory ## _unit_impl<units::unit_t<U, S, N>> : std::is_same<units::traits::base_unit_of<typename units::traits::unit_t_traits<units::unit_t<U, S, N>>::unit_type>, units::category::unitCategory ## _unit>::type {};\
}\
\
}
#define UNIT_ADD_IS_UNIT_CATEGORY_TRAIT(unitCategory)\
namespace traits\
{\
template<typename... T> struct is_ ## unitCategory ## _unit : std::integral_constant<bool, units::all_true<units::traits::detail::is_ ## unitCategory ## _unit_impl<std::decay_t<T>>::value...>::value> {};\
template<typename... T> constexpr bool is_ ## unitCategory ## _unit_v = is_ ## unitCategory ## _unit<T...>::value;\
}\
template <typename T>\
concept unitCategory ## _unit = traits::is_ ## unitCategory ## _unit_v<T>;
#define UNIT_ADD_CATEGORY_TRAIT(unitCategory)\
UNIT_ADD_CATEGORY_TRAIT_DETAIL(unitCategory)\
\
\
\
\
UNIT_ADD_IS_UNIT_CATEGORY_TRAIT(unitCategory)
#define UNIT_ADD_WITH_METRIC_PREFIXES(namespaceName, nameSingular, namePlural, abbreviation, ...)\
UNIT_ADD(namespaceName, nameSingular, namePlural, abbreviation, __VA_ARGS__)\
UNIT_ADD(namespaceName, femto ## nameSingular, femto ## namePlural, f ## abbreviation, femto<namePlural>)\
UNIT_ADD(namespaceName, pico ## nameSingular, pico ## namePlural, p ## abbreviation, pico<namePlural>)\
UNIT_ADD(namespaceName, nano ## nameSingular, nano ## namePlural, n ## abbreviation, nano<namePlural>)\
UNIT_ADD(namespaceName, micro ## nameSingular, micro ## namePlural, u ## abbreviation, micro<namePlural>)\
UNIT_ADD(namespaceName, milli ## nameSingular, milli ## namePlural, m ## abbreviation, milli<namePlural>)\
UNIT_ADD(namespaceName, centi ## nameSingular, centi ## namePlural, c ## abbreviation, centi<namePlural>)\
UNIT_ADD(namespaceName, deci ## nameSingular, deci ## namePlural, d ## abbreviation, deci<namePlural>)\
UNIT_ADD(namespaceName, deca ## nameSingular, deca ## namePlural, da ## abbreviation, deca<namePlural>)\
UNIT_ADD(namespaceName, hecto ## nameSingular, hecto ## namePlural, h ## abbreviation, hecto<namePlural>)\
UNIT_ADD(namespaceName, kilo ## nameSingular, kilo ## namePlural, k ## abbreviation, kilo<namePlural>)\
UNIT_ADD(namespaceName, mega ## nameSingular, mega ## namePlural, M ## abbreviation, mega<namePlural>)\
UNIT_ADD(namespaceName, giga ## nameSingular, giga ## namePlural, G ## abbreviation, giga<namePlural>)\
UNIT_ADD(namespaceName, tera ## nameSingular, tera ## namePlural, T ## abbreviation, tera<namePlural>)\
UNIT_ADD(namespaceName, peta ## nameSingular, peta ## namePlural, P ## abbreviation, peta<namePlural>)\
#define UNIT_ADD_WITH_METRIC_AND_BINARY_PREFIXES(namespaceName, nameSingular, namePlural, abbreviation, ...)\
UNIT_ADD_WITH_METRIC_PREFIXES(namespaceName, nameSingular, namePlural, abbreviation, __VA_ARGS__)\
UNIT_ADD(namespaceName, kibi ## nameSingular, kibi ## namePlural, Ki ## abbreviation, kibi<namePlural>)\
UNIT_ADD(namespaceName, mebi ## nameSingular, mebi ## namePlural, Mi ## abbreviation, mebi<namePlural>)\
UNIT_ADD(namespaceName, gibi ## nameSingular, gibi ## namePlural, Gi ## abbreviation, gibi<namePlural>)\
UNIT_ADD(namespaceName, tebi ## nameSingular, tebi ## namePlural, Ti ## abbreviation, tebi<namePlural>)\
UNIT_ADD(namespaceName, pebi ## nameSingular, pebi ## namePlural, Pi ## abbreviation, pebi<namePlural>)\
UNIT_ADD(namespaceName, exbi ## nameSingular, exbi ## namePlural, Ei ## abbreviation, exbi<namePlural>)
namespace units
{
namespace constants
{
namespace detail
{
static constexpr const UNIT_LIB_DEFAULT_TYPE PI_VAL = 3.14159265358979323846264338327950288419716939937510;
}
}
namespace detail
{
template<class T>
struct has_num_impl
{
template<class U>
static constexpr auto test(U*)->std::is_integral<decltype(U::num)> {return std::is_integral<decltype(U::num)>{}; }
template<typename>
static constexpr std::false_type test(...) { return std::false_type{}; }
using type = decltype(test<T>(0));
};
}
template<class T>
struct has_num : units::detail::has_num_impl<T>::type {};
namespace detail
{
template<class T>
struct has_den_impl
{
template<class U>
static constexpr auto test(U*)->std::is_integral<decltype(U::den)> { return std::is_integral<decltype(U::den)>{}; }
template<typename>
static constexpr std::false_type test(...) { return std::false_type{}; }
using type = decltype(test<T>(0));
};
}
template<class T>
struct has_den : units::detail::has_den_impl<T>::type {};
namespace traits
{
template<class T>
struct is_ratio : std::integral_constant<bool,
has_num<T>::value &&
has_den<T>::value>
{};
template<class T>
constexpr bool is_ratio_v = is_ratio<T>::value;
}
template<class ...>
struct void_t { typedef void type; };
template<bool...> struct bool_pack {};
template<bool... Args>
struct all_true : std::is_same<units::bool_pack<true, Args...>, units::bool_pack<Args..., true>> {};
template<bool... Args>
constexpr bool all_true_t_v = all_true<Args...>::type::value;
namespace traits
{
#ifdef FOR_DOXYGEN_PURPOSES_ONLY
template<class T>
struct unit_traits
{
typedef typename T::base_unit_type base_unit_type; typedef typename T::conversion_ratio conversion_ratio; typedef typename T::pi_exponent_ratio pi_exponent_ratio; typedef typename T::translation_ratio translation_ratio; };
#endif
template<class T, typename = void>
struct unit_traits
{
typedef void base_unit_type;
typedef void conversion_ratio;
typedef void pi_exponent_ratio;
typedef void translation_ratio;
};
template<class T>
struct unit_traits
<T, typename void_t<
typename T::base_unit_type,
typename T::conversion_ratio,
typename T::pi_exponent_ratio,
typename T::translation_ratio>::type>
{
typedef typename T::base_unit_type base_unit_type; typedef typename T::conversion_ratio conversion_ratio; typedef typename T::pi_exponent_ratio pi_exponent_ratio; typedef typename T::translation_ratio translation_ratio; };
}
namespace detail
{
struct _base_unit_t {};
}
namespace traits
{
template<class T>
struct is_base_unit : std::is_base_of<units::detail::_base_unit_t, T> {};
}
namespace detail
{
struct _unit {};
template<std::intmax_t Num, std::intmax_t Den = 1>
using meter_ratio = std::ratio<Num, Den>;
}
namespace traits
{
template<class T>
struct is_unit : std::is_base_of<units::detail::_unit, T>::type {};
template<class T>
constexpr bool is_unit_v = is_unit<T>::value;
}
template<class Meter = detail::meter_ratio<0>,
class Kilogram = std::ratio<0>,
class Second = std::ratio<0>,
class Radian = std::ratio<0>,
class Ampere = std::ratio<0>,
class Kelvin = std::ratio<0>,
class Mole = std::ratio<0>,
class Candela = std::ratio<0>,
class Byte = std::ratio<0>>
struct base_unit : units::detail::_base_unit_t
{
static_assert(traits::is_ratio<Meter>::value, "Template parameter `Meter` must be a `std::ratio` representing the exponent of meters the unit has");
static_assert(traits::is_ratio<Kilogram>::value, "Template parameter `Kilogram` must be a `std::ratio` representing the exponent of kilograms the unit has");
static_assert(traits::is_ratio<Second>::value, "Template parameter `Second` must be a `std::ratio` representing the exponent of seconds the unit has");
static_assert(traits::is_ratio<Ampere>::value, "Template parameter `Ampere` must be a `std::ratio` representing the exponent of amperes the unit has");
static_assert(traits::is_ratio<Kelvin>::value, "Template parameter `Kelvin` must be a `std::ratio` representing the exponent of kelvin the unit has");
static_assert(traits::is_ratio<Candela>::value, "Template parameter `Candela` must be a `std::ratio` representing the exponent of candelas the unit has");
static_assert(traits::is_ratio<Mole>::value, "Template parameter `Mole` must be a `std::ratio` representing the exponent of moles the unit has");
static_assert(traits::is_ratio<Radian>::value, "Template parameter `Radian` must be a `std::ratio` representing the exponent of radians the unit has");
static_assert(traits::is_ratio<Byte>::value, "Template parameter `Byte` must be a `std::ratio` representing the exponent of bytes the unit has");
typedef Meter meter_ratio;
typedef Kilogram kilogram_ratio;
typedef Second second_ratio;
typedef Radian radian_ratio;
typedef Ampere ampere_ratio;
typedef Kelvin kelvin_ratio;
typedef Mole mole_ratio;
typedef Candela candela_ratio;
typedef Byte byte_ratio;
};
namespace category
{
typedef base_unit<> scalar_unit; typedef base_unit<> dimensionless_unit;
typedef base_unit<detail::meter_ratio<1>> length_unit; typedef base_unit<detail::meter_ratio<0>, std::ratio<1>> mass_unit; typedef base_unit<detail::meter_ratio<0>, std::ratio<0>, std::ratio<1>> time_unit; typedef base_unit<detail::meter_ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>> angle_unit; typedef base_unit<detail::meter_ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>> current_unit; typedef base_unit<detail::meter_ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>> temperature_unit; typedef base_unit<detail::meter_ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>> substance_unit; typedef base_unit<detail::meter_ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>> luminous_intensity_unit;
typedef base_unit<detail::meter_ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<2>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>> solid_angle_unit; typedef base_unit<detail::meter_ratio<0>, std::ratio<0>, std::ratio<-1>> frequency_unit; typedef base_unit<detail::meter_ratio<1>, std::ratio<0>, std::ratio<-1>> velocity_unit; typedef base_unit<detail::meter_ratio<0>, std::ratio<0>, std::ratio<-1>, std::ratio<1>> angular_velocity_unit; typedef base_unit<detail::meter_ratio<1>, std::ratio<0>, std::ratio<-2>> acceleration_unit; typedef base_unit<detail::meter_ratio<0>, std::ratio<0>, std::ratio<-2>, std::ratio<1>> angular_acceleration_unit; typedef base_unit<detail::meter_ratio<0>, std::ratio<0>, std::ratio<-3>, std::ratio<1>> angular_jerk_unit; typedef base_unit<detail::meter_ratio<1>, std::ratio<1>, std::ratio<-2>> force_unit; typedef base_unit<detail::meter_ratio<-1>, std::ratio<1>, std::ratio<-2>> pressure_unit; typedef base_unit<detail::meter_ratio<0>, std::ratio<0>, std::ratio<1>, std::ratio<0>, std::ratio<1>> charge_unit; typedef base_unit<detail::meter_ratio<2>, std::ratio<1>, std::ratio<-2>> energy_unit; typedef base_unit<detail::meter_ratio<2>, std::ratio<1>, std::ratio<-3>> power_unit; typedef base_unit<detail::meter_ratio<2>, std::ratio<1>, std::ratio<-3>, std::ratio<0>, std::ratio<-1>> voltage_unit; typedef base_unit<detail::meter_ratio<-2>, std::ratio<-1>, std::ratio<4>, std::ratio<0>, std::ratio<2>> capacitance_unit; typedef base_unit<detail::meter_ratio<2>, std::ratio<1>, std::ratio<-3>, std::ratio<0>, std::ratio<-2>> impedance_unit; typedef base_unit<detail::meter_ratio<-2>, std::ratio<-1>, std::ratio<3>, std::ratio<0>, std::ratio<2>> conductance_unit; typedef base_unit<detail::meter_ratio<2>, std::ratio<1>, std::ratio<-2>, std::ratio<0>, std::ratio<-1>> magnetic_flux_unit; typedef base_unit<detail::meter_ratio<0>, std::ratio<1>, std::ratio<-2>, std::ratio<0>, std::ratio<-1>> magnetic_field_strength_unit; typedef base_unit<detail::meter_ratio<2>, std::ratio<1>, std::ratio<-2>, std::ratio<0>, std::ratio<-2>> inductance_unit; typedef base_unit<detail::meter_ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<2>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>> luminous_flux_unit; typedef base_unit<detail::meter_ratio<-2>, std::ratio<0>, std::ratio<0>, std::ratio<2>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>> illuminance_unit; typedef base_unit<detail::meter_ratio<0>, std::ratio<0>, std::ratio<-1>> radioactivity_unit;
typedef base_unit<detail::meter_ratio<2>, std::ratio<1>, std::ratio<-2>> torque_unit; typedef base_unit<detail::meter_ratio<2>> area_unit; typedef base_unit<detail::meter_ratio<3>> volume_unit; typedef base_unit<detail::meter_ratio<-3>, std::ratio<1>> density_unit; typedef base_unit<> concentration_unit; typedef base_unit<detail::meter_ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>> data_unit; typedef base_unit<detail::meter_ratio<0>, std::ratio<0>, std::ratio<-1>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>> data_transfer_rate_unit; }
template <class, class, class, class> struct unit;
template<class Conversion, class... Exponents, class PiExponent, class Translation>
struct unit<Conversion, base_unit<Exponents...>, PiExponent, Translation> : units::detail::_unit
{
static_assert(traits::is_ratio<Conversion>::value, "Template parameter `Conversion` must be a `std::ratio` representing the conversion factor to `BaseUnit`.");
static_assert(traits::is_ratio<PiExponent>::value, "Template parameter `PiExponent` must be a `std::ratio` representing the exponents of Pi the unit has.");
static_assert(traits::is_ratio<Translation>::value, "Template parameter `Translation` must be a `std::ratio` representing an additive translation required by the unit conversion.");
typedef typename units::base_unit<Exponents...> base_unit_type;
typedef Conversion conversion_ratio;
typedef Translation translation_ratio;
typedef PiExponent pi_exponent_ratio;
};
template<class Conversion, class BaseUnit, class PiExponent = std::ratio<0>, class Translation = std::ratio<0>>
struct unit : units::detail::_unit
{
static_assert(traits::is_unit<BaseUnit>::value, "Template parameter `BaseUnit` must be a `unit` type.");
static_assert(traits::is_ratio<Conversion>::value, "Template parameter `Conversion` must be a `std::ratio` representing the conversion factor to `BaseUnit`.");
static_assert(traits::is_ratio<PiExponent>::value, "Template parameter `PiExponent` must be a `std::ratio` representing the exponents of Pi the unit has.");
typedef typename units::traits::unit_traits<BaseUnit>::base_unit_type base_unit_type;
typedef typename std::ratio_multiply<typename BaseUnit::conversion_ratio, Conversion> conversion_ratio;
typedef typename std::ratio_add<typename BaseUnit::pi_exponent_ratio, PiExponent> pi_exponent_ratio;
typedef typename std::ratio_add<std::ratio_multiply<typename BaseUnit::conversion_ratio, Translation>, typename BaseUnit::translation_ratio> translation_ratio;
};
namespace detail
{
template<class> struct base_unit_of_impl;
template<class Conversion, class BaseUnit, class PiExponent, class Translation>
struct base_unit_of_impl<unit<Conversion, BaseUnit, PiExponent, Translation>> : base_unit_of_impl<BaseUnit> {};
template<class... Exponents>
struct base_unit_of_impl<base_unit<Exponents...>>
{
typedef base_unit<Exponents...> type;
};
template<>
struct base_unit_of_impl<void>
{
typedef void type;
};
}
namespace traits
{
template<class U>
using base_unit_of = typename units::detail::base_unit_of_impl<U>::type;
}
namespace detail
{
template<class, class> struct base_unit_multiply_impl;
template<class... Exponents1, class... Exponents2>
struct base_unit_multiply_impl<base_unit<Exponents1...>, base_unit<Exponents2...>> {
using type = base_unit<std::ratio_add<Exponents1, Exponents2>...>;
};
template<class U1, class U2>
using base_unit_multiply = typename base_unit_multiply_impl<U1, U2>::type;
template<class, class> struct base_unit_divide_impl;
template<class... Exponents1, class... Exponents2>
struct base_unit_divide_impl<base_unit<Exponents1...>, base_unit<Exponents2...>> {
using type = base_unit<std::ratio_subtract<Exponents1, Exponents2>...>;
};
template<class U1, class U2>
using base_unit_divide = typename base_unit_divide_impl<U1, U2>::type;
template<class> struct inverse_base_impl;
template<class... Exponents>
struct inverse_base_impl<base_unit<Exponents...>> {
using type = base_unit<std::ratio_multiply<Exponents, std::ratio<-1>>...>;
};
template<class U> using inverse_base = typename inverse_base_impl<U>::type;
template<class U> struct squared_base_impl;
template<class... Exponents>
struct squared_base_impl<base_unit<Exponents...>> {
using type = base_unit<std::ratio_multiply<Exponents, std::ratio<2>>...>;
};
template<class U> using squared_base = typename squared_base_impl<U>::type;
template<class U> struct cubed_base_impl;
template<class... Exponents>
struct cubed_base_impl<base_unit<Exponents...>> {
using type = base_unit<std::ratio_multiply<Exponents, std::ratio<3>>...>;
};
template<class U> using cubed_base = typename cubed_base_impl<U>::type;
template<class U> struct sqrt_base_impl;
template<class... Exponents>
struct sqrt_base_impl<base_unit<Exponents...>> {
using type = base_unit<std::ratio_divide<Exponents, std::ratio<2>>...>;
};
template<class U> using sqrt_base = typename sqrt_base_impl<U>::type;
template<class U> struct cbrt_base_impl;
template<class... Exponents>
struct cbrt_base_impl<base_unit<Exponents...>> {
using type = base_unit<std::ratio_divide<Exponents, std::ratio<3>>...>;
};
template<class U> using cbrt_base = typename cbrt_base_impl<U>::type;
}
namespace detail
{
template<class Unit1, class Unit2>
struct unit_multiply_impl
{
using type = unit < std::ratio_multiply<typename Unit1::conversion_ratio, typename Unit2::conversion_ratio>,
base_unit_multiply <traits::base_unit_of<typename Unit1::base_unit_type>, traits::base_unit_of<typename Unit2::base_unit_type>>,
std::ratio_add<typename Unit1::pi_exponent_ratio, typename Unit2::pi_exponent_ratio>,
std::ratio < 0 >> ;
};
template<class U1, class U2>
using unit_multiply = typename unit_multiply_impl<U1, U2>::type;
template<class Unit1, class Unit2>
struct unit_divide_impl
{
using type = unit < std::ratio_divide<typename Unit1::conversion_ratio, typename Unit2::conversion_ratio>,
base_unit_divide<traits::base_unit_of<typename Unit1::base_unit_type>, traits::base_unit_of<typename Unit2::base_unit_type>>,
std::ratio_subtract<typename Unit1::pi_exponent_ratio, typename Unit2::pi_exponent_ratio>,
std::ratio < 0 >> ;
};
template<class U1, class U2>
using unit_divide = typename unit_divide_impl<U1, U2>::type;
template<class Unit>
struct inverse_impl
{
using type = unit < std::ratio<Unit::conversion_ratio::den, Unit::conversion_ratio::num>,
inverse_base<traits::base_unit_of<typename units::traits::unit_traits<Unit>::base_unit_type>>,
std::ratio_multiply<typename units::traits::unit_traits<Unit>::pi_exponent_ratio, std::ratio<-1>>,
std::ratio < 0 >> ; };
}
template<class U> using inverse = typename units::detail::inverse_impl<U>::type;
namespace detail
{
template<class Unit>
struct squared_impl
{
static_assert(traits::is_unit<Unit>::value, "Template parameter `Unit` must be a `unit` type.");
using Conversion = typename Unit::conversion_ratio;
using type = unit < std::ratio_multiply<Conversion, Conversion>,
squared_base<traits::base_unit_of<typename Unit::base_unit_type>>,
std::ratio_multiply<typename Unit::pi_exponent_ratio, std::ratio<2>>,
typename Unit::translation_ratio
> ;
};
}
template<class U>
using squared = typename units::detail::squared_impl<U>::type;
namespace detail
{
template<class Unit>
struct cubed_impl
{
static_assert(traits::is_unit<Unit>::value, "Template parameter `Unit` must be a `unit` type.");
using Conversion = typename Unit::conversion_ratio;
using type = unit < std::ratio_multiply<Conversion, std::ratio_multiply<Conversion, Conversion>>,
cubed_base<traits::base_unit_of<typename Unit::base_unit_type>>,
std::ratio_multiply<typename Unit::pi_exponent_ratio, std::ratio<3>>,
typename Unit::translation_ratio> ;
};
}
template<class U>
using cubed = typename units::detail::cubed_impl<U>::type;
namespace detail
{
using Zero = std::ratio<0>;
using One = std::ratio<1>;
template <typename R> using Square = std::ratio_multiply<R, R>;
template <template <std::intmax_t N> class Predicate, typename enabled = void>
struct BinarySearch {
template <std::intmax_t N>
struct SafeDouble_ {
static constexpr const std::intmax_t value = 2 * N;
static_assert(value > 0, "Overflows when computing 2 * N");
};
template <intmax_t Lower, intmax_t Upper, typename Condition1 = void, typename Condition2 = void>
struct DoubleSidedSearch_ : DoubleSidedSearch_<Lower, Upper,
std::integral_constant<bool, (Upper - Lower == 1)>,
std::integral_constant<bool, ((Upper - Lower>1 && Predicate<Lower + (Upper - Lower) / 2>::value))>> {};
template <intmax_t Lower, intmax_t Upper>
struct DoubleSidedSearch_<Lower, Upper, std::false_type, std::false_type> : DoubleSidedSearch_<Lower, Lower + (Upper - Lower) / 2> {};
template <intmax_t Lower, intmax_t Upper, typename Condition2>
struct DoubleSidedSearch_<Lower, Upper, std::true_type, Condition2> : std::integral_constant<intmax_t, Lower>{};
template <intmax_t Lower, intmax_t Upper, typename Condition1>
struct DoubleSidedSearch_<Lower, Upper, Condition1, std::true_type> : DoubleSidedSearch_<Lower + (Upper - Lower) / 2, Upper>{};
template <std::intmax_t Lower, class enabled1 = void>
struct SingleSidedSearch_ : SingleSidedSearch_<Lower, std::integral_constant<bool, Predicate<SafeDouble_<Lower>::value>::value>>{};
template <std::intmax_t Lower>
struct SingleSidedSearch_<Lower, std::false_type> : DoubleSidedSearch_<Lower, SafeDouble_<Lower>::value> {};
template <std::intmax_t Lower>
struct SingleSidedSearch_<Lower, std::true_type> : SingleSidedSearch_<SafeDouble_<Lower>::value>{};
static constexpr const std::intmax_t value = SingleSidedSearch_<1>::value;
};
template <template <std::intmax_t N> class Predicate>
struct BinarySearch<Predicate, std::enable_if_t<!Predicate<1>::value>> : std::integral_constant<std::intmax_t, 0>{};
template <typename R>
struct Integer {
template <std::intmax_t N> using Predicate_ = std::ratio_less_equal<std::ratio<N>, std::ratio_divide<R, std::ratio<N>>>;
static constexpr const std::intmax_t value = BinarySearch<Predicate_>::value;
};
template <typename R>
struct IsPerfectSquare {
static constexpr const std::intmax_t DenSqrt_ = Integer<std::ratio<R::den>>::value;
static constexpr const std::intmax_t NumSqrt_ = Integer<std::ratio<R::num>>::value;
static constexpr const bool value =( DenSqrt_ * DenSqrt_ == R::den && NumSqrt_ * NumSqrt_ == R::num);
using Sqrt = std::ratio<NumSqrt_, DenSqrt_>;
};
template <typename Tp, typename Tq>
struct Remainder {
using P = Tp;
using Q = Tq;
};
template <typename R>
struct Reciprocal {
using P_ = typename R::P;
using Q_ = typename R::Q;
using Den_ = std::ratio_subtract<P_, Square<Q_>>;
using A_ = std::ratio_divide<Q_, Den_>;
using B_ = std::ratio_divide<P_, Square<Den_>>;
static constexpr const std::intmax_t I_ = (A_::num + Integer<std::ratio_multiply<B_, Square<std::ratio<A_::den>>>>::value) / A_::den;
using I = std::ratio<I_>;
using Rem = Remainder<B_, std::ratio_subtract<I, A_>>;
};
template <typename Tr, std::intmax_t N>
struct ContinuedFraction {
template <typename T>
using Abs_ = std::conditional_t<std::ratio_less<T, Zero>::value, std::ratio_subtract<Zero, T>, T>;
using R = Tr;
using Last_ = ContinuedFraction<R, N - 1>;
using Reciprocal_ = Reciprocal<typename Last_::Rem>;
using Rem = typename Reciprocal_::Rem;
using I_ = typename Reciprocal_::I;
using Den_ = std::ratio_add<typename Last_::W, I_>;
using U = std::ratio_divide<typename Last_::V, Den_>;
using V = std::ratio_divide<std::ratio_add<typename Last_::U, std::ratio_multiply<typename Last_::V, I_>>, Den_>;
using W = std::ratio_divide<One, Den_>;
using Error = Abs_<std::ratio_divide<std::ratio_subtract<U, std::ratio_multiply<V, W>>, typename Reciprocal<Rem>::I>>;
};
template <typename Tr>
struct ContinuedFraction<Tr, 1> {
using R = Tr;
using U = One;
using V = std::ratio<Integer<R>::value>;
using W = Zero;
using Rem = Remainder<R, V>;
using Error = std::ratio_divide<One, typename Reciprocal<Rem>::I>;
};
template <typename R, typename Eps, std::intmax_t N = 1, typename enabled = void>
struct Sqrt_ : Sqrt_<R, Eps, N + 1> {};
template <typename R, typename Eps, std::intmax_t N>
struct Sqrt_<R, Eps, N, std::enable_if_t<std::ratio_less_equal<typename ContinuedFraction<R, N>::Error, Eps>::value>> {
using type = typename ContinuedFraction<R, N>::V;
};
template <typename R, typename Eps, typename enabled = void>
struct Sqrt {
static_assert(std::ratio_greater_equal<R, Zero>::value, "R can't be negative");
};
template <typename R, typename Eps>
struct Sqrt<R, Eps, std::enable_if_t<std::ratio_greater_equal<R, Zero>::value && IsPerfectSquare<R>::value>> {
using type = typename IsPerfectSquare<R>::Sqrt;
};
template <typename R, typename Eps>
struct Sqrt<R, Eps, std::enable_if_t<(std::ratio_greater_equal<R, Zero>::value && !IsPerfectSquare<R>::value)>> : Sqrt_<R, Eps>{};
}
template<typename Ratio, std::intmax_t Eps = 10000000000>
using ratio_sqrt = typename units::detail::Sqrt<Ratio, std::ratio<1, Eps>>::type;
namespace detail
{
template<class Unit, std::intmax_t Eps>
struct sqrt_impl
{
static_assert(traits::is_unit<Unit>::value, "Template parameter `Unit` must be a `unit` type.");
using Conversion = typename Unit::conversion_ratio;
using type = unit <ratio_sqrt<Conversion, Eps>,
sqrt_base<traits::base_unit_of<typename Unit::base_unit_type>>,
std::ratio_divide<typename Unit::pi_exponent_ratio, std::ratio<2>>,
typename Unit::translation_ratio>;
};
}
template<class U, std::intmax_t Eps = 10000000000>
using square_root = typename units::detail::sqrt_impl<U, Eps>::type;
namespace detail
{
template<class U, class... Us> struct compound_impl;
template<class U> struct compound_impl<U> { using type = U; };
template<class U1, class U2, class...Us>
struct compound_impl<U1, U2, Us...>
: compound_impl<unit_multiply<U1, U2>, Us...> {};
}
template<class U, class... Us>
using compound_unit = typename units::detail::compound_impl<U, Us...>::type;
namespace detail
{
template<class Ratio, class Unit>
struct prefix
{
static_assert(traits::is_ratio<Ratio>::value, "Template parameter `Ratio` must be a `std::ratio`.");
static_assert(traits::is_unit<Unit>::value, "Template parameter `Unit` must be a `unit` type.");
typedef typename units::unit<Ratio, Unit> type;
};
template <int N, class U>
struct power_of_ratio
{
typedef std::ratio_multiply<U, typename power_of_ratio<N - 1, U>::type> type;
};
template <class U>
struct power_of_ratio<1, U>
{
typedef U type;
};
}
template<class U> using atto = typename units::detail::prefix<std::atto, U>::type; template<class U> using femto = typename units::detail::prefix<std::femto,U>::type; template<class U> using pico = typename units::detail::prefix<std::pico, U>::type; template<class U> using nano = typename units::detail::prefix<std::nano, U>::type; template<class U> using micro = typename units::detail::prefix<std::micro,U>::type; template<class U> using milli = typename units::detail::prefix<std::milli,U>::type; template<class U> using centi = typename units::detail::prefix<std::centi,U>::type; template<class U> using deci = typename units::detail::prefix<std::deci, U>::type; template<class U> using deca = typename units::detail::prefix<std::deca, U>::type; template<class U> using hecto = typename units::detail::prefix<std::hecto,U>::type; template<class U> using kilo = typename units::detail::prefix<std::kilo, U>::type; template<class U> using mega = typename units::detail::prefix<std::mega, U>::type; template<class U> using giga = typename units::detail::prefix<std::giga, U>::type; template<class U> using tera = typename units::detail::prefix<std::tera, U>::type; template<class U> using peta = typename units::detail::prefix<std::peta, U>::type; template<class U> using exa = typename units::detail::prefix<std::exa, U>::type;
template<class U> using kibi = typename units::detail::prefix<std::ratio<1024>, U>::type; template<class U> using mebi = typename units::detail::prefix<std::ratio<1048576>, U>::type; template<class U> using gibi = typename units::detail::prefix<std::ratio<1073741824>, U>::type; template<class U> using tebi = typename units::detail::prefix<std::ratio<1099511627776>, U>::type; template<class U> using pebi = typename units::detail::prefix<std::ratio<1125899906842624>, U>::type; template<class U> using exbi = typename units::detail::prefix<std::ratio<1152921504606846976>, U>::type;
namespace traits
{
template<class U1, class U2>
struct is_convertible_unit : std::is_same <traits::base_unit_of<typename units::traits::unit_traits<U1>::base_unit_type>,
base_unit_of<typename units::traits::unit_traits<U2>::base_unit_type >> {};
template<class U1, class U2>
constexpr bool is_convertible_unit_v = is_convertible_unit<U1, U2>::value;
}
namespace detail
{
constexpr inline UNIT_LIB_DEFAULT_TYPE pow(UNIT_LIB_DEFAULT_TYPE x, unsigned long long y)
{
return y == 0 ? 1.0 : x * pow(x, y - 1);
}
constexpr inline UNIT_LIB_DEFAULT_TYPE abs(UNIT_LIB_DEFAULT_TYPE x)
{
return x < 0 ? -x : x;
}
template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
static constexpr T convert(const T& value, std::true_type, std::false_type, std::false_type) noexcept
{
return value;
}
template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
static constexpr T convert(const T& value, std::true_type, std::false_type, std::true_type) noexcept
{
return value;
}
template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
static constexpr T convert(const T& value, std::true_type, std::true_type, std::false_type) noexcept
{
return value;
}
template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
static constexpr T convert(const T& value, std::true_type, std::true_type, std::true_type) noexcept
{
return value;
}
template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
static constexpr T convert(const T& value, std::false_type, std::false_type, std::false_type) noexcept
{
return ((value * Ratio::num) / Ratio::den);
}
template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
static constexpr
std::enable_if_t<(PiRatio::num / PiRatio::den >= 1 && PiRatio::num % PiRatio::den == 0), T>
convert(const T& value, std::false_type, std::true_type, std::false_type) noexcept
{
return ((value * pow(constants::detail::PI_VAL, PiRatio::num / PiRatio::den) * Ratio::num) / Ratio::den);
}
template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
static constexpr
std::enable_if_t<(PiRatio::num / PiRatio::den <= -1 && PiRatio::num % PiRatio::den == 0), T>
convert(const T& value, std::false_type, std::true_type, std::false_type) noexcept
{
return (value * Ratio::num) / (Ratio::den * pow(constants::detail::PI_VAL, -PiRatio::num / PiRatio::den));
}
template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
static inline std::enable_if_t<(PiRatio::num / PiRatio::den < 1 && PiRatio::num / PiRatio::den > -1), T>
convert(const T& value, std::false_type, std::true_type, std::false_type) noexcept
{
return ((value * std::pow(constants::detail::PI_VAL, PiRatio::num / PiRatio::den) * Ratio::num) / Ratio::den);
}
template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
static constexpr T convert(const T& value, std::false_type, std::false_type, std::true_type) noexcept
{
return ((value * Ratio::num) / Ratio::den) + (static_cast<UNIT_LIB_DEFAULT_TYPE>(Translation::num) / Translation::den);
}
template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
static constexpr T convert(const T& value, const std::false_type, const std::true_type, const std::true_type) noexcept
{
return ((value * std::pow(constants::detail::PI_VAL, PiRatio::num / PiRatio::den) * Ratio::num) / Ratio::den) + (static_cast<UNIT_LIB_DEFAULT_TYPE>(Translation::num) / Translation::den);
}
}
template<class UnitFrom, class UnitTo, typename T = UNIT_LIB_DEFAULT_TYPE>
static constexpr T convert(const T& value) noexcept
{
static_assert(traits::is_unit<UnitFrom>::value, "Template parameter `UnitFrom` must be a `unit` type.");
static_assert(traits::is_unit<UnitTo>::value, "Template parameter `UnitTo` must be a `unit` type.");
static_assert(traits::is_convertible_unit<UnitFrom, UnitTo>::value, "Units are not compatible.");
using Ratio = std::ratio_divide<typename UnitFrom::conversion_ratio, typename UnitTo::conversion_ratio>;
using PiRatio = std::ratio_subtract<typename UnitFrom::pi_exponent_ratio, typename UnitTo::pi_exponent_ratio>;
using Translation = std::ratio_divide<std::ratio_subtract<typename UnitFrom::translation_ratio, typename UnitTo::translation_ratio>, typename UnitTo::conversion_ratio>;
using isSame = typename std::is_same<std::decay_t<UnitFrom>, std::decay_t<UnitTo>>::type;
using piRequired = std::integral_constant<bool, !(std::is_same<std::ratio<0>, PiRatio>::value)>;
using translationRequired = std::integral_constant<bool, !(std::is_same<std::ratio<0>, Translation>::value)>;
return units::detail::convert<UnitFrom, UnitTo, Ratio, PiRatio, Translation, T>
(value, isSame{}, piRequired{}, translationRequired{});
}
namespace traits
{
namespace detail
{
template<class T, class Ret>
struct has_operator_parenthesis_impl
{
template<class U>
static constexpr auto test(U*) -> decltype(std::declval<U>()()) { return decltype(std::declval<U>()()){}; }
template<typename>
static constexpr std::false_type test(...) { return std::false_type{}; }
using type = typename std::is_same<Ret, decltype(test<T>(0))>::type;
};
}
template<class T, class Ret>
struct has_operator_parenthesis : traits::detail::has_operator_parenthesis_impl<T, Ret>::type {};
}
namespace traits
{
namespace detail
{
template<class T, class Ret>
struct has_value_member_impl
{
template<class U>
static constexpr auto test(U* p) -> decltype(p->m_value) { return p->m_value; }
template<typename>
static constexpr auto test(...)->std::false_type { return std::false_type{}; }
using type = typename std::is_same<std::decay_t<Ret>, std::decay_t<decltype(test<T>(0))>>::type;
};
}
template<class T, class Ret>
struct has_value_member : traits::detail::has_value_member_impl<T, Ret>::type {};
template<class T, class Ret>
constexpr bool has_value_member_v = has_value_member<T, Ret>::value;
}
namespace traits
{
template<class T, class Ret>
struct is_nonlinear_scale : std::integral_constant<bool,
std::is_default_constructible<T>::value &&
has_operator_parenthesis<T, Ret>::value &&
has_value_member<T, Ret>::value &&
std::is_trivial<T>::value>
{};
}
namespace traits
{
#ifdef FOR_DOXYGEN_PURPOSES_ONLY
template<typename T>
struct unit_t_traits
{
typedef typename T::non_linear_scale_type non_linear_scale_type; typedef typename T::underlying_type underlying_type; typedef typename T::value_type value_type; typedef typename T::unit_type unit_type; };
#endif
template<typename T, typename = void>
struct unit_t_traits
{
typedef void non_linear_scale_type;
typedef void underlying_type;
typedef void value_type;
typedef void unit_type;
};
template<typename T>
struct unit_t_traits <T, typename void_t<
typename T::non_linear_scale_type,
typename T::underlying_type,
typename T::value_type,
typename T::unit_type>::type>
{
typedef typename T::non_linear_scale_type non_linear_scale_type;
typedef typename T::underlying_type underlying_type;
typedef typename T::value_type value_type;
typedef typename T::unit_type unit_type;
};
}
namespace traits
{
template<class U1, class U2>
struct is_convertible_unit_t : std::integral_constant<bool,
is_convertible_unit<typename units::traits::unit_t_traits<U1>::unit_type, typename units::traits::unit_t_traits<U2>::unit_type>::value>
{};
}
template<typename T> struct linear_scale;
template<typename T> struct decibel_scale;
namespace detail
{
struct _unit_t {};
}
namespace traits
{
#if !defined(_MSC_VER) || _MSC_VER > 1800
template<typename... T> struct is_dimensionless_unit;
#else
template<typename T1, typename T2 = T1, typename T3 = T1> struct is_dimensionless_unit;
#endif
template<class T>
struct is_unit_t : std::is_base_of<units::detail::_unit_t, T>::type {};
template<class T>
constexpr bool is_unit_t_v = is_unit_t<T>::value;
}
template<class Units, typename T = UNIT_LIB_DEFAULT_TYPE, template<typename> class NonLinearScale = linear_scale>
class unit_t : public NonLinearScale<T>, units::detail::_unit_t
{
static_assert(traits::is_unit<Units>::value, "Template parameter `Units` must be a unit tag. Check that you aren't using a unit type (_t).");
static_assert(traits::is_nonlinear_scale<NonLinearScale<T>, T>::value, "Template parameter `NonLinearScale` does not conform to the `is_nonlinear_scale` concept.");
protected:
using nls = NonLinearScale<T>;
using nls::m_value;
public:
typedef NonLinearScale<T> non_linear_scale_type; typedef T underlying_type; typedef T value_type; typedef Units unit_type;
constexpr unit_t() = default;
template<class... Args>
inline explicit constexpr unit_t(const T value, const Args&... args) noexcept : nls(value, args...)
{
}
template<class Ty, class = typename std::enable_if<traits::is_dimensionless_unit<Units>::value && std::is_arithmetic<Ty>::value>::type>
constexpr unit_t(const Ty value) noexcept : nls(value)
{
}
template<class Rep, class Period, class = std::enable_if_t<std::is_arithmetic<Rep>::value && traits::is_ratio<Period>::value>>
constexpr unit_t(const std::chrono::duration<Rep, Period>& value) noexcept :
nls(units::convert<unit<std::ratio<1,1000000000>, category::time_unit>, Units>(static_cast<T>(std::chrono::duration_cast<std::chrono::nanoseconds>(value).count())))
{
}
template<class UnitsRhs, typename Ty, template<typename> class NlsRhs>
requires traits::is_unit_v<UnitsRhs> && traits::is_unit_v<Units> && traits::is_convertible_unit_v<UnitsRhs, Units>
constexpr unit_t(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) noexcept :
nls(units::convert<UnitsRhs, Units, T>(rhs.m_value), std::true_type() )
{
}
template<class UnitsRhs, typename Ty, template<typename> class NlsRhs>
inline unit_t& operator=(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) noexcept
{
nls::m_value = units::convert<UnitsRhs, Units, T>(rhs.m_value);
return *this;
}
template<class Ty, class = std::enable_if_t<traits::is_dimensionless_unit<Units>::value && std::is_arithmetic<Ty>::value>>
inline unit_t& operator=(const Ty& rhs) noexcept
{
nls::m_value = rhs;
return *this;
}
template<class UnitsRhs, typename Ty, template<typename> class NlsRhs>
constexpr bool operator<(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept
{
return (nls::m_value < units::convert<UnitsRhs, Units>(rhs.m_value));
}
template<class UnitsRhs, typename Ty, template<typename> class NlsRhs>
constexpr bool operator<=(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept
{
return (nls::m_value <= units::convert<UnitsRhs, Units>(rhs.m_value));
}
template<class UnitsRhs, typename Ty, template<typename> class NlsRhs>
constexpr bool operator>(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept
{
return (nls::m_value > units::convert<UnitsRhs, Units>(rhs.m_value));
}
template<class UnitsRhs, typename Ty, template<typename> class NlsRhs>
constexpr bool operator>=(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept
{
return (nls::m_value >= units::convert<UnitsRhs, Units>(rhs.m_value));
}
template<class UnitsRhs, typename Ty, template<typename> class NlsRhs, std::enable_if_t<std::is_floating_point<T>::value || std::is_floating_point<Ty>::value, int> = 0>
constexpr bool operator==(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept
{
return detail::abs(nls::m_value - units::convert<UnitsRhs, Units>(rhs.m_value)) < std::numeric_limits<T>::epsilon() *
detail::abs(nls::m_value + units::convert<UnitsRhs, Units>(rhs.m_value)) ||
detail::abs(nls::m_value - units::convert<UnitsRhs, Units>(rhs.m_value)) < (std::numeric_limits<T>::min)();
}
template<class UnitsRhs, typename Ty, template<typename> class NlsRhs, std::enable_if_t<std::is_integral<T>::value && std::is_integral<Ty>::value, int> = 0>
constexpr bool operator==(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept
{
return nls::m_value == units::convert<UnitsRhs, Units>(rhs.m_value);
}
template<class UnitsRhs, typename Ty, template<typename> class NlsRhs>
constexpr bool operator!=(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept
{
return !(*this == rhs);
}
constexpr underlying_type value() const noexcept
{
return static_cast<underlying_type>(*this);
}
template<typename Ty, class = std::enable_if_t<std::is_arithmetic<Ty>::value>>
constexpr Ty to() const noexcept
{
return static_cast<Ty>(*this);
}
template<typename Ty, class = std::enable_if_t<std::is_arithmetic<Ty>::value>>
constexpr Ty toLinearized() const noexcept
{
return static_cast<Ty>(m_value);
}
template<class U>
constexpr unit_t<U> convert() const noexcept
{
static_assert(traits::is_unit<U>::value, "Template parameter `U` must be a unit type.");
return unit_t<U>(*this);
}
template<class Ty, std::enable_if_t<traits::is_dimensionless_unit<Units>::value && std::is_arithmetic<Ty>::value, int> = 0>
constexpr operator Ty() const noexcept
{
return static_cast<Ty>(units::convert<Units, unit<std::ratio<1>, units::category::scalar_unit>>((*this)()));
}
template<class Ty, std::enable_if_t<!traits::is_dimensionless_unit<Units>::value && std::is_arithmetic<Ty>::value, int> = 0>
constexpr explicit operator Ty() const noexcept
{
return static_cast<Ty>((*this)());
}
template<typename U = Units, std::enable_if_t<units::traits::is_convertible_unit<U, unit<std::ratio<1>, category::time_unit>>::value, int> = 0>
constexpr operator std::chrono::nanoseconds() const noexcept
{
return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::duration<double, std::nano>(units::convert<Units, unit<std::ratio<1,1000000000>, category::time_unit>>((*this)())));
}
constexpr const char* name() const noexcept
{
return units::name(*this);
}
constexpr const char* abbreviation() const noexcept
{
return units::abbreviation(*this);
}
public:
template<class U, typename Ty, template<typename> class Nlt>
friend class unit_t;
};
template<class UnitType, typename T, class = std::enable_if_t<std::is_arithmetic<T>::value>>
constexpr UnitType make_unit(const T value) noexcept
{
static_assert(traits::is_unit_t<UnitType>::value, "Template parameter `UnitType` must be a unit type (_t).");
return UnitType(value);
}
#if defined(UNIT_LIB_ENABLE_IOSTREAM)
template<class Units, typename T, template<typename> class NonLinearScale>
inline std::ostream& operator<<(std::ostream& os, const unit_t<Units, T, NonLinearScale>& obj) noexcept
{
using BaseUnits = unit<std::ratio<1>, typename traits::unit_traits<Units>::base_unit_type>;
os << convert<Units, BaseUnits>(obj());
if (traits::unit_traits<Units>::base_unit_type::meter_ratio::num != 0) { os << " m"; }
if (traits::unit_traits<Units>::base_unit_type::meter_ratio::num != 0 &&
traits::unit_traits<Units>::base_unit_type::meter_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::meter_ratio::num; }
if (traits::unit_traits<Units>::base_unit_type::meter_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::meter_ratio::den; }
if (traits::unit_traits<Units>::base_unit_type::kilogram_ratio::num != 0) { os << " kg"; }
if (traits::unit_traits<Units>::base_unit_type::kilogram_ratio::num != 0 &&
traits::unit_traits<Units>::base_unit_type::kilogram_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::kilogram_ratio::num; }
if (traits::unit_traits<Units>::base_unit_type::kilogram_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::kilogram_ratio::den; }
if (traits::unit_traits<Units>::base_unit_type::second_ratio::num != 0) { os << " s"; }
if (traits::unit_traits<Units>::base_unit_type::second_ratio::num != 0 &&
traits::unit_traits<Units>::base_unit_type::second_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::second_ratio::num; }
if (traits::unit_traits<Units>::base_unit_type::second_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::second_ratio::den; }
if (traits::unit_traits<Units>::base_unit_type::ampere_ratio::num != 0) { os << " A"; }
if (traits::unit_traits<Units>::base_unit_type::ampere_ratio::num != 0 &&
traits::unit_traits<Units>::base_unit_type::ampere_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::ampere_ratio::num; }
if (traits::unit_traits<Units>::base_unit_type::ampere_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::ampere_ratio::den; }
if (traits::unit_traits<Units>::base_unit_type::kelvin_ratio::num != 0) { os << " K"; }
if (traits::unit_traits<Units>::base_unit_type::kelvin_ratio::num != 0 &&
traits::unit_traits<Units>::base_unit_type::kelvin_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::kelvin_ratio::num; }
if (traits::unit_traits<Units>::base_unit_type::kelvin_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::kelvin_ratio::den; }
if (traits::unit_traits<Units>::base_unit_type::mole_ratio::num != 0) { os << " mol"; }
if (traits::unit_traits<Units>::base_unit_type::mole_ratio::num != 0 &&
traits::unit_traits<Units>::base_unit_type::mole_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::mole_ratio::num; }
if (traits::unit_traits<Units>::base_unit_type::mole_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::mole_ratio::den; }
if (traits::unit_traits<Units>::base_unit_type::candela_ratio::num != 0) { os << " cd"; }
if (traits::unit_traits<Units>::base_unit_type::candela_ratio::num != 0 &&
traits::unit_traits<Units>::base_unit_type::candela_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::candela_ratio::num; }
if (traits::unit_traits<Units>::base_unit_type::candela_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::candela_ratio::den; }
if (traits::unit_traits<Units>::base_unit_type::radian_ratio::num != 0) { os << " rad"; }
if (traits::unit_traits<Units>::base_unit_type::radian_ratio::num != 0 &&
traits::unit_traits<Units>::base_unit_type::radian_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::radian_ratio::num; }
if (traits::unit_traits<Units>::base_unit_type::radian_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::radian_ratio::den; }
if (traits::unit_traits<Units>::base_unit_type::byte_ratio::num != 0) { os << " b"; }
if (traits::unit_traits<Units>::base_unit_type::byte_ratio::num != 0 &&
traits::unit_traits<Units>::base_unit_type::byte_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::byte_ratio::num; }
if (traits::unit_traits<Units>::base_unit_type::byte_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::byte_ratio::den; }
return os;
}
#endif
template<class Units, typename T, template<typename> class NonLinearScale, typename RhsType>
constexpr unit_t<Units, T, NonLinearScale>& operator+=(unit_t<Units, T, NonLinearScale>& lhs, const RhsType& rhs) noexcept
{
static_assert(traits::is_convertible_unit_t<unit_t<Units, T, NonLinearScale>, RhsType>::value ||
(traits::is_dimensionless_unit<decltype(lhs)>::value && std::is_arithmetic<RhsType>::value),
"parameters are not compatible units.");
lhs = lhs + rhs;
return lhs;
}
template<class Units, typename T, template<typename> class NonLinearScale, typename RhsType>
constexpr unit_t<Units, T, NonLinearScale>& operator-=(unit_t<Units, T, NonLinearScale>& lhs, const RhsType& rhs) noexcept
{
static_assert(traits::is_convertible_unit_t<unit_t<Units, T, NonLinearScale>, RhsType>::value ||
(traits::is_dimensionless_unit<decltype(lhs)>::value && std::is_arithmetic<RhsType>::value),
"parameters are not compatible units.");
lhs = lhs - rhs;
return lhs;
}
template<class Units, typename T, template<typename> class NonLinearScale, typename RhsType>
constexpr unit_t<Units, T, NonLinearScale>& operator*=(unit_t<Units, T, NonLinearScale>& lhs, const RhsType& rhs) noexcept
{
static_assert((traits::is_dimensionless_unit<RhsType>::value || std::is_arithmetic<RhsType>::value),
"right-hand side parameter must be dimensionless.");
lhs = lhs * rhs;
return lhs;
}
template<class Units, typename T, template<typename> class NonLinearScale, typename RhsType>
constexpr unit_t<Units, T, NonLinearScale>& operator/=(unit_t<Units, T, NonLinearScale>& lhs, const RhsType& rhs) noexcept
{
static_assert((traits::is_dimensionless_unit<RhsType>::value || std::is_arithmetic<RhsType>::value),
"right-hand side parameter must be dimensionless.");
lhs = lhs / rhs;
return lhs;
}
template<class Units, typename T, template<typename> class NonLinearScale>
constexpr unit_t<Units, T, NonLinearScale> operator+(const unit_t<Units, T, NonLinearScale>& u) noexcept
{
return u;
}
template<class Units, typename T, template<typename> class NonLinearScale>
constexpr unit_t<Units, T, NonLinearScale>& operator++(unit_t<Units, T, NonLinearScale>& u) noexcept
{
u = unit_t<Units, T, NonLinearScale>(u() + 1);
return u;
}
template<class Units, typename T, template<typename> class NonLinearScale>
constexpr unit_t<Units, T, NonLinearScale> operator++(unit_t<Units, T, NonLinearScale>& u, int) noexcept
{
auto ret = u;
u = unit_t<Units, T, NonLinearScale>(u() + 1);
return ret;
}
template<class Units, typename T, template<typename> class NonLinearScale>
constexpr unit_t<Units, T, NonLinearScale> operator-(const unit_t<Units, T, NonLinearScale>& u) noexcept
{
return unit_t<Units, T, NonLinearScale>(-u());
}
template<class Units, typename T, template<typename> class NonLinearScale>
constexpr unit_t<Units, T, NonLinearScale>& operator--(unit_t<Units, T, NonLinearScale>& u) noexcept
{
u = unit_t<Units, T, NonLinearScale>(u() - 1);
return u;
}
template<class Units, typename T, template<typename> class NonLinearScale>
constexpr unit_t<Units, T, NonLinearScale> operator--(unit_t<Units, T, NonLinearScale>& u, int) noexcept
{
auto ret = u;
u = unit_t<Units, T, NonLinearScale>(u() - 1);
return ret;
}
template<typename T, typename Units, class = std::enable_if_t<std::is_arithmetic<T>::value && traits::is_unit_t<Units>::value>>
constexpr T unit_cast(const Units& value) noexcept
{
return static_cast<T>(value);
}
template<typename T> struct decibel_scale;
namespace traits
{
#if !defined(_MSC_VER) || _MSC_VER > 1800
template<typename... T>
struct has_linear_scale : std::integral_constant<bool, units::all_true<std::is_base_of<units::linear_scale<typename units::traits::unit_t_traits<T>::underlying_type>, T>::value...>::value > {};
template<typename... T>
constexpr bool has_linear_scale_v = has_linear_scale<T...>::value;
#else
template<typename T1, typename T2 = T1, typename T3 = T1>
struct has_linear_scale : std::integral_constant<bool,
std::is_base_of<units::linear_scale<typename units::traits::unit_t_traits<T1>::underlying_type>, T1>::value &&
std::is_base_of<units::linear_scale<typename units::traits::unit_t_traits<T2>::underlying_type>, T2>::value &&
std::is_base_of<units::linear_scale<typename units::traits::unit_t_traits<T3>::underlying_type>, T3>::value> {};
template<typename T1, typename T2 = T1, typename T3 = T1>
constexpr bool has_linear_scale_v = has_linear_scale<T1, T2, T3>::value;
#endif
#if !defined(_MSC_VER) || _MSC_VER > 1800
template<typename... T>
struct has_decibel_scale : std::integral_constant<bool, units::all_true<std::is_base_of<units::decibel_scale<typename units::traits::unit_t_traits<T>::underlying_type>, T>::value...>::value> {};
template<typename... T>
constexpr bool has_decibel_scale_v = has_decibel_scale<T...>::value;
#else
template<typename T1, typename T2 = T1, typename T3 = T1>
struct has_decibel_scale : std::integral_constant<bool,
std::is_base_of<units::decibel_scale<typename units::traits::unit_t_traits<T1>::underlying_type>, T1>::value &&
std::is_base_of<units::decibel_scale<typename units::traits::unit_t_traits<T2>::underlying_type>, T2>::value &&
std::is_base_of<units::decibel_scale<typename units::traits::unit_t_traits<T2>::underlying_type>, T3>::value> {};
template<typename T1, typename T2 = T1, typename T3 = T1>
constexpr bool has_decibel_scale_v = has_decibel_scale<T1, T2, T3>::value;
#endif
template<typename T1, typename T2>
struct is_same_scale : std::integral_constant<bool,
std::is_same<typename units::traits::unit_t_traits<T1>::non_linear_scale_type, typename units::traits::unit_t_traits<T2>::non_linear_scale_type>::value>
{};
template<typename T1, typename T2>
constexpr bool is_same_scale_v = is_same_scale<T1, T2>::value;
}
template<typename T>
struct linear_scale
{
constexpr linear_scale() = default; constexpr linear_scale(const linear_scale&) = default;
inline ~linear_scale() = default;
inline linear_scale& operator=(const linear_scale&) = default;
#if defined(_MSC_VER) && (_MSC_VER > 1800)
constexpr linear_scale(linear_scale&&) = default;
inline linear_scale& operator=(linear_scale&&) = default;
#endif
template<class... Args>
constexpr linear_scale(const T& value, Args&&...) noexcept : m_value(value) {} constexpr T operator()() const noexcept { return m_value; }
T m_value; };
namespace dimensionless
{
typedef unit<std::ratio<1>, units::category::scalar_unit> scalar;
typedef unit<std::ratio<1>, units::category::dimensionless_unit> dimensionless;
typedef unit_t<scalar> scalar_t;
typedef scalar_t dimensionless_t;
}
#if defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable : 4348)
#endif
UNIT_ADD_CATEGORY_TRAIT(scalar)
UNIT_ADD_CATEGORY_TRAIT(dimensionless)
#if defined(_MSC_VER)
# pragma warning(pop)
#endif
template<class UnitTypeLhs, class UnitTypeRhs, std::enable_if_t<!traits::is_same_scale<UnitTypeLhs, UnitTypeRhs>::value, int> = 0>
constexpr inline int operator+(const UnitTypeLhs& , const UnitTypeRhs& ) noexcept
{
static_assert(traits::is_same_scale<UnitTypeLhs, UnitTypeRhs>::value, "Cannot add units with different linear/non-linear scales.");
return 0;
}
template<class UnitTypeLhs, class UnitTypeRhs, std::enable_if_t<traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value, int> = 0>
constexpr UnitTypeLhs operator+(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept
{
using UnitsLhs = typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type;
using UnitsRhs = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type;
return UnitTypeLhs(lhs() + convert<UnitsRhs, UnitsLhs>(rhs()));
}
template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, int> = 0>
constexpr dimensionless::scalar_t operator+(const dimensionless::scalar_t& lhs, T rhs) noexcept
{
return dimensionless::scalar_t(lhs() + rhs);
}
template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, int> = 0>
constexpr dimensionless::scalar_t operator+(T lhs, const dimensionless::scalar_t& rhs) noexcept
{
return dimensionless::scalar_t(lhs + rhs());
}
template<class UnitTypeLhs, class UnitTypeRhs, std::enable_if_t<traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value, int> = 0>
constexpr UnitTypeLhs operator-(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept
{
using UnitsLhs = typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type;
using UnitsRhs = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type;
return UnitTypeLhs(lhs() - convert<UnitsRhs, UnitsLhs>(rhs()));
}
template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, int> = 0>
constexpr dimensionless::scalar_t operator-(const dimensionless::scalar_t& lhs, T rhs) noexcept
{
return dimensionless::scalar_t(lhs() - rhs);
}
template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, int> = 0>
constexpr dimensionless::scalar_t operator-(T lhs, const dimensionless::scalar_t& rhs) noexcept
{
return dimensionless::scalar_t(lhs - rhs());
}
template<class UnitTypeLhs, class UnitTypeRhs,
std::enable_if_t<traits::is_convertible_unit_t<UnitTypeLhs, UnitTypeRhs>::value && traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value, int> = 0>
constexpr auto operator*(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept -> unit_t<compound_unit<squared<typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type>>>
{
using UnitsLhs = typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type;
using UnitsRhs = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type;
return unit_t<compound_unit<squared<typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type>>>
(lhs() * convert<UnitsRhs, UnitsLhs>(rhs()));
}
template<class UnitTypeLhs, class UnitTypeRhs,
std::enable_if_t<!traits::is_convertible_unit_t<UnitTypeLhs, UnitTypeRhs>::value && traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value && !traits::is_dimensionless_unit<UnitTypeLhs>::value && !traits::is_dimensionless_unit<UnitTypeRhs>::value, int> = 0>
constexpr auto operator*(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept -> unit_t<compound_unit<typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type, typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type>>
{
using UnitsLhs = typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type;
using UnitsRhs = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type;
return unit_t<compound_unit<UnitsLhs, UnitsRhs>>
(lhs() * rhs());
}
template<class UnitTypeLhs, typename UnitTypeRhs,
std::enable_if_t<traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value && !traits::is_dimensionless_unit<UnitTypeLhs>::value && traits::is_dimensionless_unit<UnitTypeRhs>::value, int> = 0>
constexpr UnitTypeLhs operator*(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept
{
return UnitTypeLhs(lhs() * static_cast<UNIT_LIB_DEFAULT_TYPE>(rhs));
}
template<class UnitTypeLhs, typename UnitTypeRhs,
std::enable_if_t<traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value && traits::is_dimensionless_unit<UnitTypeLhs>::value && !traits::is_dimensionless_unit<UnitTypeRhs>::value, int> = 0>
constexpr UnitTypeRhs operator*(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept
{
return UnitTypeRhs(static_cast<UNIT_LIB_DEFAULT_TYPE>(lhs) * rhs());
}
template<class UnitTypeLhs, typename T,
std::enable_if_t<std::is_arithmetic<T>::value && traits::has_linear_scale<UnitTypeLhs>::value, int> = 0>
constexpr UnitTypeLhs operator*(const UnitTypeLhs& lhs, T rhs) noexcept
{
return UnitTypeLhs(lhs() * rhs);
}
template<class UnitTypeRhs, typename T,
std::enable_if_t<std::is_arithmetic<T>::value && traits::has_linear_scale<UnitTypeRhs>::value, int> = 0>
constexpr UnitTypeRhs operator*(T lhs, const UnitTypeRhs& rhs) noexcept
{
return UnitTypeRhs(lhs * rhs());
}
template<class UnitTypeLhs, class UnitTypeRhs,
std::enable_if_t<traits::is_convertible_unit_t<UnitTypeLhs, UnitTypeRhs>::value && traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value, int> = 0>
constexpr dimensionless::scalar_t operator/(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept
{
using UnitsLhs = typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type;
using UnitsRhs = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type;
return dimensionless::scalar_t(lhs() / convert<UnitsRhs, UnitsLhs>(rhs()));
}
template<class UnitTypeLhs, class UnitTypeRhs,
std::enable_if_t<!traits::is_convertible_unit_t<UnitTypeLhs, UnitTypeRhs>::value && traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value && !traits::is_dimensionless_unit<UnitTypeLhs>::value && !traits::is_dimensionless_unit<UnitTypeRhs>::value, int> = 0>
constexpr auto operator/(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept -> unit_t<compound_unit<typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type, inverse<typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type>>>
{
using UnitsLhs = typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type;
using UnitsRhs = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type;
return unit_t<compound_unit<UnitsLhs, inverse<UnitsRhs>>>
(lhs() / rhs());
}
template<class UnitTypeLhs, class UnitTypeRhs,
std::enable_if_t<traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value && !traits::is_dimensionless_unit<UnitTypeLhs>::value && traits::is_dimensionless_unit<UnitTypeRhs>::value, int> = 0>
constexpr UnitTypeLhs operator/(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept
{
return UnitTypeLhs(lhs() / static_cast<UNIT_LIB_DEFAULT_TYPE>(rhs));
}
template<class UnitTypeLhs, class UnitTypeRhs,
std::enable_if_t<traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value && traits::is_dimensionless_unit<UnitTypeLhs>::value && !traits::is_dimensionless_unit<UnitTypeRhs>::value, int> = 0>
constexpr auto operator/(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept -> unit_t<inverse<typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type>>
{
return unit_t<inverse<typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type>>
(static_cast<UNIT_LIB_DEFAULT_TYPE>(lhs) / rhs());
}
template<class UnitTypeLhs, typename T,
std::enable_if_t<std::is_arithmetic<T>::value && traits::has_linear_scale<UnitTypeLhs>::value, int> = 0>
constexpr UnitTypeLhs operator/(const UnitTypeLhs& lhs, T rhs) noexcept
{
return UnitTypeLhs(lhs() / rhs);
}
template<class UnitTypeRhs, typename T,
std::enable_if_t<std::is_arithmetic<T>::value && traits::has_linear_scale<UnitTypeRhs>::value, int> = 0>
constexpr auto operator/(T lhs, const UnitTypeRhs& rhs) noexcept -> unit_t<inverse<typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type>>
{
using UnitsRhs = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type;
return unit_t<inverse<UnitsRhs>>
(lhs / rhs());
}
template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>>
constexpr bool operator==(const UNIT_LIB_DEFAULT_TYPE lhs, const Units& rhs) noexcept
{
return detail::abs(lhs - static_cast<UNIT_LIB_DEFAULT_TYPE>(rhs)) < std::numeric_limits<UNIT_LIB_DEFAULT_TYPE>::epsilon() * detail::abs(lhs + static_cast<UNIT_LIB_DEFAULT_TYPE>(rhs)) ||
detail::abs(lhs - static_cast<UNIT_LIB_DEFAULT_TYPE>(rhs)) < (std::numeric_limits<UNIT_LIB_DEFAULT_TYPE>::min)();
}
template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>>
constexpr bool operator==(const Units& lhs, const UNIT_LIB_DEFAULT_TYPE rhs) noexcept
{
return detail::abs(static_cast<UNIT_LIB_DEFAULT_TYPE>(lhs) - rhs) < std::numeric_limits<UNIT_LIB_DEFAULT_TYPE>::epsilon() * detail::abs(static_cast<UNIT_LIB_DEFAULT_TYPE>(lhs) + rhs) ||
detail::abs(static_cast<UNIT_LIB_DEFAULT_TYPE>(lhs) - rhs) < (std::numeric_limits<UNIT_LIB_DEFAULT_TYPE>::min)();
}
template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>>
constexpr bool operator!=(const UNIT_LIB_DEFAULT_TYPE lhs, const Units& rhs) noexcept
{
return!(lhs == static_cast<UNIT_LIB_DEFAULT_TYPE>(rhs));
}
template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>>
constexpr bool operator!=(const Units& lhs, const UNIT_LIB_DEFAULT_TYPE rhs) noexcept
{
return !(static_cast<UNIT_LIB_DEFAULT_TYPE>(lhs) == rhs);
}
template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>>
constexpr bool operator>=(const UNIT_LIB_DEFAULT_TYPE lhs, const Units& rhs) noexcept
{
return std::isgreaterequal(lhs, static_cast<UNIT_LIB_DEFAULT_TYPE>(rhs));
}
template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>>
constexpr bool operator>=(const Units& lhs, const UNIT_LIB_DEFAULT_TYPE rhs) noexcept
{
return std::isgreaterequal(static_cast<UNIT_LIB_DEFAULT_TYPE>(lhs), rhs);
}
template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>>
constexpr bool operator>(const UNIT_LIB_DEFAULT_TYPE lhs, const Units& rhs) noexcept
{
return lhs > static_cast<UNIT_LIB_DEFAULT_TYPE>(rhs);
}
template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>>
constexpr bool operator>(const Units& lhs, const UNIT_LIB_DEFAULT_TYPE rhs) noexcept
{
return static_cast<UNIT_LIB_DEFAULT_TYPE>(lhs) > rhs;
}
template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>>
constexpr bool operator<=(const UNIT_LIB_DEFAULT_TYPE lhs, const Units& rhs) noexcept
{
return std::islessequal(lhs, static_cast<UNIT_LIB_DEFAULT_TYPE>(rhs));
}
template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>>
constexpr bool operator<=(const Units& lhs, const UNIT_LIB_DEFAULT_TYPE rhs) noexcept
{
return std::islessequal(static_cast<UNIT_LIB_DEFAULT_TYPE>(lhs), rhs);
}
template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>>
constexpr bool operator<(const UNIT_LIB_DEFAULT_TYPE lhs, const Units& rhs) noexcept
{
return lhs < static_cast<UNIT_LIB_DEFAULT_TYPE>(rhs);
}
template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>>
constexpr bool operator<(const Units& lhs, const UNIT_LIB_DEFAULT_TYPE rhs) noexcept
{
return static_cast<UNIT_LIB_DEFAULT_TYPE>(lhs) < rhs;
}
namespace detail
{
template <int N, class U> struct power_of_unit
{
typedef typename units::detail::unit_multiply<U, typename power_of_unit<N - 1, U>::type> type;
};
template <class U> struct power_of_unit<1, U>
{
typedef U type;
};
}
namespace math
{
template<int power, class UnitType, class = typename std::enable_if<traits::has_linear_scale<UnitType>::value, int>>
constexpr auto pow(const UnitType& value) noexcept -> unit_t<typename units::detail::power_of_unit<power, typename units::traits::unit_t_traits<UnitType>::unit_type>::type, typename units::traits::unit_t_traits<UnitType>::underlying_type, linear_scale>
{
return unit_t<typename units::detail::power_of_unit<power, typename units::traits::unit_t_traits<UnitType>::unit_type>::type, typename units::traits::unit_t_traits<UnitType>::underlying_type, linear_scale>
(gcem::pow(value(), power));
}
template<int power, class UnitType, class = typename std::enable_if<traits::has_linear_scale<UnitType>::value, int>>
constexpr auto cpow(const UnitType& value) noexcept -> unit_t<typename units::detail::power_of_unit<power, typename units::traits::unit_t_traits<UnitType>::unit_type>::type, typename units::traits::unit_t_traits<UnitType>::underlying_type, linear_scale>
{
static_assert(power >= 0, "cpow cannot accept negative numbers. Try units::math::pow instead.");
return unit_t<typename units::detail::power_of_unit<power, typename units::traits::unit_t_traits<UnitType>::unit_type>::type, typename units::traits::unit_t_traits<UnitType>::underlying_type, linear_scale>
(detail::pow(value(), power));
}
}
template<typename T>
struct decibel_scale
{
constexpr decibel_scale() = default;
constexpr decibel_scale(const decibel_scale&) = default;
inline ~decibel_scale() = default;
inline decibel_scale& operator=(const decibel_scale&) = default;
#if defined(_MSC_VER) && (_MSC_VER > 1800)
constexpr decibel_scale(decibel_scale&&) = default;
inline decibel_scale& operator=(decibel_scale&&) = default;
#endif
constexpr decibel_scale(const T value) noexcept : m_value(std::pow(10, value / 10)) {}
template<class... Args>
constexpr decibel_scale(const T value, std::true_type, Args&&...) noexcept : m_value(value) {}
constexpr T operator()() const noexcept { return 10 * std::log10(m_value); }
T m_value; };
namespace dimensionless
{
typedef unit_t<scalar, UNIT_LIB_DEFAULT_TYPE, decibel_scale> dB_t;
typedef dB_t dBi_t;
}
#if defined(UNIT_LIB_ENABLE_IOSTREAM)
namespace dimensionless
{
inline std::ostream& operator<<(std::ostream& os, const dB_t& obj) { os << obj() << " dB"; return os; }
}
#endif
}
#if __has_include(<fmt/format.h>) && !defined(UNIT_LIB_DISABLE_FMT)
template <>
struct fmt::formatter<units::dimensionless::dB_t> : fmt::formatter<double>
{
template <typename FmtContext>
auto format(
const units::dimensionless::dB_t& obj,
FmtContext& ctx) const
{
auto out = ctx.out();
out = fmt::formatter<double>::format(obj(), ctx);
return fmt::format_to(out, " dB");
}
};
#endif
namespace units {
template<class UnitTypeLhs, class UnitTypeRhs,
std::enable_if_t<traits::has_decibel_scale<UnitTypeLhs, UnitTypeRhs>::value, int> = 0>
constexpr inline auto operator+(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept -> unit_t<compound_unit<squared<typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type>>, typename units::traits::unit_t_traits<UnitTypeLhs>::underlying_type, decibel_scale>
{
using LhsUnits = typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type;
using RhsUnits = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type;
using underlying_type = typename units::traits::unit_t_traits<UnitTypeLhs>::underlying_type;
return unit_t<compound_unit<squared<LhsUnits>>, underlying_type, decibel_scale>
(lhs.template toLinearized<underlying_type>() * convert<RhsUnits, LhsUnits>(rhs.template toLinearized<underlying_type>()), std::true_type());
}
template<class UnitTypeLhs, std::enable_if_t<traits::has_decibel_scale<UnitTypeLhs>::value && !traits::is_dimensionless_unit<UnitTypeLhs>::value, int> = 0>
constexpr inline UnitTypeLhs operator+(const UnitTypeLhs& lhs, const dimensionless::dB_t& rhs) noexcept
{
using underlying_type = typename units::traits::unit_t_traits<UnitTypeLhs>::underlying_type;
return UnitTypeLhs(lhs.template toLinearized<underlying_type>() * rhs.template toLinearized<underlying_type>(), std::true_type());
}
template<class UnitTypeRhs, std::enable_if_t<traits::has_decibel_scale<UnitTypeRhs>::value && !traits::is_dimensionless_unit<UnitTypeRhs>::value, int> = 0>
constexpr inline UnitTypeRhs operator+(const dimensionless::dB_t& lhs, const UnitTypeRhs& rhs) noexcept
{
using underlying_type = typename units::traits::unit_t_traits<UnitTypeRhs>::underlying_type;
return UnitTypeRhs(lhs.template toLinearized<underlying_type>() * rhs.template toLinearized<underlying_type>(), std::true_type());
}
template<class UnitTypeLhs, class UnitTypeRhs, std::enable_if_t<traits::has_decibel_scale<UnitTypeLhs, UnitTypeRhs>::value, int> = 0>
constexpr inline auto operator-(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept -> unit_t<compound_unit<typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type, inverse<typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type>>, typename units::traits::unit_t_traits<UnitTypeLhs>::underlying_type, decibel_scale>
{
using LhsUnits = typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type;
using RhsUnits = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type;
using underlying_type = typename units::traits::unit_t_traits<UnitTypeLhs>::underlying_type;
return unit_t<compound_unit<LhsUnits, inverse<RhsUnits>>, underlying_type, decibel_scale>
(lhs.template toLinearized<underlying_type>() / convert<RhsUnits, LhsUnits>(rhs.template toLinearized<underlying_type>()), std::true_type());
}
template<class UnitTypeLhs, std::enable_if_t<traits::has_decibel_scale<UnitTypeLhs>::value && !traits::is_dimensionless_unit<UnitTypeLhs>::value, int> = 0>
constexpr inline UnitTypeLhs operator-(const UnitTypeLhs& lhs, const dimensionless::dB_t& rhs) noexcept
{
using underlying_type = typename units::traits::unit_t_traits<UnitTypeLhs>::underlying_type;
return UnitTypeLhs(lhs.template toLinearized<underlying_type>() / rhs.template toLinearized<underlying_type>(), std::true_type());
}
template<class UnitTypeRhs, std::enable_if_t<traits::has_decibel_scale<UnitTypeRhs>::value && !traits::is_dimensionless_unit<UnitTypeRhs>::value, int> = 0>
constexpr inline auto operator-(const dimensionless::dB_t& lhs, const UnitTypeRhs& rhs) noexcept -> unit_t<inverse<typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type>, typename units::traits::unit_t_traits<UnitTypeRhs>::underlying_type, decibel_scale>
{
using RhsUnits = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type;
using underlying_type = typename units::traits::unit_t_traits<RhsUnits>::underlying_type;
return unit_t<inverse<RhsUnits>, underlying_type, decibel_scale>
(lhs.template toLinearized<underlying_type>() / rhs.template toLinearized<underlying_type>(), std::true_type());
}
namespace detail
{
template<class Units>
struct _unit_value_t {};
}
namespace traits
{
#ifdef FOR_DOXYGEN_PURPOSES_ONLY
template<typename T>
struct unit_value_t_traits
{
typedef typename T::unit_type unit_type; typedef typename T::ratio ratio; };
#endif
template<typename T, typename = void>
struct unit_value_t_traits
{
typedef void unit_type;
typedef void ratio;
};
template<typename T>
struct unit_value_t_traits <T, typename void_t<
typename T::unit_type,
typename T::ratio>::type>
{
typedef typename T::unit_type unit_type;
typedef typename T::ratio ratio;
};
}
template<typename Units, std::uintmax_t Num, std::uintmax_t Denom = 1>
struct unit_value_t : units::detail::_unit_value_t<Units>
{
typedef Units unit_type;
typedef std::ratio<Num, Denom> ratio;
static_assert(traits::is_unit<Units>::value, "Template parameter `Units` must be a unit type.");
static constexpr const unit_t<Units> value() { return unit_t<Units>((UNIT_LIB_DEFAULT_TYPE)ratio::num / ratio::den); }
};
namespace traits
{
template<typename T, typename Units = typename traits::unit_value_t_traits<T>::unit_type>
struct is_unit_value_t : std::integral_constant<bool,
std::is_base_of<units::detail::_unit_value_t<Units>, T>::value>
{};
template<typename T, typename Units = typename traits::unit_value_t_traits<T>::unit_type>
constexpr bool is_unit_value_t_v = is_unit_value_t<T, Units>::value;
template<typename Category, typename T>
struct is_unit_value_t_category : std::integral_constant<bool,
std::is_same<units::traits::base_unit_of<typename traits::unit_value_t_traits<T>::unit_type>, Category>::value>
{
static_assert(is_base_unit<Category>::value, "Template parameter `Category` must be a `base_unit` type.");
};
template<typename Category, typename T>
constexpr bool is_unit_value_t_category_v = is_unit_value_t_category<Category, T>::value;
}
namespace detail
{
template<class U1, class U2>
struct unit_value_arithmetic
{
static_assert(traits::is_unit_value_t<U1>::value, "Template parameter `U1` must be a `unit_value_t` type.");
static_assert(traits::is_unit_value_t<U2>::value, "Template parameter `U2` must be a `unit_value_t` type.");
using _UNIT1 = typename traits::unit_value_t_traits<U1>::unit_type;
using _UNIT2 = typename traits::unit_value_t_traits<U2>::unit_type;
using _CONV1 = typename units::traits::unit_traits<_UNIT1>::conversion_ratio;
using _CONV2 = typename units::traits::unit_traits<_UNIT2>::conversion_ratio;
using _RATIO1 = typename traits::unit_value_t_traits<U1>::ratio;
using _RATIO2 = typename traits::unit_value_t_traits<U2>::ratio;
using _RATIO2CONV = typename std::ratio_divide<std::ratio_multiply<_RATIO2, _CONV2>, _CONV1>;
using _PI_EXP = std::ratio_subtract<typename units::traits::unit_traits<_UNIT2>::pi_exponent_ratio, typename units::traits::unit_traits<_UNIT1>::pi_exponent_ratio>;
};
}
template<class U1, class U2>
struct unit_value_add : units::detail::unit_value_arithmetic<U1, U2>, units::detail::_unit_value_t<typename traits::unit_value_t_traits<U1>::unit_type>
{
using Base = units::detail::unit_value_arithmetic<U1, U2>;
typedef typename Base::_UNIT1 unit_type;
using ratio = std::ratio_add<typename Base::_RATIO1, typename Base::_RATIO2CONV>;
static_assert(traits::is_convertible_unit<typename Base::_UNIT1, typename Base::_UNIT2>::value, "Unit types are not compatible.");
static constexpr const unit_t<unit_type> value() noexcept
{
using UsePi = std::integral_constant<bool, Base::_PI_EXP::num != 0>;
return value(UsePi());
}
static constexpr const unit_t<unit_type> value(std::false_type) noexcept
{
return unit_t<unit_type>((UNIT_LIB_DEFAULT_TYPE)ratio::num / ratio::den);
}
static constexpr const unit_t<unit_type> value(std::true_type) noexcept
{
return unit_t<unit_type>(((UNIT_LIB_DEFAULT_TYPE)Base::_RATIO1::num / Base::_RATIO1::den) +
((UNIT_LIB_DEFAULT_TYPE)Base::_RATIO2CONV::num / Base::_RATIO2CONV::den) * std::pow(units::constants::detail::PI_VAL, ((UNIT_LIB_DEFAULT_TYPE)Base::_PI_EXP::num / Base::_PI_EXP::den)));
}
};
template<class U1, class U2>
struct unit_value_subtract : units::detail::unit_value_arithmetic<U1, U2>, units::detail::_unit_value_t<typename traits::unit_value_t_traits<U1>::unit_type>
{
using Base = units::detail::unit_value_arithmetic<U1, U2>;
typedef typename Base::_UNIT1 unit_type;
using ratio = std::ratio_subtract<typename Base::_RATIO1, typename Base::_RATIO2CONV>;
static_assert(traits::is_convertible_unit<typename Base::_UNIT1, typename Base::_UNIT2>::value, "Unit types are not compatible.");
static constexpr const unit_t<unit_type> value() noexcept
{
using UsePi = std::integral_constant<bool, Base::_PI_EXP::num != 0>;
return value(UsePi());
}
static constexpr const unit_t<unit_type> value(std::false_type) noexcept
{
return unit_t<unit_type>((UNIT_LIB_DEFAULT_TYPE)ratio::num / ratio::den);
}
static constexpr const unit_t<unit_type> value(std::true_type) noexcept
{
return unit_t<unit_type>(((UNIT_LIB_DEFAULT_TYPE)Base::_RATIO1::num / Base::_RATIO1::den) - ((UNIT_LIB_DEFAULT_TYPE)Base::_RATIO2CONV::num / Base::_RATIO2CONV::den)
* std::pow(units::constants::detail::PI_VAL, ((UNIT_LIB_DEFAULT_TYPE)Base::_PI_EXP::num / Base::_PI_EXP::den)));
}
};
template<class U1, class U2>
struct unit_value_multiply : units::detail::unit_value_arithmetic<U1, U2>,
units::detail::_unit_value_t<typename std::conditional<traits::is_convertible_unit<typename traits::unit_value_t_traits<U1>::unit_type,
typename traits::unit_value_t_traits<U2>::unit_type>::value, compound_unit<squared<typename traits::unit_value_t_traits<U1>::unit_type>>,
compound_unit<typename traits::unit_value_t_traits<U1>::unit_type, typename traits::unit_value_t_traits<U2>::unit_type>>::type>
{
using Base = units::detail::unit_value_arithmetic<U1, U2>;
using unit_type = std::conditional_t<traits::is_convertible_unit<typename Base::_UNIT1, typename Base::_UNIT2>::value, compound_unit<squared<typename Base::_UNIT1>>, compound_unit<typename Base::_UNIT1, typename Base::_UNIT2>>;
using ratio = std::conditional_t<traits::is_convertible_unit<typename Base::_UNIT1, typename Base::_UNIT2>::value, std::ratio_multiply<typename Base::_RATIO1, typename Base::_RATIO2CONV>, std::ratio_multiply<typename Base::_RATIO1, typename Base::_RATIO2>>;
static constexpr const unit_t<unit_type> value() noexcept
{
using UsePi = std::integral_constant<bool, Base::_PI_EXP::num != 0>;
return value(UsePi());
}
static constexpr const unit_t<unit_type> value(std::false_type) noexcept
{
return unit_t<unit_type>((UNIT_LIB_DEFAULT_TYPE)ratio::num / ratio::den);
}
static constexpr const unit_t<unit_type> value(std::true_type) noexcept
{
return unit_t<unit_type>(((UNIT_LIB_DEFAULT_TYPE)ratio::num / ratio::den) * std::pow(units::constants::detail::PI_VAL, ((UNIT_LIB_DEFAULT_TYPE)Base::_PI_EXP::num / Base::_PI_EXP::den)));
}
};
template<class U1, class U2>
struct unit_value_divide : units::detail::unit_value_arithmetic<U1, U2>,
units::detail::_unit_value_t<typename std::conditional<traits::is_convertible_unit<typename traits::unit_value_t_traits<U1>::unit_type,
typename traits::unit_value_t_traits<U2>::unit_type>::value, dimensionless::scalar, compound_unit<typename traits::unit_value_t_traits<U1>::unit_type,
inverse<typename traits::unit_value_t_traits<U2>::unit_type>>>::type>
{
using Base = units::detail::unit_value_arithmetic<U1, U2>;
using unit_type = std::conditional_t<traits::is_convertible_unit<typename Base::_UNIT1, typename Base::_UNIT2>::value, dimensionless::scalar, compound_unit<typename Base::_UNIT1, inverse<typename Base::_UNIT2>>>;
using ratio = std::conditional_t<traits::is_convertible_unit<typename Base::_UNIT1, typename Base::_UNIT2>::value, std::ratio_divide<typename Base::_RATIO1, typename Base::_RATIO2CONV>, std::ratio_divide<typename Base::_RATIO1, typename Base::_RATIO2>>;
static constexpr const unit_t<unit_type> value() noexcept
{
using UsePi = std::integral_constant<bool, Base::_PI_EXP::num != 0>;
return value(UsePi());
}
static constexpr const unit_t<unit_type> value(std::false_type) noexcept
{
return unit_t<unit_type>((UNIT_LIB_DEFAULT_TYPE)ratio::num / ratio::den);
}
static constexpr const unit_t<unit_type> value(std::true_type) noexcept
{
return unit_t<unit_type>(((UNIT_LIB_DEFAULT_TYPE)ratio::num / ratio::den) * std::pow(units::constants::detail::PI_VAL, ((UNIT_LIB_DEFAULT_TYPE)Base::_PI_EXP::num / Base::_PI_EXP::den)));
}
};
template<class U1, int power>
struct unit_value_power : units::detail::unit_value_arithmetic<U1, U1>, units::detail::_unit_value_t<typename units::detail::power_of_unit<power, typename traits::unit_value_t_traits<U1>::unit_type>::type>
{
using Base = units::detail::unit_value_arithmetic<U1, U1>;
using unit_type = typename units::detail::power_of_unit<power, typename Base::_UNIT1>::type;
using ratio = typename units::detail::power_of_ratio<power, typename Base::_RATIO1>::type;
using pi_exponent = std::ratio_multiply<std::ratio<power>, typename Base::_UNIT1::pi_exponent_ratio>;
static constexpr const unit_t<unit_type> value() noexcept
{
using UsePi = std::integral_constant<bool, Base::_PI_EXP::num != 0>;
return value(UsePi());
}
static constexpr const unit_t<unit_type> value(std::false_type) noexcept
{
return unit_t<unit_type>((UNIT_LIB_DEFAULT_TYPE)ratio::num / ratio::den);
}
static constexpr const unit_t<unit_type> value(std::true_type) noexcept
{
return unit_t<unit_type>(((UNIT_LIB_DEFAULT_TYPE)ratio::num / ratio::den) * std::pow(units::constants::detail::PI_VAL, ((UNIT_LIB_DEFAULT_TYPE)pi_exponent::num / pi_exponent::den)));
}
};
template<class U1, std::intmax_t Eps = 10000000000>
struct unit_value_sqrt : units::detail::unit_value_arithmetic<U1, U1>, units::detail::_unit_value_t<square_root<typename traits::unit_value_t_traits<U1>::unit_type, Eps>>
{
using Base = units::detail::unit_value_arithmetic<U1, U1>;
using unit_type = square_root<typename Base::_UNIT1, Eps>;
using ratio = ratio_sqrt<typename Base::_RATIO1, Eps>;
using pi_exponent = ratio_sqrt<typename Base::_UNIT1::pi_exponent_ratio, Eps>;
static constexpr const unit_t<unit_type> value() noexcept
{
using UsePi = std::integral_constant<bool, Base::_PI_EXP::num != 0>;
return value(UsePi());
}
static constexpr const unit_t<unit_type> value(std::false_type) noexcept
{
return unit_t<unit_type>((UNIT_LIB_DEFAULT_TYPE)ratio::num / ratio::den);
}
static constexpr const unit_t<unit_type> value(std::true_type) noexcept
{
return unit_t<unit_type>(((UNIT_LIB_DEFAULT_TYPE)ratio::num / ratio::den) * std::pow(units::constants::detail::PI_VAL, ((UNIT_LIB_DEFAULT_TYPE)pi_exponent::num / pi_exponent::den)));
}
};
namespace math
{
template<class UnitTypeLhs, class UnitTypeRhs>
constexpr UnitTypeLhs (min)(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs)
{
static_assert(traits::is_convertible_unit_t<UnitTypeLhs, UnitTypeRhs>::value, "Unit types are not compatible.");
UnitTypeLhs r(rhs);
return (lhs < r ? lhs : r);
}
template<class UnitTypeLhs, class UnitTypeRhs>
constexpr UnitTypeLhs (max)(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs)
{
static_assert(traits::is_convertible_unit_t<UnitTypeLhs, UnitTypeRhs>::value, "Unit types are not compatible.");
UnitTypeLhs r(rhs);
return (lhs > r ? lhs : r);
}
}
}
#ifdef _MSC_VER
# if _MSC_VER <= 1800
# pragma warning(pop)
# undef constexpr
# pragma pop_macro("constexpr")
# undef noexcept
# pragma pop_macro("noexcept")
# undef _ALLOW_KEYWORD_MACROS
# endif # pragma pop_macro("pascal")
#endif
#if defined(UNIT_HAS_LITERAL_SUPPORT)
namespace units::literals {}
using namespace units::literals;
#endif
#if __has_include(<fmt/format.h>) && !defined(UNIT_LIB_DISABLE_FMT)
#include "units/formatter.h"
#endif