From 6d90519d36b3c143c09115581807f9f8cf16f95f Mon Sep 17 00:00:00 2001 From: Guillaume Giraud Date: Fri, 31 Mar 2023 15:59:24 +0200 Subject: [PATCH 1/3] Fix compilation error when using units::sqrt with a float underlying type (as opposed to double) --- include/units/core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/units/core.h b/include/units/core.h index 6ef9e2fc..548a472a 100644 --- a/include/units/core.h +++ b/include/units/core.h @@ -1618,7 +1618,7 @@ namespace units template, int> = 0> constexpr T sqrtNewtonRaphson(T x, T curr, T prev) { - return curr == prev ? curr : sqrtNewtonRaphson(x, 0.5 * (curr + x / curr), curr); + return curr == prev ? curr : sqrtNewtonRaphson(x, T{0.5} * (curr + x / curr), curr); } } // namespace Detail /** @endcond */ // END DOXYGEN IGNORE From 302f308585a2248c534c4f597b2d03f909dfc9c8 Mon Sep 17 00:00:00 2001 From: Guillaume Giraud Date: Fri, 31 Mar 2023 16:21:10 +0200 Subject: [PATCH 2/3] endline CRLF->LF conversion --- include/units/core.h | 7868 +++++++++++++++++++++--------------------- 1 file changed, 3934 insertions(+), 3934 deletions(-) diff --git a/include/units/core.h b/include/units/core.h index 548a472a..28f24e01 100644 --- a/include/units/core.h +++ b/include/units/core.h @@ -1,3934 +1,3934 @@ -//-------------------------------------------------------------------------------------------------- -// -// UnitConversion: A compile-time c++14 unit conversion library with no dependencies -// -//-------------------------------------------------------------------------------------------------- -// -// The MIT License (MIT) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software -// and associated documentation files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING -// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -//-------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2016 Nic Holthaus -// -//-------------------------------------------------------------------------------------------------- -// -// ATTRIBUTION: -// Parts of this work have been adapted from: -// http://stackoverflow.com/questions/35069778/create-comparison-trait-for-template-classes-whose-parameters-are-in-a-different -// http://stackoverflow.com/questions/28253399/check-traits-for-all-variadic-template-arguments/28253503 -// http://stackoverflow.com/questions/36321295/rational-approximation-of-square-root-of-stdratio-at-compile-time?noredirect=1#comment60266601_36321295 -// https://github.com/swatanabe/cppnow17-units -// -//-------------------------------------------------------------------------------------------------- -// -/// @file units/core.h -/// @brief `unit`, dimensional analisys, generic cmath functions, traits (not dimension-specific), -/// and what they're implemented with (`conversion_factor`, unit manipulators, etc.) -// -//-------------------------------------------------------------------------------------------------- - -#pragma once - -#ifndef units_core_h__ -#define units_core_h__ - -#ifndef UNIT_LIB_DEFAULT_TYPE -#define UNIT_LIB_DEFAULT_TYPE double -#endif - -//-------------------- -// INCLUDES -//-------------------- - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if !defined(UNIT_LIB_DISABLE_IOSTREAM) -#include -#include -#include - -//------------------------------ -// STRING FORMATTER -//------------------------------ - -namespace units -{ - namespace detail - { - template - std::string to_string(const T& t) - { - std::string str{std::to_string(t)}; - int offset{1}; - - // remove trailing decimal points for integer value units. Locale aware! - struct lconv* lc; - lc = localeconv(); - char decimalPoint = *lc->decimal_point; - if (str.find_last_not_of('0') == str.find(decimalPoint)) - { - offset = 0; - } - str.erase(str.find_last_not_of('0') + offset, std::string::npos); - return str; - } - } // namespace detail -} // namespace units -#endif - -//------------------------------ -// FORWARD DECLARATIONS -//------------------------------ - -namespace units -{ - template - struct unit_name; - template - struct unit_abbreviation; - - template - inline constexpr const char* unit_name_v = unit_name::value; - template - inline constexpr const char* unit_abbreviation_v = unit_abbreviation::value; -} // namespace units - -//------------------------------ -// MACROS -//------------------------------ - -/** - * @def UNIT_ADD_UNIT_TAGS(namespaceName,nameSingular, namePlural, abbreviation, definition) - * @brief Helper macro for generating the boiler-plate code generating the tags of a new unit. - * @details The macro generates singular, plural, and abbreviated forms - * of the unit definition (e.g. `meter`, `meters`, and `m`), as aliases for the - * unit tag. - * @param namespaceName namespace in which the new units will be encapsulated. - * @param nameSingular singular version of the unit name, e.g. 'meter' - * @param namePlural - plural version of the unit name, e.g. 'meters' - * @param abbreviation - abbreviated unit name, e.g. 'm' - * @param definition - the variadic parameter is used for the definition of the unit - * (e.g. `conversion_factor, units::dimension::length>`) - * @note a variadic template is used for the definition to allow templates with - * commas to be easily expanded. All the variadic 'arguments' should together - * comprise the unit definition. - */ -#define UNIT_ADD_UNIT_TAGS(namespaceName, nameSingular, namePlural, abbreviation, /*definition*/...) \ - inline namespace namespaceName \ - { \ - /** @name UnitConversion (full names plural) */ /** @{ */ struct namePlural : __VA_ARGS__ \ - { \ - }; /** @} */ \ - /** @name UnitConversion (full names singular) */ /** @{ */ using nameSingular = namePlural; /** @} */ \ - /** @name UnitConversion (abbreviated) */ /** @{ */ using abbreviation = namePlural; /** @} */ \ - } \ - namespace traits \ - { \ - template<> \ - struct strong<__VA_ARGS__> \ - { \ - using type = namespaceName::namePlural; \ - }; \ - } - -/** - * @def UNIT_ADD_UNIT_DEFINITION(namespaceName,nameSingular) - * @brief Macro for generating the boiler-plate code for the unit type definition. - * @details The macro generates the definition of the unit container types, e.g. `meter_t` - * @param namespaceName namespace in which the new units will be encapsulated. - * @param nameSingular singular version of the unit name, e.g. 'meter' - */ -#define UNIT_ADD_UNIT_DEFINITION(namespaceName, nameSingular) \ - inline namespace namespaceName \ - { \ - /** @name Unit Containers */ /** @{ */ template \ - using nameSingular##_t = unit; /** @} */ \ - } - -/** - * @def UNIT_ADD_IO(namespaceName,nameSingular, abbreviation) - * @brief Macro for generating the boiler-plate code needed for I/O for a new unit. - * @details The macro generates the code to insert units into an ostream. It - * prints both the value and abbreviation of the unit when invoked. - * @param namespaceName namespace in which the new units will be encapsulated. - * @param nameSingular singular version of the unit name, e.g. 'meter' - * @param abbrev - abbreviated unit name, e.g. 'm' - * @note When UNIT_LIB_DISABLE_IOSTREAM is defined, the macro does not generate any code - */ -#if defined(UNIT_LIB_DISABLE_IOSTREAM) -#define UNIT_ADD_IO(namespaceName, nameSingular, abbrev) -#else -#define UNIT_ADD_IO(namespaceName, nameSingular, abbrev) \ - inline namespace namespaceName \ - { \ - template \ - inline std::ostream& operator<<(std::ostream& os, const nameSingular##_t& obj) \ - { \ - os << obj() << " " #abbrev; \ - return os; \ - } \ - template \ - inline std::string to_string(const nameSingular##_t& obj) \ - { \ - return units::detail::to_string(obj()) + std::string(" " #abbrev); \ - } \ - } -#endif - -/** - * @def UNIT_ADD_NAME(namespaceName,nameSingular,abbreviation) - * @brief Macro for generating constexpr names/abbreviations for units. - * @details The macro generates names for units. E.g. name() of 1_m would be "meter", and - * abbreviation would be "m". - * @param namespaceName namespace in which the new units will be encapsulated. All literal values - * are placed in the `units::literals` namespace. - * @param nameSingular singular version of the unit name, e.g. 'meter' - * @param abbreviation - abbreviated unit name, e.g. 'm' - */ -#define UNIT_ADD_NAME(namespaceName, nameSingular, abbrev) \ - template \ - struct unit_name> \ - { \ - static constexpr const char* value = #nameSingular; \ - }; \ -\ - template \ - struct unit_abbreviation> \ - { \ - static constexpr const char* value = #abbrev; \ - }; - -/** - * @def UNIT_ADD_LITERALS(namespaceName,nameSingular,abbreviation) - * @brief Macro for generating user-defined literals for units. - * @details The macro generates user-defined literals for units. A literal suffix is created - * using the abbreviation (e.g. `10.0_m`). - * @param namespaceName namespace in which the new units will be encapsulated. All literal values - * are placed in the `units::literals` namespace. - * @param nameSingular singular version of the unit name, e.g. 'meter' - * @param abbreviation - abbreviated unit name, e.g. 'm' - * @note When UNIT_HAS_LITERAL_SUPPORT is not defined, the macro does not generate any code - */ -#define UNIT_ADD_LITERALS(namespaceName, nameSingular, abbreviation) \ - namespace literals \ - { \ - constexpr namespaceName::nameSingular##_t operator""_##abbreviation(long double d) noexcept \ - { \ - return namespaceName::nameSingular##_t(static_cast(d)); \ - } \ - constexpr namespaceName::nameSingular##_t operator""_##abbreviation(unsigned long long d) noexcept \ - { \ - return namespaceName::nameSingular##_t(static_cast(d)); \ - } \ - } - -/** - * @def UNIT_ADD(namespaceName,nameSingular, namePlural, abbreviation, definition) - * @brief Macro for generating the boiler-plate code needed for a new unit. - * @details The macro generates singular, plural, and abbreviated forms - * of the unit definition (e.g. `meter`, `meters`, and `m`), as well as the - * appropriately named unit container (e.g. `meter_t`). A literal suffix is created - * using the abbreviation (e.g. `10.0_m`). It also defines a class-specific - * cout function which prints both the value and abbreviation of the unit when invoked. - * @param namespaceName namespace in which the new units will be encapsulated. All literal values - * are placed in the `units::literals` namespace. - * @param nameSingular singular version of the unit name, e.g. 'meter' - * @param namePlural - plural version of the unit name, e.g. 'meters' - * @param abbreviation - abbreviated unit name, e.g. 'm' - * @param definition - the variadic parameter is used for the definition of the unit - * (e.g. `conversion_factor, units::dimension::length>`) - * @note a variadic template is used for the definition to allow templates with - * commas to be easily expanded. All the variadic 'arguments' should together - * comprise the unit definition. - */ -#define UNIT_ADD(namespaceName, nameSingular, namePlural, abbreviation, /*definition*/...) \ - UNIT_ADD_UNIT_TAGS(namespaceName, nameSingular, namePlural, abbreviation, __VA_ARGS__) \ - UNIT_ADD_UNIT_DEFINITION(namespaceName, nameSingular) \ - UNIT_ADD_NAME(namespaceName, nameSingular, abbreviation) \ - UNIT_ADD_IO(namespaceName, nameSingular, abbreviation) \ - UNIT_ADD_LITERALS(namespaceName, nameSingular, abbreviation) - -/** - * @def UNIT_ADD_WITH_CUSTOM_TYPE(namespaceName,nameSingular, namePlural, abbreviation, underlyingType, - * definition) - * @brief Macro for generating the boiler-plate code needed for a new unit with a non-default underlying type. - * @details The macro generates singular, plural, and abbreviated forms - * of the unit definition (e.g. `meter`, `meters`, and `m`), as well as the - * appropriately named unit container (e.g. `meter_t`). A literal suffix is created - * using the abbreviation (e.g. `10.0_m`). It also defines a class-specific - * cout function which prints both the value and abbreviation of the unit when invoked. - * @param namespaceName namespace in which the new units will be encapsulated. All literal values - * are placed in the `units::literals` namespace. - * @param nameSingular singular version of the unit name, e.g. 'meter' - * @param namePlural - plural version of the unit name, e.g. 'meters' - * @param abbreviation - abbreviated unit name, e.g. 'm' - * @param underlyingType - the underlying type, e.g. 'int' or 'float' - * @param definition - the variadic parameter is used for the definition of the unit - * (e.g. `conversion_factor, units::dimension::length>`) - * @note a variadic template is used for the definition to allow templates with - * commas to be easily expanded. All the variadic 'arguments' should together - * comprise the unit definition. - */ -#define UNIT_ADD_WITH_CUSTOM_TYPE( \ - namespaceName, nameSingular, namePlural, abbreviation, underlyingType, /*definition*/...) \ - UNIT_ADD_UNIT_TAGS(namespaceName, nameSingular, namePlural, abbreviation, __VA_ARGS__) \ - UNIT_ADD_CUSTOM_TYPE_UNIT_DEFINITION(namespaceName, nameSingular, underlyingType) \ - UNIT_ADD_IO(namespaceName, nameSingular, abbreviation) \ - UNIT_ADD_LITERALS(namespaceName, nameSingular, abbreviation) - -/** - * @def UNIT_ADD_DECIBEL(namespaceName, nameSingular, abbreviation) - * @brief Macro to create decibel container and literals for an existing unit type. - * @details This macro generates the decibel unit container, cout overload, and literal definitions. - * @param namespaceName namespace in which the new units will be encapsulated. All literal values - * are placed in the `units::literals` namespace. - * @param nameSingular singular version of the dimension name, e.g. 'watt' - * @param abbreviation - abbreviated decibel unit name, e.g. 'dBW' - */ -#define UNIT_ADD_DECIBEL(namespaceName, nameSingular, abbreviation) \ - inline namespace namespaceName \ - { \ - /** @name Unit Containers */ /** @{ */ template \ - using abbreviation##_t = unit; /** @} */ \ - } \ - UNIT_ADD_IO(namespaceName, abbreviation, abbreviation) \ - UNIT_ADD_LITERALS(namespaceName, abbreviation, abbreviation) - -/** - * @def UNIT_ADD_DIMENSION_TRAIT(unitdimension) - * @brief Macro to create the `is_dimension_unit` type trait. - * @details This trait allows users to test whether a given type matches - * an intended dimension. This macro comprises all the boiler-plate - * code necessary to do so. - * @param unitdimension The name of the dimension of unit, e.g. length or mass. - */ - -#define UNIT_ADD_DIMENSION_TRAIT(unitdimension) \ - /** @ingroup TypeTraits*/ \ - /** @brief Trait which tests whether a type represents a unit of unitdimension*/ \ - /** @details Inherits from `std::true_type` or `std::false_type`. Use `is_ ## unitdimension ## _unit_v` to \ - ** test the unit represents a unitdimension quantity.*/ \ - /** @tparam T one or more types to test*/ \ - namespace traits \ - { \ - template \ - struct is_##unitdimension##_unit \ - : std::conjunction<::units::detail::has_dimension_of, units::dimension::unitdimension>...> \ - { \ - }; \ - template \ - inline constexpr bool is_##unitdimension##_unit_v = is_##unitdimension##_unit::value; \ - } - -/** - * @def UNIT_ADD_WITH_METRIC_PREFIXES(nameSingular, namePlural, abbreviation, definition) - * @brief Macro for generating the boiler-plate code needed for a new unit, including its metric - * prefixes from femto to peta. - * @details See UNIT_ADD. In addition to generating the unit definition and containers '(e.g. `meters` and - * 'meter_t', it also creates corresponding units with metric suffixes such as `millimeters`, and - * `millimeter_t`), as well as the literal suffixes (e.g. `10.0_mm`). - * @param namespaceName namespace in which the new units will be encapsulated. All literal values - * are placed in the `units::literals` namespace. - * @param nameSingular singular version of the unit name, e.g. 'meter' - * @param namePlural - plural version of the unit name, e.g. 'meters' - * @param abbreviation - abbreviated unit name, e.g. 'm' - * @param definition - the variadic parameter is used for the definition of the unit - * (e.g. `conversion_factor, units::dimension::length>`) - * @note a variadic template is used for the definition to allow templates with - * commas to be easily expanded. All the variadic 'arguments' should together - * comprise the unit definition. - */ -#define UNIT_ADD_WITH_METRIC_PREFIXES(namespaceName, nameSingular, namePlural, abbreviation, /*definition*/...) \ - UNIT_ADD(namespaceName, nameSingular, namePlural, abbreviation, __VA_ARGS__) \ - UNIT_ADD(namespaceName, femto##nameSingular, femto##namePlural, f##abbreviation, femto) \ - UNIT_ADD(namespaceName, pico##nameSingular, pico##namePlural, p##abbreviation, pico) \ - UNIT_ADD(namespaceName, nano##nameSingular, nano##namePlural, n##abbreviation, nano) \ - UNIT_ADD(namespaceName, micro##nameSingular, micro##namePlural, u##abbreviation, micro) \ - UNIT_ADD(namespaceName, milli##nameSingular, milli##namePlural, m##abbreviation, milli) \ - UNIT_ADD(namespaceName, centi##nameSingular, centi##namePlural, c##abbreviation, centi) \ - UNIT_ADD(namespaceName, deci##nameSingular, deci##namePlural, d##abbreviation, deci) \ - UNIT_ADD(namespaceName, deca##nameSingular, deca##namePlural, da##abbreviation, deca) \ - UNIT_ADD(namespaceName, hecto##nameSingular, hecto##namePlural, h##abbreviation, hecto) \ - UNIT_ADD(namespaceName, kilo##nameSingular, kilo##namePlural, k##abbreviation, kilo) \ - UNIT_ADD(namespaceName, mega##nameSingular, mega##namePlural, M##abbreviation, mega) \ - UNIT_ADD(namespaceName, giga##nameSingular, giga##namePlural, G##abbreviation, giga) \ - UNIT_ADD(namespaceName, tera##nameSingular, tera##namePlural, T##abbreviation, tera) \ - UNIT_ADD(namespaceName, peta##nameSingular, peta##namePlural, P##abbreviation, peta) - -/** - * @def UNIT_ADD_WITH_METRIC_AND_BINARY_PREFIXES(nameSingular, namePlural, abbreviation, definition) - * @brief Macro for generating the boiler-plate code needed for a new unit, including its metric - * prefixes from femto to peta, and binary prefixes from kibi to exbi. - * @details See UNIT_ADD. In addition to generating the unit definition and containers '(e.g. `bytes` and 'byte_t', - * it also creates corresponding units with metric suffixes such as `millimeters`, and `millimeter_t`), as - * well as the literal suffixes (e.g. `10.0_B`). - * @param namespaceName namespace in which the new units will be encapsulated. All literal values - * are placed in the `units::literals` namespace. - * @param nameSingular singular version of the unit name, e.g. 'byte' - * @param namePlural - plural version of the unit name, e.g. 'bytes' - * @param abbreviation - abbreviated unit name, e.g. 'B' - * @param definition - the variadic parameter is used for the definition of the unit - * (e.g. `conversion_factor, units::dimension::data>`) - * @note a variadic template is used for the definition to allow templates with - * commas to be easily expanded. All the variadic 'arguments' should together - * comprise the unit definition. - */ -#define UNIT_ADD_WITH_METRIC_AND_BINARY_PREFIXES( \ - namespaceName, nameSingular, namePlural, abbreviation, /*definition*/...) \ - UNIT_ADD_WITH_METRIC_PREFIXES(namespaceName, nameSingular, namePlural, abbreviation, __VA_ARGS__) \ - UNIT_ADD(namespaceName, kibi##nameSingular, kibi##namePlural, Ki##abbreviation, kibi) \ - UNIT_ADD(namespaceName, mebi##nameSingular, mebi##namePlural, Mi##abbreviation, mebi) \ - UNIT_ADD(namespaceName, gibi##nameSingular, gibi##namePlural, Gi##abbreviation, gibi) \ - UNIT_ADD(namespaceName, tebi##nameSingular, tebi##namePlural, Ti##abbreviation, tebi) \ - UNIT_ADD(namespaceName, pebi##nameSingular, pebi##namePlural, Pi##abbreviation, pebi) \ - UNIT_ADD(namespaceName, exbi##nameSingular, exbi##namePlural, Ei##abbreviation, exbi) - -//-------------------- -// UNITS NAMESPACE -//-------------------- - -/** - * @namespace units - * @brief Unit Conversion Library namespace - */ -namespace units -{ - //---------------------------------- - // DOXYGEN - //---------------------------------- - - /** - * @defgroup UnitContainers Unit Containers - * @brief Defines a series of classes which contain dimensioned values. Unit containers - * store a value, and support various arithmetic operations. - */ - - /** - * @defgroup UnitTypes Unit Types - * @brief Defines a series of classes which represent units. These types are tags used by - * the conversion function, to create compound units, or to create `unit` types. - * By themselves, they are not containers and have no stored value. - */ - - /** - * @defgroup UnitManipulators Unit Manipulators - * @brief Defines a series of classes used to manipulate unit types, such as `inverse<>`, `squared<>`, and - * metric prefixes. Unit manipulators can be chained together, e.g. - * `inverse>>` to represent picoseconds^-2. - */ - - /** - * @defgroup UnitMath Unit Math - * @brief Defines a collection of unit-enabled, strongly-typed versions of `` functions. - * @details Includes most c++11 extensions. - */ - - /** - * @defgroup Conversion Explicit Conversion - * @brief Functions used to convert values of one logical type to another. - */ - - /** - * @defgroup TypeTraits Type Traits - * @brief Defines a series of classes to obtain unit type information at compile-time. - */ - - /** - * @defgroup STDTypeTraits Standard Type Traits Specializations - * @brief Specialization of `std::common_type` for unit types. - */ - - //------------------------------ - // FORWARD DECLARATIONS - //------------------------------ - - /** @cond */ // DOXYGEN IGNORE - namespace constants - { - namespace detail - { - inline constexpr UNIT_LIB_DEFAULT_TYPE PI_VAL = 3.14159265358979323846264338327950288419716939937510; - } - } // namespace constants - /** @endcond */ // END DOXYGEN IGNORE - - //------------------------------ - // RATIO TRAITS - //------------------------------ - - /** - * @ingroup TypeTraits - * @{ - */ - - namespace traits - { - /** @cond */ // DOXYGEN IGNORE - namespace detail - { - template - struct is_ratio_impl : std::false_type - { - }; - - template - struct is_ratio_impl> : std::true_type - { - }; - } // namespace detail - /** @endcond */ // END DOXYGEN IGNORE - - /** - * @brief Trait that tests whether a type represents a std::ratio. - * @details Inherits from `std::true_type` or `std::false_type`. Use `is_ratio_v` to test - * whether `class T` implements a std::ratio. - */ - template - using is_ratio = detail::is_ratio_impl; - - template - inline constexpr bool is_ratio_v = is_ratio::value; - } // namespace traits - - //------------------------------ - // UNIT TRAITS - //------------------------------ - - /** - * @brief namespace representing type traits which can access the properties of types provided by the units library. - */ - namespace traits - { -#ifdef FOR_DOXYGEN_PURPOSES_ONLY - /** - * @ingroup TypeTraits - * @brief Traits class defining the properties of units. - * @details The units library determines certain properties of the units passed to - * them and what they represent by using the members of the corresponding - * unit_traits instantiation. - */ - template - struct conversion_factor_traits - { - typedef typename T::dimension_type - dimension_type; ///< Unit type that the unit was derived from. May be a `dimension` or another - ///< `conversion_factor`. Use the `dimension_of_t` trait to find the SI dimension type. - ///< This will be `void` if type `T` is not a unit. - typedef typename T::conversion_ratio - conversion_ratio; ///< `std::ratio` representing the conversion factor to the `dimension_type`. This - ///< will be `void` if type `T` is not a unit. - 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. - typedef typename T::translation_ratio - translation_ratio; ///< `std::ratio` representing a datum translation to the dimension (i.e. degrees C - ///< to degrees F conversion). This will be `void` if type `T` is not a unit. - }; -#endif - /** @cond */ // DOXYGEN IGNORE - /** - * @brief unit traits implementation for classes which are not units. - */ - template - struct conversion_factor_traits - { - using dimension_type = void; - using conversion_ratio = void; - using pi_exponent_ratio = void; - using translation_ratio = void; - }; - - template - struct conversion_factor_traits> - { - using dimension_type = - typename T::dimension_type; ///< Unit type that the unit was derived from. May be a `dimension` or - ///< another `conversion_factor`. Use the `dimension_of_t` trait to find the - ///< SI dimension type. This will be `void` if type `T` is not a unit. - using conversion_ratio = - typename T::conversion_ratio; ///< `std::ratio` representing the conversion factor to the - ///< `dimension_type`. This will be `void` if type `T` is not a unit. - using pi_exponent_ratio = - typename T::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. - using translation_ratio = - typename T::translation_ratio; ///< `std::ratio` representing a datum translation to the dimension (i.e. - ///< degrees C to degrees F conversion). This will be `void` if type `T` - ///< is not a unit. - }; - /** @endcond */ // END DOXYGEN IGNORE - } // namespace traits - - /** @cond */ // DOXYGEN IGNORE - namespace detail - { - /** - * @brief helper type to identify units. - * @details A non-templated base class for `unit` which enables compile-time testing. - */ - struct _conversion_factor - { - }; - } // namespace detail - - /** @endcond */ // END DOXYGEN IGNORE - - namespace traits - { - /** - * @ingroup TypeTraits - * @brief Traits which tests if a class is a `unit` - * @details Inherits from `std::true_type` or `std::false_type`. Use `is_unit_v` to test - * whether `class T` implements a `unit`. - */ - template - using is_conversion_factor = typename std::is_base_of::type; - - template - inline constexpr bool is_conversion_factor_v = is_conversion_factor::value; - - /** - * @ingroup TypeTraits - * @brief SFINAE-able trait that maps a `conversion_factor` to its strengthened type. - * @details If `T` is a cv-unqualified `conversion_factor`, the member `type` alias names the strong - * type alias of `T`, if any, and `T` otherwise. Otherwise, there is no `type` member. This may - * be specialized only if `T` depends on a program-defined type. - */ - template - struct strong : std::enable_if && std::is_same_v>, T> - { - }; - - template - using strong_t = typename strong::type; - } // namespace traits - - /** @} */ // end of TypeTraits - - //------------------------------ - // DIMENSIONS - //------------------------------ - // see: https://github.com/swatanabe/cppnow17-units - // license for this code: https://github.com/swatanabe/cppnow17-units/blob/master/LICENSE_1_0.txt - //------------------------------ - - template - struct dim - { - using dimension = D; - using exponent = E; - }; - - template - struct dimension_t; - - template<> - struct dimension_t<> - { - static const constexpr bool empty = true; - }; - - template - struct dimension_t - { - static const constexpr bool empty = false; - using front = D0; - using pop_front = dimension_t; - }; - - template - using combine_dims = dim>; - - template - struct merge_dimensions_impl; - - constexpr int const_strcmp(const char* lhs, const char* rhs) - { - return (*lhs && *rhs) ? (*lhs == *rhs ? const_strcmp(lhs + 1, rhs + 1) : (*lhs < *rhs ? -1 : 1)) - : ((!*lhs && !*rhs) ? 0 : (!*lhs ? -1 : 1)); - } - - template - struct merge_dimensions_recurse_impl; - - template<> - struct merge_dimensions_recurse_impl - { - template - using apply = typename merge_dimensions_impl::template apply; - }; - - template - struct append; - - template - struct append, dimension_t> - { - using type = dimension_t; - }; - - template<> - struct merge_dimensions_recurse_impl - { - template - using apply = typename append, T>::type; - }; - - template<> - struct merge_dimensions_recurse_impl - { - template - using apply = typename append, U>::type; - }; - - template<> - struct merge_dimensions_recurse_impl - { - template - using apply = dimension_t; - }; - - template - using merge_dimensions_recurse = - typename merge_dimensions_recurse_impl::template apply; - - template<> - struct merge_dimensions_impl<1> - { - template - using apply = merge_dimensions_recurse; - }; - - template<> - struct merge_dimensions_impl<-1> - { - template - using apply = merge_dimensions_recurse; - }; - - template - struct merge_dimensions_combine_impl; - - template<> - struct merge_dimensions_combine_impl - { - template - using apply = merge_dimensions_recurse; - }; - - template<> - struct merge_dimensions_combine_impl - { - template - using apply = merge_dimensions_recurse; - }; - - template<> - struct merge_dimensions_impl<0> - { - template - using apply = typename merge_dimensions_combine_impl< - std::ratio_add::num == - 0>::template apply>, - R...>; - }; - - template - using merge_dimensions = merge_dimensions_recurse; - - template - struct dimension_pow_impl; - - template - struct dimension_pow_impl...>, R> - { - using type = dimension_t>...>; - }; - - template - using dimension_pow = typename dimension_pow_impl::type; - - template - using dimension_root = dimension_pow, E>>; - - template - using dimension_multiply = merge_dimensions; - - template - using dimension_divide = merge_dimensions>>; - - template, class... Rest> - struct make_dimension_list - { - using type = dimension_multiply>, typename make_dimension_list::type>; - }; - - template - struct make_dimension_list, N0, Rest...> - { - using type = - dimension_multiply, N0>, typename make_dimension_list::type>; - }; - - template<> - struct make_dimension_list<> - { - using type = dimension_t<>; - }; - - template - using make_dimension = typename make_dimension_list::type; - - //------------------------------ - // UNIT DIMENSIONS - //------------------------------ - - /** - * @brief namespace representing the implemented base and derived unit types. These will not generally be - * needed by library users. - * @sa dimension for the definition of the dimension parameters. - */ - namespace dimension - { - // DIMENSION TAGS - struct length_tag - { - static constexpr const char* const name = "length"; - static constexpr const char* const abbreviation = "m"; - }; - - struct mass_tag - { - static constexpr const char* const name = "mass"; - static constexpr const char* const abbreviation = "kg"; - }; - - struct time_tag - { - static constexpr const char* const name = "time"; - static constexpr const char* const abbreviation = "s"; - }; - - struct current_tag - { - static constexpr const char* const name = "current"; - static constexpr const char* const abbreviation = "A"; - }; - - struct temperature_tag - { - static constexpr const char* const name = "temperature"; - static constexpr const char* const abbreviation = "K"; - }; - - struct substance_tag - { - static constexpr const char* const name = "amount of substance"; - static constexpr const char* const abbreviation = "mol"; - }; - - struct luminous_intensity_tag - { - static constexpr const char* const name = "luminous intensity"; - static constexpr const char* const abbreviation = "cd"; - }; - - struct angle_tag - { - static constexpr const char* const name = "angle"; - static constexpr const char* const abbreviation = "rad"; - }; - - struct data_tag - { - static constexpr const char* const name = "data"; - static constexpr const char* const abbreviation = "byte"; - }; - - // SI BASE UNITS - using length = make_dimension; - using mass = make_dimension; - using time = make_dimension; - using current = make_dimension; - using temperature = make_dimension; - using substance = make_dimension; - using luminous_intensity = make_dimension; - - // dimensionless (DIMENSIONLESS) TYPES - using dimensionless = dimension_t<>; ///< Represents a quantity with no dimension. - using angle = make_dimension; ///< Represents a quantity of angle - - // SI DERIVED UNIT TYPES - using solid_angle = dimension_pow>; ///< Represents an SI derived unit of solid angle - using frequency = make_dimension>; ///< Represents an SI derived unit of frequency - using velocity = dimension_divide; ///< Represents an SI derived unit of velocity - using angular_velocity = dimension_divide; ///< Represents an SI derived unit of angular velocity - using acceleration = dimension_divide; ///< Represents an SI derived unit of acceleration - using force = dimension_multiply; ///< Represents an SI derived unit of force - using area = dimension_pow>; ///< Represents an SI derived unit of area - using pressure = dimension_divide; ///< Represents an SI derived unit of pressure - using charge = dimension_multiply; ///< Represents an SI derived unit of charge - using energy = dimension_multiply; ///< Represents an SI derived unit of energy - using power = dimension_divide; ///< Represents an SI derived unit of power - using voltage = dimension_divide; ///< Represents an SI derived unit of voltage - using capacitance = dimension_divide; ///< Represents an SI derived unit of capacitance - using impedance = dimension_divide; ///< Represents an SI derived unit of impedance - using conductance = dimension_divide; ///< Represents an SI derived unit of conductance - using magnetic_flux = dimension_divide; ///< Represents an SI derived unit of magnetic flux - using magnetic_field_strength = make_dimension, time, std::ratio<-2>, current, - std::ratio<-1>>; ///< Represents an SI derived unit of magnetic field strength - using inductance = dimension_multiply; ///< Represents an SI derived unit of inductance - using luminous_flux = - dimension_multiply; ///< Represents an SI derived unit of luminous flux - using illuminance = make_dimension, length, - std::ratio<-2>>; ///< Represents an SI derived unit of illuminance - using radioactivity = make_dimension, time, - std::ratio<-2>>; ///< Represents an SI derived unit of radioactivity - - // OTHER UNIT TYPES - using torque = dimension_multiply; ///< Represents an SI derived unit of torque - using volume = dimension_pow>; ///< Represents an SI derived unit of volume - using density = dimension_divide; ///< Represents an SI derived unit of density - using concentration = make_dimension>; ///< Represents a unit of concentration - using data = make_dimension; ///< Represents a unit of data size - using data_transfer_rate = make_dimension>; ///< Represents a unit of data transfer rate - } // namespace dimension - - //------------------------------ - // UNIT CLASSES - //------------------------------ - - /** @cond */ // DOXYGEN IGNORE - /** - * @brief unit type template specialization for units derived from dimensions. - */ - template - struct conversion_factor; - template - struct conversion_factor, PiExponent, Translation> - : units::detail::_conversion_factor - { - static_assert(traits::is_ratio_v, - "Template parameter `Conversion` must be a `std::ratio` representing the conversion factor to " - "`Dimension`."); - static_assert(traits::is_ratio_v, - "Template parameter `PiExponent` must be a `std::ratio` representing the exponents of Pi the unit has."); - static_assert(traits::is_ratio_v, - "Template parameter `Translation` must be a `std::ratio` representing an additive translation required by " - "the unit conversion."); - - using dimension_type = dimension_t; - using conversion_ratio = Conversion; - using translation_ratio = Translation; - using pi_exponent_ratio = PiExponent; - }; - /** @endcond */ // END DOXYGEN IGNORE - - /** @cond */ // DOXYGEN IGNORE - namespace traits - { - template - struct strong> - { - using type = conversion_factor; - }; - } // namespace traits - - namespace detail - { - template - conversion_factor conversion_factor_base_t_impl(conversion_factor*); - - template - using conversion_factor_base_t = decltype(conversion_factor_base_t_impl(std::declval())); - - /** - * @brief dimension_of_t trait implementation - * @details recursively seeks dimension type that a unit is derived from. Since units can be - * derived from other units, the `dimension_type` typedef may not represent this type. - */ - template - struct dimension_of_impl : dimension_of_impl> - { - }; - - template - struct dimension_of_impl> - : dimension_of_impl - { - }; - - template - struct dimension_of_impl> - { - using type = dimension_t; - }; - - template<> - struct dimension_of_impl - { - using type = void; - }; - } // namespace detail - /** @endcond */ // END DOXYGEN IGNORE - - namespace traits - { - /** - * @brief Trait which returns the `dimension_t` type that a unit is originally derived from. - * @details Since units can be derived from other `conversion_factor` types in addition to `dimension_t` - * types, the `dimension_type` typedef will not always be a `dimension_t` (or unit dimension). - */ - template - using dimension_of_t = typename units::detail::dimension_of_impl::type; - } // namespace traits - - /** @cond */ // DOXYGEN IGNORE - template class NonLinearScale> - class unit; - - namespace detail - { - template - struct has_dimension_of_impl : std::false_type - { - }; - - template - struct has_dimension_of_impl : has_dimension_of_impl, Dim, true>::type - { - }; - - template - struct has_dimension_of_impl, Dim, true> - : std::is_same::dimension_type, Dim>::type - { - }; - - template class N, class Dim> - struct has_dimension_of_impl, Dim> : std::is_same, Dim>::type - { - }; - - template - using has_dimension_of = typename has_dimension_of_impl>::type; - } // namespace detail - /** @endcond */ // END DOXYGEN IGNORE - - /** - * @brief Type representing an arbitrary unit. - * @ingroup UnitTypes - * @details `conversion_factor` types are used as tags for the `conversion` function. They are *not* containers - * (see `unit` for a container class). Each unit is defined by: - * - * - A `std::ratio` defining the conversion factor to the dimension type. (e.g. `std::ratio<1,12>` for - * inches to feet) - * - A dimension that the unit is derived from (or a unit dimension. Must be of type - * `conversion_factor` or `dimension`) - * - An exponent representing factors of PI required by the conversion. (e.g. `std::ratio<-1>` for a - * radians to degrees conversion) - * - a ratio representing a datum translation required for the conversion (e.g. `std::ratio<32>` for a - * farenheit to celsius conversion) - * - * Typically, a specific unit, like `meters`, would be implemented as a type alias - * of `conversion_factor`, i.e. `using meters = conversion_factor, - * units::dimension::length>`, or `using inches = conversion_factor, feet>`. - * @tparam Conversion std::ratio representing dimensionless multiplication factor. - * @tparam BaseUnit Unit type which this unit is derived from. May be a `dimension`, or another - * `conversion_factor`. - * @tparam PiExponent std::ratio representing the exponent of pi required by the conversion. - * @tparam Translation std::ratio representing any datum translation required by the conversion. - */ - template, class Translation = std::ratio<0>> - struct conversion_factor : units::detail::_conversion_factor - { - static_assert(traits::is_conversion_factor_v, - "Template parameter `BaseUnit` must be a `conversion_factor` type."); - static_assert(traits::is_ratio_v, - "Template parameter `Conversion` must be a `std::ratio` representing the conversion factor to `BaseUnit`."); - static_assert(traits::is_ratio_v, - "Template parameter `PiExponent` must be a `std::ratio` representing the exponents of Pi the unit has."); - - using dimension_type = units::traits::dimension_of_t; - using conversion_ratio = typename std::ratio_multiply; - using pi_exponent_ratio = typename std::ratio_add; - using translation_ratio = - typename std::ratio_add, - typename BaseUnit::translation_ratio>; - }; - - //------------------------------ - // UNIT MANIPULATORS - //------------------------------ - - /** @cond */ // DOXYGEN IGNORE - namespace detail - { - /** - * @brief implementation of `unit_multiply`. - * @details multiplies two units. The dimension becomes the dimensions of each with their exponents - * added together. The conversion factors of each are multiplied by each other. Pi exponent ratios - * are added, and datum translations are removed. - */ - template - struct unit_multiply_impl - { - using type = conversion_factor< - std::ratio_multiply, - dimension_multiply, - traits::dimension_of_t>, - std::ratio_add, std::ratio<0>>; - }; - - /** - * @brief represents the type of two units multiplied together. - * @details recalculates conversion and exponent ratios at compile-time. - */ - template - using unit_multiply = typename unit_multiply_impl::type; - - /** - * @brief implementation of `unit_divide`. - * @details divides two units. The dimension becomes the dimensions of each with their exponents - * subtracted from each other. The conversion factors of each are divided by each other. Pi - * exponent ratios are subtracted, and datum translations are removed. - */ - template - struct unit_divide_impl - { - using type = - conversion_factor, - dimension_divide, - traits::dimension_of_t>, - std::ratio_subtract, - std::ratio<0>>; - }; - - /** - * @brief represents the type of two units divided by each other. - * @details recalculates conversion and exponent ratios at compile-time. - */ - template - using unit_divide = typename unit_divide_impl::type; - - /** - * @brief implementation of `inverse` - * @details inverts a unit (equivalent to 1/unit). The `dimension` and pi exponents are all multiplied by - * -1. The conversion ratio numerator and denominator are swapped. Datum translation - * ratios are removed. - */ - template - struct inverse_impl - { - using type = conversion_factor, - dimension_pow< - traits::dimension_of_t::dimension_type>, - std::ratio<-1>>, - std::ratio_multiply::pi_exponent_ratio, - std::ratio<-1>>, - std::ratio<0>>; // inverses are rates or change, the translation factor goes away. - }; - } // namespace detail - /** @endcond */ // END DOXYGEN IGNORE - - /** - * @brief represents the inverse unit type of `class U`. - * @ingroup UnitManipulators - * @tparam U `unit` type to invert. - * @details E.g. `inverse` will represent meters^-1 (i.e. 1/meters). - */ - template - using inverse = typename units::detail::inverse_impl::type; - - /** @cond */ // DOXYGEN IGNORE - namespace detail - { - /** - * @brief implementation of `squared` - * @details Squares the conversion ratio, `dimension` exponents, pi exponents, and removes - * datum translation ratios. - */ - template - struct squared_impl - { - static_assert(traits::is_conversion_factor_v, "Template parameter `Unit` must be a `unit` type."); - using Conversion = typename Unit::conversion_ratio; - using type = conversion_factor, - dimension_pow, std::ratio<2>>, - std::ratio_multiply>, typename Unit::translation_ratio>; - }; - } // namespace detail - /** @endcond */ // END DOXYGEN IGNORE - - /** - * @brief represents the unit type of `class U` squared - * @ingroup UnitManipulators - * @tparam U `unit` type to square. - * @details E.g. `square` will represent meters^2. - */ - template - using squared = typename units::detail::squared_impl::type; - - /** @cond */ // DOXYGEN IGNORE - namespace detail - { - /** - * @brief implementation of `cubed` - * @details Cubes the conversion ratio, `dimension` exponents, pi exponents, and removes - * datum translation ratios. - */ - template - struct cubed_impl - { - static_assert(traits::is_conversion_factor_v, "Template parameter `Unit` must be a `unit` type."); - using Conversion = typename Unit::conversion_ratio; - using type = conversion_factor>, - dimension_pow, std::ratio<3>>, - std::ratio_multiply>, typename Unit::translation_ratio>; - }; - } // namespace detail - /** @endcond */ // END DOXYGEN IGNORE - - /** - * @brief represents the type of `class U` cubed. - * @ingroup UnitManipulators - * @tparam U `unit` type to cube. - * @details E.g. `cubed` will represent meters^3. - */ - template - using cubed = typename units::detail::cubed_impl::type; - - /** @cond */ // DOXYGEN IGNORE - // clang-format off - namespace detail - { - //---------------------------------- - // RATIO_SQRT IMPLEMENTATION - //---------------------------------- - - using Zero = std::ratio<0>; - using One = std::ratio<1>; - template using Square = std::ratio_multiply; - - // Find the largest std::integer N such that Predicate::value is true. - template