1 //-------------------------------------------------------------------------------------------------- 2 // 3 // Units: A compile-time c++14 unit conversion library with no dependencies 4 // 5 //-------------------------------------------------------------------------------------------------- 6 // 7 // The MIT License (MIT) 8 // 9 // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 10 // and associated documentation files (the "Software"), to deal in the Software without 11 // restriction, including without limitation the rights to use, copy, modify, merge, publish, 12 // distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 13 // Software is furnished to do so, subject to the following conditions: 14 // 15 // The above copyright notice and this permission notice shall be included in all copies or 16 // substantial portions of the Software. 17 // 18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 19 // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 21 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 // 24 //-------------------------------------------------------------------------------------------------- 25 // 26 // Copyright (c) 2016 Nic Holthaus 27 // 28 //-------------------------------------------------------------------------------------------------- 29 // 30 // ATTRIBUTION: 31 // Parts of this work have been adapted from: 32 // http://stackoverflow.com/questions/35069778/create-comparison-trait-for-template-classes-whose-parameters-are-in-a-different 33 // http://stackoverflow.com/questions/28253399/check-traits-for-all-variadic-template-arguments/28253503 34 // http://stackoverflow.com/questions/36321295/rational-approximation-of-square-root-of-stdratio-at-compile-time?noredirect=1#comment60266601_36321295 35 // 36 //-------------------------------------------------------------------------------------------------- 37 // 38 /// @file units.h 39 /// @brief Complete implementation of `units` - a compile-time, header-only, unit conversion 40 /// library built on c++14 with no dependencies. 41 // 42 //-------------------------------------------------------------------------------------------------- 43 44 #pragma once 45 46 #ifndef units_h__ 47 #define units_h__ 48 49 #ifdef _MSC_VER 50 # pragma push_macro("pascal") 51 # undef pascal 52 # if _MSC_VER <= 1800 53 # define _ALLOW_KEYWORD_MACROS 54 # pragma warning(push) 55 # pragma warning(disable : 4520) 56 # pragma push_macro("constexpr") 57 # define constexpr /*constexpr*/ 58 # pragma push_macro("noexcept") 59 # define noexcept throw() 60 # endif // _MSC_VER < 1800 61 #endif // _MSC_VER 62 63 #if !defined(_MSC_VER) || _MSC_VER > 1800 64 # define UNIT_HAS_LITERAL_SUPPORT 65 # define UNIT_HAS_VARIADIC_TEMPLATE_SUPPORT 66 #endif 67 68 #ifndef UNIT_LIB_DEFAULT_TYPE 69 # define UNIT_LIB_DEFAULT_TYPE double 70 #endif 71 72 //-------------------- 73 // INCLUDES 74 //-------------------- 75 76 #include <chrono> 77 #include <ratio> 78 #include <type_traits> 79 #include <cstdint> 80 #include <cmath> 81 #include <limits> 82 83 #if !defined(UNIT_LIB_DISABLE_IOSTREAM) 84 #include <iostream> 85 #include <string> 86 #include <locale> 87 88 //------------------------------ 89 // STRING FORMATTER 90 //------------------------------ 91 92 namespace units 93 { 94 namespace detail 95 { to_string(const T & t)96 template <typename T> std::string to_string(const T& t) 97 { 98 std::string str{ std::to_string(t) }; 99 int offset{ 1 }; 100 101 // remove trailing decimal points for integer value units. Locale aware! 102 struct lconv * lc; 103 lc = localeconv(); 104 char decimalPoint = *lc->decimal_point; 105 if (str.find_last_not_of('0') == str.find(decimalPoint)) { offset = 0; } 106 str.erase(str.find_last_not_of('0') + offset, std::string::npos); 107 return str; 108 } 109 } 110 } 111 #endif 112 113 namespace units 114 { 115 template<typename T> inline constexpr const char* name(const T&); 116 template<typename T> inline constexpr const char* abbreviation(const T&); 117 } 118 119 //------------------------------ 120 // MACROS 121 //------------------------------ 122 123 /** 124 * @def UNIT_ADD_UNIT_TAGS(namespaceName,nameSingular, namePlural, abbreviation, definition) 125 * @brief Helper macro for generating the boiler-plate code generating the tags of a new unit. 126 * @details The macro generates singular, plural, and abbreviated forms 127 * of the unit definition (e.g. `meter`, `meters`, and `m`), as aliases for the 128 * unit tag. 129 * @param namespaceName namespace in which the new units will be encapsulated. 130 * @param nameSingular singular version of the unit name, e.g. 'meter' 131 * @param namePlural - plural version of the unit name, e.g. 'meters' 132 * @param abbreviation - abbreviated unit name, e.g. 'm' 133 * @param definition - the variadic parameter is used for the definition of the unit 134 * (e.g. `unit<std::ratio<1>, units::category::length_unit>`) 135 * @note a variadic template is used for the definition to allow templates with 136 * commas to be easily expanded. All the variadic 'arguments' should together 137 * comprise the unit definition. 138 */ 139 #define UNIT_ADD_UNIT_TAGS(namespaceName,nameSingular, namePlural, abbreviation, /*definition*/...)\ 140 namespace namespaceName\ 141 {\ 142 /** @name Units (full names plural) */ /** @{ */ typedef __VA_ARGS__ namePlural; /** @} */\ 143 /** @name Units (full names singular) */ /** @{ */ typedef namePlural nameSingular; /** @} */\ 144 /** @name Units (abbreviated) */ /** @{ */ typedef namePlural abbreviation; /** @} */\ 145 } 146 147 /** 148 * @def UNIT_ADD_UNIT_DEFINITION(namespaceName,nameSingular) 149 * @brief Macro for generating the boiler-plate code for the unit_t type definition. 150 * @details The macro generates the definition of the unit container types, e.g. `meter_t` 151 * @param namespaceName namespace in which the new units will be encapsulated. 152 * @param nameSingular singular version of the unit name, e.g. 'meter' 153 */ 154 #define UNIT_ADD_UNIT_DEFINITION(namespaceName,nameSingular)\ 155 namespace namespaceName\ 156 {\ 157 /** @name Unit Containers */ /** @{ */ typedef unit_t<nameSingular> nameSingular ## _t; /** @} */\ 158 } 159 160 /** 161 * @def UNIT_ADD_CUSTOM_TYPE_UNIT_DEFINITION(namespaceName,nameSingular,underlyingType) 162 * @brief Macro for generating the boiler-plate code for a unit_t type definition with a non-default underlying type. 163 * @details The macro generates the definition of the unit container types, e.g. `meter_t` 164 * @param namespaceName namespace in which the new units will be encapsulated. 165 * @param nameSingular singular version of the unit name, e.g. 'meter' 166 * @param underlyingType the underlying type 167 */ 168 #define UNIT_ADD_CUSTOM_TYPE_UNIT_DEFINITION(namespaceName,nameSingular, underlyingType)\ 169 namespace namespaceName\ 170 {\ 171 /** @name Unit Containers */ /** @{ */ typedef unit_t<nameSingular,underlyingType> nameSingular ## _t; /** @} */\ 172 } 173 /** 174 * @def UNIT_ADD_IO(namespaceName,nameSingular, abbreviation) 175 * @brief Macro for generating the boiler-plate code needed for I/O for a new unit. 176 * @details The macro generates the code to insert units into an ostream. It 177 * prints both the value and abbreviation of the unit when invoked. 178 * @param namespaceName namespace in which the new units will be encapsulated. 179 * @param nameSingular singular version of the unit name, e.g. 'meter' 180 * @param abbrev - abbreviated unit name, e.g. 'm' 181 * @note When UNIT_LIB_DISABLE_IOSTREAM is defined, the macro does not generate any code 182 */ 183 #if defined(UNIT_LIB_DISABLE_IOSTREAM) 184 #define UNIT_ADD_IO(namespaceName, nameSingular, abbrev) 185 #else 186 #define UNIT_ADD_IO(namespaceName, nameSingular, abbrev)\ 187 namespace namespaceName\ 188 {\ 189 inline std::ostream& operator<<(std::ostream& os, const nameSingular ## _t& obj) \ 190 {\ 191 os << obj() << " "#abbrev; return os; \ 192 }\ 193 inline std::string to_string(const nameSingular ## _t& obj)\ 194 {\ 195 return units::detail::to_string(obj()) + std::string(" "#abbrev);\ 196 }\ 197 } 198 #endif 199 200 /** 201 * @def UNIT_ADD_NAME(namespaceName,nameSingular,abbreviation) 202 * @brief Macro for generating constexpr names/abbreviations for units. 203 * @details The macro generates names for units. E.g. name() of 1_m would be "meter", and 204 * abbreviation would be "m". 205 * @param namespaceName namespace in which the new units will be encapsulated. All literal values 206 * are placed in the `units::literals` namespace. 207 * @param nameSingular singular version of the unit name, e.g. 'meter' 208 * @param abbreviation - abbreviated unit name, e.g. 'm' 209 */ 210 #define UNIT_ADD_NAME(namespaceName, nameSingular, abbrev)\ 211 template<> inline constexpr const char* name(const namespaceName::nameSingular ## _t&)\ 212 {\ 213 return #nameSingular;\ 214 }\ 215 template<> inline constexpr const char* abbreviation(const namespaceName::nameSingular ## _t&)\ 216 {\ 217 return #abbrev;\ 218 } 219 220 /** 221 * @def UNIT_ADD_LITERALS(namespaceName,nameSingular,abbreviation) 222 * @brief Macro for generating user-defined literals for units. 223 * @details The macro generates user-defined literals for units. A literal suffix is created 224 * using the abbreviation (e.g. `10.0_m`). 225 * @param namespaceName namespace in which the new units will be encapsulated. All literal values 226 * are placed in the `units::literals` namespace. 227 * @param nameSingular singular version of the unit name, e.g. 'meter' 228 * @param abbreviation - abbreviated unit name, e.g. 'm' 229 * @note When UNIT_HAS_LITERAL_SUPPORT is not defined, the macro does not generate any code 230 */ 231 #if defined(UNIT_HAS_LITERAL_SUPPORT) 232 #define UNIT_ADD_LITERALS(namespaceName, nameSingular, abbreviation)\ 233 namespace literals\ 234 {\ 235 inline constexpr namespaceName::nameSingular ## _t operator""_ ## abbreviation(long double d)\ 236 {\ 237 return namespaceName::nameSingular ## _t(static_cast<namespaceName::nameSingular ## _t::underlying_type>(d));\ 238 }\ 239 inline constexpr namespaceName::nameSingular ## _t operator""_ ## abbreviation (unsigned long long d)\ 240 {\ 241 return namespaceName::nameSingular ## _t(static_cast<namespaceName::nameSingular ## _t::underlying_type>(d));\ 242 }\ 243 } 244 #else 245 #define UNIT_ADD_LITERALS(namespaceName, nameSingular, abbreviation) 246 #endif 247 248 /** 249 * @def UNIT_ADD(namespaceName,nameSingular, namePlural, abbreviation, definition) 250 * @brief Macro for generating the boiler-plate code needed for a new unit. 251 * @details The macro generates singular, plural, and abbreviated forms 252 * of the unit definition (e.g. `meter`, `meters`, and `m`), as well as the 253 * appropriately named unit container (e.g. `meter_t`). A literal suffix is created 254 * using the abbreviation (e.g. `10.0_m`). It also defines a class-specific 255 * cout function which prints both the value and abbreviation of the unit when invoked. 256 * @param namespaceName namespace in which the new units will be encapsulated. All literal values 257 * are placed in the `units::literals` namespace. 258 * @param nameSingular singular version of the unit name, e.g. 'meter' 259 * @param namePlural - plural version of the unit name, e.g. 'meters' 260 * @param abbreviation - abbreviated unit name, e.g. 'm' 261 * @param definition - the variadic parameter is used for the definition of the unit 262 * (e.g. `unit<std::ratio<1>, units::category::length_unit>`) 263 * @note a variadic template is used for the definition to allow templates with 264 * commas to be easily expanded. All the variadic 'arguments' should together 265 * comprise the unit definition. 266 */ 267 #define UNIT_ADD(namespaceName, nameSingular, namePlural, abbreviation, /*definition*/...)\ 268 UNIT_ADD_UNIT_TAGS(namespaceName,nameSingular, namePlural, abbreviation, __VA_ARGS__)\ 269 UNIT_ADD_UNIT_DEFINITION(namespaceName,nameSingular)\ 270 UNIT_ADD_NAME(namespaceName,nameSingular, abbreviation)\ 271 UNIT_ADD_IO(namespaceName,nameSingular, abbreviation)\ 272 UNIT_ADD_LITERALS(namespaceName,nameSingular, abbreviation) 273 274 /** 275 * @def UNIT_ADD_WITH_CUSTOM_TYPE(namespaceName,nameSingular, namePlural, abbreviation, underlyingType, definition) 276 * @brief Macro for generating the boiler-plate code needed for a new unit with a non-default underlying type. 277 * @details The macro generates singular, plural, and abbreviated forms 278 * of the unit definition (e.g. `meter`, `meters`, and `m`), as well as the 279 * appropriately named unit container (e.g. `meter_t`). A literal suffix is created 280 * using the abbreviation (e.g. `10.0_m`). It also defines a class-specific 281 * cout function which prints both the value and abbreviation of the unit when invoked. 282 * @param namespaceName namespace in which the new units will be encapsulated. All literal values 283 * are placed in the `units::literals` namespace. 284 * @param nameSingular singular version of the unit name, e.g. 'meter' 285 * @param namePlural - plural version of the unit name, e.g. 'meters' 286 * @param abbreviation - abbreviated unit name, e.g. 'm' 287 * @param underlyingType - the underlying type, e.g. 'int' or 'float' 288 * @param definition - the variadic parameter is used for the definition of the unit 289 * (e.g. `unit<std::ratio<1>, units::category::length_unit>`) 290 * @note a variadic template is used for the definition to allow templates with 291 * commas to be easily expanded. All the variadic 'arguments' should together 292 * comprise the unit definition. 293 */ 294 #define UNIT_ADD_WITH_CUSTOM_TYPE(namespaceName, nameSingular, namePlural, abbreviation, underlyingType, /*definition*/...)\ 295 UNIT_ADD_UNIT_TAGS(namespaceName,nameSingular, namePlural, abbreviation, __VA_ARGS__)\ 296 UNIT_ADD_CUSTOM_TYPE_UNIT_DEFINITION(namespaceName,nameSingular,underlyingType)\ 297 UNIT_ADD_IO(namespaceName,nameSingular, abbreviation)\ 298 UNIT_ADD_LITERALS(namespaceName,nameSingular, abbreviation) 299 300 /** 301 * @def UNIT_ADD_DECIBEL(namespaceName, nameSingular, abbreviation) 302 * @brief Macro to create decibel container and literals for an existing unit type. 303 * @details This macro generates the decibel unit container, cout overload, and literal definitions. 304 * @param namespaceName namespace in which the new units will be encapsulated. All literal values 305 * are placed in the `units::literals` namespace. 306 * @param nameSingular singular version of the base unit name, e.g. 'watt' 307 * @param abbreviation - abbreviated decibel unit name, e.g. 'dBW' 308 */ 309 #define UNIT_ADD_DECIBEL(namespaceName, nameSingular, abbreviation)\ 310 namespace namespaceName\ 311 {\ 312 /** @name Unit Containers */ /** @{ */ typedef unit_t<nameSingular, UNIT_LIB_DEFAULT_TYPE, units::decibel_scale> abbreviation ## _t; /** @} */\ 313 }\ 314 UNIT_ADD_IO(namespaceName, abbreviation, abbreviation)\ 315 UNIT_ADD_LITERALS(namespaceName, abbreviation, abbreviation) 316 317 /** 318 * @def UNIT_ADD_CATEGORY_TRAIT(unitCategory, baseUnit) 319 * @brief Macro to create the `is_category_unit` type trait. 320 * @details This trait allows users to test whether a given type matches 321 * an intended category. This macro comprises all the boiler-plate 322 * code necessary to do so. 323 * @param unitCategory The name of the category of unit, e.g. length or mass. 324 */ 325 326 #define UNIT_ADD_CATEGORY_TRAIT_DETAIL(unitCategory)\ 327 namespace traits\ 328 {\ 329 /** @cond */\ 330 namespace detail\ 331 {\ 332 template<typename T> struct is_ ## unitCategory ## _unit_impl : std::false_type {};\ 333 template<typename C, typename U, typename P, typename T>\ 334 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 {};\ 335 template<typename U, typename S, template<typename> class N>\ 336 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 {};\ 337 }\ 338 /** @endcond */\ 339 } 340 341 #if defined(UNIT_HAS_VARIADIC_TEMPLATE_SUPPORT) 342 #define UNIT_ADD_IS_UNIT_CATEGORY_TRAIT(unitCategory)\ 343 namespace traits\ 344 {\ 345 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> {};\ 346 } 347 #else 348 #define UNIT_ADD_IS_UNIT_CATEGORY_TRAIT(unitCategory)\ 349 namespace traits\ 350 {\ 351 template<typename T1, typename T2 = T1, typename T3 = T1>\ 352 struct is_ ## unitCategory ## _unit : std::integral_constant<bool, units::traits::detail::is_ ## unitCategory ## _unit_impl<typename std::decay<T1>::type>::value &&\ 353 units::traits::detail::is_ ## unitCategory ## _unit_impl<typename std::decay<T2>::type>::value &&\ 354 units::traits::detail::is_ ## unitCategory ## _unit_impl<typename std::decay<T3>::type>::value>{};\ 355 } 356 #endif 357 358 #define UNIT_ADD_CATEGORY_TRAIT(unitCategory)\ 359 UNIT_ADD_CATEGORY_TRAIT_DETAIL(unitCategory)\ 360 /** @ingroup TypeTraits*/\ 361 /** @brief Trait which tests whether a type represents a unit of unitCategory*/\ 362 /** @details Inherits from `std::true_type` or `std::false_type`. Use `is_ ## unitCategory ## _unit<T>::value` to test the unit represents a unitCategory quantity.*/\ 363 /** @tparam T one or more types to test*/\ 364 UNIT_ADD_IS_UNIT_CATEGORY_TRAIT(unitCategory) 365 366 /** 367 * @def UNIT_ADD_WITH_METRIC_PREFIXES(nameSingular, namePlural, abbreviation, definition) 368 * @brief Macro for generating the boiler-plate code needed for a new unit, including its metric 369 * prefixes from femto to peta. 370 * @details See UNIT_ADD. In addition to generating the unit definition and containers '(e.g. `meters` and 'meter_t', 371 * it also creates corresponding units with metric suffixes such as `millimeters`, and `millimeter_t`), as well as the 372 * literal suffixes (e.g. `10.0_mm`). 373 * @param namespaceName namespace in which the new units will be encapsulated. All literal values 374 * are placed in the `units::literals` namespace. 375 * @param nameSingular singular version of the unit name, e.g. 'meter' 376 * @param namePlural - plural version of the unit name, e.g. 'meters' 377 * @param abbreviation - abbreviated unit name, e.g. 'm' 378 * @param definition - the variadic parameter is used for the definition of the unit 379 * (e.g. `unit<std::ratio<1>, units::category::length_unit>`) 380 * @note a variadic template is used for the definition to allow templates with 381 * commas to be easily expanded. All the variadic 'arguments' should together 382 * comprise the unit definition. 383 */ 384 #define UNIT_ADD_WITH_METRIC_PREFIXES(namespaceName, nameSingular, namePlural, abbreviation, /*definition*/...)\ 385 UNIT_ADD(namespaceName, nameSingular, namePlural, abbreviation, __VA_ARGS__)\ 386 UNIT_ADD(namespaceName, femto ## nameSingular, femto ## namePlural, f ## abbreviation, femto<namePlural>)\ 387 UNIT_ADD(namespaceName, pico ## nameSingular, pico ## namePlural, p ## abbreviation, pico<namePlural>)\ 388 UNIT_ADD(namespaceName, nano ## nameSingular, nano ## namePlural, n ## abbreviation, nano<namePlural>)\ 389 UNIT_ADD(namespaceName, micro ## nameSingular, micro ## namePlural, u ## abbreviation, micro<namePlural>)\ 390 UNIT_ADD(namespaceName, milli ## nameSingular, milli ## namePlural, m ## abbreviation, milli<namePlural>)\ 391 UNIT_ADD(namespaceName, centi ## nameSingular, centi ## namePlural, c ## abbreviation, centi<namePlural>)\ 392 UNIT_ADD(namespaceName, deci ## nameSingular, deci ## namePlural, d ## abbreviation, deci<namePlural>)\ 393 UNIT_ADD(namespaceName, deca ## nameSingular, deca ## namePlural, da ## abbreviation, deca<namePlural>)\ 394 UNIT_ADD(namespaceName, hecto ## nameSingular, hecto ## namePlural, h ## abbreviation, hecto<namePlural>)\ 395 UNIT_ADD(namespaceName, kilo ## nameSingular, kilo ## namePlural, k ## abbreviation, kilo<namePlural>)\ 396 UNIT_ADD(namespaceName, mega ## nameSingular, mega ## namePlural, M ## abbreviation, mega<namePlural>)\ 397 UNIT_ADD(namespaceName, giga ## nameSingular, giga ## namePlural, G ## abbreviation, giga<namePlural>)\ 398 UNIT_ADD(namespaceName, tera ## nameSingular, tera ## namePlural, T ## abbreviation, tera<namePlural>)\ 399 UNIT_ADD(namespaceName, peta ## nameSingular, peta ## namePlural, P ## abbreviation, peta<namePlural>)\ 400 401 /** 402 * @def UNIT_ADD_WITH_METRIC_AND_BINARY_PREFIXES(nameSingular, namePlural, abbreviation, definition) 403 * @brief Macro for generating the boiler-plate code needed for a new unit, including its metric 404 * prefixes from femto to peta, and binary prefixes from kibi to exbi. 405 * @details See UNIT_ADD. In addition to generating the unit definition and containers '(e.g. `bytes` and 'byte_t', 406 * it also creates corresponding units with metric suffixes such as `millimeters`, and `millimeter_t`), as well as the 407 * literal suffixes (e.g. `10.0_B`). 408 * @param namespaceName namespace in which the new units will be encapsulated. All literal values 409 * are placed in the `units::literals` namespace. 410 * @param nameSingular singular version of the unit name, e.g. 'byte' 411 * @param namePlural - plural version of the unit name, e.g. 'bytes' 412 * @param abbreviation - abbreviated unit name, e.g. 'B' 413 * @param definition - the variadic parameter is used for the definition of the unit 414 * (e.g. `unit<std::ratio<1>, units::category::data_unit>`) 415 * @note a variadic template is used for the definition to allow templates with 416 * commas to be easily expanded. All the variadic 'arguments' should together 417 * comprise the unit definition. 418 */ 419 #define UNIT_ADD_WITH_METRIC_AND_BINARY_PREFIXES(namespaceName, nameSingular, namePlural, abbreviation, /*definition*/...)\ 420 UNIT_ADD_WITH_METRIC_PREFIXES(namespaceName, nameSingular, namePlural, abbreviation, __VA_ARGS__)\ 421 UNIT_ADD(namespaceName, kibi ## nameSingular, kibi ## namePlural, Ki ## abbreviation, kibi<namePlural>)\ 422 UNIT_ADD(namespaceName, mebi ## nameSingular, mebi ## namePlural, Mi ## abbreviation, mebi<namePlural>)\ 423 UNIT_ADD(namespaceName, gibi ## nameSingular, gibi ## namePlural, Gi ## abbreviation, gibi<namePlural>)\ 424 UNIT_ADD(namespaceName, tebi ## nameSingular, tebi ## namePlural, Ti ## abbreviation, tebi<namePlural>)\ 425 UNIT_ADD(namespaceName, pebi ## nameSingular, pebi ## namePlural, Pi ## abbreviation, pebi<namePlural>)\ 426 UNIT_ADD(namespaceName, exbi ## nameSingular, exbi ## namePlural, Ei ## abbreviation, exbi<namePlural>) 427 428 //-------------------- 429 // UNITS NAMESPACE 430 //-------------------- 431 432 /** 433 * @namespace units 434 * @brief Unit Conversion Library namespace 435 */ 436 namespace units 437 { 438 //---------------------------------- 439 // DOXYGEN 440 //---------------------------------- 441 442 /** 443 * @defgroup UnitContainers Unit Containers 444 * @brief Defines a series of classes which contain dimensioned values. Unit containers 445 * store a value, and support various arithmetic operations. 446 */ 447 448 /** 449 * @defgroup UnitTypes Unit Types 450 * @brief Defines a series of classes which represent units. These types are tags used by 451 * the conversion function, to create compound units, or to create `unit_t` types. 452 * By themselves, they are not containers and have no stored value. 453 */ 454 455 /** 456 * @defgroup UnitManipulators Unit Manipulators 457 * @brief Defines a series of classes used to manipulate unit types, such as `inverse<>`, `squared<>`, and metric prefixes. 458 * Unit manipulators can be chained together, e.g. `inverse<squared<pico<time::seconds>>>` to 459 * represent picoseconds^-2. 460 */ 461 462 /** 463 * @defgroup CompileTimeUnitManipulators Compile-time Unit Manipulators 464 * @brief Defines a series of classes used to manipulate `unit_value_t` types at compile-time, such as `unit_value_add<>`, `unit_value_sqrt<>`, etc. 465 * Compile-time manipulators can be chained together, e.g. `unit_value_sqrt<unit_value_add<unit_value_power<a, 2>, unit_value_power<b, 2>>>` to 466 * represent `c = sqrt(a^2 + b^2). 467 */ 468 469 /** 470 * @defgroup UnitMath Unit Math 471 * @brief Defines a collection of unit-enabled, strongly-typed versions of `<cmath>` functions. 472 * @details Includes most c++11 extensions. 473 */ 474 475 /** 476 * @defgroup Conversion Explicit Conversion 477 * @brief Functions used to convert values of one logical type to another. 478 */ 479 480 /** 481 * @defgroup TypeTraits Type Traits 482 * @brief Defines a series of classes to obtain unit type information at compile-time. 483 */ 484 485 //------------------------------ 486 // FORWARD DECLARATIONS 487 //------------------------------ 488 489 /** @cond */ // DOXYGEN IGNORE 490 namespace constants 491 { 492 namespace detail 493 { 494 static constexpr const UNIT_LIB_DEFAULT_TYPE PI_VAL = 3.14159265358979323846264338327950288419716939937510; 495 } 496 } 497 /** @endcond */ // END DOXYGEN IGNORE 498 499 //------------------------------ 500 // RATIO TRAITS 501 //------------------------------ 502 503 /** 504 * @ingroup TypeTraits 505 * @{ 506 */ 507 508 /** @cond */ // DOXYGEN IGNORE 509 namespace detail 510 { 511 /// has_num implementation. 512 template<class T> 513 struct has_num_impl 514 { 515 template<class U> testunits::detail::has_num_impl516 static constexpr auto test(U*)->std::is_integral<decltype(U::num)> {return std::is_integral<decltype(U::num)>{}; } 517 template<typename> testunits::detail::has_num_impl518 static constexpr std::false_type test(...) { return std::false_type{}; } 519 520 using type = decltype(test<T>(0)); 521 }; 522 } 523 524 /** 525 * @brief Trait which checks for the existence of a static numerator. 526 * @details Inherits from `std::true_type` or `std::false_type`. Use `has_num<T>::value` to test 527 * whether `class T` has a numerator static member. 528 */ 529 template<class T> 530 struct has_num : units::detail::has_num_impl<T>::type {}; 531 532 namespace detail 533 { 534 /// has_den implementation. 535 template<class T> 536 struct has_den_impl 537 { 538 template<class U> testunits::detail::has_den_impl539 static constexpr auto test(U*)->std::is_integral<decltype(U::den)> { return std::is_integral<decltype(U::den)>{}; } 540 template<typename> testunits::detail::has_den_impl541 static constexpr std::false_type test(...) { return std::false_type{}; } 542 543 using type = decltype(test<T>(0)); 544 }; 545 } 546 547 /** 548 * @brief Trait which checks for the existence of a static denominator. 549 * @details Inherits from `std::true_type` or `std::false_type`. Use `has_den<T>::value` to test 550 * whether `class T` has a denominator static member. 551 */ 552 template<class T> 553 struct has_den : units::detail::has_den_impl<T>::type {}; 554 555 /** @endcond */ // END DOXYGEN IGNORE 556 557 namespace traits 558 { 559 /** 560 * @brief Trait that tests whether a type represents a std::ratio. 561 * @details Inherits from `std::true_type` or `std::false_type`. Use `is_ratio<T>::value` to test 562 * whether `class T` implements a std::ratio. 563 */ 564 template<class T> 565 struct is_ratio : std::integral_constant<bool, 566 has_num<T>::value && 567 has_den<T>::value> 568 {}; 569 } 570 571 //------------------------------ 572 // UNIT TRAITS 573 //------------------------------ 574 575 /** @cond */ // DOXYGEN IGNORE 576 /** 577 * @brief void type. 578 * @details Helper class for creating type traits. 579 */ 580 template<class ...> 581 struct void_t { typedef void type; }; 582 583 /** 584 * @brief parameter pack for boolean arguments. 585 */ 586 template<bool...> struct bool_pack {}; 587 588 /** 589 * @brief Trait which tests that a set of other traits are all true. 590 */ 591 template<bool... Args> 592 struct all_true : std::is_same<units::bool_pack<true, Args...>, units::bool_pack<Args..., true>> {}; 593 /** @endcond */ // DOXYGEN IGNORE 594 595 /** 596 * @brief namespace representing type traits which can access the properties of types provided by the units library. 597 */ 598 namespace traits 599 { 600 #ifdef FOR_DOXYGEN_PURPOSES_ONLY 601 /** 602 * @ingroup TypeTraits 603 * @brief Traits class defining the properties of units. 604 * @details The units library determines certain properties of the units passed to 605 * them and what they represent by using the members of the corresponding 606 * unit_traits instantiation. 607 */ 608 template<class T> 609 struct unit_traits 610 { 611 typedef typename T::base_unit_type base_unit_type; ///< Unit type that the unit was derived from. May be a `base_unit` or another `unit`. Use the `base_unit_of` trait to find the SI base unit type. This will be `void` if type `T` is not a unit. 612 typedef typename T::conversion_ratio conversion_ratio; ///< `std::ratio` representing the conversion factor to the `base_unit_type`. This will be `void` if type `T` is not a unit. 613 typedef typename T::pi_exponent_ratio pi_exponent_ratio; ///< `std::ratio` representing the exponent of pi to be used in the conversion. This will be `void` if type `T` is not a unit. 614 typedef typename T::translation_ratio translation_ratio; ///< `std::ratio` representing a datum translation to the base unit (i.e. degrees C to degrees F conversion). This will be `void` if type `T` is not a unit. 615 }; 616 #endif 617 /** @cond */ // DOXYGEN IGNORE 618 /** 619 * @brief unit traits implementation for classes which are not units. 620 */ 621 template<class T, typename = void> 622 struct unit_traits 623 { 624 typedef void base_unit_type; 625 typedef void conversion_ratio; 626 typedef void pi_exponent_ratio; 627 typedef void translation_ratio; 628 }; 629 630 template<class T> 631 struct unit_traits 632 <T, typename void_t< 633 typename T::base_unit_type, 634 typename T::conversion_ratio, 635 typename T::pi_exponent_ratio, 636 typename T::translation_ratio>::type> 637 { 638 typedef typename T::base_unit_type base_unit_type; ///< Unit type that the unit was derived from. May be a `base_unit` or another `unit`. Use the `base_unit_of` trait to find the SI base unit type. This will be `void` if type `T` is not a unit. 639 typedef typename T::conversion_ratio conversion_ratio; ///< `std::ratio` representing the conversion factor to the `base_unit_type`. This will be `void` if type `T` is not a unit. 640 typedef typename T::pi_exponent_ratio pi_exponent_ratio; ///< `std::ratio` representing the exponent of pi to be used in the conversion. This will be `void` if type `T` is not a unit. 641 typedef typename T::translation_ratio translation_ratio; ///< `std::ratio` representing a datum translation to the base unit (i.e. degrees C to degrees F conversion). This will be `void` if type `T` is not a unit. 642 }; 643 /** @endcond */ // END DOXYGEN IGNORE 644 } 645 646 /** @cond */ // DOXYGEN IGNORE 647 namespace detail 648 { 649 /** 650 * @brief helper type to identify base units. 651 * @details A non-templated base class for `base_unit` which enables RTTI testing. 652 */ 653 struct _base_unit_t {}; 654 } 655 /** @endcond */ // END DOXYGEN IGNORE 656 657 namespace traits 658 { 659 /** 660 * @ingroup TypeTraits 661 * @brief Trait which tests if a class is a `base_unit` type. 662 * @details Inherits from `std::true_type` or `std::false_type`. Use `is_base_unit<T>::value` to test 663 * whether `class T` implements a `base_unit`. 664 */ 665 template<class T> 666 struct is_base_unit : std::is_base_of<units::detail::_base_unit_t, T> {}; 667 } 668 669 /** @cond */ // DOXYGEN IGNORE 670 namespace detail 671 { 672 /** 673 * @brief helper type to identify units. 674 * @details A non-templated base class for `unit` which enables RTTI testing. 675 */ 676 struct _unit {}; 677 678 template<std::intmax_t Num, std::intmax_t Den = 1> 679 using meter_ratio = std::ratio<Num, Den>; 680 } 681 /** @endcond */ // END DOXYGEN IGNORE 682 683 namespace traits 684 { 685 /** 686 * @ingroup TypeTraits 687 * @brief Traits which tests if a class is a `unit` 688 * @details Inherits from `std::true_type` or `std::false_type`. Use `is_unit<T>::value` to test 689 * whether `class T` implements a `unit`. 690 */ 691 template<class T> 692 struct is_unit : std::is_base_of<units::detail::_unit, T>::type {}; 693 } 694 695 /** @} */ // end of TypeTraits 696 697 //------------------------------ 698 // BASE UNIT CLASS 699 //------------------------------ 700 701 /** 702 * @ingroup UnitTypes 703 * @brief Class representing SI base unit types. 704 * @details Base units are represented by a combination of `std::ratio` template parameters, each 705 * describing the exponent of the type of unit they represent. Example: meters per second 706 * would be described by a +1 exponent for meters, and a -1 exponent for seconds, thus: 707 * `base_unit<std::ratio<1>, std::ratio<0>, std::ratio<-1>>` 708 * @tparam Meter `std::ratio` representing the exponent value for meters. 709 * @tparam Kilogram `std::ratio` representing the exponent value for kilograms. 710 * @tparam Second `std::ratio` representing the exponent value for seconds. 711 * @tparam Radian `std::ratio` representing the exponent value for radians. Although radians are not SI base units, they are included because radians are described by the SI as m * m^-1, which would make them indistinguishable from scalars. 712 * @tparam Ampere `std::ratio` representing the exponent value for amperes. 713 * @tparam Kelvin `std::ratio` representing the exponent value for Kelvin. 714 * @tparam Mole `std::ratio` representing the exponent value for moles. 715 * @tparam Candela `std::ratio` representing the exponent value for candelas. 716 * @tparam Byte `std::ratio` representing the exponent value for bytes. 717 * @sa category for type aliases for SI base_unit types. 718 */ 719 template<class Meter = detail::meter_ratio<0>, 720 class Kilogram = std::ratio<0>, 721 class Second = std::ratio<0>, 722 class Radian = std::ratio<0>, 723 class Ampere = std::ratio<0>, 724 class Kelvin = std::ratio<0>, 725 class Mole = std::ratio<0>, 726 class Candela = std::ratio<0>, 727 class Byte = std::ratio<0>> 728 struct base_unit : units::detail::_base_unit_t 729 { 730 static_assert(traits::is_ratio<Meter>::value, "Template parameter `Meter` must be a `std::ratio` representing the exponent of meters the unit has"); 731 static_assert(traits::is_ratio<Kilogram>::value, "Template parameter `Kilogram` must be a `std::ratio` representing the exponent of kilograms the unit has"); 732 static_assert(traits::is_ratio<Second>::value, "Template parameter `Second` must be a `std::ratio` representing the exponent of seconds the unit has"); 733 static_assert(traits::is_ratio<Ampere>::value, "Template parameter `Ampere` must be a `std::ratio` representing the exponent of amperes the unit has"); 734 static_assert(traits::is_ratio<Kelvin>::value, "Template parameter `Kelvin` must be a `std::ratio` representing the exponent of kelvin the unit has"); 735 static_assert(traits::is_ratio<Candela>::value, "Template parameter `Candela` must be a `std::ratio` representing the exponent of candelas the unit has"); 736 static_assert(traits::is_ratio<Mole>::value, "Template parameter `Mole` must be a `std::ratio` representing the exponent of moles the unit has"); 737 static_assert(traits::is_ratio<Radian>::value, "Template parameter `Radian` must be a `std::ratio` representing the exponent of radians the unit has"); 738 static_assert(traits::is_ratio<Byte>::value, "Template parameter `Byte` must be a `std::ratio` representing the exponent of bytes the unit has"); 739 740 typedef Meter meter_ratio; 741 typedef Kilogram kilogram_ratio; 742 typedef Second second_ratio; 743 typedef Radian radian_ratio; 744 typedef Ampere ampere_ratio; 745 typedef Kelvin kelvin_ratio; 746 typedef Mole mole_ratio; 747 typedef Candela candela_ratio; 748 typedef Byte byte_ratio; 749 }; 750 751 //------------------------------ 752 // UNIT CATEGORIES 753 //------------------------------ 754 755 /** 756 * @brief namespace representing the implemented base and derived unit types. These will not generally be needed by library users. 757 * @sa base_unit for the definition of the category parameters. 758 */ 759 namespace category 760 { 761 // SCALAR (DIMENSIONLESS) TYPES 762 typedef base_unit<> scalar_unit; ///< Represents a quantity with no dimension. 763 typedef base_unit<> dimensionless_unit; ///< Represents a quantity with no dimension. 764 765 // SI BASE UNIT TYPES 766 // METERS KILOGRAMS SECONDS RADIANS AMPERES KELVIN MOLE CANDELA BYTE --- CATEGORY 767 typedef base_unit<detail::meter_ratio<1>> length_unit; ///< Represents an SI base unit of length 768 typedef base_unit<detail::meter_ratio<0>, std::ratio<1>> mass_unit; ///< Represents an SI base unit of mass 769 typedef base_unit<detail::meter_ratio<0>, std::ratio<0>, std::ratio<1>> time_unit; ///< Represents an SI base unit of time 770 typedef base_unit<detail::meter_ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>> angle_unit; ///< Represents an SI base unit of angle 771 typedef base_unit<detail::meter_ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>> current_unit; ///< Represents an SI base unit of current 772 typedef base_unit<detail::meter_ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>> temperature_unit; ///< Represents an SI base unit of temperature 773 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; ///< Represents an SI base unit of amount of substance 774 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; ///< Represents an SI base unit of luminous intensity 775 776 // SI DERIVED UNIT TYPES 777 // METERS KILOGRAMS SECONDS RADIANS AMPERES KELVIN MOLE CANDELA BYTE --- CATEGORY 778 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; ///< Represents an SI derived unit of solid angle 779 typedef base_unit<detail::meter_ratio<0>, std::ratio<0>, std::ratio<-1>> frequency_unit; ///< Represents an SI derived unit of frequency 780 typedef base_unit<detail::meter_ratio<1>, std::ratio<0>, std::ratio<-1>> velocity_unit; ///< Represents an SI derived unit of velocity 781 typedef base_unit<detail::meter_ratio<0>, std::ratio<0>, std::ratio<-1>, std::ratio<1>> angular_velocity_unit; ///< Represents an SI derived unit of angular velocity 782 typedef base_unit<detail::meter_ratio<1>, std::ratio<0>, std::ratio<-2>> acceleration_unit; ///< Represents an SI derived unit of acceleration 783 typedef base_unit<detail::meter_ratio<1>, std::ratio<1>, std::ratio<-2>> force_unit; ///< Represents an SI derived unit of force 784 typedef base_unit<detail::meter_ratio<-1>, std::ratio<1>, std::ratio<-2>> pressure_unit; ///< Represents an SI derived unit of pressure 785 typedef base_unit<detail::meter_ratio<0>, std::ratio<0>, std::ratio<1>, std::ratio<0>, std::ratio<1>> charge_unit; ///< Represents an SI derived unit of charge 786 typedef base_unit<detail::meter_ratio<2>, std::ratio<1>, std::ratio<-2>> energy_unit; ///< Represents an SI derived unit of energy 787 typedef base_unit<detail::meter_ratio<2>, std::ratio<1>, std::ratio<-3>> power_unit; ///< Represents an SI derived unit of power 788 typedef base_unit<detail::meter_ratio<2>, std::ratio<1>, std::ratio<-3>, std::ratio<0>, std::ratio<-1>> voltage_unit; ///< Represents an SI derived unit of voltage 789 typedef base_unit<detail::meter_ratio<-2>, std::ratio<-1>, std::ratio<4>, std::ratio<0>, std::ratio<2>> capacitance_unit; ///< Represents an SI derived unit of capacitance 790 typedef base_unit<detail::meter_ratio<2>, std::ratio<1>, std::ratio<-3>, std::ratio<0>, std::ratio<-2>> impedance_unit; ///< Represents an SI derived unit of impedance 791 typedef base_unit<detail::meter_ratio<-2>, std::ratio<-1>, std::ratio<3>, std::ratio<0>, std::ratio<2>> conductance_unit; ///< Represents an SI derived unit of conductance 792 typedef base_unit<detail::meter_ratio<2>, std::ratio<1>, std::ratio<-2>, std::ratio<0>, std::ratio<-1>> magnetic_flux_unit; ///< Represents an SI derived unit of magnetic flux 793 typedef base_unit<detail::meter_ratio<0>, std::ratio<1>, std::ratio<-2>, std::ratio<0>, std::ratio<-1>> magnetic_field_strength_unit; ///< Represents an SI derived unit of magnetic field strength 794 typedef base_unit<detail::meter_ratio<2>, std::ratio<1>, std::ratio<-2>, std::ratio<0>, std::ratio<-2>> inductance_unit; ///< Represents an SI derived unit of inductance 795 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; ///< Represents an SI derived unit of luminous flux 796 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; ///< Represents an SI derived unit of illuminance 797 typedef base_unit<detail::meter_ratio<0>, std::ratio<0>, std::ratio<-1>> radioactivity_unit; ///< Represents an SI derived unit of radioactivity 798 799 // OTHER UNIT TYPES 800 // METERS KILOGRAMS SECONDS RADIANS AMPERES KELVIN MOLE CANDELA BYTE --- CATEGORY 801 typedef base_unit<detail::meter_ratio<2>, std::ratio<1>, std::ratio<-2>> torque_unit; ///< Represents an SI derived unit of torque 802 typedef base_unit<detail::meter_ratio<2>> area_unit; ///< Represents an SI derived unit of area 803 typedef base_unit<detail::meter_ratio<3>> volume_unit; ///< Represents an SI derived unit of volume 804 typedef base_unit<detail::meter_ratio<-3>, std::ratio<1>> density_unit; ///< Represents an SI derived unit of density 805 typedef base_unit<> concentration_unit; ///< Represents a unit of concentration 806 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; ///< Represents a unit of data size 807 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; ///< Represents a unit of data transfer rate 808 } 809 810 //------------------------------ 811 // UNIT CLASSES 812 //------------------------------ 813 814 /** @cond */ // DOXYGEN IGNORE 815 /** 816 * @brief unit type template specialization for units derived from base units. 817 */ 818 template <class, class, class, class> struct unit; 819 template<class Conversion, class... Exponents, class PiExponent, class Translation> 820 struct unit<Conversion, base_unit<Exponents...>, PiExponent, Translation> : units::detail::_unit 821 { 822 static_assert(traits::is_ratio<Conversion>::value, "Template parameter `Conversion` must be a `std::ratio` representing the conversion factor to `BaseUnit`."); 823 static_assert(traits::is_ratio<PiExponent>::value, "Template parameter `PiExponent` must be a `std::ratio` representing the exponents of Pi the unit has."); 824 static_assert(traits::is_ratio<Translation>::value, "Template parameter `Translation` must be a `std::ratio` representing an additive translation required by the unit conversion."); 825 826 typedef typename units::base_unit<Exponents...> base_unit_type; 827 typedef Conversion conversion_ratio; 828 typedef Translation translation_ratio; 829 typedef PiExponent pi_exponent_ratio; 830 }; 831 /** @endcond */ // END DOXYGEN IGNORE 832 833 /** 834 * @brief Type representing an arbitrary unit. 835 * @ingroup UnitTypes 836 * @details `unit` types are used as tags for the `conversion` function. They are *not* containers 837 * (see `unit_t` for a container class). Each unit is defined by: 838 * 839 * - A `std::ratio` defining the conversion factor to the base unit type. (e.g. `std::ratio<1,12>` for inches to feet) 840 * - A base unit that the unit is derived from (or a unit category. Must be of type `unit` or `base_unit`) 841 * - An exponent representing factors of PI required by the conversion. (e.g. `std::ratio<-1>` for a radians to degrees conversion) 842 * - a ratio representing a datum translation required for the conversion (e.g. `std::ratio<32>` for a farenheit to celsius conversion) 843 * 844 * Typically, a specific unit, like `meters`, would be implemented as a type alias 845 * of `unit`, i.e. `using meters = unit<std::ratio<1>, units::category::length_unit`, or 846 * `using inches = unit<std::ratio<1,12>, feet>`. 847 * @tparam Conversion std::ratio representing scalar multiplication factor. 848 * @tparam BaseUnit Unit type which this unit is derived from. May be a `base_unit`, or another `unit`. 849 * @tparam PiExponent std::ratio representing the exponent of pi required by the conversion. 850 * @tparam Translation std::ratio representing any datum translation required by the conversion. 851 */ 852 template<class Conversion, class BaseUnit, class PiExponent = std::ratio<0>, class Translation = std::ratio<0>> 853 struct unit : units::detail::_unit 854 { 855 static_assert(traits::is_unit<BaseUnit>::value, "Template parameter `BaseUnit` must be a `unit` type."); 856 static_assert(traits::is_ratio<Conversion>::value, "Template parameter `Conversion` must be a `std::ratio` representing the conversion factor to `BaseUnit`."); 857 static_assert(traits::is_ratio<PiExponent>::value, "Template parameter `PiExponent` must be a `std::ratio` representing the exponents of Pi the unit has."); 858 859 typedef typename units::traits::unit_traits<BaseUnit>::base_unit_type base_unit_type; 860 typedef typename std::ratio_multiply<typename BaseUnit::conversion_ratio, Conversion> conversion_ratio; 861 typedef typename std::ratio_add<typename BaseUnit::pi_exponent_ratio, PiExponent> pi_exponent_ratio; 862 typedef typename std::ratio_add<std::ratio_multiply<typename BaseUnit::conversion_ratio, Translation>, typename BaseUnit::translation_ratio> translation_ratio; 863 }; 864 865 //------------------------------ 866 // BASE UNIT MANIPULATORS 867 //------------------------------ 868 869 /** @cond */ // DOXYGEN IGNORE 870 namespace detail 871 { 872 /** 873 * @brief base_unit_of trait implementation 874 * @details recursively seeks base_unit type that a unit is derived from. Since units can be 875 * derived from other units, the `base_unit_type` typedef may not represent this value. 876 */ 877 template<class> struct base_unit_of_impl; 878 template<class Conversion, class BaseUnit, class PiExponent, class Translation> 879 struct base_unit_of_impl<unit<Conversion, BaseUnit, PiExponent, Translation>> : base_unit_of_impl<BaseUnit> {}; 880 template<class... Exponents> 881 struct base_unit_of_impl<base_unit<Exponents...>> 882 { 883 typedef base_unit<Exponents...> type; 884 }; 885 template<> 886 struct base_unit_of_impl<void> 887 { 888 typedef void type; 889 }; 890 } 891 /** @endcond */ // END DOXYGEN IGNORE 892 893 namespace traits 894 { 895 /** 896 * @brief Trait which returns the `base_unit` type that a unit is originally derived from. 897 * @details Since units can be derived from other `unit` types in addition to `base_unit` types, 898 * the `base_unit_type` typedef will not always be a `base_unit` (or unit category). 899 * Since compatible 900 */ 901 template<class U> 902 using base_unit_of = typename units::detail::base_unit_of_impl<U>::type; 903 } 904 905 /** @cond */ // DOXYGEN IGNORE 906 namespace detail 907 { 908 /** 909 * @brief implementation of base_unit_multiply 910 * @details 'multiples' (adds exponent ratios of) two base unit types. Base units can be found 911 * using `base_unit_of`. 912 */ 913 template<class, class> struct base_unit_multiply_impl; 914 template<class... Exponents1, class... Exponents2> 915 struct base_unit_multiply_impl<base_unit<Exponents1...>, base_unit<Exponents2...>> { 916 using type = base_unit<std::ratio_add<Exponents1, Exponents2>...>; 917 }; 918 919 /** 920 * @brief represents type of two base units multiplied together 921 */ 922 template<class U1, class U2> 923 using base_unit_multiply = typename base_unit_multiply_impl<U1, U2>::type; 924 925 /** 926 * @brief implementation of base_unit_divide 927 * @details 'dived' (subtracts exponent ratios of) two base unit types. Base units can be found 928 * using `base_unit_of`. 929 */ 930 template<class, class> struct base_unit_divide_impl; 931 template<class... Exponents1, class... Exponents2> 932 struct base_unit_divide_impl<base_unit<Exponents1...>, base_unit<Exponents2...>> { 933 using type = base_unit<std::ratio_subtract<Exponents1, Exponents2>...>; 934 }; 935 936 /** 937 * @brief represents the resulting type of `base_unit` U1 divided by U2. 938 */ 939 template<class U1, class U2> 940 using base_unit_divide = typename base_unit_divide_impl<U1, U2>::type; 941 942 /** 943 * @brief implementation of inverse_base 944 * @details multiplies all `base_unit` exponent ratios by -1. The resulting type represents 945 * the inverse base unit of the given `base_unit` type. 946 */ 947 template<class> struct inverse_base_impl; 948 949 template<class... Exponents> 950 struct inverse_base_impl<base_unit<Exponents...>> { 951 using type = base_unit<std::ratio_multiply<Exponents, std::ratio<-1>>...>; 952 }; 953 954 /** 955 * @brief represent the inverse type of `class U` 956 * @details E.g. if `U` is `length_unit`, then `inverse<U>` will represent `length_unit^-1`. 957 */ 958 template<class U> using inverse_base = typename inverse_base_impl<U>::type; 959 960 /** 961 * @brief implementation of `squared_base` 962 * @details multiplies all the exponent ratios of the given class by 2. The resulting type is 963 * equivalent to the given type squared. 964 */ 965 template<class U> struct squared_base_impl; 966 template<class... Exponents> 967 struct squared_base_impl<base_unit<Exponents...>> { 968 using type = base_unit<std::ratio_multiply<Exponents, std::ratio<2>>...>; 969 }; 970 971 /** 972 * @brief represents the type of a `base_unit` squared. 973 * @details E.g. `squared<length_unit>` will represent `length_unit^2`. 974 */ 975 template<class U> using squared_base = typename squared_base_impl<U>::type; 976 977 /** 978 * @brief implementation of `cubed_base` 979 * @details multiplies all the exponent ratios of the given class by 3. The resulting type is 980 * equivalent to the given type cubed. 981 */ 982 template<class U> struct cubed_base_impl; 983 template<class... Exponents> 984 struct cubed_base_impl<base_unit<Exponents...>> { 985 using type = base_unit<std::ratio_multiply<Exponents, std::ratio<3>>...>; 986 }; 987 988 /** 989 * @brief represents the type of a `base_unit` cubed. 990 * @details E.g. `cubed<length_unit>` will represent `length_unit^3`. 991 */ 992 template<class U> using cubed_base = typename cubed_base_impl<U>::type; 993 994 /** 995 * @brief implementation of `sqrt_base` 996 * @details divides all the exponent ratios of the given class by 2. The resulting type is 997 * equivalent to the square root of the given type. 998 */ 999 template<class U> struct sqrt_base_impl; 1000 template<class... Exponents> 1001 struct sqrt_base_impl<base_unit<Exponents...>> { 1002 using type = base_unit<std::ratio_divide<Exponents, std::ratio<2>>...>; 1003 }; 1004 1005 /** 1006 * @brief represents the square-root type of a `base_unit`. 1007 * @details E.g. `sqrt<length_unit>` will represent `length_unit^(1/2)`. 1008 */ 1009 template<class U> using sqrt_base = typename sqrt_base_impl<U>::type; 1010 1011 /** 1012 * @brief implementation of `cbrt_base` 1013 * @details divides all the exponent ratios of the given class by 3. The resulting type is 1014 * equivalent to the given type's cube-root. 1015 */ 1016 template<class U> struct cbrt_base_impl; 1017 template<class... Exponents> 1018 struct cbrt_base_impl<base_unit<Exponents...>> { 1019 using type = base_unit<std::ratio_divide<Exponents, std::ratio<3>>...>; 1020 }; 1021 1022 /** 1023 * @brief represents the cube-root type of a `base_unit` . 1024 * @details E.g. `cbrt<length_unit>` will represent `length_unit^(1/3)`. 1025 */ 1026 template<class U> using cbrt_base = typename cbrt_base_impl<U>::type; 1027 } 1028 /** @endcond */ // END DOXYGEN IGNORE 1029 1030 //------------------------------ 1031 // UNIT MANIPULATORS 1032 //------------------------------ 1033 1034 /** @cond */ // DOXYGEN IGNORE 1035 namespace detail 1036 { 1037 /** 1038 * @brief implementation of `unit_multiply`. 1039 * @details multiplies two units. The base unit becomes the base units of each with their exponents 1040 * added together. The conversion factors of each are multiplied by each other. Pi exponent ratios 1041 * are added, and datum translations are removed. 1042 */ 1043 template<class Unit1, class Unit2> 1044 struct unit_multiply_impl 1045 { 1046 using type = unit < std::ratio_multiply<typename Unit1::conversion_ratio, typename Unit2::conversion_ratio>, 1047 base_unit_multiply <traits::base_unit_of<typename Unit1::base_unit_type>, traits::base_unit_of<typename Unit2::base_unit_type>>, 1048 std::ratio_add<typename Unit1::pi_exponent_ratio, typename Unit2::pi_exponent_ratio>, 1049 std::ratio < 0 >> ; 1050 }; 1051 1052 /** 1053 * @brief represents the type of two units multiplied together. 1054 * @details recalculates conversion and exponent ratios at compile-time. 1055 */ 1056 template<class U1, class U2> 1057 using unit_multiply = typename unit_multiply_impl<U1, U2>::type; 1058 1059 /** 1060 * @brief implementation of `unit_divide`. 1061 * @details divides two units. The base unit becomes the base units of each with their exponents 1062 * subtracted from each other. The conversion factors of each are divided by each other. Pi exponent ratios 1063 * are subtracted, and datum translations are removed. 1064 */ 1065 template<class Unit1, class Unit2> 1066 struct unit_divide_impl 1067 { 1068 using type = unit < std::ratio_divide<typename Unit1::conversion_ratio, typename Unit2::conversion_ratio>, 1069 base_unit_divide<traits::base_unit_of<typename Unit1::base_unit_type>, traits::base_unit_of<typename Unit2::base_unit_type>>, 1070 std::ratio_subtract<typename Unit1::pi_exponent_ratio, typename Unit2::pi_exponent_ratio>, 1071 std::ratio < 0 >> ; 1072 }; 1073 1074 /** 1075 * @brief represents the type of two units divided by each other. 1076 * @details recalculates conversion and exponent ratios at compile-time. 1077 */ 1078 template<class U1, class U2> 1079 using unit_divide = typename unit_divide_impl<U1, U2>::type; 1080 1081 /** 1082 * @brief implementation of `inverse` 1083 * @details inverts a unit (equivalent to 1/unit). The `base_unit` and pi exponents are all multiplied by 1084 * -1. The conversion ratio numerator and denominator are swapped. Datum translation 1085 * ratios are removed. 1086 */ 1087 template<class Unit> 1088 struct inverse_impl 1089 { 1090 using type = unit < std::ratio<Unit::conversion_ratio::den, Unit::conversion_ratio::num>, 1091 inverse_base<traits::base_unit_of<typename units::traits::unit_traits<Unit>::base_unit_type>>, 1092 std::ratio_multiply<typename units::traits::unit_traits<Unit>::pi_exponent_ratio, std::ratio<-1>>, 1093 std::ratio < 0 >> ; // inverses are rates or change, the translation factor goes away. 1094 }; 1095 } 1096 /** @endcond */ // END DOXYGEN IGNORE 1097 1098 /** 1099 * @brief represents the inverse unit type of `class U`. 1100 * @ingroup UnitManipulators 1101 * @tparam U `unit` type to invert. 1102 * @details E.g. `inverse<meters>` will represent meters^-1 (i.e. 1/meters). 1103 */ 1104 template<class U> using inverse = typename units::detail::inverse_impl<U>::type; 1105 1106 /** @cond */ // DOXYGEN IGNORE 1107 namespace detail 1108 { 1109 /** 1110 * @brief implementation of `squared` 1111 * @details Squares the conversion ratio, `base_unit` exponents, pi exponents, and removes 1112 * datum translation ratios. 1113 */ 1114 template<class Unit> 1115 struct squared_impl 1116 { 1117 static_assert(traits::is_unit<Unit>::value, "Template parameter `Unit` must be a `unit` type."); 1118 using Conversion = typename Unit::conversion_ratio; 1119 using type = unit < std::ratio_multiply<Conversion, Conversion>, 1120 squared_base<traits::base_unit_of<typename Unit::base_unit_type>>, 1121 std::ratio_multiply<typename Unit::pi_exponent_ratio, std::ratio<2>>, 1122 typename Unit::translation_ratio 1123 > ; 1124 }; 1125 } 1126 /** @endcond */ // END DOXYGEN IGNORE 1127 1128 /** 1129 * @brief represents the unit type of `class U` squared 1130 * @ingroup UnitManipulators 1131 * @tparam U `unit` type to square. 1132 * @details E.g. `square<meters>` will represent meters^2. 1133 */ 1134 template<class U> 1135 using squared = typename units::detail::squared_impl<U>::type; 1136 1137 /** @cond */ // DOXYGEN IGNORE 1138 namespace detail 1139 { 1140 /** 1141 * @brief implementation of `cubed` 1142 * @details Cubes the conversion ratio, `base_unit` exponents, pi exponents, and removes 1143 * datum translation ratios. 1144 */ 1145 template<class Unit> 1146 struct cubed_impl 1147 { 1148 static_assert(traits::is_unit<Unit>::value, "Template parameter `Unit` must be a `unit` type."); 1149 using Conversion = typename Unit::conversion_ratio; 1150 using type = unit < std::ratio_multiply<Conversion, std::ratio_multiply<Conversion, Conversion>>, 1151 cubed_base<traits::base_unit_of<typename Unit::base_unit_type>>, 1152 std::ratio_multiply<typename Unit::pi_exponent_ratio, std::ratio<3>>, 1153 typename Unit::translation_ratio> ; 1154 }; 1155 } 1156 /** @endcond */ // END DOXYGEN IGNORE 1157 1158 /** 1159 * @brief represents the type of `class U` cubed. 1160 * @ingroup UnitManipulators 1161 * @tparam U `unit` type to cube. 1162 * @details E.g. `cubed<meters>` will represent meters^3. 1163 */ 1164 template<class U> 1165 using cubed = typename units::detail::cubed_impl<U>::type; 1166 1167 /** @cond */ // DOXYGEN IGNORE 1168 namespace detail 1169 { 1170 //---------------------------------- 1171 // RATIO_SQRT IMPLEMENTATION 1172 //---------------------------------- 1173 1174 using Zero = std::ratio<0>; 1175 using One = std::ratio<1>; 1176 template <typename R> using Square = std::ratio_multiply<R, R>; 1177 1178 // Find the largest std::integer N such that Predicate<N>::value is true. 1179 template <template <std::intmax_t N> class Predicate, typename enabled = void> 1180 struct BinarySearch { 1181 template <std::intmax_t N> 1182 struct SafeDouble_ { 1183 static constexpr const std::intmax_t value = 2 * N; 1184 static_assert(value > 0, "Overflows when computing 2 * N"); 1185 }; 1186 1187 template <intmax_t Lower, intmax_t Upper, typename Condition1 = void, typename Condition2 = void> 1188 struct DoubleSidedSearch_ : DoubleSidedSearch_<Lower, Upper, 1189 std::integral_constant<bool, (Upper - Lower == 1)>, 1190 std::integral_constant<bool, ((Upper - Lower>1 && Predicate<Lower + (Upper - Lower) / 2>::value))>> {}; 1191 1192 template <intmax_t Lower, intmax_t Upper> 1193 struct DoubleSidedSearch_<Lower, Upper, std::false_type, std::false_type> : DoubleSidedSearch_<Lower, Lower + (Upper - Lower) / 2> {}; 1194 1195 template <intmax_t Lower, intmax_t Upper, typename Condition2> 1196 struct DoubleSidedSearch_<Lower, Upper, std::true_type, Condition2> : std::integral_constant<intmax_t, Lower>{}; 1197 1198 template <intmax_t Lower, intmax_t Upper, typename Condition1> 1199 struct DoubleSidedSearch_<Lower, Upper, Condition1, std::true_type> : DoubleSidedSearch_<Lower + (Upper - Lower) / 2, Upper>{}; 1200 1201 template <std::intmax_t Lower, class enabled1 = void> 1202 struct SingleSidedSearch_ : SingleSidedSearch_<Lower, std::integral_constant<bool, Predicate<SafeDouble_<Lower>::value>::value>>{}; 1203 1204 template <std::intmax_t Lower> 1205 struct SingleSidedSearch_<Lower, std::false_type> : DoubleSidedSearch_<Lower, SafeDouble_<Lower>::value> {}; 1206 1207 template <std::intmax_t Lower> 1208 struct SingleSidedSearch_<Lower, std::true_type> : SingleSidedSearch_<SafeDouble_<Lower>::value>{}; 1209 1210 static constexpr const std::intmax_t value = SingleSidedSearch_<1>::value; 1211 }; 1212 1213 template <template <std::intmax_t N> class Predicate> 1214 struct BinarySearch<Predicate, std::enable_if_t<!Predicate<1>::value>> : std::integral_constant<std::intmax_t, 0>{}; 1215 1216 // Find largest std::integer N such that N<=sqrt(R) 1217 template <typename R> 1218 struct Integer { 1219 template <std::intmax_t N> using Predicate_ = std::ratio_less_equal<std::ratio<N>, std::ratio_divide<R, std::ratio<N>>>; 1220 static constexpr const std::intmax_t value = BinarySearch<Predicate_>::value; 1221 }; 1222 1223 template <typename R> 1224 struct IsPerfectSquare { 1225 static constexpr const std::intmax_t DenSqrt_ = Integer<std::ratio<R::den>>::value; 1226 static constexpr const std::intmax_t NumSqrt_ = Integer<std::ratio<R::num>>::value; 1227 static constexpr const bool value =( DenSqrt_ * DenSqrt_ == R::den && NumSqrt_ * NumSqrt_ == R::num); 1228 using Sqrt = std::ratio<NumSqrt_, DenSqrt_>; 1229 }; 1230 1231 // Represents sqrt(P)-Q. 1232 template <typename Tp, typename Tq> 1233 struct Remainder { 1234 using P = Tp; 1235 using Q = Tq; 1236 }; 1237 1238 // Represents 1/R = I + Rem where R is a Remainder. 1239 template <typename R> 1240 struct Reciprocal { 1241 using P_ = typename R::P; 1242 using Q_ = typename R::Q; 1243 using Den_ = std::ratio_subtract<P_, Square<Q_>>; 1244 using A_ = std::ratio_divide<Q_, Den_>; 1245 using B_ = std::ratio_divide<P_, Square<Den_>>; 1246 static constexpr const std::intmax_t I_ = (A_::num + Integer<std::ratio_multiply<B_, Square<std::ratio<A_::den>>>>::value) / A_::den; 1247 using I = std::ratio<I_>; 1248 using Rem = Remainder<B_, std::ratio_subtract<I, A_>>; 1249 }; 1250 1251 // Expands sqrt(R) to continued fraction: 1252 // f(x)=C1+1/(C2+1/(C3+1/(...+1/(Cn+x)))) = (U*x+V)/(W*x+1) and sqrt(R)=f(Rem). 1253 // The error |f(Rem)-V| = |(U-W*V)x/(W*x+1)| <= |U-W*V|*Rem <= |U-W*V|/I' where 1254 // I' is the std::integer part of reciprocal of Rem. 1255 template <typename Tr, std::intmax_t N> 1256 struct ContinuedFraction { 1257 template <typename T> 1258 using Abs_ = std::conditional_t<std::ratio_less<T, Zero>::value, std::ratio_subtract<Zero, T>, T>; 1259 1260 using R = Tr; 1261 using Last_ = ContinuedFraction<R, N - 1>; 1262 using Reciprocal_ = Reciprocal<typename Last_::Rem>; 1263 using Rem = typename Reciprocal_::Rem; 1264 using I_ = typename Reciprocal_::I; 1265 using Den_ = std::ratio_add<typename Last_::W, I_>; 1266 using U = std::ratio_divide<typename Last_::V, Den_>; 1267 using V = std::ratio_divide<std::ratio_add<typename Last_::U, std::ratio_multiply<typename Last_::V, I_>>, Den_>; 1268 using W = std::ratio_divide<One, Den_>; 1269 using Error = Abs_<std::ratio_divide<std::ratio_subtract<U, std::ratio_multiply<V, W>>, typename Reciprocal<Rem>::I>>; 1270 }; 1271 1272 template <typename Tr> 1273 struct ContinuedFraction<Tr, 1> { 1274 using R = Tr; 1275 using U = One; 1276 using V = std::ratio<Integer<R>::value>; 1277 using W = Zero; 1278 using Rem = Remainder<R, V>; 1279 using Error = std::ratio_divide<One, typename Reciprocal<Rem>::I>; 1280 }; 1281 1282 template <typename R, typename Eps, std::intmax_t N = 1, typename enabled = void> 1283 struct Sqrt_ : Sqrt_<R, Eps, N + 1> {}; 1284 1285 template <typename R, typename Eps, std::intmax_t N> 1286 struct Sqrt_<R, Eps, N, std::enable_if_t<std::ratio_less_equal<typename ContinuedFraction<R, N>::Error, Eps>::value>> { 1287 using type = typename ContinuedFraction<R, N>::V; 1288 }; 1289 1290 template <typename R, typename Eps, typename enabled = void> 1291 struct Sqrt { 1292 static_assert(std::ratio_greater_equal<R, Zero>::value, "R can't be negative"); 1293 }; 1294 1295 template <typename R, typename Eps> 1296 struct Sqrt<R, Eps, std::enable_if_t<std::ratio_greater_equal<R, Zero>::value && IsPerfectSquare<R>::value>> { 1297 using type = typename IsPerfectSquare<R>::Sqrt; 1298 }; 1299 1300 template <typename R, typename Eps> 1301 struct Sqrt<R, Eps, std::enable_if_t<(std::ratio_greater_equal<R, Zero>::value && !IsPerfectSquare<R>::value)>> : Sqrt_<R, Eps>{}; 1302 } 1303 /** @endcond */ // END DOXYGEN IGNORE 1304 1305 /** 1306 * @ingroup TypeTraits 1307 * @brief Calculate square root of a ratio at compile-time 1308 * @details Calculates a rational approximation of the square root of the ratio. The error 1309 * in the calculation is bounded by 1/epsilon (Eps). E.g. for the default value 1310 * of 10000000000, the maximum error will be a/10000000000, or 1e-8, or said another way, 1311 * the error will be on the order of 10^-9. Since these calculations are done at 1312 * compile time, it is advisable to set epsilon to the highest value that does not 1313 * cause an integer overflow in the calculation. If you can't compile `ratio_sqrt` 1314 * due to overflow errors, reducing the value of epsilon sufficiently will correct 1315 * the problem.\n\n 1316 * `ratio_sqrt` is guaranteed to converge for all values of `Ratio` which do not 1317 * overflow. 1318 * @note This function provides a rational approximation, _NOT_ an exact value. 1319 * @tparam Ratio ratio to take the square root of. This can represent any rational value, 1320 * _not_ just integers or values with integer roots. 1321 * @tparam Eps Value of epsilon, which represents the inverse of the maximum allowable 1322 * error. This value should be chosen to be as high as possible before 1323 * integer overflow errors occur in the compiler. 1324 */ 1325 template<typename Ratio, std::intmax_t Eps = 10000000000> 1326 using ratio_sqrt = typename units::detail::Sqrt<Ratio, std::ratio<1, Eps>>::type; 1327 1328 /** @cond */ // DOXYGEN IGNORE 1329 namespace detail 1330 { 1331 /** 1332 * @brief implementation of `sqrt` 1333 * @details square roots the conversion ratio, `base_unit` exponents, pi exponents, and removes 1334 * datum translation ratios. 1335 */ 1336 template<class Unit, std::intmax_t Eps> 1337 struct sqrt_impl 1338 { 1339 static_assert(traits::is_unit<Unit>::value, "Template parameter `Unit` must be a `unit` type."); 1340 using Conversion = typename Unit::conversion_ratio; 1341 using type = unit <ratio_sqrt<Conversion, Eps>, 1342 sqrt_base<traits::base_unit_of<typename Unit::base_unit_type>>, 1343 std::ratio_divide<typename Unit::pi_exponent_ratio, std::ratio<2>>, 1344 typename Unit::translation_ratio>; 1345 }; 1346 } 1347 /** @endcond */ // END DOXYGEN IGNORE 1348 1349 /** 1350 * @ingroup UnitManipulators 1351 * @brief represents the square root of type `class U`. 1352 * @details Calculates a rational approximation of the square root of the unit. The error 1353 * in the calculation is bounded by 1/epsilon (Eps). E.g. for the default value 1354 * of 10000000000, the maximum error will be a/10000000000, or 1e-8, or said another way, 1355 * the error will be on the order of 10^-9. Since these calculations are done at 1356 * compile time, it is advisable to set epsilon to the highest value that does not 1357 * cause an integer overflow in the calculation. If you can't compile `ratio_sqrt` 1358 * due to overflow errors, reducing the value of epsilon sufficiently will correct 1359 * the problem.\n\n 1360 * `ratio_sqrt` is guaranteed to converge for all values of `Ratio` which do not 1361 * overflow. 1362 * @tparam U `unit` type to take the square root of. 1363 * @tparam Eps Value of epsilon, which represents the inverse of the maximum allowable 1364 * error. This value should be chosen to be as high as possible before 1365 * integer overflow errors occur in the compiler. 1366 * @note USE WITH CAUTION. The is an approximate value. In general, squared<sqrt<meter>> != meter, 1367 * i.e. the operation is not reversible, and it will result in propogated approximations. 1368 * Use only when absolutely necessary. 1369 */ 1370 template<class U, std::intmax_t Eps = 10000000000> 1371 using square_root = typename units::detail::sqrt_impl<U, Eps>::type; 1372 1373 //------------------------------ 1374 // COMPOUND UNITS 1375 //------------------------------ 1376 1377 /** @cond */ // DOXYGEN IGNORE 1378 namespace detail 1379 { 1380 /** 1381 * @brief implementation of compound_unit 1382 * @details multiplies a variadic list of units together, and is inherited from the resulting 1383 * type. 1384 */ 1385 template<class U, class... Us> struct compound_impl; 1386 template<class U> struct compound_impl<U> { using type = U; }; 1387 template<class U1, class U2, class...Us> 1388 struct compound_impl<U1, U2, Us...> 1389 : compound_impl<unit_multiply<U1, U2>, Us...> {}; 1390 } 1391 /** @endcond */ // END DOXYGEN IGNORE 1392 1393 /** 1394 * @brief Represents a unit type made up from other units. 1395 * @details Compound units are formed by multiplying the units of all the types provided in 1396 * the template argument. Types provided must inherit from `unit`. A compound unit can 1397 * be formed from any number of other units, and unit manipulators like `inverse` and 1398 * `squared` are supported. E.g. to specify acceleration, on could create 1399 * `using acceleration = compound_unit<length::meters, inverse<squared<seconds>>;` 1400 * @tparam U... units which, when multiplied together, form the desired compound unit. 1401 * @ingroup UnitTypes 1402 */ 1403 template<class U, class... Us> 1404 using compound_unit = typename units::detail::compound_impl<U, Us...>::type; 1405 1406 //------------------------------ 1407 // PREFIXES 1408 //------------------------------ 1409 1410 /** @cond */ // DOXYGEN IGNORE 1411 namespace detail 1412 { 1413 /** 1414 * @brief prefix applicator. 1415 * @details creates a unit type from a prefix and a unit 1416 */ 1417 template<class Ratio, class Unit> 1418 struct prefix 1419 { 1420 static_assert(traits::is_ratio<Ratio>::value, "Template parameter `Ratio` must be a `std::ratio`."); 1421 static_assert(traits::is_unit<Unit>::value, "Template parameter `Unit` must be a `unit` type."); 1422 typedef typename units::unit<Ratio, Unit> type; 1423 }; 1424 1425 /// recursive exponential implementation 1426 template <int N, class U> 1427 struct power_of_ratio 1428 { 1429 typedef std::ratio_multiply<U, typename power_of_ratio<N - 1, U>::type> type; 1430 }; 1431 1432 /// End recursion 1433 template <class U> 1434 struct power_of_ratio<1, U> 1435 { 1436 typedef U type; 1437 }; 1438 } 1439 /** @endcond */ // END DOXYGEN IGNORE 1440 1441 /** 1442 * @ingroup UnitManipulators 1443 * @{ 1444 * @ingroup Decimal Prefixes 1445 * @{ 1446 */ 1447 template<class U> using atto = typename units::detail::prefix<std::atto, U>::type; ///< Represents the type of `class U` with the metric 'atto' prefix appended. @details E.g. atto<meters> represents meters*10^-18 @tparam U unit type to apply the prefix to. 1448 template<class U> using femto = typename units::detail::prefix<std::femto,U>::type; ///< Represents the type of `class U` with the metric 'femto' prefix appended. @details E.g. femto<meters> represents meters*10^-15 @tparam U unit type to apply the prefix to. 1449 template<class U> using pico = typename units::detail::prefix<std::pico, U>::type; ///< Represents the type of `class U` with the metric 'pico' prefix appended. @details E.g. pico<meters> represents meters*10^-12 @tparam U unit type to apply the prefix to. 1450 template<class U> using nano = typename units::detail::prefix<std::nano, U>::type; ///< Represents the type of `class U` with the metric 'nano' prefix appended. @details E.g. nano<meters> represents meters*10^-9 @tparam U unit type to apply the prefix to. 1451 template<class U> using micro = typename units::detail::prefix<std::micro,U>::type; ///< Represents the type of `class U` with the metric 'micro' prefix appended. @details E.g. micro<meters> represents meters*10^-6 @tparam U unit type to apply the prefix to. 1452 template<class U> using milli = typename units::detail::prefix<std::milli,U>::type; ///< Represents the type of `class U` with the metric 'milli' prefix appended. @details E.g. milli<meters> represents meters*10^-3 @tparam U unit type to apply the prefix to. 1453 template<class U> using centi = typename units::detail::prefix<std::centi,U>::type; ///< Represents the type of `class U` with the metric 'centi' prefix appended. @details E.g. centi<meters> represents meters*10^-2 @tparam U unit type to apply the prefix to. 1454 template<class U> using deci = typename units::detail::prefix<std::deci, U>::type; ///< Represents the type of `class U` with the metric 'deci' prefix appended. @details E.g. deci<meters> represents meters*10^-1 @tparam U unit type to apply the prefix to. 1455 template<class U> using deca = typename units::detail::prefix<std::deca, U>::type; ///< Represents the type of `class U` with the metric 'deca' prefix appended. @details E.g. deca<meters> represents meters*10^1 @tparam U unit type to apply the prefix to. 1456 template<class U> using hecto = typename units::detail::prefix<std::hecto,U>::type; ///< Represents the type of `class U` with the metric 'hecto' prefix appended. @details E.g. hecto<meters> represents meters*10^2 @tparam U unit type to apply the prefix to. 1457 template<class U> using kilo = typename units::detail::prefix<std::kilo, U>::type; ///< Represents the type of `class U` with the metric 'kilo' prefix appended. @details E.g. kilo<meters> represents meters*10^3 @tparam U unit type to apply the prefix to. 1458 template<class U> using mega = typename units::detail::prefix<std::mega, U>::type; ///< Represents the type of `class U` with the metric 'mega' prefix appended. @details E.g. mega<meters> represents meters*10^6 @tparam U unit type to apply the prefix to. 1459 template<class U> using giga = typename units::detail::prefix<std::giga, U>::type; ///< Represents the type of `class U` with the metric 'giga' prefix appended. @details E.g. giga<meters> represents meters*10^9 @tparam U unit type to apply the prefix to. 1460 template<class U> using tera = typename units::detail::prefix<std::tera, U>::type; ///< Represents the type of `class U` with the metric 'tera' prefix appended. @details E.g. tera<meters> represents meters*10^12 @tparam U unit type to apply the prefix to. 1461 template<class U> using peta = typename units::detail::prefix<std::peta, U>::type; ///< Represents the type of `class U` with the metric 'peta' prefix appended. @details E.g. peta<meters> represents meters*10^15 @tparam U unit type to apply the prefix to. 1462 template<class U> using exa = typename units::detail::prefix<std::exa, U>::type; ///< Represents the type of `class U` with the metric 'exa' prefix appended. @details E.g. exa<meters> represents meters*10^18 @tparam U unit type to apply the prefix to. 1463 /** @} @} */ 1464 1465 /** 1466 * @ingroup UnitManipulators 1467 * @{ 1468 * @ingroup Binary Prefixes 1469 * @{ 1470 */ 1471 template<class U> using kibi = typename units::detail::prefix<std::ratio<1024>, U>::type; ///< Represents the type of `class U` with the binary 'kibi' prefix appended. @details E.g. kibi<bytes> represents bytes*2^10 @tparam U unit type to apply the prefix to. 1472 template<class U> using mebi = typename units::detail::prefix<std::ratio<1048576>, U>::type; ///< Represents the type of `class U` with the binary 'mibi' prefix appended. @details E.g. mebi<bytes> represents bytes*2^20 @tparam U unit type to apply the prefix to. 1473 template<class U> using gibi = typename units::detail::prefix<std::ratio<1073741824>, U>::type; ///< Represents the type of `class U` with the binary 'gibi' prefix appended. @details E.g. gibi<bytes> represents bytes*2^30 @tparam U unit type to apply the prefix to. 1474 template<class U> using tebi = typename units::detail::prefix<std::ratio<1099511627776>, U>::type; ///< Represents the type of `class U` with the binary 'tebi' prefix appended. @details E.g. tebi<bytes> represents bytes*2^40 @tparam U unit type to apply the prefix to. 1475 template<class U> using pebi = typename units::detail::prefix<std::ratio<1125899906842624>, U>::type; ///< Represents the type of `class U` with the binary 'pebi' prefix appended. @details E.g. pebi<bytes> represents bytes*2^50 @tparam U unit type to apply the prefix to. 1476 template<class U> using exbi = typename units::detail::prefix<std::ratio<1152921504606846976>, U>::type; ///< Represents the type of `class U` with the binary 'exbi' prefix appended. @details E.g. exbi<bytes> represents bytes*2^60 @tparam U unit type to apply the prefix to. 1477 /** @} @} */ 1478 1479 //------------------------------ 1480 // CONVERSION TRAITS 1481 //------------------------------ 1482 1483 namespace traits 1484 { 1485 /** 1486 * @ingroup TypeTraits 1487 * @brief Trait which checks whether two units can be converted to each other 1488 * @details Inherits from `std::true_type` or `std::false_type`. Use `is_convertible_unit<U1, U2>::value` to test 1489 * whether `class U1` is convertible to `class U2`. Note: convertible has both the semantic meaning, 1490 * (i.e. meters can be converted to feet), and the c++ meaning of conversion (type meters can be 1491 * converted to type feet). Conversion is always symmetric, so if U1 is convertible to U2, then 1492 * U2 will be convertible to U1. 1493 * @tparam U1 Unit to convert from. 1494 * @tparam U2 Unit to convert to. 1495 * @sa is_convertible_unit_t 1496 */ 1497 template<class U1, class U2> 1498 struct is_convertible_unit : std::is_same <traits::base_unit_of<typename units::traits::unit_traits<U1>::base_unit_type>, 1499 base_unit_of<typename units::traits::unit_traits<U2>::base_unit_type >> {}; 1500 } 1501 1502 //------------------------------ 1503 // CONVERSION FUNCTION 1504 //------------------------------ 1505 1506 /** @cond */ // DOXYGEN IGNORE 1507 namespace detail 1508 { pow(UNIT_LIB_DEFAULT_TYPE x,unsigned long long y)1509 constexpr inline UNIT_LIB_DEFAULT_TYPE pow(UNIT_LIB_DEFAULT_TYPE x, unsigned long long y) 1510 { 1511 return y == 0 ? 1.0 : x * pow(x, y - 1); 1512 } 1513 abs(UNIT_LIB_DEFAULT_TYPE x)1514 constexpr inline UNIT_LIB_DEFAULT_TYPE abs(UNIT_LIB_DEFAULT_TYPE x) 1515 { 1516 return x < 0 ? -x : x; 1517 } 1518 1519 /// convert dispatch for units which are both the same 1520 template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T> convert(const T & value,std::true_type,std::false_type,std::false_type)1521 static inline constexpr T convert(const T& value, std::true_type, std::false_type, std::false_type) noexcept 1522 { 1523 return value; 1524 } 1525 1526 /// convert dispatch for units which are both the same 1527 template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T> convert(const T & value,std::true_type,std::false_type,std::true_type)1528 static inline constexpr T convert(const T& value, std::true_type, std::false_type, std::true_type) noexcept 1529 { 1530 return value; 1531 } 1532 1533 /// convert dispatch for units which are both the same 1534 template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T> convert(const T & value,std::true_type,std::true_type,std::false_type)1535 static inline constexpr T convert(const T& value, std::true_type, std::true_type, std::false_type) noexcept 1536 { 1537 return value; 1538 } 1539 1540 /// convert dispatch for units which are both the same 1541 template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T> convert(const T & value,std::true_type,std::true_type,std::true_type)1542 static inline constexpr T convert(const T& value, std::true_type, std::true_type, std::true_type) noexcept 1543 { 1544 return value; 1545 } 1546 1547 /// convert dispatch for units of different types w/ no translation and no PI 1548 template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T> convert(const T & value,std::false_type,std::false_type,std::false_type)1549 static inline constexpr T convert(const T& value, std::false_type, std::false_type, std::false_type) noexcept 1550 { 1551 return ((value * Ratio::num) / Ratio::den); 1552 } 1553 1554 /// convert dispatch for units of different types w/ no translation, but has PI in numerator 1555 // constepxr with PI in numerator 1556 template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T> 1557 static inline constexpr 1558 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)1559 convert(const T& value, std::false_type, std::true_type, std::false_type) noexcept 1560 { 1561 return ((value * pow(constants::detail::PI_VAL, PiRatio::num / PiRatio::den) * Ratio::num) / Ratio::den); 1562 } 1563 1564 /// convert dispatch for units of different types w/ no translation, but has PI in denominator 1565 // constexpr with PI in denominator 1566 template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T> 1567 static inline constexpr 1568 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)1569 convert(const T& value, std::false_type, std::true_type, std::false_type) noexcept 1570 { 1571 return (value * Ratio::num) / (Ratio::den * pow(constants::detail::PI_VAL, -PiRatio::num / PiRatio::den)); 1572 } 1573 1574 /// convert dispatch for units of different types w/ no translation, but has PI in numerator 1575 // Not constexpr - uses std::pow 1576 template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T> 1577 static inline // sorry, this can't be constexpr! 1578 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)1579 convert(const T& value, std::false_type, std::true_type, std::false_type) noexcept 1580 { 1581 return ((value * std::pow(constants::detail::PI_VAL, PiRatio::num / PiRatio::den) * Ratio::num) / Ratio::den); 1582 } 1583 1584 /// convert dispatch for units of different types with a translation, but no PI 1585 template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T> convert(const T & value,std::false_type,std::false_type,std::true_type)1586 static inline constexpr T convert(const T& value, std::false_type, std::false_type, std::true_type) noexcept 1587 { 1588 return ((value * Ratio::num) / Ratio::den) + (static_cast<UNIT_LIB_DEFAULT_TYPE>(Translation::num) / Translation::den); 1589 } 1590 1591 /// convert dispatch for units of different types with a translation AND PI 1592 template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T> convert(const T & value,const std::false_type,const std::true_type,const std::true_type)1593 static inline constexpr T convert(const T& value, const std::false_type, const std::true_type, const std::true_type) noexcept 1594 { 1595 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); 1596 } 1597 } 1598 /** @endcond */ // END DOXYGEN IGNORE 1599 1600 /** 1601 * @ingroup Conversion 1602 * @brief converts a <i>value</i> from one type to another. 1603 * @details Converts a <i>value</i> of a built-in arithmetic type to another unit. This does not change 1604 * the type of <i>value</i>, only what it contains. E.g. @code double result = convert<length::meters, length::feet>(1.0); // result == 3.28084 @endcode 1605 * @sa unit_t for implicit conversion of unit containers. 1606 * @tparam UnitFrom unit tag to convert <i>value</i> from. Must be a `unit` type (i.e. is_unit<UnitFrom>::value == true), 1607 * and must be convertible to `UnitTo` (i.e. is_convertible_unit<UnitFrom, UnitTo>::value == true). 1608 * @tparam UnitTo unit tag to convert <i>value</i> to. Must be a `unit` type (i.e. is_unit<UnitTo>::value == true), 1609 * and must be convertible from `UnitFrom` (i.e. is_convertible_unit<UnitFrom, UnitTo>::value == true). 1610 * @tparam T type of <i>value</i>. It is inferred from <i>value</i>, and is expected to be a built-in arithmetic type. 1611 * @param[in] value Arithmetic value to convert from `UnitFrom` to `UnitTo`. The value should represent 1612 * a quantity in units of `UnitFrom`. 1613 * @returns value, converted from units of `UnitFrom` to `UnitTo`. 1614 */ 1615 template<class UnitFrom, class UnitTo, typename T = UNIT_LIB_DEFAULT_TYPE> convert(const T & value)1616 static inline constexpr T convert(const T& value) noexcept 1617 { 1618 static_assert(traits::is_unit<UnitFrom>::value, "Template parameter `UnitFrom` must be a `unit` type."); 1619 static_assert(traits::is_unit<UnitTo>::value, "Template parameter `UnitTo` must be a `unit` type."); 1620 static_assert(traits::is_convertible_unit<UnitFrom, UnitTo>::value, "Units are not compatible."); 1621 1622 using Ratio = std::ratio_divide<typename UnitFrom::conversion_ratio, typename UnitTo::conversion_ratio>; 1623 using PiRatio = std::ratio_subtract<typename UnitFrom::pi_exponent_ratio, typename UnitTo::pi_exponent_ratio>; 1624 using Translation = std::ratio_divide<std::ratio_subtract<typename UnitFrom::translation_ratio, typename UnitTo::translation_ratio>, typename UnitTo::conversion_ratio>; 1625 1626 using isSame = typename std::is_same<std::decay_t<UnitFrom>, std::decay_t<UnitTo>>::type; 1627 using piRequired = std::integral_constant<bool, !(std::is_same<std::ratio<0>, PiRatio>::value)>; 1628 using translationRequired = std::integral_constant<bool, !(std::is_same<std::ratio<0>, Translation>::value)>; 1629 1630 return units::detail::convert<UnitFrom, UnitTo, Ratio, PiRatio, Translation, T> 1631 (value, isSame{}, piRequired{}, translationRequired{}); 1632 } 1633 1634 //---------------------------------- 1635 // NON-LINEAR SCALE TRAITS 1636 //---------------------------------- 1637 1638 /** @cond */ // DOXYGEN IGNORE 1639 namespace traits 1640 { 1641 namespace detail 1642 { 1643 /** 1644 * @brief implementation of has_operator_parenthesis 1645 * @details checks that operator() returns the same type as `Ret` 1646 */ 1647 template<class T, class Ret> 1648 struct has_operator_parenthesis_impl 1649 { 1650 template<class U> testunits::traits::detail::has_operator_parenthesis_impl1651 static constexpr auto test(U*) -> decltype(std::declval<U>()()) { return decltype(std::declval<U>()()){}; } 1652 template<typename> testunits::traits::detail::has_operator_parenthesis_impl1653 static constexpr std::false_type test(...) { return std::false_type{}; } 1654 1655 using type = typename std::is_same<Ret, decltype(test<T>(0))>::type; 1656 }; 1657 } 1658 1659 /** 1660 * @brief checks that `class T` has an `operator()` member which returns `Ret` 1661 * @details used as part of the linear_scale concept. 1662 */ 1663 template<class T, class Ret> 1664 struct has_operator_parenthesis : traits::detail::has_operator_parenthesis_impl<T, Ret>::type {}; 1665 } 1666 1667 namespace traits 1668 { 1669 namespace detail 1670 { 1671 /** 1672 * @brief implementation of has_value_member 1673 * @details checks for a member named `m_member` with type `Ret` 1674 */ 1675 template<class T, class Ret> 1676 struct has_value_member_impl 1677 { 1678 template<class U> testunits::traits::detail::has_value_member_impl1679 static constexpr auto test(U* p) -> decltype(p->m_value) { return p->m_value; } 1680 template<typename> testunits::traits::detail::has_value_member_impl1681 static constexpr auto test(...)->std::false_type { return std::false_type{}; } 1682 1683 using type = typename std::is_same<std::decay_t<Ret>, std::decay_t<decltype(test<T>(0))>>::type; 1684 }; 1685 } 1686 1687 /** 1688 * @brief checks for a member named `m_member` with type `Ret` 1689 * @details used as part of the linear_scale concept checker. 1690 */ 1691 template<class T, class Ret> 1692 struct has_value_member : traits::detail::has_value_member_impl<T, Ret>::type {}; 1693 } 1694 /** @endcond */ // END DOXYGEN IGNORE 1695 1696 namespace traits 1697 { 1698 /** 1699 * @ingroup TypeTraits 1700 * @brief Trait which tests that `class T` meets the requirements for a non-linear scale 1701 * @details A non-linear scale must: 1702 * - be default constructible 1703 * - have an `operator()` member which returns the non-linear value stored in the scale 1704 * - have an accessible `m_value` member type which stores the linearized value in the scale. 1705 * 1706 * Linear/nonlinear scales are used by `units::unit` to store values and scale them 1707 * if they represent things like dB. 1708 */ 1709 template<class T, class Ret> 1710 struct is_nonlinear_scale : std::integral_constant<bool, 1711 std::is_default_constructible<T>::value && 1712 has_operator_parenthesis<T, Ret>::value && 1713 has_value_member<T, Ret>::value && 1714 std::is_trivial<T>::value> 1715 {}; 1716 } 1717 1718 //------------------------------ 1719 // UNIT_T TYPE TRAITS 1720 //------------------------------ 1721 1722 namespace traits 1723 { 1724 #ifdef FOR_DOXYGEN_PURPOSOES_ONLY 1725 /** 1726 * @ingroup TypeTraits 1727 * @brief Trait for accessing the publically defined types of `units::unit_t` 1728 * @details The units library determines certain properties of the unit_t types passed to them 1729 * and what they represent by using the members of the corresponding unit_t_traits instantiation. 1730 */ 1731 template<typename T> 1732 struct unit_t_traits 1733 { 1734 typedef typename T::non_linear_scale_type non_linear_scale_type; ///< Type of the unit_t non_linear_scale (e.g. linear_scale, decibel_scale). This property is used to enable the proper linear or logarithmic arithmetic functions. 1735 typedef typename T::underlying_type underlying_type; ///< Underlying storage type of the `unit_t`, e.g. `double`. 1736 typedef typename T::value_type value_type; ///< Synonym for underlying type. May be removed in future versions. Prefer underlying_type. 1737 typedef typename T::unit_type unit_type; ///< Type of unit the `unit_t` represents, e.g. `meters` 1738 }; 1739 #endif 1740 1741 /** @cond */ // DOXYGEN IGNORE 1742 /** 1743 * @brief unit_t_traits specialization for things which are not unit_t 1744 * @details 1745 */ 1746 template<typename T, typename = void> 1747 struct unit_t_traits 1748 { 1749 typedef void non_linear_scale_type; 1750 typedef void underlying_type; 1751 typedef void value_type; 1752 typedef void unit_type; 1753 }; 1754 1755 /** 1756 * @ingroup TypeTraits 1757 * @brief Trait for accessing the publically defined types of `units::unit_t` 1758 * @details 1759 */ 1760 template<typename T> 1761 struct unit_t_traits <T, typename void_t< 1762 typename T::non_linear_scale_type, 1763 typename T::underlying_type, 1764 typename T::value_type, 1765 typename T::unit_type>::type> 1766 { 1767 typedef typename T::non_linear_scale_type non_linear_scale_type; 1768 typedef typename T::underlying_type underlying_type; 1769 typedef typename T::value_type value_type; 1770 typedef typename T::unit_type unit_type; 1771 }; 1772 /** @endcond */ // END DOXYGEN IGNORE 1773 } 1774 1775 namespace traits 1776 { 1777 /** 1778 * @ingroup TypeTraits 1779 * @brief Trait which tests whether two container types derived from `unit_t` are convertible to each other 1780 * @details Inherits from `std::true_type` or `std::false_type`. Use `is_convertible_unit_t<U1, U2>::value` to test 1781 * whether `class U1` is convertible to `class U2`. Note: convertible has both the semantic meaning, 1782 * (i.e. meters can be converted to feet), and the c++ meaning of conversion (type meters can be 1783 * converted to type feet). Conversion is always symmetric, so if U1 is convertible to U2, then 1784 * U2 will be convertible to U1. 1785 * @tparam U1 Unit to convert from. 1786 * @tparam U2 Unit to convert to. 1787 * @sa is_convertible_unit 1788 */ 1789 template<class U1, class U2> 1790 struct is_convertible_unit_t : std::integral_constant<bool, 1791 is_convertible_unit<typename units::traits::unit_t_traits<U1>::unit_type, typename units::traits::unit_t_traits<U2>::unit_type>::value> 1792 {}; 1793 } 1794 1795 //---------------------------------- 1796 // UNIT TYPE 1797 //---------------------------------- 1798 1799 /** @cond */ // DOXYGEN IGNORE 1800 // forward declaration 1801 template<typename T> struct linear_scale; 1802 template<typename T> struct decibel_scale; 1803 1804 namespace detail 1805 { 1806 /** 1807 * @brief helper type to identify units. 1808 * @details A non-templated base class for `unit` which enables RTTI testing. 1809 */ 1810 struct _unit_t {}; 1811 } 1812 /** @endcond */ // END DOXYGEN IGNORE 1813 1814 namespace traits 1815 { 1816 // forward declaration 1817 #if !defined(_MSC_VER) || _MSC_VER > 1800 // bug in VS2013 prevents this from working 1818 template<typename... T> struct is_dimensionless_unit; 1819 #else 1820 template<typename T1, typename T2 = T1, typename T3 = T1> struct is_dimensionless_unit; 1821 #endif 1822 1823 /** 1824 * @ingroup TypeTraits 1825 * @brief Traits which tests if a class is a `unit` 1826 * @details Inherits from `std::true_type` or `std::false_type`. Use `is_unit<T>::value` to test 1827 * whether `class T` implements a `unit`. 1828 */ 1829 template<class T> 1830 struct is_unit_t : std::is_base_of<units::detail::_unit_t, T>::type {}; 1831 } 1832 1833 /** 1834 * @ingroup UnitContainers 1835 * @brief Container for values which represent quantities of a given unit. 1836 * @details Stores a value which represents a quantity in the given units. Unit containers 1837 * (except scalar values) are *not* convertible to built-in c++ types, in order to 1838 * provide type safety in dimensional analysis. Unit containers *are* implicitly 1839 * convertible to other compatible unit container types. Unit containers support 1840 * various types of arithmetic operations, depending on their scale type. 1841 * 1842 * The value of a `unit_t` can only be changed on construction, or by assignment 1843 * from another `unit_t` type. If necessary, the underlying value can be accessed 1844 * using `operator()`: @code 1845 * meter_t m(5.0); 1846 * double val = m(); // val == 5.0 @endcode. 1847 * @tparam Units unit tag for which type of units the `unit_t` represents (e.g. meters) 1848 * @tparam T underlying type of the storage. Defaults to double. 1849 * @tparam NonLinearScale optional scale class for the units. Defaults to linear (i.e. does 1850 * not scale the unit value). Examples of non-linear scales could be logarithmic, 1851 * decibel, or richter scales. Non-linear scales must adhere to the non-linear-scale 1852 * concept, i.e. `is_nonlinear_scale<...>::value` must be `true`. 1853 * @sa 1854 * - \ref lengthContainers "length unit containers" 1855 * - \ref massContainers "mass unit containers" 1856 * - \ref timeContainers "time unit containers" 1857 * - \ref angleContainers "angle unit containers" 1858 * - \ref currentContainers "current unit containers" 1859 * - \ref temperatureContainers "temperature unit containers" 1860 * - \ref substanceContainers "substance unit containers" 1861 * - \ref luminousIntensityContainers "luminous intensity unit containers" 1862 * - \ref solidAngleContainers "solid angle unit containers" 1863 * - \ref frequencyContainers "frequency unit containers" 1864 * - \ref velocityContainers "velocity unit containers" 1865 * - \ref angularVelocityContainers "angular velocity unit containers" 1866 * - \ref accelerationContainers "acceleration unit containers" 1867 * - \ref forceContainers "force unit containers" 1868 * - \ref pressureContainers "pressure unit containers" 1869 * - \ref chargeContainers "charge unit containers" 1870 * - \ref energyContainers "energy unit containers" 1871 * - \ref powerContainers "power unit containers" 1872 * - \ref voltageContainers "voltage unit containers" 1873 * - \ref capacitanceContainers "capacitance unit containers" 1874 * - \ref impedanceContainers "impedance unit containers" 1875 * - \ref magneticFluxContainers "magnetic flux unit containers" 1876 * - \ref magneticFieldStrengthContainers "magnetic field strength unit containers" 1877 * - \ref inductanceContainers "inductance unit containers" 1878 * - \ref luminousFluxContainers "luminous flux unit containers" 1879 * - \ref illuminanceContainers "illuminance unit containers" 1880 * - \ref radiationContainers "radiation unit containers" 1881 * - \ref torqueContainers "torque unit containers" 1882 * - \ref areaContainers "area unit containers" 1883 * - \ref volumeContainers "volume unit containers" 1884 * - \ref densityContainers "density unit containers" 1885 * - \ref concentrationContainers "concentration unit containers" 1886 * - \ref constantContainers "constant unit containers" 1887 */ 1888 template<class Units, typename T = UNIT_LIB_DEFAULT_TYPE, template<typename> class NonLinearScale = linear_scale> 1889 class unit_t : public NonLinearScale<T>, units::detail::_unit_t 1890 { 1891 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)."); 1892 static_assert(traits::is_nonlinear_scale<NonLinearScale<T>, T>::value, "Template parameter `NonLinearScale` does not conform to the `is_nonlinear_scale` concept."); 1893 1894 protected: 1895 1896 using nls = NonLinearScale<T>; 1897 using nls::m_value; 1898 1899 public: 1900 1901 typedef NonLinearScale<T> non_linear_scale_type; ///< Type of the non-linear scale of the unit_t (e.g. linear_scale) 1902 typedef T underlying_type; ///< Type of the underlying storage of the unit_t (e.g. double) 1903 typedef T value_type; ///< Synonym for underlying type. May be removed in future versions. Prefer underlying_type. 1904 typedef Units unit_type; ///< Type of `unit` the `unit_t` represents (e.g. meters) 1905 1906 /** 1907 * @ingroup Constructors 1908 * @brief default constructor. 1909 */ 1910 constexpr unit_t() = default; 1911 1912 /** 1913 * @brief constructor 1914 * @details constructs a new unit_t using the non-linear scale's constructor. 1915 * @param[in] value unit value magnitude. 1916 * @param[in] args additional constructor arguments are forwarded to the non-linear scale constructor. Which 1917 * args are required depends on which scale is used. For the default (linear) scale, 1918 * no additional args are necessary. 1919 */ 1920 template<class... Args> unit_t(const T value,const Args &...args)1921 inline explicit constexpr unit_t(const T value, const Args&... args) noexcept : nls(value, args...) 1922 { 1923 1924 } 1925 1926 /** 1927 * @brief constructor 1928 * @details enable implicit conversions from T types ONLY for linear scalar units 1929 * @param[in] value value of the unit_t 1930 */ 1931 template<class Ty, class = typename std::enable_if<traits::is_dimensionless_unit<Units>::value && std::is_arithmetic<Ty>::value>::type> unit_t(const Ty value)1932 inline constexpr unit_t(const Ty value) noexcept : nls(value) 1933 { 1934 1935 } 1936 1937 /** 1938 * @brief chrono constructor 1939 * @details enable implicit conversions from std::chrono::duration types ONLY for time units 1940 * @param[in] value value of the unit_t 1941 */ 1942 template<class Rep, class Period, class = std::enable_if_t<std::is_arithmetic<Rep>::value && traits::is_ratio<Period>::value>> unit_t(const std::chrono::duration<Rep,Period> & value)1943 inline constexpr unit_t(const std::chrono::duration<Rep, Period>& value) noexcept : 1944 nls(units::convert<unit<std::ratio<1,1000000000>, category::time_unit>, Units>(static_cast<T>(std::chrono::duration_cast<std::chrono::nanoseconds>(value).count()))) 1945 { 1946 1947 } 1948 1949 /** 1950 * @brief copy constructor (converting) 1951 * @details performs implicit unit conversions if required. 1952 * @param[in] rhs unit to copy. 1953 */ 1954 template<class UnitsRhs, typename Ty, template<typename> class NlsRhs> unit_t(const unit_t<UnitsRhs,Ty,NlsRhs> & rhs)1955 inline constexpr unit_t(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) noexcept : 1956 nls(units::convert<UnitsRhs, Units, T>(rhs.m_value), std::true_type() /*store linear value*/) 1957 { 1958 1959 } 1960 1961 /** 1962 * @brief assignment 1963 * @details performs implicit unit conversions if required 1964 * @param[in] rhs unit to copy. 1965 */ 1966 template<class UnitsRhs, typename Ty, template<typename> class NlsRhs> operator =(const unit_t<UnitsRhs,Ty,NlsRhs> & rhs)1967 inline unit_t& operator=(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) noexcept 1968 { 1969 nls::m_value = units::convert<UnitsRhs, Units, T>(rhs.m_value); 1970 return *this; 1971 } 1972 1973 /** 1974 * @brief assignment 1975 * @details performs implicit conversions from built-in types ONLY for scalar units 1976 * @param[in] rhs value to copy. 1977 */ 1978 template<class Ty, class = std::enable_if_t<traits::is_dimensionless_unit<Units>::value && std::is_arithmetic<Ty>::value>> operator =(const Ty & rhs)1979 inline unit_t& operator=(const Ty& rhs) noexcept 1980 { 1981 nls::m_value = rhs; 1982 return *this; 1983 } 1984 1985 /** 1986 * @brief less-than 1987 * @details compares the linearized value of two units. Performs unit conversions if necessary. 1988 * @param[in] rhs right-hand side unit for the comparison 1989 * @returns true IFF the value of `this` is less than the value of `rhs` 1990 */ 1991 template<class UnitsRhs, typename Ty, template<typename> class NlsRhs> operator <(const unit_t<UnitsRhs,Ty,NlsRhs> & rhs) const1992 inline constexpr bool operator<(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept 1993 { 1994 return (nls::m_value < units::convert<UnitsRhs, Units>(rhs.m_value)); 1995 } 1996 1997 /** 1998 * @brief less-than or equal 1999 * @details compares the linearized value of two units. Performs unit conversions if necessary. 2000 * @param[in] rhs right-hand side unit for the comparison 2001 * @returns true IFF the value of `this` is less than or equal to the value of `rhs` 2002 */ 2003 template<class UnitsRhs, typename Ty, template<typename> class NlsRhs> operator <=(const unit_t<UnitsRhs,Ty,NlsRhs> & rhs) const2004 inline constexpr bool operator<=(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept 2005 { 2006 return (nls::m_value <= units::convert<UnitsRhs, Units>(rhs.m_value)); 2007 } 2008 2009 /** 2010 * @brief greater-than 2011 * @details compares the linearized value of two units. Performs unit conversions if necessary. 2012 * @param[in] rhs right-hand side unit for the comparison 2013 * @returns true IFF the value of `this` is greater than the value of `rhs` 2014 */ 2015 template<class UnitsRhs, typename Ty, template<typename> class NlsRhs> operator >(const unit_t<UnitsRhs,Ty,NlsRhs> & rhs) const2016 inline constexpr bool operator>(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept 2017 { 2018 return (nls::m_value > units::convert<UnitsRhs, Units>(rhs.m_value)); 2019 } 2020 2021 /** 2022 * @brief greater-than or equal 2023 * @details compares the linearized value of two units. Performs unit conversions if necessary. 2024 * @param[in] rhs right-hand side unit for the comparison 2025 * @returns true IFF the value of `this` is greater than or equal to the value of `rhs` 2026 */ 2027 template<class UnitsRhs, typename Ty, template<typename> class NlsRhs> operator >=(const unit_t<UnitsRhs,Ty,NlsRhs> & rhs) const2028 inline constexpr bool operator>=(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept 2029 { 2030 return (nls::m_value >= units::convert<UnitsRhs, Units>(rhs.m_value)); 2031 } 2032 2033 /** 2034 * @brief equality 2035 * @details compares the linearized value of two units. Performs unit conversions if necessary. 2036 * @param[in] rhs right-hand side unit for the comparison 2037 * @returns true IFF the value of `this` exactly equal to the value of rhs. 2038 * @note This may not be suitable for all applications when the underlying_type of unit_t is a double. 2039 */ 2040 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> operator ==(const unit_t<UnitsRhs,Ty,NlsRhs> & rhs) const2041 inline constexpr bool operator==(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept 2042 { 2043 return detail::abs(nls::m_value - units::convert<UnitsRhs, Units>(rhs.m_value)) < std::numeric_limits<T>::epsilon() * 2044 detail::abs(nls::m_value + units::convert<UnitsRhs, Units>(rhs.m_value)) || 2045 detail::abs(nls::m_value - units::convert<UnitsRhs, Units>(rhs.m_value)) < std::numeric_limits<T>::min(); 2046 } 2047 2048 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> operator ==(const unit_t<UnitsRhs,Ty,NlsRhs> & rhs) const2049 inline constexpr bool operator==(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept 2050 { 2051 return nls::m_value == units::convert<UnitsRhs, Units>(rhs.m_value); 2052 } 2053 2054 /** 2055 * @brief inequality 2056 * @details compares the linearized value of two units. Performs unit conversions if necessary. 2057 * @param[in] rhs right-hand side unit for the comparison 2058 * @returns true IFF the value of `this` is not equal to the value of rhs. 2059 * @note This may not be suitable for all applications when the underlying_type of unit_t is a double. 2060 */ 2061 template<class UnitsRhs, typename Ty, template<typename> class NlsRhs> operator !=(const unit_t<UnitsRhs,Ty,NlsRhs> & rhs) const2062 inline constexpr bool operator!=(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept 2063 { 2064 return !(*this == rhs); 2065 } 2066 2067 /** 2068 * @brief unit value 2069 * @returns value of the unit in it's underlying, non-safe type. 2070 */ value() const2071 inline constexpr underlying_type value() const noexcept 2072 { 2073 return static_cast<underlying_type>(*this); 2074 } 2075 2076 /** 2077 * @brief unit value 2078 * @returns value of the unit converted to an arithmetic, non-safe type. 2079 */ 2080 template<typename Ty, class = std::enable_if_t<std::is_arithmetic<Ty>::value>> to() const2081 inline constexpr Ty to() const noexcept 2082 { 2083 return static_cast<Ty>(*this); 2084 } 2085 2086 /** 2087 * @brief linearized unit value 2088 * @returns linearized value of unit which has a non-linear scale. For `unit_t` types with 2089 * linear scales, this is equivalent to `value`. 2090 */ 2091 template<typename Ty, class = std::enable_if_t<std::is_arithmetic<Ty>::value>> toLinearized() const2092 inline constexpr Ty toLinearized() const noexcept 2093 { 2094 return static_cast<Ty>(m_value); 2095 } 2096 2097 /** 2098 * @brief conversion 2099 * @details Converts to a different unit container. Units can be converted to other containers 2100 * implicitly, but this can be used in cases where explicit notation of a conversion 2101 * is beneficial, or where an r-value container is needed. 2102 * @tparam U unit (not unit_t) to convert to 2103 * @returns a unit container with the specified units containing the equivalent value to 2104 * *this. 2105 */ 2106 template<class U> convert() const2107 inline constexpr unit_t<U> convert() const noexcept 2108 { 2109 static_assert(traits::is_unit<U>::value, "Template parameter `U` must be a unit type."); 2110 return unit_t<U>(*this); 2111 } 2112 2113 /** 2114 * @brief implicit type conversion. 2115 * @details only enabled for scalar unit types. 2116 */ 2117 template<class Ty, std::enable_if_t<traits::is_dimensionless_unit<Units>::value && std::is_arithmetic<Ty>::value, int> = 0> operator Ty() const2118 inline constexpr operator Ty() const noexcept 2119 { 2120 // this conversion also resolves any PI exponents, by converting from a non-zero PI ratio to a zero-pi ratio. 2121 return static_cast<Ty>(units::convert<Units, unit<std::ratio<1>, units::category::scalar_unit>>((*this)())); 2122 } 2123 2124 /** 2125 * @brief explicit type conversion. 2126 * @details only enabled for non-dimensionless unit types. 2127 */ 2128 template<class Ty, std::enable_if_t<!traits::is_dimensionless_unit<Units>::value && std::is_arithmetic<Ty>::value, int> = 0> operator Ty() const2129 inline constexpr explicit operator Ty() const noexcept 2130 { 2131 return static_cast<Ty>((*this)()); 2132 } 2133 2134 /** 2135 * @brief chrono implicit type conversion. 2136 * @details only enabled for time unit types. 2137 */ 2138 template<typename U = Units, std::enable_if_t<units::traits::is_convertible_unit<U, unit<std::ratio<1>, category::time_unit>>::value, int> = 0> operator std::chrono::nanoseconds() const2139 inline constexpr operator std::chrono::nanoseconds() const noexcept 2140 { 2141 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)()))); 2142 } 2143 2144 /** 2145 * @brief returns the unit name 2146 */ name() const2147 inline constexpr const char* name() const noexcept 2148 { 2149 return units::name(*this); 2150 } 2151 2152 /** 2153 * @brief returns the unit abbreviation 2154 */ abbreviation() const2155 inline constexpr const char* abbreviation() const noexcept 2156 { 2157 return units::abbreviation(*this); 2158 } 2159 2160 public: 2161 2162 template<class U, typename Ty, template<typename> class Nlt> 2163 friend class unit_t; 2164 }; 2165 2166 //------------------------------ 2167 // UNIT_T NON-MEMBER FUNCTIONS 2168 //------------------------------ 2169 2170 /** 2171 * @ingroup UnitContainers 2172 * @brief Constructs a unit container from an arithmetic type. 2173 * @details make_unit can be used to construct a unit container from an arithmetic type, as an alternative to 2174 * using the explicit constructor. Unlike the explicit constructor it forces the user to explicitly 2175 * specify the units. 2176 * @tparam UnitType Type to construct. 2177 * @tparam Ty Arithmetic type. 2178 * @param[in] value Arithmetic value that represents a quantity in units of `UnitType`. 2179 */ 2180 template<class UnitType, typename T, class = std::enable_if_t<std::is_arithmetic<T>::value>> make_unit(const T value)2181 inline constexpr UnitType make_unit(const T value) noexcept 2182 { 2183 static_assert(traits::is_unit_t<UnitType>::value, "Template parameter `UnitType` must be a unit type (_t)."); 2184 2185 return UnitType(value); 2186 } 2187 2188 #if !defined(UNIT_LIB_DISABLE_IOSTREAM) 2189 template<class Units, typename T, template<typename> class NonLinearScale> operator <<(std::ostream & os,const unit_t<Units,T,NonLinearScale> & obj)2190 inline std::ostream& operator<<(std::ostream& os, const unit_t<Units, T, NonLinearScale>& obj) noexcept 2191 { 2192 // change made by twhuang 2193 // we don't need the long name as defined in the original library. 2194 os << obj.value() << ' ' << units::abbreviation(obj); 2195 return os; 2196 2197 /*using BaseUnits = unit<std::ratio<1>, typename traits::unit_traits<Units>::base_unit_type>; 2198 os << convert<Units, BaseUnits>(obj()); 2199 2200 2201 2202 if (traits::unit_traits<Units>::base_unit_type::meter_ratio::num != 0) { os << " m"; } 2203 if (traits::unit_traits<Units>::base_unit_type::meter_ratio::num != 0 && 2204 traits::unit_traits<Units>::base_unit_type::meter_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::meter_ratio::num; } 2205 if (traits::unit_traits<Units>::base_unit_type::meter_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::meter_ratio::den; } 2206 2207 if (traits::unit_traits<Units>::base_unit_type::kilogram_ratio::num != 0) { os << " kg"; } 2208 if (traits::unit_traits<Units>::base_unit_type::kilogram_ratio::num != 0 && 2209 traits::unit_traits<Units>::base_unit_type::kilogram_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::kilogram_ratio::num; } 2210 if (traits::unit_traits<Units>::base_unit_type::kilogram_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::kilogram_ratio::den; } 2211 2212 if (traits::unit_traits<Units>::base_unit_type::second_ratio::num != 0) { os << " s"; } 2213 if (traits::unit_traits<Units>::base_unit_type::second_ratio::num != 0 && 2214 traits::unit_traits<Units>::base_unit_type::second_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::second_ratio::num; } 2215 if (traits::unit_traits<Units>::base_unit_type::second_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::second_ratio::den; } 2216 2217 if (traits::unit_traits<Units>::base_unit_type::ampere_ratio::num != 0) { os << " A"; } 2218 if (traits::unit_traits<Units>::base_unit_type::ampere_ratio::num != 0 && 2219 traits::unit_traits<Units>::base_unit_type::ampere_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::ampere_ratio::num; } 2220 if (traits::unit_traits<Units>::base_unit_type::ampere_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::ampere_ratio::den; } 2221 2222 if (traits::unit_traits<Units>::base_unit_type::kelvin_ratio::num != 0) { os << " K"; } 2223 if (traits::unit_traits<Units>::base_unit_type::kelvin_ratio::num != 0 && 2224 traits::unit_traits<Units>::base_unit_type::kelvin_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::kelvin_ratio::num; } 2225 if (traits::unit_traits<Units>::base_unit_type::kelvin_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::kelvin_ratio::den; } 2226 2227 if (traits::unit_traits<Units>::base_unit_type::mole_ratio::num != 0) { os << " mol"; } 2228 if (traits::unit_traits<Units>::base_unit_type::mole_ratio::num != 0 && 2229 traits::unit_traits<Units>::base_unit_type::mole_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::mole_ratio::num; } 2230 if (traits::unit_traits<Units>::base_unit_type::mole_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::mole_ratio::den; } 2231 2232 if (traits::unit_traits<Units>::base_unit_type::candela_ratio::num != 0) { os << " cd"; } 2233 if (traits::unit_traits<Units>::base_unit_type::candela_ratio::num != 0 && 2234 traits::unit_traits<Units>::base_unit_type::candela_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::candela_ratio::num; } 2235 if (traits::unit_traits<Units>::base_unit_type::candela_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::candela_ratio::den; } 2236 2237 if (traits::unit_traits<Units>::base_unit_type::radian_ratio::num != 0) { os << " rad"; } 2238 if (traits::unit_traits<Units>::base_unit_type::radian_ratio::num != 0 && 2239 traits::unit_traits<Units>::base_unit_type::radian_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::radian_ratio::num; } 2240 if (traits::unit_traits<Units>::base_unit_type::radian_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::radian_ratio::den; } 2241 2242 if (traits::unit_traits<Units>::base_unit_type::byte_ratio::num != 0) { os << " b"; } 2243 if (traits::unit_traits<Units>::base_unit_type::byte_ratio::num != 0 && 2244 traits::unit_traits<Units>::base_unit_type::byte_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::byte_ratio::num; } 2245 if (traits::unit_traits<Units>::base_unit_type::byte_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::byte_ratio::den; } 2246 2247 return os;*/ 2248 } 2249 #endif 2250 2251 template<class Units, typename T, template<typename> class NonLinearScale, typename RhsType> operator +=(unit_t<Units,T,NonLinearScale> & lhs,const RhsType & rhs)2252 inline unit_t<Units, T, NonLinearScale>& operator+=(unit_t<Units, T, NonLinearScale>& lhs, const RhsType& rhs) noexcept 2253 { 2254 static_assert(traits::is_convertible_unit_t<unit_t<Units, T, NonLinearScale>, RhsType>::value || 2255 (traits::is_dimensionless_unit<decltype(lhs)>::value && std::is_arithmetic<RhsType>::value), 2256 "parameters are not compatible units."); 2257 2258 lhs = lhs + rhs; 2259 return lhs; 2260 } 2261 2262 template<class Units, typename T, template<typename> class NonLinearScale, typename RhsType> operator -=(unit_t<Units,T,NonLinearScale> & lhs,const RhsType & rhs)2263 inline unit_t<Units, T, NonLinearScale>& operator-=(unit_t<Units, T, NonLinearScale>& lhs, const RhsType& rhs) noexcept 2264 { 2265 static_assert(traits::is_convertible_unit_t<unit_t<Units, T, NonLinearScale>, RhsType>::value || 2266 (traits::is_dimensionless_unit<decltype(lhs)>::value && std::is_arithmetic<RhsType>::value), 2267 "parameters are not compatible units."); 2268 2269 lhs = lhs - rhs; 2270 return lhs; 2271 } 2272 2273 template<class Units, typename T, template<typename> class NonLinearScale, typename RhsType> operator *=(unit_t<Units,T,NonLinearScale> & lhs,const RhsType & rhs)2274 inline unit_t<Units, T, NonLinearScale>& operator*=(unit_t<Units, T, NonLinearScale>& lhs, const RhsType& rhs) noexcept 2275 { 2276 static_assert((traits::is_dimensionless_unit<RhsType>::value || std::is_arithmetic<RhsType>::value), 2277 "right-hand side parameter must be dimensionless."); 2278 2279 lhs = lhs * rhs; 2280 return lhs; 2281 } 2282 2283 template<class Units, typename T, template<typename> class NonLinearScale, typename RhsType> operator /=(unit_t<Units,T,NonLinearScale> & lhs,const RhsType & rhs)2284 inline unit_t<Units, T, NonLinearScale>& operator/=(unit_t<Units, T, NonLinearScale>& lhs, const RhsType& rhs) noexcept 2285 { 2286 static_assert((traits::is_dimensionless_unit<RhsType>::value || std::is_arithmetic<RhsType>::value), 2287 "right-hand side parameter must be dimensionless."); 2288 2289 lhs = lhs / rhs; 2290 return lhs; 2291 } 2292 2293 //------------------------------ 2294 // UNIT_T UNARY OPERATORS 2295 //------------------------------ 2296 2297 // unary addition: +T 2298 template<class Units, typename T, template<typename> class NonLinearScale> operator +(const unit_t<Units,T,NonLinearScale> & u)2299 inline unit_t<Units, T, NonLinearScale> operator+(const unit_t<Units, T, NonLinearScale>& u) noexcept 2300 { 2301 return u; 2302 } 2303 2304 // prefix increment: ++T 2305 template<class Units, typename T, template<typename> class NonLinearScale> operator ++(unit_t<Units,T,NonLinearScale> & u)2306 inline unit_t<Units, T, NonLinearScale>& operator++(unit_t<Units, T, NonLinearScale>& u) noexcept 2307 { 2308 u = unit_t<Units, T, NonLinearScale>(u() + 1); 2309 return u; 2310 } 2311 2312 // postfix increment: T++ 2313 template<class Units, typename T, template<typename> class NonLinearScale> operator ++(unit_t<Units,T,NonLinearScale> & u,int)2314 inline unit_t<Units, T, NonLinearScale> operator++(unit_t<Units, T, NonLinearScale>& u, int) noexcept 2315 { 2316 auto ret = u; 2317 u = unit_t<Units, T, NonLinearScale>(u() + 1); 2318 return ret; 2319 } 2320 2321 // unary addition: -T 2322 template<class Units, typename T, template<typename> class NonLinearScale> operator -(const unit_t<Units,T,NonLinearScale> & u)2323 inline unit_t<Units, T, NonLinearScale> operator-(const unit_t<Units, T, NonLinearScale>& u) noexcept 2324 { 2325 return unit_t<Units, T, NonLinearScale>(-u()); 2326 } 2327 2328 // prefix increment: --T 2329 template<class Units, typename T, template<typename> class NonLinearScale> operator --(unit_t<Units,T,NonLinearScale> & u)2330 inline unit_t<Units, T, NonLinearScale>& operator--(unit_t<Units, T, NonLinearScale>& u) noexcept 2331 { 2332 u = unit_t<Units, T, NonLinearScale>(u() - 1); 2333 return u; 2334 } 2335 2336 // postfix increment: T-- 2337 template<class Units, typename T, template<typename> class NonLinearScale> operator --(unit_t<Units,T,NonLinearScale> & u,int)2338 inline unit_t<Units, T, NonLinearScale> operator--(unit_t<Units, T, NonLinearScale>& u, int) noexcept 2339 { 2340 auto ret = u; 2341 u = unit_t<Units, T, NonLinearScale>(u() - 1); 2342 return ret; 2343 } 2344 2345 //------------------------------ 2346 // UNIT_CAST 2347 //------------------------------ 2348 2349 /** 2350 * @ingroup Conversion 2351 * @brief Casts a unit container to an arithmetic type. 2352 * @details unit_cast can be used to remove the strong typing from a unit class, and convert it 2353 * to a built-in arithmetic type. This may be useful for compatibility with libraries 2354 * and legacy code that don't support `unit_t` types. E.g 2355 * @code meter_t unitVal(5); 2356 * double value = units::unit_cast<double>(unitVal); // value = 5.0 2357 * @endcode 2358 * @tparam T Type to cast the unit type to. Must be a built-in arithmetic type. 2359 * @param value Unit value to cast. 2360 * @sa unit_t::to 2361 */ 2362 template<typename T, typename Units, class = std::enable_if_t<std::is_arithmetic<T>::value && traits::is_unit_t<Units>::value>> unit_cast(const Units & value)2363 inline constexpr T unit_cast(const Units& value) noexcept 2364 { 2365 return static_cast<T>(value); 2366 } 2367 2368 //------------------------------ 2369 // NON-LINEAR SCALE TRAITS 2370 //------------------------------ 2371 2372 // forward declaration 2373 template<typename T> struct decibel_scale; 2374 2375 namespace traits 2376 { 2377 /** 2378 * @ingroup TypeTraits 2379 * @brief Trait which tests whether a type is inherited from a linear scale. 2380 * @details Inherits from `std::true_type` or `std::false_type`. Use `has_linear_scale<U1 [, U2, ...]>::value` to test 2381 * one or more types to see if they represent unit_t's whose scale is linear. 2382 * @tparam T one or more types to test. 2383 */ 2384 #if !defined(_MSC_VER) || _MSC_VER > 1800 // bug in VS2013 prevents this from working 2385 template<typename... T> 2386 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 > {}; 2387 #else 2388 template<typename T1, typename T2 = T1, typename T3 = T1> 2389 struct has_linear_scale : std::integral_constant<bool, 2390 std::is_base_of<units::linear_scale<typename units::traits::unit_t_traits<T1>::underlying_type>, T1>::value && 2391 std::is_base_of<units::linear_scale<typename units::traits::unit_t_traits<T2>::underlying_type>, T2>::value && 2392 std::is_base_of<units::linear_scale<typename units::traits::unit_t_traits<T3>::underlying_type>, T3>::value> {}; 2393 #endif 2394 2395 /** 2396 * @ingroup TypeTraits 2397 * @brief Trait which tests whether a type is inherited from a decibel scale. 2398 * @details Inherits from `std::true_type` or `std::false_type`. Use `has_decibel_scale<U1 [, U2, ...]>::value` to test 2399 * one or more types to see if they represent unit_t's whose scale is in decibels. 2400 * @tparam T one or more types to test. 2401 */ 2402 #if !defined(_MSC_VER) || _MSC_VER > 1800 // bug in VS2013 prevents this from working 2403 template<typename... T> 2404 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> {}; 2405 #else 2406 template<typename T1, typename T2 = T1, typename T3 = T1> 2407 struct has_decibel_scale : std::integral_constant<bool, 2408 std::is_base_of<units::decibel_scale<typename units::traits::unit_t_traits<T1>::underlying_type>, T1>::value && 2409 std::is_base_of<units::decibel_scale<typename units::traits::unit_t_traits<T2>::underlying_type>, T2>::value && 2410 std::is_base_of<units::decibel_scale<typename units::traits::unit_t_traits<T2>::underlying_type>, T3>::value> {}; 2411 #endif 2412 2413 /** 2414 * @ingroup TypeTraits 2415 * @brief Trait which tests whether two types has the same non-linear scale. 2416 * @details Inherits from `std::true_type` or `std::false_type`. Use `is_same_scale<U1 , U2>::value` to test 2417 * whether two types have the same non-linear scale. 2418 * @tparam T1 left hand type. 2419 * @tparam T2 right hand type 2420 */ 2421 template<typename T1, typename T2> 2422 struct is_same_scale : std::integral_constant<bool, 2423 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> 2424 {}; 2425 } 2426 2427 //---------------------------------- 2428 // NON-LINEAR SCALES 2429 //---------------------------------- 2430 2431 // Non-linear transforms are used to pre and post scale units which are defined in terms of non- 2432 // linear functions of their current value. A good example of a non-linear scale would be a 2433 // logarithmic or decibel scale 2434 2435 //------------------------------ 2436 // LINEAR SCALE 2437 //------------------------------ 2438 2439 /** 2440 * @brief unit_t scale which is linear 2441 * @details Represents units on a linear scale. This is the appropriate unit_t scale for almost 2442 * all units almost all of the time. 2443 * @tparam T underlying storage type 2444 * @sa unit_t 2445 */ 2446 template<typename T> 2447 struct linear_scale 2448 { 2449 inline constexpr linear_scale() = default; ///< default constructor. 2450 inline constexpr linear_scale(const linear_scale&) = default; 2451 inline ~linear_scale() = default; 2452 inline linear_scale& operator=(const linear_scale&) = default; 2453 #if defined(_MSC_VER) && (_MSC_VER > 1800) 2454 inline constexpr linear_scale(linear_scale&&) = default; 2455 inline linear_scale& operator=(linear_scale&&) = default; 2456 #endif 2457 template<class... Args> linear_scaleunits::linear_scale2458 inline constexpr linear_scale(const T& value, Args&&...) noexcept : m_value(value) {} ///< constructor. operator ()units::linear_scale2459 inline constexpr T operator()() const noexcept { return m_value; } ///< returns value. 2460 2461 T m_value; ///< linearized value. 2462 }; 2463 2464 //---------------------------------- 2465 // SCALAR (LINEAR) UNITS 2466 //---------------------------------- 2467 2468 // Scalar units are the *ONLY* units implicitly convertible to/from built-in types. 2469 namespace dimensionless 2470 { 2471 typedef unit<std::ratio<1>, units::category::scalar_unit> scalar; 2472 typedef unit<std::ratio<1>, units::category::dimensionless_unit> dimensionless; 2473 2474 typedef unit_t<scalar> scalar_t; 2475 typedef scalar_t dimensionless_t; 2476 } 2477 2478 // ignore the redeclaration of the default template parameters 2479 #if defined(_MSC_VER) 2480 # pragma warning(push) 2481 # pragma warning(disable : 4348) 2482 #endif 2483 UNIT_ADD_CATEGORY_TRAIT(scalar) 2484 UNIT_ADD_CATEGORY_TRAIT(dimensionless) 2485 #if defined(_MSC_VER) 2486 # pragma warning(pop) 2487 #endif 2488 2489 //------------------------------ 2490 // LINEAR ARITHMETIC 2491 //------------------------------ 2492 2493 template<class UnitTypeLhs, class UnitTypeRhs, std::enable_if_t<!traits::is_same_scale<UnitTypeLhs, UnitTypeRhs>::value, int> = 0> 2494 constexpr inline int operator+(const UnitTypeLhs& /* lhs */, const UnitTypeRhs& /* rhs */) noexcept 2495 { 2496 static_assert(traits::is_same_scale<UnitTypeLhs, UnitTypeRhs>::value, "Cannot add units with different linear/non-linear scales."); 2497 return 0; 2498 } 2499 2500 /// Addition operator for unit_t types with a linear_scale. 2501 template<class UnitTypeLhs, class UnitTypeRhs, std::enable_if_t<traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value, int> = 0> operator +(const UnitTypeLhs & lhs,const UnitTypeRhs & rhs)2502 inline constexpr UnitTypeLhs operator+(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept 2503 { 2504 using UnitsLhs = typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type; 2505 using UnitsRhs = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type; 2506 return UnitTypeLhs(lhs() + convert<UnitsRhs, UnitsLhs>(rhs())); 2507 } 2508 2509 /// Addition operator for scalar unit_t types with a linear_scale. Scalar types can be implicitly converted to built-in types. 2510 template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, int> = 0> operator +(const dimensionless::scalar_t & lhs,T rhs)2511 inline constexpr dimensionless::scalar_t operator+(const dimensionless::scalar_t& lhs, T rhs) noexcept 2512 { 2513 return dimensionless::scalar_t(lhs() + rhs); 2514 } 2515 2516 /// Addition operator for scalar unit_t types with a linear_scale. Scalar types can be implicitly converted to built-in types. 2517 template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, int> = 0> operator +(T lhs,const dimensionless::scalar_t & rhs)2518 inline constexpr dimensionless::scalar_t operator+(T lhs, const dimensionless::scalar_t& rhs) noexcept 2519 { 2520 return dimensionless::scalar_t(lhs + rhs()); 2521 } 2522 2523 /// Subtraction operator for unit_t types with a linear_scale. 2524 template<class UnitTypeLhs, class UnitTypeRhs, std::enable_if_t<traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value, int> = 0> operator -(const UnitTypeLhs & lhs,const UnitTypeRhs & rhs)2525 inline constexpr UnitTypeLhs operator-(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept 2526 { 2527 using UnitsLhs = typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type; 2528 using UnitsRhs = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type; 2529 return UnitTypeLhs(lhs() - convert<UnitsRhs, UnitsLhs>(rhs())); 2530 } 2531 2532 /// Subtraction operator for scalar unit_t types with a linear_scale. Scalar types can be implicitly converted to built-in types. 2533 template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, int> = 0> operator -(const dimensionless::scalar_t & lhs,T rhs)2534 inline constexpr dimensionless::scalar_t operator-(const dimensionless::scalar_t& lhs, T rhs) noexcept 2535 { 2536 return dimensionless::scalar_t(lhs() - rhs); 2537 } 2538 2539 /// Subtraction operator for scalar unit_t types with a linear_scale. Scalar types can be implicitly converted to built-in types. 2540 template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, int> = 0> operator -(T lhs,const dimensionless::scalar_t & rhs)2541 inline constexpr dimensionless::scalar_t operator-(T lhs, const dimensionless::scalar_t& rhs) noexcept 2542 { 2543 return dimensionless::scalar_t(lhs - rhs()); 2544 } 2545 2546 /// Multiplication type for convertible unit_t types with a linear scale. @returns the multiplied value, with the same type as left-hand side unit. 2547 template<class UnitTypeLhs, class UnitTypeRhs, 2548 std::enable_if_t<traits::is_convertible_unit_t<UnitTypeLhs, UnitTypeRhs>::value && traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value, int> = 0> operator *(const UnitTypeLhs & lhs,const UnitTypeRhs & rhs)2549 inline constexpr auto operator*(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept -> unit_t<compound_unit<squared<typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type>>> 2550 { 2551 using UnitsLhs = typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type; 2552 using UnitsRhs = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type; 2553 return unit_t<compound_unit<squared<typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type>>> 2554 (lhs() * convert<UnitsRhs, UnitsLhs>(rhs())); 2555 } 2556 2557 /// Multiplication type for non-convertible unit_t types with a linear scale. @returns the multiplied value, whose type is a compound unit of the left and right hand side values. 2558 template<class UnitTypeLhs, class UnitTypeRhs, 2559 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> operator *(const UnitTypeLhs & lhs,const UnitTypeRhs & rhs)2560 inline 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>> 2561 { 2562 using UnitsLhs = typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type; 2563 using UnitsRhs = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type; 2564 return unit_t<compound_unit<UnitsLhs, UnitsRhs>> 2565 (lhs() * rhs()); 2566 } 2567 2568 /// Multiplication by a dimensionless unit for unit_t types with a linear scale. 2569 template<class UnitTypeLhs, typename UnitTypeRhs, 2570 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> operator *(const UnitTypeLhs & lhs,const UnitTypeRhs & rhs)2571 inline constexpr UnitTypeLhs operator*(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept 2572 { 2573 // the cast makes sure factors of PI are handled as expected 2574 return UnitTypeLhs(lhs() * static_cast<UNIT_LIB_DEFAULT_TYPE>(rhs)); 2575 } 2576 2577 /// Multiplication by a dimensionless unit for unit_t types with a linear scale. 2578 template<class UnitTypeLhs, typename UnitTypeRhs, 2579 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> operator *(const UnitTypeLhs & lhs,const UnitTypeRhs & rhs)2580 inline constexpr UnitTypeRhs operator*(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept 2581 { 2582 // the cast makes sure factors of PI are handled as expected 2583 return UnitTypeRhs(static_cast<UNIT_LIB_DEFAULT_TYPE>(lhs) * rhs()); 2584 } 2585 2586 /// Multiplication by a scalar for unit_t types with a linear scale. 2587 template<class UnitTypeLhs, typename T, 2588 std::enable_if_t<std::is_arithmetic<T>::value && traits::has_linear_scale<UnitTypeLhs>::value, int> = 0> operator *(const UnitTypeLhs & lhs,T rhs)2589 inline constexpr UnitTypeLhs operator*(const UnitTypeLhs& lhs, T rhs) noexcept 2590 { 2591 return UnitTypeLhs(lhs() * rhs); 2592 } 2593 2594 /// Multiplication by a scalar for unit_t types with a linear scale. 2595 template<class UnitTypeRhs, typename T, 2596 std::enable_if_t<std::is_arithmetic<T>::value && traits::has_linear_scale<UnitTypeRhs>::value, int> = 0> operator *(T lhs,const UnitTypeRhs & rhs)2597 inline constexpr UnitTypeRhs operator*(T lhs, const UnitTypeRhs& rhs) noexcept 2598 { 2599 return UnitTypeRhs(lhs * rhs()); 2600 } 2601 2602 /// Division for convertible unit_t types with a linear scale. @returns the lhs divided by rhs value, whose type is a scalar 2603 template<class UnitTypeLhs, class UnitTypeRhs, 2604 std::enable_if_t<traits::is_convertible_unit_t<UnitTypeLhs, UnitTypeRhs>::value && traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value, int> = 0> operator /(const UnitTypeLhs & lhs,const UnitTypeRhs & rhs)2605 inline constexpr dimensionless::scalar_t operator/(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept 2606 { 2607 using UnitsLhs = typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type; 2608 using UnitsRhs = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type; 2609 return dimensionless::scalar_t(lhs() / convert<UnitsRhs, UnitsLhs>(rhs())); 2610 } 2611 2612 /// Division for non-convertible unit_t types with a linear scale. @returns the lhs divided by the rhs, with a compound unit type of lhs/rhs 2613 template<class UnitTypeLhs, class UnitTypeRhs, 2614 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> operator /(const UnitTypeLhs & lhs,const UnitTypeRhs & rhs)2615 inline 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>>> 2616 { 2617 using UnitsLhs = typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type; 2618 using UnitsRhs = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type; 2619 return unit_t<compound_unit<UnitsLhs, inverse<UnitsRhs>>> 2620 (lhs() / rhs()); 2621 } 2622 2623 /// Division by a dimensionless unit for unit_t types with a linear scale 2624 template<class UnitTypeLhs, class UnitTypeRhs, 2625 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> operator /(const UnitTypeLhs & lhs,const UnitTypeRhs & rhs)2626 inline constexpr UnitTypeLhs operator/(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept 2627 { 2628 return UnitTypeLhs(lhs() / static_cast<UNIT_LIB_DEFAULT_TYPE>(rhs)); 2629 } 2630 2631 /// Division of a dimensionless unit by a unit_t type with a linear scale 2632 template<class UnitTypeLhs, class UnitTypeRhs, 2633 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> operator /(const UnitTypeLhs & lhs,const UnitTypeRhs & rhs)2634 inline constexpr auto operator/(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept -> unit_t<inverse<typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type>> 2635 { 2636 return unit_t<inverse<typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type>> 2637 (static_cast<UNIT_LIB_DEFAULT_TYPE>(lhs) / rhs()); 2638 } 2639 2640 /// Division by a scalar for unit_t types with a linear scale 2641 template<class UnitTypeLhs, typename T, 2642 std::enable_if_t<std::is_arithmetic<T>::value && traits::has_linear_scale<UnitTypeLhs>::value, int> = 0> operator /(const UnitTypeLhs & lhs,T rhs)2643 inline constexpr UnitTypeLhs operator/(const UnitTypeLhs& lhs, T rhs) noexcept 2644 { 2645 return UnitTypeLhs(lhs() / rhs); 2646 } 2647 2648 /// Division of a scalar by a unit_t type with a linear scale 2649 template<class UnitTypeRhs, typename T, 2650 std::enable_if_t<std::is_arithmetic<T>::value && traits::has_linear_scale<UnitTypeRhs>::value, int> = 0> operator /(T lhs,const UnitTypeRhs & rhs)2651 inline constexpr auto operator/(T lhs, const UnitTypeRhs& rhs) noexcept -> unit_t<inverse<typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type>> 2652 { 2653 using UnitsRhs = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type; 2654 return unit_t<inverse<UnitsRhs>> 2655 (lhs / rhs()); 2656 } 2657 2658 //---------------------------------- 2659 // SCALAR COMPARISONS 2660 //---------------------------------- 2661 2662 template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>> operator ==(const UNIT_LIB_DEFAULT_TYPE lhs,const Units & rhs)2663 constexpr bool operator==(const UNIT_LIB_DEFAULT_TYPE lhs, const Units& rhs) noexcept 2664 { 2665 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)) || 2666 detail::abs(lhs - static_cast<UNIT_LIB_DEFAULT_TYPE>(rhs)) < std::numeric_limits<UNIT_LIB_DEFAULT_TYPE>::min(); 2667 } 2668 2669 template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>> operator ==(const Units & lhs,const UNIT_LIB_DEFAULT_TYPE rhs)2670 constexpr bool operator==(const Units& lhs, const UNIT_LIB_DEFAULT_TYPE rhs) noexcept 2671 { 2672 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) || 2673 detail::abs(static_cast<UNIT_LIB_DEFAULT_TYPE>(lhs) - rhs) < std::numeric_limits<UNIT_LIB_DEFAULT_TYPE>::min(); 2674 } 2675 2676 template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>> operator !=(const UNIT_LIB_DEFAULT_TYPE lhs,const Units & rhs)2677 constexpr bool operator!=(const UNIT_LIB_DEFAULT_TYPE lhs, const Units& rhs) noexcept 2678 { 2679 return!(lhs == static_cast<UNIT_LIB_DEFAULT_TYPE>(rhs)); 2680 } 2681 2682 template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>> operator !=(const Units & lhs,const UNIT_LIB_DEFAULT_TYPE rhs)2683 constexpr bool operator!=(const Units& lhs, const UNIT_LIB_DEFAULT_TYPE rhs) noexcept 2684 { 2685 return !(static_cast<UNIT_LIB_DEFAULT_TYPE>(lhs) == rhs); 2686 } 2687 2688 template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>> operator >=(const UNIT_LIB_DEFAULT_TYPE lhs,const Units & rhs)2689 constexpr bool operator>=(const UNIT_LIB_DEFAULT_TYPE lhs, const Units& rhs) noexcept 2690 { 2691 return std::isgreaterequal(lhs, static_cast<UNIT_LIB_DEFAULT_TYPE>(rhs)); 2692 } 2693 2694 template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>> operator >=(const Units & lhs,const UNIT_LIB_DEFAULT_TYPE rhs)2695 constexpr bool operator>=(const Units& lhs, const UNIT_LIB_DEFAULT_TYPE rhs) noexcept 2696 { 2697 return std::isgreaterequal(static_cast<UNIT_LIB_DEFAULT_TYPE>(lhs), rhs); 2698 } 2699 2700 template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>> operator >(const UNIT_LIB_DEFAULT_TYPE lhs,const Units & rhs)2701 constexpr bool operator>(const UNIT_LIB_DEFAULT_TYPE lhs, const Units& rhs) noexcept 2702 { 2703 return lhs > static_cast<UNIT_LIB_DEFAULT_TYPE>(rhs); 2704 } 2705 2706 template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>> operator >(const Units & lhs,const UNIT_LIB_DEFAULT_TYPE rhs)2707 constexpr bool operator>(const Units& lhs, const UNIT_LIB_DEFAULT_TYPE rhs) noexcept 2708 { 2709 return static_cast<UNIT_LIB_DEFAULT_TYPE>(lhs) > rhs; 2710 } 2711 2712 template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>> operator <=(const UNIT_LIB_DEFAULT_TYPE lhs,const Units & rhs)2713 constexpr bool operator<=(const UNIT_LIB_DEFAULT_TYPE lhs, const Units& rhs) noexcept 2714 { 2715 return std::islessequal(lhs, static_cast<UNIT_LIB_DEFAULT_TYPE>(rhs)); 2716 } 2717 2718 template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>> operator <=(const Units & lhs,const UNIT_LIB_DEFAULT_TYPE rhs)2719 constexpr bool operator<=(const Units& lhs, const UNIT_LIB_DEFAULT_TYPE rhs) noexcept 2720 { 2721 return std::islessequal(static_cast<UNIT_LIB_DEFAULT_TYPE>(lhs), rhs); 2722 } 2723 2724 template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>> operator <(const UNIT_LIB_DEFAULT_TYPE lhs,const Units & rhs)2725 constexpr bool operator<(const UNIT_LIB_DEFAULT_TYPE lhs, const Units& rhs) noexcept 2726 { 2727 return lhs < static_cast<UNIT_LIB_DEFAULT_TYPE>(rhs); 2728 } 2729 2730 template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>> operator <(const Units & lhs,const UNIT_LIB_DEFAULT_TYPE rhs)2731 constexpr bool operator<(const Units& lhs, const UNIT_LIB_DEFAULT_TYPE rhs) noexcept 2732 { 2733 return static_cast<UNIT_LIB_DEFAULT_TYPE>(lhs) < rhs; 2734 } 2735 2736 //---------------------------------- 2737 // POW 2738 //---------------------------------- 2739 2740 /** @cond */ // DOXYGEN IGNORE 2741 namespace detail 2742 { 2743 /// recursive exponential implementation 2744 template <int N, class U> struct power_of_unit 2745 { 2746 typedef typename units::detail::unit_multiply<U, typename power_of_unit<N - 1, U>::type> type; 2747 }; 2748 2749 /// End recursion 2750 template <class U> struct power_of_unit<1, U> 2751 { 2752 typedef U type; 2753 }; 2754 } 2755 /** @endcond */ // END DOXYGEN IGNORE 2756 2757 namespace math 2758 { 2759 /** 2760 * @brief computes the value of <i>value</i> raised to the <i>power</i> 2761 * @details Only implemented for linear_scale units. <i>Power</i> must be known at compile time, so the resulting unit type can be deduced. 2762 * @tparam power exponential power to raise <i>value</i> by. 2763 * @param[in] value `unit_t` derived type to raise to the given <i>power</i> 2764 * @returns new unit_t, raised to the given exponent 2765 */ 2766 template<int power, class UnitType, class = typename std::enable_if<traits::has_linear_scale<UnitType>::value, int>> pow(const UnitType & value)2767 inline 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> 2768 { 2769 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> 2770 (std::pow(value(), power)); 2771 } 2772 2773 /** 2774 * @brief computes the value of <i>value</i> raised to the <i>power</i> as a constexpr 2775 * @details Only implemented for linear_scale units. <i>Power</i> must be known at compile time, so the resulting unit type can be deduced. 2776 * Additionally, the power must be <i>a positive, integral, value</i>. 2777 * @tparam power exponential power to raise <i>value</i> by. 2778 * @param[in] value `unit_t` derived type to raise to the given <i>power</i> 2779 * @returns new unit_t, raised to the given exponent 2780 */ 2781 template<int power, class UnitType, class = typename std::enable_if<traits::has_linear_scale<UnitType>::value, int>> cpow(const UnitType & value)2782 inline 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> 2783 { 2784 static_assert(power >= 0, "cpow cannot accept negative numbers. Try units::math::pow instead."); 2785 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> 2786 (detail::pow(value(), power)); 2787 } 2788 } 2789 2790 //------------------------------ 2791 // DECIBEL SCALE 2792 //------------------------------ 2793 2794 /** 2795 * @brief unit_t scale for representing decibel values. 2796 * @details internally stores linearized values. `operator()` returns the value in dB. 2797 * @tparam T underlying storage type 2798 * @sa unit_t 2799 */ 2800 template<typename T> 2801 struct decibel_scale 2802 { 2803 inline constexpr decibel_scale() = default; 2804 inline constexpr decibel_scale(const decibel_scale&) = default; 2805 inline ~decibel_scale() = default; 2806 inline decibel_scale& operator=(const decibel_scale&) = default; 2807 #if defined(_MSC_VER) && (_MSC_VER > 1800) 2808 inline constexpr decibel_scale(decibel_scale&&) = default; 2809 inline decibel_scale& operator=(decibel_scale&&) = default; 2810 #endif decibel_scaleunits::decibel_scale2811 inline constexpr decibel_scale(const T value) noexcept : m_value(std::pow(10, value / 10)) {} 2812 template<class... Args> decibel_scaleunits::decibel_scale2813 inline constexpr decibel_scale(const T value, std::true_type, Args&&...) noexcept : m_value(value) {} operator ()units::decibel_scale2814 inline constexpr T operator()() const noexcept { return 10 * std::log10(m_value); } 2815 2816 T m_value; ///< linearized value 2817 }; 2818 2819 //------------------------------ 2820 // SCALAR (DECIBEL) UNITS 2821 //------------------------------ 2822 2823 /** 2824 * @brief namespace for unit types and containers for units that have no dimension (scalar units) 2825 * @sa See unit_t for more information on unit type containers. 2826 */ 2827 namespace dimensionless 2828 { 2829 typedef unit_t<scalar, UNIT_LIB_DEFAULT_TYPE, decibel_scale> dB_t; 2830 #if !defined(UNIT_LIB_DISABLE_IOSTREAM) operator <<(std::ostream & os,const dB_t & obj)2831 inline std::ostream& operator<<(std::ostream& os, const dB_t& obj) { os << obj() << " dB"; return os; } 2832 #endif 2833 typedef dB_t dBi_t; 2834 } 2835 2836 //------------------------------ 2837 // DECIBEL ARITHMETIC 2838 //------------------------------ 2839 2840 /// Addition for convertible unit_t types with a decibel_scale 2841 template<class UnitTypeLhs, class UnitTypeRhs, 2842 std::enable_if_t<traits::has_decibel_scale<UnitTypeLhs, UnitTypeRhs>::value, int> = 0> operator +(const UnitTypeLhs & lhs,const UnitTypeRhs & rhs)2843 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> 2844 { 2845 using LhsUnits = typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type; 2846 using RhsUnits = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type; 2847 using underlying_type = typename units::traits::unit_t_traits<UnitTypeLhs>::underlying_type; 2848 2849 return unit_t<compound_unit<squared<LhsUnits>>, underlying_type, decibel_scale> 2850 (lhs.template toLinearized<underlying_type>() * convert<RhsUnits, LhsUnits>(rhs.template toLinearized<underlying_type>()), std::true_type()); 2851 } 2852 2853 /// Addition between unit_t types with a decibel_scale and dimensionless dB units 2854 template<class UnitTypeLhs, std::enable_if_t<traits::has_decibel_scale<UnitTypeLhs>::value && !traits::is_dimensionless_unit<UnitTypeLhs>::value, int> = 0> operator +(const UnitTypeLhs & lhs,const dimensionless::dB_t & rhs)2855 constexpr inline UnitTypeLhs operator+(const UnitTypeLhs& lhs, const dimensionless::dB_t& rhs) noexcept 2856 { 2857 using underlying_type = typename units::traits::unit_t_traits<UnitTypeLhs>::underlying_type; 2858 return UnitTypeLhs(lhs.template toLinearized<underlying_type>() * rhs.template toLinearized<underlying_type>(), std::true_type()); 2859 } 2860 2861 /// Addition between unit_t types with a decibel_scale and dimensionless dB units 2862 template<class UnitTypeRhs, std::enable_if_t<traits::has_decibel_scale<UnitTypeRhs>::value && !traits::is_dimensionless_unit<UnitTypeRhs>::value, int> = 0> operator +(const dimensionless::dB_t & lhs,const UnitTypeRhs & rhs)2863 constexpr inline UnitTypeRhs operator+(const dimensionless::dB_t& lhs, const UnitTypeRhs& rhs) noexcept 2864 { 2865 using underlying_type = typename units::traits::unit_t_traits<UnitTypeRhs>::underlying_type; 2866 return UnitTypeRhs(lhs.template toLinearized<underlying_type>() * rhs.template toLinearized<underlying_type>(), std::true_type()); 2867 } 2868 2869 /// Subtraction for convertible unit_t types with a decibel_scale 2870 template<class UnitTypeLhs, class UnitTypeRhs, std::enable_if_t<traits::has_decibel_scale<UnitTypeLhs, UnitTypeRhs>::value, int> = 0> operator -(const UnitTypeLhs & lhs,const UnitTypeRhs & rhs)2871 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> 2872 { 2873 using LhsUnits = typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type; 2874 using RhsUnits = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type; 2875 using underlying_type = typename units::traits::unit_t_traits<UnitTypeLhs>::underlying_type; 2876 2877 return unit_t<compound_unit<LhsUnits, inverse<RhsUnits>>, underlying_type, decibel_scale> 2878 (lhs.template toLinearized<underlying_type>() / convert<RhsUnits, LhsUnits>(rhs.template toLinearized<underlying_type>()), std::true_type()); 2879 } 2880 2881 /// Subtraction between unit_t types with a decibel_scale and dimensionless dB units 2882 template<class UnitTypeLhs, std::enable_if_t<traits::has_decibel_scale<UnitTypeLhs>::value && !traits::is_dimensionless_unit<UnitTypeLhs>::value, int> = 0> operator -(const UnitTypeLhs & lhs,const dimensionless::dB_t & rhs)2883 constexpr inline UnitTypeLhs operator-(const UnitTypeLhs& lhs, const dimensionless::dB_t& rhs) noexcept 2884 { 2885 using underlying_type = typename units::traits::unit_t_traits<UnitTypeLhs>::underlying_type; 2886 return UnitTypeLhs(lhs.template toLinearized<underlying_type>() / rhs.template toLinearized<underlying_type>(), std::true_type()); 2887 } 2888 2889 /// Subtraction between unit_t types with a decibel_scale and dimensionless dB units 2890 template<class UnitTypeRhs, std::enable_if_t<traits::has_decibel_scale<UnitTypeRhs>::value && !traits::is_dimensionless_unit<UnitTypeRhs>::value, int> = 0> operator -(const dimensionless::dB_t & lhs,const UnitTypeRhs & rhs)2891 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> 2892 { 2893 using RhsUnits = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type; 2894 using underlying_type = typename units::traits::unit_t_traits<RhsUnits>::underlying_type; 2895 2896 return unit_t<inverse<RhsUnits>, underlying_type, decibel_scale> 2897 (lhs.template toLinearized<underlying_type>() / rhs.template toLinearized<underlying_type>(), std::true_type()); 2898 } 2899 2900 //---------------------------------- 2901 // UNIT RATIO CLASS 2902 //---------------------------------- 2903 2904 /** @cond */ // DOXYGEN IGNORE 2905 namespace detail 2906 { 2907 template<class Units> 2908 struct _unit_value_t {}; 2909 } 2910 /** @endcond */ // END DOXYGEN IGNORE 2911 2912 namespace traits 2913 { 2914 #ifdef FOR_DOXYGEN_PURPOSES_ONLY 2915 /** 2916 * @ingroup TypeTraits 2917 * @brief Trait for accessing the publically defined types of `units::unit_value_t_traits` 2918 * @details The units library determines certain properties of the `unit_value_t` types passed to 2919 * them and what they represent by using the members of the corresponding `unit_value_t_traits` 2920 * instantiation. 2921 */ 2922 template<typename T> 2923 struct unit_value_t_traits 2924 { 2925 typedef typename T::unit_type unit_type; ///< Dimension represented by the `unit_value_t`. 2926 typedef typename T::ratio ratio; ///< Quantity represented by the `unit_value_t`, expressed as arational number. 2927 }; 2928 #endif 2929 2930 /** @cond */ // DOXYGEN IGNORE 2931 /** 2932 * @brief unit_value_t_traits specialization for things which are not unit_t 2933 * @details 2934 */ 2935 template<typename T, typename = void> 2936 struct unit_value_t_traits 2937 { 2938 typedef void unit_type; 2939 typedef void ratio; 2940 }; 2941 2942 /** 2943 * @ingroup TypeTraits 2944 * @brief Trait for accessing the publically defined types of `units::unit_value_t_traits` 2945 * @details 2946 */ 2947 template<typename T> 2948 struct unit_value_t_traits <T, typename void_t< 2949 typename T::unit_type, 2950 typename T::ratio>::type> 2951 { 2952 typedef typename T::unit_type unit_type; 2953 typedef typename T::ratio ratio; 2954 }; 2955 /** @endcond */ // END DOXYGEN IGNORE 2956 } 2957 2958 //------------------------------------------------------------------------------ 2959 // COMPILE-TIME UNIT VALUES AND ARITHMETIC 2960 //------------------------------------------------------------------------------ 2961 2962 /** 2963 * @ingroup UnitContainers 2964 * @brief Stores a rational unit value as a compile-time constant 2965 * @details unit_value_t is useful for performing compile-time arithmetic on known 2966 * unit quantities. 2967 * @tparam Units units represented by the `unit_value_t` 2968 * @tparam Num numerator of the represented value. 2969 * @tparam Denom denominator of the represented value. 2970 * @sa unit_value_t_traits to access information about the properties of the class, 2971 * such as it's unit type and rational value. 2972 * @note This is intentionally identical in concept to a `std::ratio`. 2973 * 2974 */ 2975 template<typename Units, std::uintmax_t Num, std::uintmax_t Denom = 1> 2976 struct unit_value_t : units::detail::_unit_value_t<Units> 2977 { 2978 typedef Units unit_type; 2979 typedef std::ratio<Num, Denom> ratio; 2980 2981 static_assert(traits::is_unit<Units>::value, "Template parameter `Units` must be a unit type."); valueunits::unit_value_t2982 static constexpr const unit_t<Units> value() { return unit_t<Units>((UNIT_LIB_DEFAULT_TYPE)ratio::num / ratio::den); } 2983 }; 2984 2985 namespace traits 2986 { 2987 /** 2988 * @ingroup TypeTraits 2989 * @brief Trait which tests whether a type is a unit_value_t representing the given unit type. 2990 * @details e.g. `is_unit_value_t<meters, myType>::value` would test that `myType` is a 2991 * `unit_value_t<meters>`. 2992 * @tparam Units units that the `unit_value_t` is supposed to have. 2993 * @tparam T type to test. 2994 */ 2995 template<typename T, typename Units = typename traits::unit_value_t_traits<T>::unit_type> 2996 struct is_unit_value_t : std::integral_constant<bool, 2997 std::is_base_of<units::detail::_unit_value_t<Units>, T>::value> 2998 {}; 2999 3000 /** 3001 * @ingroup TypeTraits 3002 * @brief Trait which tests whether type T is a unit_value_t with a unit type in the given category. 3003 * @details e.g. `is_unit_value_t_category<units::category::length, unit_value_t<feet>>::value` would be true 3004 */ 3005 template<typename Category, typename T> 3006 struct is_unit_value_t_category : std::integral_constant<bool, 3007 std::is_same<units::traits::base_unit_of<typename traits::unit_value_t_traits<T>::unit_type>, Category>::value> 3008 { 3009 static_assert(is_base_unit<Category>::value, "Template parameter `Category` must be a `base_unit` type."); 3010 }; 3011 } 3012 3013 /** @cond */ // DOXYGEN IGNORE 3014 namespace detail 3015 { 3016 // base class for common arithmetic 3017 template<class U1, class U2> 3018 struct unit_value_arithmetic 3019 { 3020 static_assert(traits::is_unit_value_t<U1>::value, "Template parameter `U1` must be a `unit_value_t` type."); 3021 static_assert(traits::is_unit_value_t<U2>::value, "Template parameter `U2` must be a `unit_value_t` type."); 3022 3023 using _UNIT1 = typename traits::unit_value_t_traits<U1>::unit_type; 3024 using _UNIT2 = typename traits::unit_value_t_traits<U2>::unit_type; 3025 using _CONV1 = typename units::traits::unit_traits<_UNIT1>::conversion_ratio; 3026 using _CONV2 = typename units::traits::unit_traits<_UNIT2>::conversion_ratio; 3027 using _RATIO1 = typename traits::unit_value_t_traits<U1>::ratio; 3028 using _RATIO2 = typename traits::unit_value_t_traits<U2>::ratio; 3029 using _RATIO2CONV = typename std::ratio_divide<std::ratio_multiply<_RATIO2, _CONV2>, _CONV1>; 3030 using _PI_EXP = std::ratio_subtract<typename units::traits::unit_traits<_UNIT2>::pi_exponent_ratio, typename units::traits::unit_traits<_UNIT1>::pi_exponent_ratio>; 3031 }; 3032 } 3033 /** @endcond */ // END DOXYGEN IGNORE 3034 3035 /** 3036 * @ingroup CompileTimeUnitManipulators 3037 * @brief adds two unit_value_t types at compile-time 3038 * @details The resulting unit will the the `unit_type` of `U1` 3039 * @tparam U1 left-hand `unit_value_t` 3040 * @tparam U2 right-hand `unit_value_t` 3041 * @sa unit_value_t_traits to access information about the properties of the class, 3042 * such as it's unit type and rational value. 3043 * @note very similar in concept to `std::ratio_add` 3044 */ 3045 template<class U1, class U2> 3046 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> 3047 { 3048 /** @cond */ // DOXYGEN IGNORE 3049 using Base = units::detail::unit_value_arithmetic<U1, U2>; 3050 typedef typename Base::_UNIT1 unit_type; 3051 using ratio = std::ratio_add<typename Base::_RATIO1, typename Base::_RATIO2CONV>; 3052 3053 static_assert(traits::is_convertible_unit<typename Base::_UNIT1, typename Base::_UNIT2>::value, "Unit types are not compatible."); 3054 /** @endcond */ // END DOXYGEN IGNORE 3055 3056 /** 3057 * @brief Value of sum 3058 * @details Returns the calculated value of the sum of `U1` and `U2`, in the same 3059 * units as `U1`. 3060 * @returns Value of the sum in the appropriate units. 3061 */ valueunits::unit_value_add3062 static constexpr const unit_t<unit_type> value() noexcept 3063 { 3064 using UsePi = std::integral_constant<bool, Base::_PI_EXP::num != 0>; 3065 return value(UsePi()); 3066 } 3067 3068 /** @cond */ // DOXYGEN IGNORE 3069 // value if PI isn't involved valueunits::unit_value_add3070 static constexpr const unit_t<unit_type> value(std::false_type) noexcept 3071 { 3072 return unit_t<unit_type>((UNIT_LIB_DEFAULT_TYPE)ratio::num / ratio::den); 3073 } 3074 3075 // value if PI *is* involved valueunits::unit_value_add3076 static constexpr const unit_t<unit_type> value(std::true_type) noexcept 3077 { 3078 return unit_t<unit_type>(((UNIT_LIB_DEFAULT_TYPE)Base::_RATIO1::num / Base::_RATIO1::den) + 3079 ((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))); 3080 } 3081 /** @endcond */ // END DOXYGEN IGNORE 3082 }; 3083 3084 /** 3085 * @ingroup CompileTimeUnitManipulators 3086 * @brief subtracts two unit_value_t types at compile-time 3087 * @details The resulting unit will the the `unit_type` of `U1` 3088 * @tparam U1 left-hand `unit_value_t` 3089 * @tparam U2 right-hand `unit_value_t` 3090 * @sa unit_value_t_traits to access information about the properties of the class, 3091 * such as it's unit type and rational value. 3092 * @note very similar in concept to `std::ratio_subtract` 3093 */ 3094 template<class U1, class U2> 3095 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> 3096 { 3097 /** @cond */ // DOXYGEN IGNORE 3098 using Base = units::detail::unit_value_arithmetic<U1, U2>; 3099 3100 typedef typename Base::_UNIT1 unit_type; 3101 using ratio = std::ratio_subtract<typename Base::_RATIO1, typename Base::_RATIO2CONV>; 3102 3103 static_assert(traits::is_convertible_unit<typename Base::_UNIT1, typename Base::_UNIT2>::value, "Unit types are not compatible."); 3104 /** @endcond */ // END DOXYGEN IGNORE 3105 3106 /** 3107 * @brief Value of difference 3108 * @details Returns the calculated value of the difference of `U1` and `U2`, in the same 3109 * units as `U1`. 3110 * @returns Value of the difference in the appropriate units. 3111 */ valueunits::unit_value_subtract3112 static constexpr const unit_t<unit_type> value() noexcept 3113 { 3114 using UsePi = std::integral_constant<bool, Base::_PI_EXP::num != 0>; 3115 return value(UsePi()); 3116 } 3117 3118 /** @cond */ // DOXYGEN IGNORE 3119 // value if PI isn't involved valueunits::unit_value_subtract3120 static constexpr const unit_t<unit_type> value(std::false_type) noexcept 3121 { 3122 return unit_t<unit_type>((UNIT_LIB_DEFAULT_TYPE)ratio::num / ratio::den); 3123 } 3124 3125 // value if PI *is* involved valueunits::unit_value_subtract3126 static constexpr const unit_t<unit_type> value(std::true_type) noexcept 3127 { 3128 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) 3129 * std::pow(units::constants::detail::PI_VAL, ((UNIT_LIB_DEFAULT_TYPE)Base::_PI_EXP::num / Base::_PI_EXP::den))); 3130 } 3131 /** @endcond */ // END DOXYGEN IGNORE }; 3132 }; 3133 3134 /** 3135 * @ingroup CompileTimeUnitManipulators 3136 * @brief multiplies two unit_value_t types at compile-time 3137 * @details The resulting unit will the the `unit_type` of `U1 * U2` 3138 * @tparam U1 left-hand `unit_value_t` 3139 * @tparam U2 right-hand `unit_value_t` 3140 * @sa unit_value_t_traits to access information about the properties of the class, 3141 * such as it's unit type and rational value. 3142 * @note very similar in concept to `std::ratio_multiply` 3143 */ 3144 template<class U1, class U2> 3145 struct unit_value_multiply : units::detail::unit_value_arithmetic<U1, U2>, 3146 units::detail::_unit_value_t<typename std::conditional<traits::is_convertible_unit<typename traits::unit_value_t_traits<U1>::unit_type, 3147 typename traits::unit_value_t_traits<U2>::unit_type>::value, compound_unit<squared<typename traits::unit_value_t_traits<U1>::unit_type>>, 3148 compound_unit<typename traits::unit_value_t_traits<U1>::unit_type, typename traits::unit_value_t_traits<U2>::unit_type>>::type> 3149 { 3150 /** @cond */ // DOXYGEN IGNORE 3151 using Base = units::detail::unit_value_arithmetic<U1, U2>; 3152 3153 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>>; 3154 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>>; 3155 /** @endcond */ // END DOXYGEN IGNORE 3156 3157 /** 3158 * @brief Value of product 3159 * @details Returns the calculated value of the product of `U1` and `U2`, in units 3160 * of `U1 x U2`. 3161 * @returns Value of the product in the appropriate units. 3162 */ valueunits::unit_value_multiply3163 static constexpr const unit_t<unit_type> value() noexcept 3164 { 3165 using UsePi = std::integral_constant<bool, Base::_PI_EXP::num != 0>; 3166 return value(UsePi()); 3167 } 3168 3169 /** @cond */ // DOXYGEN IGNORE 3170 // value if PI isn't involved valueunits::unit_value_multiply3171 static constexpr const unit_t<unit_type> value(std::false_type) noexcept 3172 { 3173 return unit_t<unit_type>((UNIT_LIB_DEFAULT_TYPE)ratio::num / ratio::den); 3174 } 3175 3176 // value if PI *is* involved valueunits::unit_value_multiply3177 static constexpr const unit_t<unit_type> value(std::true_type) noexcept 3178 { 3179 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))); 3180 } 3181 /** @endcond */ // END DOXYGEN IGNORE 3182 }; 3183 3184 /** 3185 * @ingroup CompileTimeUnitManipulators 3186 * @brief divides two unit_value_t types at compile-time 3187 * @details The resulting unit will the the `unit_type` of `U1` 3188 * @tparam U1 left-hand `unit_value_t` 3189 * @tparam U2 right-hand `unit_value_t` 3190 * @sa unit_value_t_traits to access information about the properties of the class, 3191 * such as it's unit type and rational value. 3192 * @note very similar in concept to `std::ratio_divide` 3193 */ 3194 template<class U1, class U2> 3195 struct unit_value_divide : units::detail::unit_value_arithmetic<U1, U2>, 3196 units::detail::_unit_value_t<typename std::conditional<traits::is_convertible_unit<typename traits::unit_value_t_traits<U1>::unit_type, 3197 typename traits::unit_value_t_traits<U2>::unit_type>::value, dimensionless::scalar, compound_unit<typename traits::unit_value_t_traits<U1>::unit_type, 3198 inverse<typename traits::unit_value_t_traits<U2>::unit_type>>>::type> 3199 { 3200 /** @cond */ // DOXYGEN IGNORE 3201 using Base = units::detail::unit_value_arithmetic<U1, U2>; 3202 3203 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>>>; 3204 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>>; 3205 /** @endcond */ // END DOXYGEN IGNORE 3206 3207 /** 3208 * @brief Value of quotient 3209 * @details Returns the calculated value of the quotient of `U1` and `U2`, in units 3210 * of `U1 x U2`. 3211 * @returns Value of the quotient in the appropriate units. 3212 */ valueunits::unit_value_divide3213 static constexpr const unit_t<unit_type> value() noexcept 3214 { 3215 using UsePi = std::integral_constant<bool, Base::_PI_EXP::num != 0>; 3216 return value(UsePi()); 3217 } 3218 3219 /** @cond */ // DOXYGEN IGNORE 3220 // value if PI isn't involved valueunits::unit_value_divide3221 static constexpr const unit_t<unit_type> value(std::false_type) noexcept 3222 { 3223 return unit_t<unit_type>((UNIT_LIB_DEFAULT_TYPE)ratio::num / ratio::den); 3224 } 3225 3226 // value if PI *is* involved valueunits::unit_value_divide3227 static constexpr const unit_t<unit_type> value(std::true_type) noexcept 3228 { 3229 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))); 3230 } 3231 /** @endcond */ // END DOXYGEN IGNORE 3232 }; 3233 3234 /** 3235 * @ingroup CompileTimeUnitManipulators 3236 * @brief raises unit_value_to a power at compile-time 3237 * @details The resulting unit will the `unit_type` of `U1` squared 3238 * @tparam U1 `unit_value_t` to take the exponentiation of. 3239 * @sa unit_value_t_traits to access information about the properties of the class, 3240 * such as it's unit type and rational value. 3241 * @note very similar in concept to `units::math::pow` 3242 */ 3243 template<class U1, int power> 3244 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> 3245 { 3246 /** @cond */ // DOXYGEN IGNORE 3247 using Base = units::detail::unit_value_arithmetic<U1, U1>; 3248 3249 using unit_type = typename units::detail::power_of_unit<power, typename Base::_UNIT1>::type; 3250 using ratio = typename units::detail::power_of_ratio<power, typename Base::_RATIO1>::type; 3251 using pi_exponent = std::ratio_multiply<std::ratio<power>, typename Base::_UNIT1::pi_exponent_ratio>; 3252 /** @endcond */ // END DOXYGEN IGNORE 3253 3254 /** 3255 * @brief Value of exponentiation 3256 * @details Returns the calculated value of the exponentiation of `U1`, in units 3257 * of `U1^power`. 3258 * @returns Value of the exponentiation in the appropriate units. 3259 */ valueunits::unit_value_power3260 static constexpr const unit_t<unit_type> value() noexcept 3261 { 3262 using UsePi = std::integral_constant<bool, Base::_PI_EXP::num != 0>; 3263 return value(UsePi()); 3264 } 3265 3266 /** @cond */ // DOXYGEN IGNORE 3267 // value if PI isn't involved valueunits::unit_value_power3268 static constexpr const unit_t<unit_type> value(std::false_type) noexcept 3269 { 3270 return unit_t<unit_type>((UNIT_LIB_DEFAULT_TYPE)ratio::num / ratio::den); 3271 } 3272 3273 // value if PI *is* involved valueunits::unit_value_power3274 static constexpr const unit_t<unit_type> value(std::true_type) noexcept 3275 { 3276 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))); 3277 } 3278 /** @endcond */ // END DOXYGEN IGNORE }; 3279 }; 3280 3281 /** 3282 * @ingroup CompileTimeUnitManipulators 3283 * @brief calculates square root of unit_value_t at compile-time 3284 * @details The resulting unit will the square root `unit_type` of `U1` 3285 * @tparam U1 `unit_value_t` to take the square root of. 3286 * @sa unit_value_t_traits to access information about the properties of the class, 3287 * such as it's unit type and rational value. 3288 * @note very similar in concept to `units::ratio_sqrt` 3289 */ 3290 template<class U1, std::intmax_t Eps = 10000000000> 3291 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>> 3292 { 3293 /** @cond */ // DOXYGEN IGNORE 3294 using Base = units::detail::unit_value_arithmetic<U1, U1>; 3295 3296 using unit_type = square_root<typename Base::_UNIT1, Eps>; 3297 using ratio = ratio_sqrt<typename Base::_RATIO1, Eps>; 3298 using pi_exponent = ratio_sqrt<typename Base::_UNIT1::pi_exponent_ratio, Eps>; 3299 /** @endcond */ // END DOXYGEN IGNORE 3300 3301 /** 3302 * @brief Value of square root 3303 * @details Returns the calculated value of the square root of `U1`, in units 3304 * of `U1^1/2`. 3305 * @returns Value of the square root in the appropriate units. 3306 */ valueunits::unit_value_sqrt3307 static constexpr const unit_t<unit_type> value() noexcept 3308 { 3309 using UsePi = std::integral_constant<bool, Base::_PI_EXP::num != 0>; 3310 return value(UsePi()); 3311 } 3312 3313 /** @cond */ // DOXYGEN IGNORE 3314 // value if PI isn't involved valueunits::unit_value_sqrt3315 static constexpr const unit_t<unit_type> value(std::false_type) noexcept 3316 { 3317 return unit_t<unit_type>((UNIT_LIB_DEFAULT_TYPE)ratio::num / ratio::den); 3318 } 3319 3320 // value if PI *is* involved valueunits::unit_value_sqrt3321 static constexpr const unit_t<unit_type> value(std::true_type) noexcept 3322 { 3323 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))); 3324 } 3325 /** @endcond */ // END DOXYGEN IGNORE 3326 }; 3327 3328 //------------------------------ 3329 // LITERALS 3330 //------------------------------ 3331 3332 /** 3333 * @namespace units::literals 3334 * @brief namespace for unit literal definitions of all categories. 3335 * @details Literals allow for declaring unit types using suffix values. For example, a type 3336 * of `meter_t(6.2)` could be declared as `6.2_m`. All literals use an underscore 3337 * followed by the abbreviation for the unit. To enable literal syntax in your code, 3338 * include the statement `using namespace units::literals`. 3339 * @anchor unitLiterals 3340 * @sa See unit_t for more information on unit type containers. 3341 */ 3342 3343 //------------------------------ 3344 // LENGTH UNITS 3345 //------------------------------ 3346 3347 /** 3348 * @namespace units::length 3349 * @brief namespace for unit types and containers representing length values 3350 * @details The SI unit for length is `meters`, and the corresponding `base_unit` category is 3351 * `length_unit`. 3352 * @anchor lengthContainers 3353 * @sa See unit_t for more information on unit type containers. 3354 */ 3355 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_LENGTH_UNITS) 3356 UNIT_ADD_WITH_METRIC_PREFIXES(length, meter, meters, m, unit<std::ratio<1>, units::category::length_unit>) 3357 UNIT_ADD(length, foot, feet, ft, unit<std::ratio<381, 1250>, meters>) 3358 UNIT_ADD(length, mil, mils, mil, unit<std::ratio<1000>, feet>) 3359 UNIT_ADD(length, inch, inches, in, unit<std::ratio<1, 12>, feet>) 3360 UNIT_ADD(length, mile, miles, mi, unit<std::ratio<5280>, feet>) 3361 UNIT_ADD(length, nauticalMile, nauticalMiles, nmi, unit<std::ratio<1852>, meters>) 3362 UNIT_ADD(length, astronicalUnit, astronicalUnits, au, unit<std::ratio<149597870700>, meters>) 3363 UNIT_ADD(length, lightyear, lightyears, ly, unit<std::ratio<9460730472580800>, meters>) 3364 UNIT_ADD(length, parsec, parsecs, pc, unit<std::ratio<648000>, astronicalUnits, std::ratio<-1>>) 3365 UNIT_ADD(length, angstrom, angstroms, angstrom, unit<std::ratio<1, 10>, nanometers>) 3366 UNIT_ADD(length, cubit, cubits, cbt, unit<std::ratio<18>, inches>) 3367 UNIT_ADD(length, fathom, fathoms, ftm, unit<std::ratio<6>, feet>) 3368 UNIT_ADD(length, chain, chains, ch, unit<std::ratio<66>, feet>) 3369 UNIT_ADD(length, furlong, furlongs, fur, unit<std::ratio<10>, chains>) 3370 UNIT_ADD(length, hand, hands, hand, unit<std::ratio<4>, inches>) 3371 UNIT_ADD(length, league, leagues, lea, unit<std::ratio<3>, miles>) 3372 UNIT_ADD(length, nauticalLeague, nauticalLeagues, nl, unit<std::ratio<3>, nauticalMiles>) 3373 UNIT_ADD(length, yard, yards, yd, unit<std::ratio<3>, feet>) 3374 3375 UNIT_ADD_CATEGORY_TRAIT(length) 3376 #endif 3377 3378 //------------------------------ 3379 // MASS UNITS 3380 //------------------------------ 3381 3382 /** 3383 * @namespace units::mass 3384 * @brief namespace for unit types and containers representing mass values 3385 * @details The SI unit for mass is `kilograms`, and the corresponding `base_unit` category is 3386 * `mass_unit`. 3387 * @anchor massContainers 3388 * @sa See unit_t for more information on unit type containers. 3389 */ 3390 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_MASS_UNITS) 3391 UNIT_ADD_WITH_METRIC_PREFIXES(mass, gram, grams, g, unit<std::ratio<1, 1000>, units::category::mass_unit>) 3392 UNIT_ADD(mass, metric_ton, metric_tons, t, unit<std::ratio<1000>, kilograms>) 3393 UNIT_ADD(mass, pound, pounds, lb, unit<std::ratio<45359237, 100000000>, kilograms>) 3394 UNIT_ADD(mass, long_ton, long_tons, ln_t, unit<std::ratio<2240>, pounds>) 3395 UNIT_ADD(mass, short_ton, short_tons, sh_t, unit<std::ratio<2000>, pounds>) 3396 UNIT_ADD(mass, stone, stone, st, unit<std::ratio<14>, pounds>) 3397 UNIT_ADD(mass, ounce, ounces, oz, unit<std::ratio<1, 16>, pounds>) 3398 UNIT_ADD(mass, carat, carats, ct, unit<std::ratio<200>, milligrams>) 3399 UNIT_ADD(mass, slug, slugs, slug, unit<std::ratio<145939029, 10000000>, kilograms>) 3400 3401 UNIT_ADD_CATEGORY_TRAIT(mass) 3402 #endif 3403 3404 //------------------------------ 3405 // TIME UNITS 3406 //------------------------------ 3407 3408 /** 3409 * @namespace units::time 3410 * @brief namespace for unit types and containers representing time values 3411 * @details The SI unit for time is `seconds`, and the corresponding `base_unit` category is 3412 * `time_unit`. 3413 * @anchor timeContainers 3414 * @sa See unit_t for more information on unit type containers. 3415 */ 3416 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_TIME_UNITS) 3417 UNIT_ADD_WITH_METRIC_PREFIXES(time, second, seconds, s, unit<std::ratio<1>, units::category::time_unit>) 3418 UNIT_ADD(time, minute, minutes, min, unit<std::ratio<60>, seconds>) 3419 UNIT_ADD(time, hour, hours, hr, unit<std::ratio<60>, minutes>) 3420 UNIT_ADD(time, day, days, d, unit<std::ratio<24>, hours>) 3421 UNIT_ADD(time, week, weeks, wk, unit<std::ratio<7>, days>) 3422 UNIT_ADD(time, year, years, yr, unit<std::ratio<365>, days>) 3423 UNIT_ADD(time, julian_year, julian_years, a_j, unit<std::ratio<31557600>, seconds>) 3424 UNIT_ADD(time, gregorian_year, gregorian_years, a_g, unit<std::ratio<31556952>, seconds>) 3425 3426 UNIT_ADD_CATEGORY_TRAIT(time) 3427 #endif 3428 3429 //------------------------------ 3430 // ANGLE UNITS 3431 //------------------------------ 3432 3433 /** 3434 * @namespace units::angle 3435 * @brief namespace for unit types and containers representing angle values 3436 * @details The SI unit for angle is `radians`, and the corresponding `base_unit` category is 3437 * `angle_unit`. 3438 * @anchor angleContainers 3439 * @sa See unit_t for more information on unit type containers. 3440 */ 3441 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS) 3442 UNIT_ADD_WITH_METRIC_PREFIXES(angle, radian, radians, rad, unit<std::ratio<1>, units::category::angle_unit>) 3443 UNIT_ADD(angle, degree, degrees, deg, unit<std::ratio<1, 180>, radians, std::ratio<1>>) 3444 UNIT_ADD(angle, arcminute, arcminutes, arcmin, unit<std::ratio<1, 60>, degrees>) 3445 UNIT_ADD(angle, arcsecond, arcseconds, arcsec, unit<std::ratio<1, 60>, arcminutes>) 3446 UNIT_ADD(angle, milliarcsecond, milliarcseconds, mas, milli<arcseconds>) 3447 UNIT_ADD(angle, turn, turns, tr, unit<std::ratio<2>, radians, std::ratio<1>>) 3448 UNIT_ADD(angle, gradian, gradians, gon, unit<std::ratio<1, 400>, turns>) 3449 3450 UNIT_ADD_CATEGORY_TRAIT(angle) 3451 #endif 3452 3453 //------------------------------ 3454 // UNITS OF CURRENT 3455 //------------------------------ 3456 /** 3457 * @namespace units::current 3458 * @brief namespace for unit types and containers representing current values 3459 * @details The SI unit for current is `amperes`, and the corresponding `base_unit` category is 3460 * `current_unit`. 3461 * @anchor currentContainers 3462 * @sa See unit_t for more information on unit type containers. 3463 */ 3464 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_CURRENT_UNITS) 3465 UNIT_ADD_WITH_METRIC_PREFIXES(current, ampere, amperes, A, unit<std::ratio<1>, units::category::current_unit>) 3466 3467 UNIT_ADD_CATEGORY_TRAIT(current) 3468 #endif 3469 3470 //------------------------------ 3471 // UNITS OF TEMPERATURE 3472 //------------------------------ 3473 3474 // NOTE: temperature units have special conversion overloads, since they 3475 // require translations and aren't a reversible transform. 3476 3477 /** 3478 * @namespace units::temperature 3479 * @brief namespace for unit types and containers representing temperature values 3480 * @details The SI unit for temperature is `kelvin`, and the corresponding `base_unit` category is 3481 * `temperature_unit`. 3482 * @anchor temperatureContainers 3483 * @sa See unit_t for more information on unit type containers. 3484 */ 3485 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_TEMPERATURE_UNITS) 3486 UNIT_ADD(temperature, kelvin, kelvin, K, unit<std::ratio<1>, units::category::temperature_unit>) 3487 UNIT_ADD(temperature, celsius, celsius, degC, unit<std::ratio<1>, kelvin, std::ratio<0>, std::ratio<27315, 100>>) 3488 UNIT_ADD(temperature, fahrenheit, fahrenheit, degF, unit<std::ratio<5, 9>, celsius, std::ratio<0>, std::ratio<-160, 9>>) 3489 UNIT_ADD(temperature, reaumur, reaumur, Re, unit<std::ratio<10, 8>, celsius>) 3490 UNIT_ADD(temperature, rankine, rankine, Ra, unit<std::ratio<5, 9>, kelvin>) 3491 3492 UNIT_ADD_CATEGORY_TRAIT(temperature) 3493 #endif 3494 3495 //------------------------------ 3496 // UNITS OF AMOUNT OF SUBSTANCE 3497 //------------------------------ 3498 3499 /** 3500 * @namespace units::substance 3501 * @brief namespace for unit types and containers representing substance values 3502 * @details The SI unit for substance is `moles`, and the corresponding `base_unit` category is 3503 * `substance_unit`. 3504 * @anchor substanceContainers 3505 * @sa See unit_t for more information on unit type containers. 3506 */ 3507 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_SUBSTANCE_UNITS) 3508 UNIT_ADD(substance, mole, moles, mol, unit<std::ratio<1>, units::category::substance_unit>) 3509 3510 UNIT_ADD_CATEGORY_TRAIT(substance) 3511 #endif 3512 3513 //------------------------------ 3514 // UNITS OF LUMINOUS INTENSITY 3515 //------------------------------ 3516 3517 /** 3518 * @namespace units::luminous_intensity 3519 * @brief namespace for unit types and containers representing luminous_intensity values 3520 * @details The SI unit for luminous_intensity is `candelas`, and the corresponding `base_unit` category is 3521 * `luminous_intensity_unit`. 3522 * @anchor luminousIntensityContainers 3523 * @sa See unit_t for more information on unit type containers. 3524 */ 3525 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_LUMINOUS_INTENSITY_UNITS) 3526 UNIT_ADD_WITH_METRIC_PREFIXES(luminous_intensity, candela, candelas, cd, unit<std::ratio<1>, units::category::luminous_intensity_unit>) 3527 3528 UNIT_ADD_CATEGORY_TRAIT(luminous_intensity) 3529 #endif 3530 3531 //------------------------------ 3532 // UNITS OF SOLID ANGLE 3533 //------------------------------ 3534 3535 /** 3536 * @namespace units::solid_angle 3537 * @brief namespace for unit types and containers representing solid_angle values 3538 * @details The SI unit for solid_angle is `steradians`, and the corresponding `base_unit` category is 3539 * `solid_angle_unit`. 3540 * @anchor solidAngleContainers 3541 * @sa See unit_t for more information on unit type containers. 3542 */ 3543 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_SOLID_ANGLE_UNITS) 3544 UNIT_ADD_WITH_METRIC_PREFIXES(solid_angle, steradian, steradians, sr, unit<std::ratio<1>, units::category::solid_angle_unit>) 3545 UNIT_ADD(solid_angle, degree_squared, degrees_squared, sq_deg, squared<angle::degrees>) 3546 UNIT_ADD(solid_angle, spat, spats, sp, unit<std::ratio<4>, steradians, std::ratio<1>>) 3547 3548 UNIT_ADD_CATEGORY_TRAIT(solid_angle) 3549 #endif 3550 3551 //------------------------------ 3552 // FREQUENCY UNITS 3553 //------------------------------ 3554 3555 /** 3556 * @namespace units::frequency 3557 * @brief namespace for unit types and containers representing frequency values 3558 * @details The SI unit for frequency is `hertz`, and the corresponding `base_unit` category is 3559 * `frequency_unit`. 3560 * @anchor frequencyContainers 3561 * @sa See unit_t for more information on unit type containers. 3562 */ 3563 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_FREQUENCY_UNITS) 3564 UNIT_ADD_WITH_METRIC_PREFIXES(frequency, hertz, hertz, Hz, unit<std::ratio<1>, units::category::frequency_unit>) 3565 3566 UNIT_ADD_CATEGORY_TRAIT(frequency) 3567 #endif 3568 3569 //------------------------------ 3570 // VELOCITY UNITS 3571 //------------------------------ 3572 3573 /** 3574 * @namespace units::velocity 3575 * @brief namespace for unit types and containers representing velocity values 3576 * @details The SI unit for velocity is `meters_per_second`, and the corresponding `base_unit` category is 3577 * `velocity_unit`. 3578 * @anchor velocityContainers 3579 * @sa See unit_t for more information on unit type containers. 3580 */ 3581 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_VELOCITY_UNITS) 3582 UNIT_ADD(velocity, meters_per_second, meters_per_second, mps, unit<std::ratio<1>, units::category::velocity_unit>) 3583 UNIT_ADD(velocity, feet_per_second, feet_per_second, fps, compound_unit<length::feet, inverse<time::seconds>>) 3584 UNIT_ADD(velocity, miles_per_hour, miles_per_hour, mph, compound_unit<length::miles, inverse<time::hour>>) 3585 UNIT_ADD(velocity, kilometers_per_hour, kilometers_per_hour, kph, compound_unit<length::kilometers, inverse<time::hour>>) 3586 UNIT_ADD(velocity, knot, knots, kts, compound_unit<length::nauticalMiles, inverse<time::hour>>) 3587 3588 UNIT_ADD_CATEGORY_TRAIT(velocity) 3589 #endif 3590 3591 //------------------------------ 3592 // ANGULAR VELOCITY UNITS 3593 //------------------------------ 3594 3595 /** 3596 * @namespace units::angular_velocity 3597 * @brief namespace for unit types and containers representing angular velocity values 3598 * @details The SI unit for angular velocity is `radians_per_second`, and the corresponding `base_unit` category is 3599 * `angular_velocity_unit`. 3600 * @anchor angularVelocityContainers 3601 * @sa See unit_t for more information on unit type containers. 3602 */ 3603 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGULAR_VELOCITY_UNITS) 3604 UNIT_ADD(angular_velocity, radians_per_second, radians_per_second, rad_per_s, unit<std::ratio<1>, units::category::angular_velocity_unit>) 3605 UNIT_ADD(angular_velocity, degrees_per_second, degrees_per_second, deg_per_s, compound_unit<angle::degrees, inverse<time::seconds>>) 3606 UNIT_ADD(angular_velocity, revolutions_per_minute, revolutions_per_minute, rpm, unit<std::ratio<2, 60>, radians_per_second, std::ratio<1>>) 3607 UNIT_ADD(angular_velocity, milliarcseconds_per_year, milliarcseconds_per_year, mas_per_yr, compound_unit<angle::milliarcseconds, inverse<time::year>>) 3608 3609 UNIT_ADD_CATEGORY_TRAIT(angular_velocity) 3610 #endif 3611 3612 //------------------------------ 3613 // UNITS OF ACCELERATION 3614 //------------------------------ 3615 3616 /** 3617 * @namespace units::acceleration 3618 * @brief namespace for unit types and containers representing acceleration values 3619 * @details The SI unit for acceleration is `meters_per_second_squared`, and the corresponding `base_unit` category is 3620 * `acceleration_unit`. 3621 * @anchor accelerationContainers 3622 * @sa See unit_t for more information on unit type containers. 3623 */ 3624 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ACCELERATION_UNITS) 3625 UNIT_ADD(acceleration, meters_per_second_squared, meters_per_second_squared, mps_sq, unit<std::ratio<1>, units::category::acceleration_unit>) 3626 UNIT_ADD(acceleration, feet_per_second_squared, feet_per_second_squared, fps_sq, compound_unit<length::feet, inverse<squared<time::seconds>>>) 3627 UNIT_ADD(acceleration, standard_gravity, standard_gravity, SG, unit<std::ratio<980665, 100000>, meters_per_second_squared>) 3628 3629 UNIT_ADD_CATEGORY_TRAIT(acceleration) 3630 #endif 3631 3632 //------------------------------ 3633 // UNITS OF FORCE 3634 //------------------------------ 3635 3636 /** 3637 * @namespace units::force 3638 * @brief namespace for unit types and containers representing force values 3639 * @details The SI unit for force is `newtons`, and the corresponding `base_unit` category is 3640 * `force_unit`. 3641 * @anchor forceContainers 3642 * @sa See unit_t for more information on unit type containers. 3643 */ 3644 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_FORCE_UNITS) 3645 UNIT_ADD_WITH_METRIC_PREFIXES(force, newton, newtons, N, unit<std::ratio<1>, units::category::force_unit>) 3646 UNIT_ADD(force, pound, pounds, lbf, compound_unit<mass::slug, length::foot, inverse<squared<time::seconds>>>) 3647 UNIT_ADD(force, dyne, dynes, dyn, unit<std::ratio<1, 100000>, newtons>) 3648 UNIT_ADD(force, kilopond, kiloponds, kp, compound_unit<acceleration::standard_gravity, mass::kilograms>) 3649 UNIT_ADD(force, poundal, poundals, pdl, compound_unit<mass::pound, length::foot, inverse<squared<time::seconds>>>) 3650 3651 UNIT_ADD_CATEGORY_TRAIT(force) 3652 #endif 3653 3654 //------------------------------ 3655 // UNITS OF PRESSURE 3656 //------------------------------ 3657 3658 /** 3659 * @namespace units::pressure 3660 * @brief namespace for unit types and containers representing pressure values 3661 * @details The SI unit for pressure is `pascals`, and the corresponding `base_unit` category is 3662 * `pressure_unit`. 3663 * @anchor pressureContainers 3664 * @sa See unit_t for more information on unit type containers. 3665 */ 3666 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_PRESSURE_UNITS) 3667 UNIT_ADD_WITH_METRIC_PREFIXES(pressure, pascal, pascals, Pa, unit<std::ratio<1>, units::category::pressure_unit>) 3668 UNIT_ADD(pressure, bar, bars, bar, unit<std::ratio<100>, kilo<pascals>>) 3669 UNIT_ADD(pressure, mbar, mbars, mbar, unit<std::ratio<1>, milli<bar>>) 3670 UNIT_ADD(pressure, atmosphere, atmospheres, atm, unit<std::ratio<101325>, pascals>) 3671 UNIT_ADD(pressure, pounds_per_square_inch, pounds_per_square_inch, psi, compound_unit<force::pounds, inverse<squared<length::inch>>>) 3672 UNIT_ADD(pressure, torr, torrs, torr, unit<std::ratio<1, 760>, atmospheres>) 3673 3674 UNIT_ADD_CATEGORY_TRAIT(pressure) 3675 #endif 3676 3677 //------------------------------ 3678 // UNITS OF CHARGE 3679 //------------------------------ 3680 3681 /** 3682 * @namespace units::charge 3683 * @brief namespace for unit types and containers representing charge values 3684 * @details The SI unit for charge is `coulombs`, and the corresponding `base_unit` category is 3685 * `charge_unit`. 3686 * @anchor chargeContainers 3687 * @sa See unit_t for more information on unit type containers. 3688 */ 3689 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_CHARGE_UNITS) 3690 UNIT_ADD_WITH_METRIC_PREFIXES(charge, coulomb, coulombs, C, unit<std::ratio<1>, units::category::charge_unit>) 3691 UNIT_ADD_WITH_METRIC_PREFIXES(charge, ampere_hour, ampere_hours, Ah, compound_unit<current::ampere, time::hours>) 3692 3693 UNIT_ADD_CATEGORY_TRAIT(charge) 3694 #endif 3695 3696 //------------------------------ 3697 // UNITS OF ENERGY 3698 //------------------------------ 3699 3700 /** 3701 * @namespace units::energy 3702 * @brief namespace for unit types and containers representing energy values 3703 * @details The SI unit for energy is `joules`, and the corresponding `base_unit` category is 3704 * `energy_unit`. 3705 * @anchor energyContainers 3706 * @sa See unit_t for more information on unit type containers. 3707 */ 3708 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ENERGY_UNITS) 3709 UNIT_ADD_WITH_METRIC_PREFIXES(energy, joule, joules, J, unit<std::ratio<1>, units::category::energy_unit>) 3710 UNIT_ADD_WITH_METRIC_PREFIXES(energy, calorie, calories, cal, unit<std::ratio<4184, 1000>, joules>) 3711 UNIT_ADD(energy, kilowatt_hour, kilowatt_hours, kWh, unit<std::ratio<36, 10>, megajoules>) 3712 UNIT_ADD(energy, watt_hour, watt_hours, Wh, unit<std::ratio<1, 1000>, kilowatt_hours>) 3713 UNIT_ADD(energy, british_thermal_unit, british_thermal_units, BTU, unit<std::ratio<105505585262, 100000000>, joules>) 3714 UNIT_ADD(energy, british_thermal_unit_iso, british_thermal_units_iso, BTU_iso, unit<std::ratio<1055056, 1000>, joules>) 3715 UNIT_ADD(energy, british_thermal_unit_59, british_thermal_units_59, BTU59, unit<std::ratio<1054804, 1000>, joules>) 3716 UNIT_ADD(energy, therm, therms, thm, unit<std::ratio<100000>, british_thermal_units_59>) 3717 UNIT_ADD(energy, foot_pound, foot_pounds, ftlbf, unit<std::ratio<13558179483314004, 10000000000000000>, joules>) 3718 3719 UNIT_ADD_CATEGORY_TRAIT(energy) 3720 #endif 3721 3722 //------------------------------ 3723 // UNITS OF POWER 3724 //------------------------------ 3725 3726 /** 3727 * @namespace units::power 3728 * @brief namespace for unit types and containers representing power values 3729 * @details The SI unit for power is `watts`, and the corresponding `base_unit` category is 3730 * `power_unit`. 3731 * @anchor powerContainers 3732 * @sa See unit_t for more information on unit type containers. 3733 */ 3734 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_POWER_UNITS) 3735 UNIT_ADD_WITH_METRIC_PREFIXES(power, watt, watts, W, unit<std::ratio<1>, units::category::power_unit>) 3736 UNIT_ADD(power, horsepower, horsepower, hp, unit<std::ratio<7457, 10>, watts>) 3737 UNIT_ADD_DECIBEL(power, watt, dBW) 3738 UNIT_ADD_DECIBEL(power, milliwatt, dBm) 3739 3740 UNIT_ADD_CATEGORY_TRAIT(power) 3741 #endif 3742 3743 //------------------------------ 3744 // UNITS OF VOLTAGE 3745 //------------------------------ 3746 3747 /** 3748 * @namespace units::voltage 3749 * @brief namespace for unit types and containers representing voltage values 3750 * @details The SI unit for voltage is `volts`, and the corresponding `base_unit` category is 3751 * `voltage_unit`. 3752 * @anchor voltageContainers 3753 * @sa See unit_t for more information on unit type containers. 3754 */ 3755 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_VOLTAGE_UNITS) 3756 UNIT_ADD_WITH_METRIC_PREFIXES(voltage, volt, volts, V, unit<std::ratio<1>, units::category::voltage_unit>) 3757 UNIT_ADD(voltage, statvolt, statvolts, statV, unit<std::ratio<1000000, 299792458>, volts>) 3758 UNIT_ADD(voltage, abvolt, abvolts, abV, unit<std::ratio<1, 100000000>, volts>) 3759 3760 UNIT_ADD_CATEGORY_TRAIT(voltage) 3761 #endif 3762 3763 //------------------------------ 3764 // UNITS OF CAPACITANCE 3765 //------------------------------ 3766 3767 /** 3768 * @namespace units::capacitance 3769 * @brief namespace for unit types and containers representing capacitance values 3770 * @details The SI unit for capacitance is `farads`, and the corresponding `base_unit` category is 3771 * `capacitance_unit`. 3772 * @anchor capacitanceContainers 3773 * @sa See unit_t for more information on unit type containers. 3774 */ 3775 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_CAPACITANCE_UNITS) 3776 UNIT_ADD_WITH_METRIC_PREFIXES(capacitance, farad, farads, F, unit<std::ratio<1>, units::category::capacitance_unit>) 3777 3778 UNIT_ADD_CATEGORY_TRAIT(capacitance) 3779 #endif 3780 3781 //------------------------------ 3782 // UNITS OF IMPEDANCE 3783 //------------------------------ 3784 3785 /** 3786 * @namespace units::impedance 3787 * @brief namespace for unit types and containers representing impedance values 3788 * @details The SI unit for impedance is `ohms`, and the corresponding `base_unit` category is 3789 * `impedance_unit`. 3790 * @anchor impedanceContainers 3791 * @sa See unit_t for more information on unit type containers. 3792 */ 3793 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_IMPEDANCE_UNITS) 3794 UNIT_ADD_WITH_METRIC_PREFIXES(impedance, ohm, ohms, Ohm, unit<std::ratio<1>, units::category::impedance_unit>) 3795 3796 UNIT_ADD_CATEGORY_TRAIT(impedance) 3797 #endif 3798 3799 //------------------------------ 3800 // UNITS OF CONDUCTANCE 3801 //------------------------------ 3802 3803 /** 3804 * @namespace units::conductance 3805 * @brief namespace for unit types and containers representing conductance values 3806 * @details The SI unit for conductance is `siemens`, and the corresponding `base_unit` category is 3807 * `conductance_unit`. 3808 * @anchor conductanceContainers 3809 * @sa See unit_t for more information on unit type containers. 3810 */ 3811 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_CONDUCTANCE_UNITS) 3812 UNIT_ADD_WITH_METRIC_PREFIXES(conductance, siemens, siemens, S, unit<std::ratio<1>, units::category::conductance_unit>) 3813 3814 UNIT_ADD_CATEGORY_TRAIT(conductance) 3815 #endif 3816 3817 //------------------------------ 3818 // UNITS OF MAGNETIC FLUX 3819 //------------------------------ 3820 3821 /** 3822 * @namespace units::magnetic_flux 3823 * @brief namespace for unit types and containers representing magnetic_flux values 3824 * @details The SI unit for magnetic_flux is `webers`, and the corresponding `base_unit` category is 3825 * `magnetic_flux_unit`. 3826 * @anchor magneticFluxContainers 3827 * @sa See unit_t for more information on unit type containers. 3828 */ 3829 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_MAGNETIC_FLUX_UNITS) 3830 UNIT_ADD_WITH_METRIC_PREFIXES(magnetic_flux, weber, webers, Wb, unit<std::ratio<1>, units::category::magnetic_flux_unit>) 3831 UNIT_ADD(magnetic_flux, maxwell, maxwells, Mx, unit<std::ratio<1, 100000000>, webers>) 3832 3833 UNIT_ADD_CATEGORY_TRAIT(magnetic_flux) 3834 #endif 3835 3836 //---------------------------------------- 3837 // UNITS OF MAGNETIC FIELD STRENGTH 3838 //---------------------------------------- 3839 3840 /** 3841 * @namespace units::magnetic_field_strength 3842 * @brief namespace for unit types and containers representing magnetic_field_strength values 3843 * @details The SI unit for magnetic_field_strength is `teslas`, and the corresponding `base_unit` category is 3844 * `magnetic_field_strength_unit`. 3845 * @anchor magneticFieldStrengthContainers 3846 * @sa See unit_t for more information on unit type containers. 3847 */ 3848 // Unfortunately `_T` is a WINAPI macro, so we have to use `_Te` as the tesla abbreviation. 3849 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_MAGNETIC_FIELD_STRENGTH_UNITS) 3850 UNIT_ADD_WITH_METRIC_PREFIXES(magnetic_field_strength, tesla, teslas, Te, unit<std::ratio<1>, units::category::magnetic_field_strength_unit>) 3851 UNIT_ADD(magnetic_field_strength, gauss, gauss, G, compound_unit<magnetic_flux::maxwell, inverse<squared<length::centimeter>>>) 3852 3853 UNIT_ADD_CATEGORY_TRAIT(magnetic_field_strength) 3854 #endif 3855 3856 //------------------------------ 3857 // UNITS OF INDUCTANCE 3858 //------------------------------ 3859 3860 /** 3861 * @namespace units::inductance 3862 * @brief namespace for unit types and containers representing inductance values 3863 * @details The SI unit for inductance is `henrys`, and the corresponding `base_unit` category is 3864 * `inductance_unit`. 3865 * @anchor inductanceContainers 3866 * @sa See unit_t for more information on unit type containers. 3867 */ 3868 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_INDUCTANCE_UNITS) 3869 UNIT_ADD_WITH_METRIC_PREFIXES(inductance, henry, henries, H, unit<std::ratio<1>, units::category::inductance_unit>) 3870 3871 UNIT_ADD_CATEGORY_TRAIT(inductance) 3872 #endif 3873 3874 //------------------------------ 3875 // UNITS OF LUMINOUS FLUX 3876 //------------------------------ 3877 3878 /** 3879 * @namespace units::luminous_flux 3880 * @brief namespace for unit types and containers representing luminous_flux values 3881 * @details The SI unit for luminous_flux is `lumens`, and the corresponding `base_unit` category is 3882 * `luminous_flux_unit`. 3883 * @anchor luminousFluxContainers 3884 * @sa See unit_t for more information on unit type containers. 3885 */ 3886 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_LUMINOUS_FLUX_UNITS) 3887 UNIT_ADD_WITH_METRIC_PREFIXES(luminous_flux, lumen, lumens, lm, unit<std::ratio<1>, units::category::luminous_flux_unit>) 3888 3889 UNIT_ADD_CATEGORY_TRAIT(luminous_flux) 3890 #endif 3891 3892 //------------------------------ 3893 // UNITS OF ILLUMINANCE 3894 //------------------------------ 3895 3896 /** 3897 * @namespace units::illuminance 3898 * @brief namespace for unit types and containers representing illuminance values 3899 * @details The SI unit for illuminance is `luxes`, and the corresponding `base_unit` category is 3900 * `illuminance_unit`. 3901 * @anchor illuminanceContainers 3902 * @sa See unit_t for more information on unit type containers. 3903 */ 3904 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ILLUMINANCE_UNITS) 3905 UNIT_ADD_WITH_METRIC_PREFIXES(illuminance, lux, luxes, lx, unit<std::ratio<1>, units::category::illuminance_unit>) 3906 UNIT_ADD(illuminance, footcandle, footcandles, fc, compound_unit<luminous_flux::lumen, inverse<squared<length::foot>>>) 3907 UNIT_ADD(illuminance, lumens_per_square_inch, lumens_per_square_inch, lm_per_in_sq, compound_unit<luminous_flux::lumen, inverse<squared<length::inch>>>) 3908 UNIT_ADD(illuminance, phot, phots, ph, compound_unit<luminous_flux::lumens, inverse<squared<length::centimeter>>>) 3909 3910 UNIT_ADD_CATEGORY_TRAIT(illuminance) 3911 #endif 3912 3913 //------------------------------ 3914 // UNITS OF RADIATION 3915 //------------------------------ 3916 3917 /** 3918 * @namespace units::radiation 3919 * @brief namespace for unit types and containers representing radiation values 3920 * @details The SI units for radiation are: 3921 * - source activity: becquerel 3922 * - absorbed dose: gray 3923 * - equivalent dose: sievert 3924 * @anchor radiationContainers 3925 * @sa See unit_t for more information on unit type containers. 3926 */ 3927 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_RADIATION_UNITS) 3928 UNIT_ADD_WITH_METRIC_PREFIXES(radiation, becquerel, becquerels, Bq, unit<std::ratio<1>, units::frequency::hertz>) 3929 UNIT_ADD_WITH_METRIC_PREFIXES(radiation, gray, grays, Gy, compound_unit<energy::joules, inverse<mass::kilogram>>) 3930 UNIT_ADD_WITH_METRIC_PREFIXES(radiation, sievert, sieverts, Sv, unit<std::ratio<1>, grays>) 3931 UNIT_ADD(radiation, curie, curies, Ci, unit<std::ratio<37>, gigabecquerels>) 3932 UNIT_ADD(radiation, rutherford, rutherfords, rd, unit<std::ratio<1>, megabecquerels>) 3933 UNIT_ADD(radiation, rad, rads, rads, unit<std::ratio<1>, centigrays>) 3934 3935 UNIT_ADD_CATEGORY_TRAIT(radioactivity) 3936 #endif 3937 3938 //------------------------------ 3939 // UNITS OF TORQUE 3940 //------------------------------ 3941 3942 /** 3943 * @namespace units::torque 3944 * @brief namespace for unit types and containers representing torque values 3945 * @details The SI unit for torque is `newton_meters`, and the corresponding `base_unit` category is 3946 * `torque_units`. 3947 * @anchor torqueContainers 3948 * @sa See unit_t for more information on unit type containers. 3949 */ 3950 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_TORQUE_UNITS) 3951 UNIT_ADD(torque, newton_meter, newton_meters, Nm, unit<std::ratio<1>, units::energy::joule>) 3952 UNIT_ADD(torque, foot_pound, foot_pounds, ftlb, compound_unit<length::foot, force::pounds>) 3953 UNIT_ADD(torque, foot_poundal, foot_poundals, ftpdl, compound_unit<length::foot, force::poundal>) 3954 UNIT_ADD(torque, inch_pound, inch_pounds, inlb, compound_unit<length::inch, force::pounds>) 3955 UNIT_ADD(torque, meter_kilogram, meter_kilograms, mkgf, compound_unit<length::meter, force::kiloponds>) 3956 3957 UNIT_ADD_CATEGORY_TRAIT(torque) 3958 #endif 3959 3960 //------------------------------ 3961 // AREA UNITS 3962 //------------------------------ 3963 3964 /** 3965 * @namespace units::area 3966 * @brief namespace for unit types and containers representing area values 3967 * @details The SI unit for area is `square_meters`, and the corresponding `base_unit` category is 3968 * `area_unit`. 3969 * @anchor areaContainers 3970 * @sa See unit_t for more information on unit type containers. 3971 */ 3972 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_AREA_UNITS) 3973 UNIT_ADD(area, square_meter, square_meters, sq_m, unit<std::ratio<1>, units::category::area_unit>) 3974 UNIT_ADD(area, square_foot, square_feet, sq_ft, squared<length::feet>) 3975 UNIT_ADD(area, square_inch, square_inches, sq_in, squared<length::inch>) 3976 UNIT_ADD(area, square_mile, square_miles, sq_mi, squared<length::miles>) 3977 UNIT_ADD(area, square_kilometer, square_kilometers, sq_km, squared<length::kilometers>) 3978 UNIT_ADD(area, hectare, hectares, ha, unit<std::ratio<10000>, square_meters>) 3979 UNIT_ADD(area, acre, acres, acre, unit<std::ratio<43560>, square_feet>) 3980 3981 UNIT_ADD_CATEGORY_TRAIT(area) 3982 #endif 3983 3984 //------------------------------ 3985 // UNITS OF VOLUME 3986 //------------------------------ 3987 3988 /** 3989 * @namespace units::volume 3990 * @brief namespace for unit types and containers representing volume values 3991 * @details The SI unit for volume is `cubic_meters`, and the corresponding `base_unit` category is 3992 * `volume_unit`. 3993 * @anchor volumeContainers 3994 * @sa See unit_t for more information on unit type containers. 3995 */ 3996 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_VOLUME_UNITS) 3997 UNIT_ADD(volume, cubic_meter, cubic_meters, cu_m, unit<std::ratio<1>, units::category::volume_unit>) 3998 UNIT_ADD(volume, cubic_millimeter, cubic_millimeters, cu_mm, cubed<length::millimeter>) 3999 UNIT_ADD(volume, cubic_kilometer, cubic_kilometers, cu_km, cubed<length::kilometer>) 4000 UNIT_ADD_WITH_METRIC_PREFIXES(volume, liter, liters, L, cubed<deci<length::meter>>) 4001 UNIT_ADD(volume, cubic_inch, cubic_inches, cu_in, cubed<length::inches>) 4002 UNIT_ADD(volume, cubic_foot, cubic_feet, cu_ft, cubed<length::feet>) 4003 UNIT_ADD(volume, cubic_yard, cubic_yards, cu_yd, cubed<length::yards>) 4004 UNIT_ADD(volume, cubic_mile, cubic_miles, cu_mi, cubed<length::miles>) 4005 UNIT_ADD(volume, gallon, gallons, gal, unit<std::ratio<231>, cubic_inches>) 4006 UNIT_ADD(volume, quart, quarts, qt, unit<std::ratio<1, 4>, gallons>) 4007 UNIT_ADD(volume, pint, pints, pt, unit<std::ratio<1, 2>, quarts>) 4008 UNIT_ADD(volume, cup, cups, c, unit<std::ratio<1, 2>, pints>) 4009 UNIT_ADD(volume, fluid_ounce, fluid_ounces, fl_oz, unit<std::ratio<1, 8>, cups>) 4010 UNIT_ADD(volume, barrel, barrels, bl, unit<std::ratio<42>, gallons>) 4011 UNIT_ADD(volume, bushel, bushels, bu, unit<std::ratio<215042, 100>, cubic_inches>) 4012 UNIT_ADD(volume, cord, cords, cord, unit<std::ratio<128>, cubic_feet>) 4013 UNIT_ADD(volume, cubic_fathom, cubic_fathoms, cu_fm, cubed<length::fathom>) 4014 UNIT_ADD(volume, tablespoon, tablespoons, tbsp, unit<std::ratio<1, 2>, fluid_ounces>) 4015 UNIT_ADD(volume, teaspoon, teaspoons, tsp, unit<std::ratio<1, 6>, fluid_ounces>) 4016 UNIT_ADD(volume, pinch, pinches, pinch, unit<std::ratio<1, 8>, teaspoons>) 4017 UNIT_ADD(volume, dash, dashes, dash, unit<std::ratio<1, 2>, pinches>) 4018 UNIT_ADD(volume, drop, drops, drop, unit<std::ratio<1, 360>, fluid_ounces>) 4019 UNIT_ADD(volume, fifth, fifths, fifth, unit<std::ratio<1, 5>, gallons>) 4020 UNIT_ADD(volume, dram, drams, dr, unit<std::ratio<1, 8>, fluid_ounces>) 4021 UNIT_ADD(volume, gill, gills, gi, unit<std::ratio<4>, fluid_ounces>) 4022 UNIT_ADD(volume, peck, pecks, pk, unit<std::ratio<1, 4>, bushels>) 4023 UNIT_ADD(volume, sack, sacks, sacks, unit<std::ratio<3>, bushels>) 4024 UNIT_ADD(volume, shot, shots, shots, unit<std::ratio<3, 2>, fluid_ounces>) 4025 UNIT_ADD(volume, strike, strikes, strikes, unit<std::ratio<2>, bushels>) 4026 4027 UNIT_ADD_CATEGORY_TRAIT(volume) 4028 #endif 4029 4030 //------------------------------ 4031 // UNITS OF DENSITY 4032 //------------------------------ 4033 4034 /** 4035 * @namespace units::density 4036 * @brief namespace for unit types and containers representing density values 4037 * @details The SI unit for density is `kilograms_per_cubic_meter`, and the corresponding `base_unit` category is 4038 * `density_unit`. 4039 * @anchor densityContainers 4040 * @sa See unit_t for more information on unit type containers. 4041 */ 4042 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_DENSITY_UNITS) 4043 UNIT_ADD(density, kilograms_per_cubic_meter, kilograms_per_cubic_meter, kg_per_cu_m, unit<std::ratio<1>, units::category::density_unit>) 4044 UNIT_ADD(density, grams_per_milliliter, grams_per_milliliter, g_per_mL, compound_unit<mass::grams, inverse<volume::milliliter>>) 4045 UNIT_ADD(density, kilograms_per_liter, kilograms_per_liter, kg_per_L, unit<std::ratio<1>, compound_unit<mass::grams, inverse<volume::milliliter>>>) 4046 UNIT_ADD(density, ounces_per_cubic_foot, ounces_per_cubic_foot, oz_per_cu_ft, compound_unit<mass::ounces, inverse<volume::cubic_foot>>) 4047 UNIT_ADD(density, ounces_per_cubic_inch, ounces_per_cubic_inch, oz_per_cu_in, compound_unit<mass::ounces, inverse<volume::cubic_inch>>) 4048 UNIT_ADD(density, ounces_per_gallon, ounces_per_gallon, oz_per_gal, compound_unit<mass::ounces, inverse<volume::gallon>>) 4049 UNIT_ADD(density, pounds_per_cubic_foot, pounds_per_cubic_foot, lb_per_cu_ft, compound_unit<mass::pounds, inverse<volume::cubic_foot>>) 4050 UNIT_ADD(density, pounds_per_cubic_inch, pounds_per_cubic_inch, lb_per_cu_in, compound_unit<mass::pounds, inverse<volume::cubic_inch>>) 4051 UNIT_ADD(density, pounds_per_gallon, pounds_per_gallon, lb_per_gal, compound_unit<mass::pounds, inverse<volume::gallon>>) 4052 UNIT_ADD(density, slugs_per_cubic_foot, slugs_per_cubic_foot, slug_per_cu_ft, compound_unit<mass::slugs, inverse<volume::cubic_foot>>) 4053 4054 UNIT_ADD_CATEGORY_TRAIT(density) 4055 #endif 4056 4057 //------------------------------ 4058 // UNITS OF CONCENTRATION 4059 //------------------------------ 4060 4061 /** 4062 * @namespace units::concentration 4063 * @brief namespace for unit types and containers representing concentration values 4064 * @details The SI unit for concentration is `parts_per_million`, and the corresponding `base_unit` category is 4065 * `scalar_unit`. 4066 * @anchor concentrationContainers 4067 * @sa See unit_t for more information on unit type containers. 4068 */ 4069 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_CONCENTRATION_UNITS) 4070 UNIT_ADD(concentration, ppm, parts_per_million, ppm, unit<std::ratio<1, 1000000>, units::category::scalar_unit>) 4071 UNIT_ADD(concentration, ppb, parts_per_billion, ppb, unit<std::ratio<1, 1000>, parts_per_million>) 4072 UNIT_ADD(concentration, ppt, parts_per_trillion, ppt, unit<std::ratio<1, 1000>, parts_per_billion>) 4073 UNIT_ADD(concentration, percent, percent, pct, unit<std::ratio<1, 100>, units::category::scalar_unit>) 4074 4075 UNIT_ADD_CATEGORY_TRAIT(concentration) 4076 #endif 4077 4078 //------------------------------ 4079 // UNITS OF DATA 4080 //------------------------------ 4081 4082 /** 4083 * @namespace units::data 4084 * @brief namespace for unit types and containers representing data values 4085 * @details The base unit for data is `bytes`, and the corresponding `base_unit` category is 4086 * `data_unit`. 4087 * @anchor dataContainers 4088 * @sa See unit_t for more information on unit type containers. 4089 */ 4090 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_DATA_UNITS) 4091 UNIT_ADD_WITH_METRIC_AND_BINARY_PREFIXES(data, byte, bytes, B, unit<std::ratio<1>, units::category::data_unit>) 4092 UNIT_ADD(data, exabyte, exabytes, EB, unit<std::ratio<1000>, petabytes>) 4093 UNIT_ADD_WITH_METRIC_AND_BINARY_PREFIXES(data, bit, bits, b, unit<std::ratio<1, 8>, byte>) 4094 UNIT_ADD(data, exabit, exabits, Eb, unit<std::ratio<1000>, petabits>) 4095 4096 UNIT_ADD_CATEGORY_TRAIT(data) 4097 #endif 4098 4099 //------------------------------ 4100 // UNITS OF DATA TRANSFER 4101 //------------------------------ 4102 4103 /** 4104 * @namespace units::data_transfer_rate 4105 * @brief namespace for unit types and containers representing data values 4106 * @details The base unit for data is `bytes`, and the corresponding `base_unit` category is 4107 * `data_unit`. 4108 * @anchor dataContainers 4109 * @sa See unit_t for more information on unit type containers. 4110 */ 4111 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_DATA_TRANSFER_RATE_UNITS) 4112 UNIT_ADD_WITH_METRIC_AND_BINARY_PREFIXES(data_transfer_rate, bytes_per_second, bytes_per_second, Bps, unit<std::ratio<1>, units::category::data_transfer_rate_unit>) 4113 UNIT_ADD(data_transfer_rate, exabytes_per_second, exabytes_per_second, EBps, unit<std::ratio<1000>, petabytes_per_second>) 4114 UNIT_ADD_WITH_METRIC_AND_BINARY_PREFIXES(data_transfer_rate, bits_per_second, bits_per_second, bps, unit<std::ratio<1, 8>, bytes_per_second>) 4115 UNIT_ADD(data_transfer_rate, exabits_per_second, exabits_per_second, Ebps, unit<std::ratio<1000>, petabits_per_second>) 4116 4117 UNIT_ADD_CATEGORY_TRAIT(data_transfer_rate) 4118 #endif 4119 4120 //------------------------------ 4121 // CONSTANTS 4122 //------------------------------ 4123 4124 /** 4125 * @brief namespace for physical constants like PI and Avogadro's Number. 4126 * @sa See unit_t for more information on unit type containers. 4127 */ 4128 #if !defined(DISABLE_PREDEFINED_UNITS) 4129 namespace constants 4130 { 4131 /** 4132 * @name Unit Containers 4133 * @anchor constantContainers 4134 * @{ 4135 */ 4136 using PI = unit<std::ratio<1>, dimensionless::scalar, std::ratio<1>>; 4137 4138 static constexpr const unit_t<PI> pi(1); ///< Ratio of a circle's circumference to its diameter. 4139 static constexpr const velocity::meters_per_second_t c(299792458.0); ///< Speed of light in vacuum. 4140 static constexpr const unit_t<compound_unit<cubed<length::meters>, inverse<mass::kilogram>, inverse<squared<time::seconds>>>> G(6.67408e-11); ///< Newtonian constant of gravitation. 4141 static constexpr const unit_t<compound_unit<energy::joule, time::seconds>> h(6.626070040e-34); ///< Planck constant. 4142 static constexpr const unit_t<compound_unit<force::newtons, inverse<squared<current::ampere>>>> mu0(pi * 4.0e-7 * force::newton_t(1) / units::math::cpow<2>(current::ampere_t(1))); ///< vacuum permeability. 4143 static constexpr const unit_t<compound_unit<capacitance::farad, inverse<length::meter>>> epsilon0(1.0 / (mu0 * math::cpow<2>(c))); ///< vacuum permitivity. 4144 static constexpr const impedance::ohm_t Z0(mu0 * c); ///< characteristic impedance of vacuum. 4145 static constexpr const unit_t<compound_unit<force::newtons, area::square_meter, inverse<squared<charge::coulomb>>>> k_e(1.0 / (4 * pi * epsilon0)); ///< Coulomb's constant. 4146 static constexpr const charge::coulomb_t e(1.6021766208e-19); ///< elementary charge. 4147 static constexpr const mass::kilogram_t m_e(9.10938356e-31); ///< electron mass. 4148 static constexpr const mass::kilogram_t m_p(1.672621898e-27); ///< proton mass. 4149 static constexpr const unit_t<compound_unit<energy::joules, inverse<magnetic_field_strength::tesla>>> mu_B(e * h / (4 * pi *m_e)); ///< Bohr magneton. 4150 static constexpr const unit_t<inverse<substance::mol>> N_A(6.022140857e23); ///< Avagadro's Number. 4151 static constexpr const unit_t<compound_unit<energy::joules, inverse<temperature::kelvin>, inverse<substance::moles>>> R(8.3144598); ///< Gas constant. 4152 static constexpr const unit_t<compound_unit<energy::joules, inverse<temperature::kelvin>>> k_B(R / N_A); ///< Boltzmann constant. 4153 static constexpr const unit_t<compound_unit<charge::coulomb, inverse<substance::mol>>> F(N_A * e); ///< Faraday constant. 4154 static constexpr const unit_t<compound_unit<power::watts, inverse<area::square_meters>, inverse<squared<squared<temperature::kelvin>>>>> sigma((2 * math::cpow<5>(pi) * math::cpow<4>(R)) / (15 * math::cpow<3>(h) * math::cpow<2>(c) * math::cpow<4>(N_A))); ///< Stefan-Boltzmann constant. 4155 /** @} */ 4156 } 4157 #endif 4158 4159 //---------------------------------- 4160 // UNIT-ENABLED CMATH FUNCTIONS 4161 //---------------------------------- 4162 4163 /** 4164 * @brief namespace for unit-enabled versions of the `<cmath>` library 4165 * @details Includes trigonometric functions, exponential/log functions, rounding functions, etc. 4166 * @sa See `unit_t` for more information on unit type containers. 4167 */ 4168 namespace math 4169 { 4170 4171 //---------------------------------- 4172 // MIN/MAX FUNCTIONS 4173 //---------------------------------- 4174 4175 template<class UnitTypeLhs, class UnitTypeRhs> 4176 UnitTypeLhs min(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) 4177 { 4178 static_assert(traits::is_convertible_unit_t<UnitTypeLhs, UnitTypeRhs>::value, "Unit types are not compatible."); 4179 UnitTypeLhs r(rhs); 4180 return (lhs < r ? lhs : r); 4181 } 4182 4183 template<class UnitTypeLhs, class UnitTypeRhs> 4184 UnitTypeLhs max(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) 4185 { 4186 static_assert(traits::is_convertible_unit_t<UnitTypeLhs, UnitTypeRhs>::value, "Unit types are not compatible."); 4187 UnitTypeLhs r(rhs); 4188 return (lhs > r ? lhs : r); 4189 } 4190 4191 //---------------------------------- 4192 // TRIGONOMETRIC FUNCTIONS 4193 //---------------------------------- 4194 4195 /** 4196 * @ingroup UnitMath 4197 * @brief Compute cosine 4198 * @details The input value can be in any unit of angle, including radians or degrees. 4199 * @tparam AngleUnit any `unit_t` type of `category::angle_unit`. 4200 * @param[in] angle angle to compute the cosine of 4201 * @returns Returns the cosine of <i>angle</i> 4202 */ 4203 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS) 4204 template<class AngleUnit> cos(const AngleUnit angle)4205 dimensionless::scalar_t cos(const AngleUnit angle) noexcept 4206 { 4207 static_assert(traits::is_angle_unit<AngleUnit>::value, "Type `AngleUnit` must be a unit of angle derived from `unit_t`."); 4208 return dimensionless::scalar_t(std::cos(angle.template convert<angle::radian>()())); 4209 } 4210 #endif 4211 4212 /** 4213 * @ingroup UnitMath 4214 * @brief Compute sine 4215 * @details The input value can be in any unit of angle, including radians or degrees. 4216 * @tparam AngleUnit any `unit_t` type of `category::angle_unit`. 4217 * @param[in] angle angle to compute the since of 4218 * @returns Returns the sine of <i>angle</i> 4219 */ 4220 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS) 4221 template<class AngleUnit> sin(const AngleUnit angle)4222 dimensionless::scalar_t sin(const AngleUnit angle) noexcept 4223 { 4224 static_assert(traits::is_angle_unit<AngleUnit>::value, "Type `AngleUnit` must be a unit of angle derived from `unit_t`."); 4225 return dimensionless::scalar_t(std::sin(angle.template convert<angle::radian>()())); 4226 } 4227 #endif 4228 /** 4229 * @ingroup UnitMath 4230 * @brief Compute tangent 4231 * @details The input value can be in any unit of angle, including radians or degrees. 4232 * @tparam AngleUnit any `unit_t` type of `category::angle_unit`. 4233 * @param[in] angle angle to compute the tangent of 4234 * @returns Returns the tangent of <i>angle</i> 4235 */ 4236 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS) 4237 template<class AngleUnit> tan(const AngleUnit angle)4238 dimensionless::scalar_t tan(const AngleUnit angle) noexcept 4239 { 4240 static_assert(traits::is_angle_unit<AngleUnit>::value, "Type `AngleUnit` must be a unit of angle derived from `unit_t`."); 4241 return dimensionless::scalar_t(std::tan(angle.template convert<angle::radian>()())); 4242 } 4243 #endif 4244 4245 /** 4246 * @ingroup UnitMath 4247 * @brief Compute arc cosine 4248 * @details Returns the principal value of the arc cosine of x, expressed in radians. 4249 * @param[in] x Value whose arc cosine is computed, in the interval [-1,+1]. 4250 * @returns Principal arc cosine of x, in the interval [0,pi] radians. 4251 */ 4252 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS) 4253 template<class ScalarUnit> acos(const ScalarUnit x)4254 angle::radian_t acos(const ScalarUnit x) noexcept 4255 { 4256 static_assert(traits::is_dimensionless_unit<ScalarUnit>::value, "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`."); 4257 return angle::radian_t(std::acos(x())); 4258 } 4259 #endif 4260 4261 /** 4262 * @ingroup UnitMath 4263 * @brief Compute arc sine 4264 * @details Returns the principal value of the arc sine of x, expressed in radians. 4265 * @param[in] x Value whose arc sine is computed, in the interval [-1,+1]. 4266 * @returns Principal arc sine of x, in the interval [-pi/2,+pi/2] radians. 4267 */ 4268 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS) 4269 template<class ScalarUnit> asin(const ScalarUnit x)4270 angle::radian_t asin(const ScalarUnit x) noexcept 4271 { 4272 static_assert(traits::is_dimensionless_unit<ScalarUnit>::value, "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`."); 4273 return angle::radian_t(std::asin(x())); 4274 } 4275 #endif 4276 4277 /** 4278 * @ingroup UnitMath 4279 * @brief Compute arc tangent 4280 * @details Returns the principal value of the arc tangent of x, expressed in radians. 4281 * Notice that because of the sign ambiguity, the function cannot determine with 4282 * certainty in which quadrant the angle falls only by its tangent value. See 4283 * atan2 for an alternative that takes a fractional argument instead. 4284 * @tparam AngleUnit any `unit_t` type of `category::angle_unit`. 4285 * @param[in] x Value whose arc tangent is computed, in the interval [-1,+1]. 4286 * @returns Principal arc tangent of x, in the interval [-pi/2,+pi/2] radians. 4287 */ 4288 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS) 4289 template<class ScalarUnit> atan(const ScalarUnit x)4290 angle::radian_t atan(const ScalarUnit x) noexcept 4291 { 4292 static_assert(traits::is_dimensionless_unit<ScalarUnit>::value, "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`."); 4293 return angle::radian_t(std::atan(x())); 4294 } 4295 #endif 4296 4297 /** 4298 * @ingroup UnitMath 4299 * @brief Compute arc tangent with two parameters 4300 * @details To compute the value, the function takes into account the sign of both arguments in order to determine the quadrant. 4301 * @param[in] y y-component of the triangle expressed. 4302 * @param[in] x x-component of the triangle expressed. 4303 * @returns Returns the principal value of the arc tangent of <i>y/x</i>, expressed in radians. 4304 */ 4305 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS) 4306 template<class Y, class X> atan2(const Y y,const X x)4307 angle::radian_t atan2(const Y y, const X x) noexcept 4308 { 4309 static_assert(traits::is_dimensionless_unit<decltype(y/x)>::value, "The quantity y/x must yield a dimensionless ratio."); 4310 4311 // X and Y could be different length units, so normalize them 4312 return angle::radian_t(std::atan2(y.template convert<typename units::traits::unit_t_traits<X>::unit_type>()(), x())); 4313 } 4314 #endif 4315 4316 //---------------------------------- 4317 // HYPERBOLIC TRIG FUNCTIONS 4318 //---------------------------------- 4319 4320 /** 4321 * @ingroup UnitMath 4322 * @brief Compute hyperbolic cosine 4323 * @details The input value can be in any unit of angle, including radians or degrees. 4324 * @tparam AngleUnit any `unit_t` type of `category::angle_unit`. 4325 * @param[in] angle angle to compute the hyperbolic cosine of 4326 * @returns Returns the hyperbolic cosine of <i>angle</i> 4327 */ 4328 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS) 4329 template<class AngleUnit> cosh(const AngleUnit angle)4330 dimensionless::scalar_t cosh(const AngleUnit angle) noexcept 4331 { 4332 static_assert(traits::is_angle_unit<AngleUnit>::value, "Type `AngleUnit` must be a unit of angle derived from `unit_t`."); 4333 return dimensionless::scalar_t(std::cosh(angle.template convert<angle::radian>()())); 4334 } 4335 #endif 4336 4337 /** 4338 * @ingroup UnitMath 4339 * @brief Compute hyperbolic sine 4340 * @details The input value can be in any unit of angle, including radians or degrees. 4341 * @tparam AngleUnit any `unit_t` type of `category::angle_unit`. 4342 * @param[in] angle angle to compute the hyperbolic sine of 4343 * @returns Returns the hyperbolic sine of <i>angle</i> 4344 */ 4345 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS) 4346 template<class AngleUnit> sinh(const AngleUnit angle)4347 dimensionless::scalar_t sinh(const AngleUnit angle) noexcept 4348 { 4349 static_assert(traits::is_angle_unit<AngleUnit>::value, "Type `AngleUnit` must be a unit of angle derived from `unit_t`."); 4350 return dimensionless::scalar_t(std::sinh(angle.template convert<angle::radian>()())); 4351 } 4352 #endif 4353 4354 /** 4355 * @ingroup UnitMath 4356 * @brief Compute hyperbolic tangent 4357 * @details The input value can be in any unit of angle, including radians or degrees. 4358 * @tparam AngleUnit any `unit_t` type of `category::angle_unit`. 4359 * @param[in] angle angle to compute the hyperbolic tangent of 4360 * @returns Returns the hyperbolic tangent of <i>angle</i> 4361 */ 4362 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS) 4363 template<class AngleUnit> tanh(const AngleUnit angle)4364 dimensionless::scalar_t tanh(const AngleUnit angle) noexcept 4365 { 4366 static_assert(traits::is_angle_unit<AngleUnit>::value, "Type `AngleUnit` must be a unit of angle derived from `unit_t`."); 4367 return dimensionless::scalar_t(std::tanh(angle.template convert<angle::radian>()())); 4368 } 4369 #endif 4370 4371 /** 4372 * @ingroup UnitMath 4373 * @brief Compute arc hyperbolic cosine 4374 * @details Returns the nonnegative arc hyperbolic cosine of x, expressed in radians. 4375 * @param[in] x Value whose arc hyperbolic cosine is computed. If the argument is less 4376 * than 1, a domain error occurs. 4377 * @returns Nonnegative arc hyperbolic cosine of x, in the interval [0,+INFINITY] radians. 4378 */ 4379 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS) 4380 template<class ScalarUnit> acosh(const ScalarUnit x)4381 angle::radian_t acosh(const ScalarUnit x) noexcept 4382 { 4383 static_assert(traits::is_dimensionless_unit<ScalarUnit>::value, "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`."); 4384 return angle::radian_t(std::acosh(x())); 4385 } 4386 #endif 4387 4388 /** 4389 * @ingroup UnitMath 4390 * @brief Compute arc hyperbolic sine 4391 * @details Returns the arc hyperbolic sine of x, expressed in radians. 4392 * @param[in] x Value whose arc hyperbolic sine is computed. 4393 * @returns Arc hyperbolic sine of x, in radians. 4394 */ 4395 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS) 4396 template<class ScalarUnit> asinh(const ScalarUnit x)4397 angle::radian_t asinh(const ScalarUnit x) noexcept 4398 { 4399 static_assert(traits::is_dimensionless_unit<ScalarUnit>::value, "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`."); 4400 return angle::radian_t(std::asinh(x())); 4401 } 4402 #endif 4403 4404 /** 4405 * @ingroup UnitMath 4406 * @brief Compute arc hyperbolic tangent 4407 * @details Returns the arc hyperbolic tangent of x, expressed in radians. 4408 * @param[in] x Value whose arc hyperbolic tangent is computed, in the interval [-1,+1]. 4409 * If the argument is out of this interval, a domain error occurs. For 4410 * values of -1 and +1, a pole error may occur. 4411 * @returns units::angle::radian_t 4412 */ 4413 #if !defined(DISABLE_PREDEFINED_UNITS) || defined(ENABLE_PREDEFINED_ANGLE_UNITS) 4414 template<class ScalarUnit> atanh(const ScalarUnit x)4415 angle::radian_t atanh(const ScalarUnit x) noexcept 4416 { 4417 static_assert(traits::is_dimensionless_unit<ScalarUnit>::value, "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`."); 4418 return angle::radian_t(std::atanh(x())); 4419 } 4420 #endif 4421 4422 //---------------------------------- 4423 // TRANSCENDENTAL FUNCTIONS 4424 //---------------------------------- 4425 4426 // it makes NO SENSE to put dimensioned units into a transcendental function, and if you think it does you are 4427 // demonstrably wrong. https://en.wikipedia.org/wiki/Transcendental_function#Dimensional_analysis 4428 4429 /** 4430 * @ingroup UnitMath 4431 * @brief Compute exponential function 4432 * @details Returns the base-e exponential function of x, which is e raised to the power x: ex. 4433 * @param[in] x scalar value of the exponent. 4434 * @returns Exponential value of x. 4435 * If the magnitude of the result is too large to be represented by a value of the return type, the 4436 * function returns HUGE_VAL (or HUGE_VALF or HUGE_VALL) with the proper sign, and an overflow range error occurs 4437 */ 4438 template<class ScalarUnit> exp(const ScalarUnit x)4439 dimensionless::scalar_t exp(const ScalarUnit x) noexcept 4440 { 4441 static_assert(traits::is_dimensionless_unit<ScalarUnit>::value, "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`."); 4442 return dimensionless::scalar_t(std::exp(x())); 4443 } 4444 4445 /** 4446 * @ingroup UnitMath 4447 * @brief Compute natural logarithm 4448 * @details Returns the natural logarithm of x. 4449 * @param[in] x scalar value whose logarithm is calculated. If the argument is negative, a 4450 * domain error occurs. 4451 * @sa log10 for more common base-10 logarithms 4452 * @returns Natural logarithm of x. 4453 */ 4454 template<class ScalarUnit> log(const ScalarUnit x)4455 dimensionless::scalar_t log(const ScalarUnit x) noexcept 4456 { 4457 static_assert(traits::is_dimensionless_unit<ScalarUnit>::value, "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`."); 4458 return dimensionless::scalar_t(std::log(x())); 4459 } 4460 4461 /** 4462 * @ingroup UnitMath 4463 * @brief Compute common logarithm 4464 * @details Returns the common (base-10) logarithm of x. 4465 * @param[in] x Value whose logarithm is calculated. If the argument is negative, a 4466 * domain error occurs. 4467 * @returns Common logarithm of x. 4468 */ 4469 template<class ScalarUnit> log10(const ScalarUnit x)4470 dimensionless::scalar_t log10(const ScalarUnit x) noexcept 4471 { 4472 static_assert(traits::is_dimensionless_unit<ScalarUnit>::value, "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`."); 4473 return dimensionless::scalar_t(std::log10(x())); 4474 } 4475 4476 /** 4477 * @ingroup UnitMath 4478 * @brief Break into fractional and integral parts. 4479 * @details The integer part is stored in the object pointed by intpart, and the 4480 * fractional part is returned by the function. Both parts have the same sign 4481 * as x. 4482 * @param[in] x scalar value to break into parts. 4483 * @param[in] intpart Pointer to an object (of the same type as x) where the integral part 4484 * is stored with the same sign as x. 4485 * @returns The fractional part of x, with the same sign. 4486 */ 4487 template<class ScalarUnit> modf(const ScalarUnit x,ScalarUnit * intpart)4488 dimensionless::scalar_t modf(const ScalarUnit x, ScalarUnit* intpart) noexcept 4489 { 4490 static_assert(traits::is_dimensionless_unit<ScalarUnit>::value, "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`."); 4491 4492 UNIT_LIB_DEFAULT_TYPE intp; 4493 dimensionless::scalar_t fracpart = dimensionless::scalar_t(std::modf(x(), &intp)); 4494 *intpart = intp; 4495 return fracpart; 4496 } 4497 4498 /** 4499 * @ingroup UnitMath 4500 * @brief Compute binary exponential function 4501 * @details Returns the base-2 exponential function of x, which is 2 raised to the power x: 2^x. 4502 * 2param[in] x Value of the exponent. 4503 * @returns 2 raised to the power of x. 4504 */ 4505 template<class ScalarUnit> exp2(const ScalarUnit x)4506 dimensionless::scalar_t exp2(const ScalarUnit x) noexcept 4507 { 4508 static_assert(traits::is_dimensionless_unit<ScalarUnit>::value, "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`."); 4509 return dimensionless::scalar_t(std::exp2(x())); 4510 } 4511 4512 /** 4513 * @ingroup UnitMath 4514 * @brief Compute exponential minus one 4515 * @details Returns e raised to the power x minus one: e^x-1. For small magnitude values 4516 * of x, expm1 may be more accurate than exp(x)-1. 4517 * @param[in] x Value of the exponent. 4518 * @returns e raised to the power of x, minus one. 4519 */ 4520 template<class ScalarUnit> expm1(const ScalarUnit x)4521 dimensionless::scalar_t expm1(const ScalarUnit x) noexcept 4522 { 4523 static_assert(traits::is_dimensionless_unit<ScalarUnit>::value, "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`."); 4524 return dimensionless::scalar_t(std::expm1(x())); 4525 } 4526 4527 /** 4528 * @ingroup UnitMath 4529 * @brief Compute logarithm plus one 4530 * @details Returns the natural logarithm of one plus x. For small magnitude values of 4531 * x, logp1 may be more accurate than log(1+x). 4532 * @param[in] x Value whose logarithm is calculated. If the argument is less than -1, a 4533 * domain error occurs. 4534 * @returns The natural logarithm of (1+x). 4535 */ 4536 template<class ScalarUnit> log1p(const ScalarUnit x)4537 dimensionless::scalar_t log1p(const ScalarUnit x) noexcept 4538 { 4539 static_assert(traits::is_dimensionless_unit<ScalarUnit>::value, "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`."); 4540 return dimensionless::scalar_t(std::log1p(x())); 4541 } 4542 4543 /** 4544 * @ingroup UnitMath 4545 * @brief Compute binary logarithm 4546 * @details Returns the binary (base-2) logarithm of x. 4547 * @param[in] x Value whose logarithm is calculated. If the argument is negative, a 4548 * domain error occurs. 4549 * @returns The binary logarithm of x: log2x. 4550 */ 4551 template<class ScalarUnit> log2(const ScalarUnit x)4552 dimensionless::scalar_t log2(const ScalarUnit x) noexcept 4553 { 4554 static_assert(traits::is_dimensionless_unit<ScalarUnit>::value, "Type `ScalarUnit` must be a dimensionless unit derived from `unit_t`."); 4555 return dimensionless::scalar_t(std::log2(x())); 4556 } 4557 4558 //---------------------------------- 4559 // POWER FUNCTIONS 4560 //---------------------------------- 4561 4562 /* pow is implemented earlier in the library since a lot of the unit definitions depend on it */ 4563 4564 /** 4565 * @ingroup UnitMath 4566 * @brief computes the square root of <i>value</i> 4567 * @details Only implemented for linear_scale units. 4568 * @param[in] value `unit_t` derived type to compute the square root of. 4569 * @returns new unit_t, whose units are the square root of value's. E.g. if values 4570 * had units of `square_meter`, then the return type will have units of 4571 * `meter`. 4572 * @note `sqrt` provides a _rational approximation_ of the square root of <i>value</i>. 4573 * In some cases, _both_ the returned value _and_ conversion factor of the returned 4574 * unit type may have errors no larger than `1e-10`. 4575 */ 4576 template<class UnitType, std::enable_if_t<units::traits::has_linear_scale<UnitType>::value, int> = 0> sqrt(const UnitType & value)4577 inline auto sqrt(const UnitType& value) noexcept -> unit_t<square_root<typename units::traits::unit_t_traits<UnitType>::unit_type>, typename units::traits::unit_t_traits<UnitType>::underlying_type, linear_scale> 4578 { 4579 return unit_t<square_root<typename units::traits::unit_t_traits<UnitType>::unit_type>, typename units::traits::unit_t_traits<UnitType>::underlying_type, linear_scale> 4580 (std::sqrt(value())); 4581 } 4582 4583 /** 4584 * @ingroup UnitMath 4585 * @brief Computes the square root of the sum-of-squares of x and y. 4586 * @details Only implemented for linear_scale units. 4587 * @param[in] x unit_t type value 4588 * @param[in] y unit_t type value 4589 * @returns square root of the sum-of-squares of x and y in the same units 4590 * as x. 4591 */ 4592 template<class UnitTypeLhs, class UnitTypeRhs, std::enable_if_t<units::traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value, int> = 0> hypot(const UnitTypeLhs & x,const UnitTypeRhs & y)4593 inline UnitTypeLhs hypot(const UnitTypeLhs& x, const UnitTypeRhs& y) 4594 { 4595 static_assert(traits::is_convertible_unit_t<UnitTypeLhs, UnitTypeRhs>::value, "Parameters of hypot() function are not compatible units."); 4596 return UnitTypeLhs(std::hypot(x(), y.template convert<typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type>()())); 4597 } 4598 4599 //---------------------------------- 4600 // ROUNDING FUNCTIONS 4601 //---------------------------------- 4602 4603 /** 4604 * @ingroup UnitMath 4605 * @brief Round up value 4606 * @details Rounds x upward, returning the smallest integral value that is not less than x. 4607 * @param[in] x Unit value to round up. 4608 * @returns The smallest integral value that is not less than x. 4609 */ 4610 template<class UnitType, class = std::enable_if_t<traits::is_unit_t<UnitType>::value>> 4611 UnitType ceil(const UnitType x) noexcept 4612 { 4613 return UnitType(std::ceil(x())); 4614 } 4615 4616 /** 4617 * @ingroup UnitMath 4618 * @brief Round down value 4619 * @details Rounds x downward, returning the largest integral value that is not greater than x. 4620 * @param[in] x Unit value to round down. 4621 * @returns The value of x rounded downward. 4622 */ 4623 template<class UnitType, class = std::enable_if_t<traits::is_unit_t<UnitType>::value>> 4624 UnitType floor(const UnitType x) noexcept 4625 { 4626 return UnitType(std::floor(x())); 4627 } 4628 4629 /** 4630 * @ingroup UnitMath 4631 * @brief Compute remainder of division 4632 * @details Returns the floating-point remainder of numer/denom (rounded towards zero). 4633 * @param[in] numer Value of the quotient numerator. 4634 * @param[in] denom Value of the quotient denominator. 4635 * @returns The remainder of dividing the arguments. 4636 */ 4637 template<class UnitTypeLhs, class UnitTypeRhs, class = std::enable_if_t<traits::is_unit_t<UnitTypeLhs>::value && traits::is_unit_t<UnitTypeRhs>::value>> 4638 UnitTypeLhs fmod(const UnitTypeLhs numer, const UnitTypeRhs denom) noexcept 4639 { 4640 static_assert(traits::is_convertible_unit_t<UnitTypeLhs, UnitTypeRhs>::value, "Parameters of fmod() function are not compatible units."); 4641 return UnitTypeLhs(std::fmod(numer(), denom.template convert<typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type>()())); 4642 } 4643 4644 /** 4645 * @ingroup UnitMath 4646 * @brief Truncate value 4647 * @details Rounds x toward zero, returning the nearest integral value that is not 4648 * larger in magnitude than x. Effectively rounds towards 0. 4649 * @param[in] x Value to truncate 4650 * @returns The nearest integral value that is not larger in magnitude than x. 4651 */ 4652 template<class UnitType, class = std::enable_if_t<traits::is_unit_t<UnitType>::value>> 4653 UnitType trunc(const UnitType x) noexcept 4654 { 4655 return UnitType(std::trunc(x())); 4656 } 4657 4658 4659 /** 4660 * @ingroup UnitMath 4661 * @brief Round to nearest 4662 * @details Returns the integral value that is nearest to x, with halfway cases rounded 4663 * away from zero. 4664 * @param[in] x value to round. 4665 * @returns The value of x rounded to the nearest integral. 4666 */ 4667 template<class UnitType, class = std::enable_if_t<traits::is_unit_t<UnitType>::value>> 4668 UnitType round(const UnitType x) noexcept 4669 { 4670 return UnitType(std::round(x())); 4671 } 4672 4673 //---------------------------------- 4674 // FLOATING POINT MANIPULATION 4675 //---------------------------------- 4676 4677 /** 4678 * @ingroup UnitMath 4679 * @brief Copy sign 4680 * @details Returns a value with the magnitude and dimension of x, and the sign of y. 4681 * Values x and y do not have to be compatible units. 4682 * @param[in] x Value with the magnitude of the resulting value. 4683 * @param[in] y Value with the sign of the resulting value. 4684 * @returns value with the magnitude and dimension of x, and the sign of y. 4685 */ 4686 template<class UnitTypeLhs, class UnitTypeRhs, class = std::enable_if_t<traits::is_unit_t<UnitTypeLhs>::value && traits::is_unit_t<UnitTypeRhs>::value>> 4687 UnitTypeLhs copysign(const UnitTypeLhs x, const UnitTypeRhs y) noexcept 4688 { 4689 return UnitTypeLhs(std::copysign(x(), y())); // no need for conversion to get the correct sign. 4690 } 4691 4692 /// Overload to copy the sign from a raw double 4693 template<class UnitTypeLhs, class = std::enable_if_t<traits::is_unit_t<UnitTypeLhs>::value>> 4694 UnitTypeLhs copysign(const UnitTypeLhs x, const UNIT_LIB_DEFAULT_TYPE y) noexcept 4695 { 4696 return UnitTypeLhs(std::copysign(x(), y)); 4697 } 4698 4699 //---------------------------------- 4700 // MIN / MAX / DIFFERENCE 4701 //---------------------------------- 4702 4703 /** 4704 * @ingroup UnitMath 4705 * @brief Positive difference 4706 * @details The function returns x-y if x>y, and zero otherwise, in the same units as x. 4707 * Values x and y do not have to be the same type of units, but they do have to 4708 * be compatible. 4709 * @param[in] x Values whose difference is calculated. 4710 * @param[in] y Values whose difference is calculated. 4711 * @returns The positive difference between x and y. 4712 */ 4713 template<class UnitTypeLhs, class UnitTypeRhs, class = std::enable_if_t<traits::is_unit_t<UnitTypeLhs>::value && traits::is_unit_t<UnitTypeRhs>::value>> 4714 UnitTypeLhs fdim(const UnitTypeLhs x, const UnitTypeRhs y) noexcept 4715 { 4716 static_assert(traits::is_convertible_unit_t<UnitTypeLhs, UnitTypeRhs>::value, "Parameters of fdim() function are not compatible units."); 4717 return UnitTypeLhs(std::fdim(x(), y.template convert<typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type>()())); 4718 } 4719 4720 /** 4721 * @ingroup UnitMath 4722 * @brief Maximum value 4723 * @details Returns the larger of its arguments: either x or y, in the same units as x. 4724 * Values x and y do not have to be the same type of units, but they do have to 4725 * be compatible. 4726 * @param[in] x Values among which the function selects a maximum. 4727 * @param[in] y Values among which the function selects a maximum. 4728 * @returns The maximum numeric value of its arguments. 4729 */ 4730 template<class UnitTypeLhs, class UnitTypeRhs, class = std::enable_if_t<traits::is_unit_t<UnitTypeLhs>::value && traits::is_unit_t<UnitTypeRhs>::value>> 4731 UnitTypeLhs fmax(const UnitTypeLhs x, const UnitTypeRhs y) noexcept 4732 { 4733 static_assert(traits::is_convertible_unit_t<UnitTypeLhs, UnitTypeRhs>::value, "Parameters of fmax() function are not compatible units."); 4734 return UnitTypeLhs(std::fmax(x(), y.template convert<typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type>()())); 4735 } 4736 4737 /** 4738 * @ingroup UnitMath 4739 * @brief Minimum value 4740 * @details Returns the smaller of its arguments: either x or y, in the same units as x. 4741 * If one of the arguments in a NaN, the other is returned. 4742 * Values x and y do not have to be the same type of units, but they do have to 4743 * be compatible. 4744 * @param[in] x Values among which the function selects a minimum. 4745 * @param[in] y Values among which the function selects a minimum. 4746 * @returns The minimum numeric value of its arguments. 4747 */ 4748 template<class UnitTypeLhs, class UnitTypeRhs, class = std::enable_if_t<traits::is_unit_t<UnitTypeLhs>::value && traits::is_unit_t<UnitTypeRhs>::value>> 4749 UnitTypeLhs fmin(const UnitTypeLhs x, const UnitTypeRhs y) noexcept 4750 { 4751 static_assert(traits::is_convertible_unit_t<UnitTypeLhs, UnitTypeRhs>::value, "Parameters of fmin() function are not compatible units."); 4752 return UnitTypeLhs(std::fmin(x(), y.template convert<typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type>()())); 4753 } 4754 4755 //---------------------------------- 4756 // OTHER FUNCTIONS 4757 //---------------------------------- 4758 4759 /** 4760 * @ingroup UnitMath 4761 * @brief Compute absolute value 4762 * @details Returns the absolute value of x, i.e. |x|. 4763 * @param[in] x Value whose absolute value is returned. 4764 * @returns The absolute value of x. 4765 */ 4766 template<class UnitType, class = std::enable_if_t<traits::is_unit_t<UnitType>::value>> 4767 UnitType fabs(const UnitType x) noexcept 4768 { 4769 return UnitType(std::fabs(x())); 4770 } 4771 4772 /** 4773 * @ingroup UnitMath 4774 * @brief Compute absolute value 4775 * @details Returns the absolute value of x, i.e. |x|. 4776 * @param[in] x Value whose absolute value is returned. 4777 * @returns The absolute value of x. 4778 */ 4779 template<class UnitType, class = std::enable_if_t<traits::is_unit_t<UnitType>::value>> 4780 UnitType abs(const UnitType x) noexcept 4781 { 4782 return UnitType(std::fabs(x())); 4783 } 4784 4785 /** 4786 * @ingroup UnitMath 4787 * @brief Multiply-add 4788 * @details Returns x*y+z. The function computes the result without losing precision in 4789 * any intermediate result. The resulting unit type is a compound unit of x* y. 4790 * @param[in] x Values to be multiplied. 4791 * @param[in] y Values to be multiplied. 4792 * @param[in] z Value to be added. 4793 * @returns The result of x*y+z 4794 */ 4795 template<class UnitTypeLhs, class UnitMultiply, class UnitAdd, class = std::enable_if_t<traits::is_unit_t<UnitTypeLhs>::value && traits::is_unit_t<UnitMultiply>::value && traits::is_unit_t<UnitAdd>::value>> fma(const UnitTypeLhs x,const UnitMultiply y,const UnitAdd z)4796 auto fma(const UnitTypeLhs x, const UnitMultiply y, const UnitAdd z) noexcept -> decltype(x * y) 4797 { 4798 using resultType = decltype(x * y); 4799 static_assert(traits::is_convertible_unit_t<compound_unit<typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type, typename units::traits::unit_t_traits<UnitMultiply>::unit_type>, typename units::traits::unit_t_traits<UnitAdd>::unit_type>::value, "Unit types are not compatible."); 4800 return resultType(std::fma(x(), y(), resultType(z)())); 4801 } 4802 4803 } // end namespace math 4804 } // end namespace units 4805 4806 //------------------------------ 4807 // std::numeric_limits 4808 //------------------------------ 4809 4810 namespace std 4811 { 4812 template<class Units, typename T, template<typename> class NonLinearScale> 4813 class numeric_limits<units::unit_t<Units, T, NonLinearScale>> 4814 { 4815 public: min()4816 static constexpr units::unit_t<Units, T, NonLinearScale> min() 4817 { 4818 return units::unit_t<Units, T, NonLinearScale>(std::numeric_limits<T>::min()); 4819 } max()4820 static constexpr units::unit_t<Units, T, NonLinearScale> max() 4821 { 4822 return units::unit_t<Units, T, NonLinearScale>(std::numeric_limits<T>::max()); 4823 } lowest()4824 static constexpr units::unit_t<Units, T, NonLinearScale> lowest() 4825 { 4826 return units::unit_t<Units, T, NonLinearScale>(std::numeric_limits<T>::lowest()); 4827 } 4828 }; 4829 } 4830 4831 #ifdef _MSC_VER 4832 # if _MSC_VER <= 1800 4833 # pragma warning(pop) 4834 # undef constexpr 4835 # pragma pop_macro("constexpr") 4836 # undef noexcept 4837 # pragma pop_macro("noexcept") 4838 # undef _ALLOW_KEYWORD_MACROS 4839 # endif // _MSC_VER < 1800 4840 # pragma pop_macro("pascal") 4841 #endif // _MSC_VER 4842 4843 #endif // units_h__ 4844 4845 // For Emacs 4846 // Local Variables: 4847 // Mode: C++ 4848 // c-basic-offset: 2 4849 // fill-column: 116 4850 // tab-width: 4 4851 // End: 4852