WPILibC++ 2024.3.2-113-g0c822b4
base.h
Go to the documentation of this file.
1// Copyright (c) FIRST and other WPILib contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the WPILib BSD license file in the root directory of this project.
4
5// Copyright (c) 2016 Nic Holthaus
6//
7// The MIT License (MIT)
8//
9// Permission is hereby granted, free of charge, to any person obtaining a copy
10// of this software and associated documentation files (the "Software"), to deal
11// in the Software without restriction, including without limitation the rights
12// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13// copies of the Software, and to permit persons to whom the Software is
14// furnished to do so, subject to the following conditions:
15//
16// The above copyright notice and this permission notice shall be included in
17// all copies or substantial portions of the Software.
18//
19// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25// SOFTWARE.
26//
27// ATTRIBUTION:
28// Parts of this work have been adapted from:
29// http://stackoverflow.com/questions/35069778/create-comparison-trait-for-template-classes-whose-parameters-are-in-a-different
30// http://stackoverflow.com/questions/28253399/check-traits-for-all-variadic-template-arguments/28253503
31// http://stackoverflow.com/questions/36321295/rational-approximation-of-square-root-of-stdratio-at-compile-time?noredirect=1#comment60266601_36321295
32//
33
34/// @file units.h
35/// @brief Complete implementation of `units` - a compile-time, header-only,
36/// unit conversion library built on c++14 with no dependencies.
37
38#pragma once
39
40#ifdef _MSC_VER
41# pragma push_macro("pascal")
42# undef pascal
43# if _MSC_VER <= 1800
44# define _ALLOW_KEYWORD_MACROS
45# pragma warning(push)
46# pragma warning(disable : 4520)
47# pragma push_macro("constexpr")
48# define constexpr /*constexpr*/
49# pragma push_macro("noexcept")
50# define noexcept throw()
51# endif // _MSC_VER < 1800
52#endif // _MSC_VER
53
54#if !defined(_MSC_VER) || _MSC_VER > 1800
55# define UNIT_HAS_LITERAL_SUPPORT
56#endif
57
58#ifndef UNIT_LIB_DEFAULT_TYPE
59# define UNIT_LIB_DEFAULT_TYPE double
60#endif
61
62//--------------------
63// INCLUDES
64//--------------------
65
66#include <chrono>
67#include <ratio>
68#include <type_traits>
69#include <cstdint>
70#include <cmath>
71#include <limits>
72
73#if defined(UNIT_LIB_ENABLE_IOSTREAM)
74 #include <iostream>
75 #include <locale>
76 #include <string>
77#endif
78#if __has_include(<fmt/format.h>) && !defined(UNIT_LIB_DISABLE_FMT)
79 #include <locale>
80 #include <string>
81 #include <fmt/format.h>
82#endif
83
84#include <gcem.hpp>
85
86//------------------------------
87// STRING FORMATTER
88//------------------------------
89
90namespace units
91{
92 namespace detail
93 {
94 template <typename T> std::string to_string(const T& t)
95 {
96 std::string str{ std::to_string(t) };
97 int offset{ 1 };
98
99 // remove trailing decimal points for integer value units. Locale aware!
100 struct lconv * lc;
101 lc = localeconv();
102 char decimalPoint = *lc->decimal_point;
103 if (str.find_last_not_of('0') == str.find(decimalPoint)) { offset = 0; }
104 str.erase(str.find_last_not_of('0') + offset, std::string::npos);
105 return str;
106 }
107 }
108}
109
110namespace units
111{
112 template<typename T> inline constexpr const char* name(const T&);
113 template<typename T> inline constexpr const char* abbreviation(const T&);
114}
115
116//------------------------------
117// MACROS
118//------------------------------
119
120/**
121 * @def UNIT_ADD_UNIT_TAGS(namespaceName,nameSingular, namePlural, abbreviation, definition)
122 * @brief Helper macro for generating the boiler-plate code generating the tags of a new unit.
123 * @details The macro generates singular, plural, and abbreviated forms
124 * of the unit definition (e.g. `meter`, `meters`, and `m`), as aliases for the
125 * unit tag.
126 * @param namespaceName namespace in which the new units will be encapsulated.
127 * @param nameSingular singular version of the unit name, e.g. 'meter'
128 * @param namePlural - plural version of the unit name, e.g. 'meters'
129 * @param abbreviation - abbreviated unit name, e.g. 'm'
130 * @param definition - the variadic parameter is used for the definition of the unit
131 * (e.g. `unit<std::ratio<1>, units::category::length_unit>`)
132 * @note a variadic template is used for the definition to allow templates with
133 * commas to be easily expanded. All the variadic 'arguments' should together
134 * comprise the unit definition.
135 */
136#define UNIT_ADD_UNIT_TAGS(namespaceName,nameSingular, namePlural, abbreviation, /*definition*/...)\
137 namespace namespaceName\
138 {\
139 /** @name Units (full names plural) */ /** @{ */ typedef __VA_ARGS__ namePlural; /** @} */\
140 /** @name Units (full names singular) */ /** @{ */ typedef namePlural nameSingular; /** @} */\
141 /** @name Units (abbreviated) */ /** @{ */ typedef namePlural abbreviation; /** @} */\
142 }
143
144/**
145 * @def UNIT_ADD_UNIT_DEFINITION(namespaceName,nameSingular)
146 * @brief Macro for generating the boiler-plate code for the unit_t type definition.
147 * @details The macro generates the definition of the unit container types, e.g. `meter_t`
148 * @param namespaceName namespace in which the new units will be encapsulated.
149 * @param nameSingular singular version of the unit name, e.g. 'meter'
150 */
151#define UNIT_ADD_UNIT_DEFINITION(namespaceName,nameSingular)\
152 namespace namespaceName\
153 {\
154 /** @name Unit Containers */ /** @{ */ typedef unit_t<nameSingular> nameSingular ## _t; /** @} */\
155 }
156
157/**
158 * @def UNIT_ADD_CUSTOM_TYPE_UNIT_DEFINITION(namespaceName,nameSingular,underlyingType)
159 * @brief Macro for generating the boiler-plate code for a unit_t type definition with a non-default underlying type.
160 * @details The macro generates the definition of the unit container types, e.g. `meter_t`
161 * @param namespaceName namespace in which the new units will be encapsulated.
162 * @param nameSingular singular version of the unit name, e.g. 'meter'
163 * @param underlyingType the underlying type
164 */
165#define UNIT_ADD_CUSTOM_TYPE_UNIT_DEFINITION(namespaceName,nameSingular, underlyingType)\
166 namespace namespaceName\
167 {\
168 /** @name Unit Containers */ /** @{ */ typedef unit_t<nameSingular,underlyingType> nameSingular ## _t; /** @} */\
169 }
170/**
171 * @def UNIT_ADD_IO(namespaceName,nameSingular, abbreviation)
172 * @brief Macro for generating the boiler-plate code needed for I/O for a new unit.
173 * @details The macro generates the code to insert units into an ostream. It
174 * prints both the value and abbreviation of the unit when invoked.
175 * @param namespaceName namespace in which the new units will be encapsulated.
176 * @param nameSingular singular version of the unit name, e.g. 'meter'
177 * @param abbrev - abbreviated unit name, e.g. 'm'
178 * @note When UNIT_LIB_ENABLE_IOSTREAM isn't defined, the macro does not generate any code
179 */
180#if __has_include(<fmt/format.h>) && !defined(UNIT_LIB_DISABLE_FMT)
181 #define UNIT_ADD_IO(namespaceName, nameSingular, abbrev)\
182 }\
183 template <>\
184 struct fmt::formatter<units::namespaceName::nameSingular ## _t> \
185 : fmt::formatter<double> \
186 {\
187 template <typename FormatContext>\
188 auto format(const units::namespaceName::nameSingular ## _t& obj,\
189 FormatContext& ctx) -> decltype(ctx.out()) \
190 {\
191 auto out = ctx.out();\
192 out = fmt::formatter<double>::format(obj(), ctx);\
193 return fmt::format_to(out, " " #abbrev);\
194 }\
195 };\
196 namespace units\
197 {\
198 namespace namespaceName\
199 {\
200 inline std::string to_string(const nameSingular ## _t& obj)\
201 {\
202 return units::detail::to_string(obj()) + std::string(" "#abbrev);\
203 }\
204 }
205#endif
206#if defined(UNIT_LIB_ENABLE_IOSTREAM)
207 #define UNIT_ADD_IO(namespaceName, nameSingular, abbrev)\
208 namespace namespaceName\
209 {\
210 inline std::ostream& operator<<(std::ostream& os, const nameSingular ## _t& obj) \
211 {\
212 os << obj() << " "#abbrev; return os; \
213 }\
214 inline std::string to_string(const nameSingular ## _t& obj)\
215 {\
216 return units::detail::to_string(obj()) + std::string(" "#abbrev);\
217 }\
218 }
219#endif
220
221 /**
222 * @def UNIT_ADD_NAME(namespaceName,nameSingular,abbreviation)
223 * @brief Macro for generating constexpr names/abbreviations for units.
224 * @details The macro generates names for units. E.g. name() of 1_m would be "meter", and
225 * abbreviation would be "m".
226 * @param namespaceName namespace in which the new units will be encapsulated. All literal values
227 * are placed in the `units::literals` namespace.
228 * @param nameSingular singular version of the unit name, e.g. 'meter'
229 * @param abbreviation - abbreviated unit name, e.g. 'm'
230 */
231#define UNIT_ADD_NAME(namespaceName, nameSingular, abbrev)\
232template<> inline constexpr const char* name(const namespaceName::nameSingular ## _t&)\
233{\
234 return #nameSingular;\
235}\
236template<> inline constexpr const char* abbreviation(const namespaceName::nameSingular ## _t&)\
237{\
238 return #abbrev;\
239}
240
241/**
242 * @def UNIT_ADD_LITERALS(namespaceName,nameSingular,abbreviation)
243 * @brief Macro for generating user-defined literals for units.
244 * @details The macro generates user-defined literals for units. A literal suffix is created
245 * using the abbreviation (e.g. `10.0_m`).
246 * @param namespaceName namespace in which the new units will be encapsulated. All literal values
247 * are placed in the `units::literals` namespace.
248 * @param nameSingular singular version of the unit name, e.g. 'meter'
249 * @param abbreviation - abbreviated unit name, e.g. 'm'
250 * @note When UNIT_HAS_LITERAL_SUPPORT is not defined, the macro does not generate any code
251 */
252#if defined(UNIT_HAS_LITERAL_SUPPORT)
253 #define UNIT_ADD_LITERALS(namespaceName, nameSingular, abbreviation)\
254 namespace literals\
255 {\
256 inline constexpr namespaceName::nameSingular ## _t operator""_ ## abbreviation(long double d)\
257 {\
258 return namespaceName::nameSingular ## _t(static_cast<namespaceName::nameSingular ## _t::underlying_type>(d));\
259 }\
260 inline constexpr namespaceName::nameSingular ## _t operator""_ ## abbreviation (unsigned long long d)\
261 {\
262 return namespaceName::nameSingular ## _t(static_cast<namespaceName::nameSingular ## _t::underlying_type>(d));\
263 }\
264 }
265#else
266 #define UNIT_ADD_LITERALS(namespaceName, nameSingular, abbreviation)
267#endif
268
269/**
270 * @def UNIT_ADD(namespaceName,nameSingular, namePlural, abbreviation, definition)
271 * @brief Macro for generating the boiler-plate code needed for a new unit.
272 * @details The macro generates singular, plural, and abbreviated forms
273 * of the unit definition (e.g. `meter`, `meters`, and `m`), as well as the
274 * appropriately named unit container (e.g. `meter_t`). A literal suffix is created
275 * using the abbreviation (e.g. `10.0_m`). It also defines a class-specific
276 * cout function which prints both the value and abbreviation of the unit when invoked.
277 * @param namespaceName namespace in which the new units will be encapsulated. All literal values
278 * are placed in the `units::literals` namespace.
279 * @param nameSingular singular version of the unit name, e.g. 'meter'
280 * @param namePlural - plural version of the unit name, e.g. 'meters'
281 * @param abbreviation - abbreviated unit name, e.g. 'm'
282 * @param definition - the variadic parameter is used for the definition of the unit
283 * (e.g. `unit<std::ratio<1>, units::category::length_unit>`)
284 * @note a variadic template is used for the definition to allow templates with
285 * commas to be easily expanded. All the variadic 'arguments' should together
286 * comprise the unit definition.
287 */
288#define UNIT_ADD(namespaceName, nameSingular, namePlural, abbreviation, /*definition*/...)\
289 UNIT_ADD_UNIT_TAGS(namespaceName,nameSingular, namePlural, abbreviation, __VA_ARGS__)\
290 UNIT_ADD_UNIT_DEFINITION(namespaceName,nameSingular)\
291 UNIT_ADD_NAME(namespaceName,nameSingular, abbreviation)\
292 UNIT_ADD_IO(namespaceName,nameSingular, abbreviation)\
293 UNIT_ADD_LITERALS(namespaceName,nameSingular, abbreviation)
294
295/**
296 * @def UNIT_ADD_WITH_CUSTOM_TYPE(namespaceName,nameSingular, namePlural, abbreviation, underlyingType, definition)
297 * @brief Macro for generating the boiler-plate code needed for a new unit with a non-default underlying type.
298 * @details The macro generates singular, plural, and abbreviated forms
299 * of the unit definition (e.g. `meter`, `meters`, and `m`), as well as the
300 * appropriately named unit container (e.g. `meter_t`). A literal suffix is created
301 * using the abbreviation (e.g. `10.0_m`). It also defines a class-specific
302 * cout function which prints both the value and abbreviation of the unit when invoked.
303 * @param namespaceName namespace in which the new units will be encapsulated. All literal values
304 * are placed in the `units::literals` namespace.
305 * @param nameSingular singular version of the unit name, e.g. 'meter'
306 * @param namePlural - plural version of the unit name, e.g. 'meters'
307 * @param abbreviation - abbreviated unit name, e.g. 'm'
308 * @param underlyingType - the underlying type, e.g. 'int' or 'float'
309 * @param definition - the variadic parameter is used for the definition of the unit
310 * (e.g. `unit<std::ratio<1>, units::category::length_unit>`)
311 * @note a variadic template is used for the definition to allow templates with
312 * commas to be easily expanded. All the variadic 'arguments' should together
313 * comprise the unit definition.
314 */
315#define UNIT_ADD_WITH_CUSTOM_TYPE(namespaceName, nameSingular, namePlural, abbreviation, underlyingType, /*definition*/...)\
316 UNIT_ADD_UNIT_TAGS(namespaceName,nameSingular, namePlural, abbreviation, __VA_ARGS__)\
317 UNIT_ADD_CUSTOM_TYPE_UNIT_DEFINITION(namespaceName,nameSingular,underlyingType)\
318 UNIT_ADD_IO(namespaceName,nameSingular, abbreviation)\
319 UNIT_ADD_LITERALS(namespaceName,nameSingular, abbreviation)
320
321/**
322 * @def UNIT_ADD_DECIBEL(namespaceName, nameSingular, abbreviation)
323 * @brief Macro to create decibel container and literals for an existing unit type.
324 * @details This macro generates the decibel unit container, cout overload, and literal definitions.
325 * @param namespaceName namespace in which the new units will be encapsulated. All literal values
326 * are placed in the `units::literals` namespace.
327 * @param nameSingular singular version of the base unit name, e.g. 'watt'
328 * @param abbreviation - abbreviated decibel unit name, e.g. 'dBW'
329 */
330#define UNIT_ADD_DECIBEL(namespaceName, nameSingular, abbreviation)\
331 namespace namespaceName\
332 {\
333 /** @name Unit Containers */ /** @{ */ typedef unit_t<nameSingular, UNIT_LIB_DEFAULT_TYPE, units::decibel_scale> abbreviation ## _t; /** @} */\
334 }\
335 UNIT_ADD_IO(namespaceName, abbreviation, abbreviation)\
336 UNIT_ADD_LITERALS(namespaceName, abbreviation, abbreviation)
337
338/**
339 * @def UNIT_ADD_CATEGORY_TRAIT(unitCategory, baseUnit)
340 * @brief Macro to create the `is_category_unit` type trait.
341 * @details This trait allows users to test whether a given type matches
342 * an intended category. This macro comprises all the boiler-plate
343 * code necessary to do so.
344 * @param unitCategory The name of the category of unit, e.g. length or mass.
345 */
346
347#define UNIT_ADD_CATEGORY_TRAIT_DETAIL(unitCategory)\
348 namespace traits\
349 {\
350 /** @cond */\
351 namespace detail\
352 {\
353 template<typename T> struct is_ ## unitCategory ## _unit_impl : std::false_type {};\
354 template<typename C, typename U, typename P, typename T>\
355 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 {};\
356 template<typename U, typename S, template<typename> class N>\
357 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 {};\
358 }\
359 /** @endcond */\
360 }
361
362#define UNIT_ADD_IS_UNIT_CATEGORY_TRAIT(unitCategory)\
363 namespace traits\
364 {\
365 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> {};\
366 template<typename... T> inline constexpr bool is_ ## unitCategory ## _unit_v = is_ ## unitCategory ## _unit<T...>::value;\
367 }\
368 template <typename T>\
369 concept unitCategory ## _unit = traits::is_ ## unitCategory ## _unit_v<T>;
370
371#define UNIT_ADD_CATEGORY_TRAIT(unitCategory)\
372 UNIT_ADD_CATEGORY_TRAIT_DETAIL(unitCategory)\
373 /** @ingroup TypeTraits*/\
374 /** @brief Trait which tests whether a type represents a unit of unitCategory*/\
375 /** @details Inherits from `std::true_type` or `std::false_type`. Use `is_ ## unitCategory ## _unit<T>::value` to test the unit represents a unitCategory quantity.*/\
376 /** @tparam T one or more types to test*/\
377 UNIT_ADD_IS_UNIT_CATEGORY_TRAIT(unitCategory)
378
379/**
380 * @def UNIT_ADD_WITH_METRIC_PREFIXES(nameSingular, namePlural, abbreviation, definition)
381 * @brief Macro for generating the boiler-plate code needed for a new unit, including its metric
382 * prefixes from femto to peta.
383 * @details See UNIT_ADD. In addition to generating the unit definition and containers '(e.g. `meters` and 'meter_t',
384 * it also creates corresponding units with metric suffixes such as `millimeters`, and `millimeter_t`), as well as the
385 * literal suffixes (e.g. `10.0_mm`).
386 * @param namespaceName namespace in which the new units will be encapsulated. All literal values
387 * are placed in the `units::literals` namespace.
388 * @param nameSingular singular version of the unit name, e.g. 'meter'
389 * @param namePlural - plural version of the unit name, e.g. 'meters'
390 * @param abbreviation - abbreviated unit name, e.g. 'm'
391 * @param definition - the variadic parameter is used for the definition of the unit
392 * (e.g. `unit<std::ratio<1>, units::category::length_unit>`)
393 * @note a variadic template is used for the definition to allow templates with
394 * commas to be easily expanded. All the variadic 'arguments' should together
395 * comprise the unit definition.
396 */
397#define UNIT_ADD_WITH_METRIC_PREFIXES(namespaceName, nameSingular, namePlural, abbreviation, /*definition*/...)\
398 UNIT_ADD(namespaceName, nameSingular, namePlural, abbreviation, __VA_ARGS__)\
399 UNIT_ADD(namespaceName, femto ## nameSingular, femto ## namePlural, f ## abbreviation, femto<namePlural>)\
400 UNIT_ADD(namespaceName, pico ## nameSingular, pico ## namePlural, p ## abbreviation, pico<namePlural>)\
401 UNIT_ADD(namespaceName, nano ## nameSingular, nano ## namePlural, n ## abbreviation, nano<namePlural>)\
402 UNIT_ADD(namespaceName, micro ## nameSingular, micro ## namePlural, u ## abbreviation, micro<namePlural>)\
403 UNIT_ADD(namespaceName, milli ## nameSingular, milli ## namePlural, m ## abbreviation, milli<namePlural>)\
404 UNIT_ADD(namespaceName, centi ## nameSingular, centi ## namePlural, c ## abbreviation, centi<namePlural>)\
405 UNIT_ADD(namespaceName, deci ## nameSingular, deci ## namePlural, d ## abbreviation, deci<namePlural>)\
406 UNIT_ADD(namespaceName, deca ## nameSingular, deca ## namePlural, da ## abbreviation, deca<namePlural>)\
407 UNIT_ADD(namespaceName, hecto ## nameSingular, hecto ## namePlural, h ## abbreviation, hecto<namePlural>)\
408 UNIT_ADD(namespaceName, kilo ## nameSingular, kilo ## namePlural, k ## abbreviation, kilo<namePlural>)\
409 UNIT_ADD(namespaceName, mega ## nameSingular, mega ## namePlural, M ## abbreviation, mega<namePlural>)\
410 UNIT_ADD(namespaceName, giga ## nameSingular, giga ## namePlural, G ## abbreviation, giga<namePlural>)\
411 UNIT_ADD(namespaceName, tera ## nameSingular, tera ## namePlural, T ## abbreviation, tera<namePlural>)\
412 UNIT_ADD(namespaceName, peta ## nameSingular, peta ## namePlural, P ## abbreviation, peta<namePlural>)\
413
414 /**
415 * @def UNIT_ADD_WITH_METRIC_AND_BINARY_PREFIXES(nameSingular, namePlural, abbreviation, definition)
416 * @brief Macro for generating the boiler-plate code needed for a new unit, including its metric
417 * prefixes from femto to peta, and binary prefixes from kibi to exbi.
418 * @details See UNIT_ADD. In addition to generating the unit definition and containers '(e.g. `bytes` and 'byte_t',
419 * it also creates corresponding units with metric suffixes such as `millimeters`, and `millimeter_t`), as well as the
420 * literal suffixes (e.g. `10.0_B`).
421 * @param namespaceName namespace in which the new units will be encapsulated. All literal values
422 * are placed in the `units::literals` namespace.
423 * @param nameSingular singular version of the unit name, e.g. 'byte'
424 * @param namePlural - plural version of the unit name, e.g. 'bytes'
425 * @param abbreviation - abbreviated unit name, e.g. 'B'
426 * @param definition - the variadic parameter is used for the definition of the unit
427 * (e.g. `unit<std::ratio<1>, units::category::data_unit>`)
428 * @note a variadic template is used for the definition to allow templates with
429 * commas to be easily expanded. All the variadic 'arguments' should together
430 * comprise the unit definition.
431 */
432#define UNIT_ADD_WITH_METRIC_AND_BINARY_PREFIXES(namespaceName, nameSingular, namePlural, abbreviation, /*definition*/...)\
433 UNIT_ADD_WITH_METRIC_PREFIXES(namespaceName, nameSingular, namePlural, abbreviation, __VA_ARGS__)\
434 UNIT_ADD(namespaceName, kibi ## nameSingular, kibi ## namePlural, Ki ## abbreviation, kibi<namePlural>)\
435 UNIT_ADD(namespaceName, mebi ## nameSingular, mebi ## namePlural, Mi ## abbreviation, mebi<namePlural>)\
436 UNIT_ADD(namespaceName, gibi ## nameSingular, gibi ## namePlural, Gi ## abbreviation, gibi<namePlural>)\
437 UNIT_ADD(namespaceName, tebi ## nameSingular, tebi ## namePlural, Ti ## abbreviation, tebi<namePlural>)\
438 UNIT_ADD(namespaceName, pebi ## nameSingular, pebi ## namePlural, Pi ## abbreviation, pebi<namePlural>)\
439 UNIT_ADD(namespaceName, exbi ## nameSingular, exbi ## namePlural, Ei ## abbreviation, exbi<namePlural>)
440
441//--------------------
442// UNITS NAMESPACE
443//--------------------
444
445/**
446 * @namespace units
447 * @brief Unit Conversion Library namespace
448 */
449namespace units
450{
451 //----------------------------------
452 // DOXYGEN
453 //----------------------------------
454
455 /**
456 * @defgroup Units Unit API
457 */
458
459 /**
460 * @defgroup UnitContainers Unit Containers
461 * @ingroup Units
462 * @brief Defines a series of classes which contain dimensioned values. Unit containers
463 * store a value, and support various arithmetic operations.
464 */
465
466 /**
467 * @defgroup UnitTypes Unit Types
468 * @ingroup Units
469 * @brief Defines a series of classes which represent units. These types are tags used by
470 * the conversion function, to create compound units, or to create `unit_t` types.
471 * By themselves, they are not containers and have no stored value.
472 */
473
474 /**
475 * @defgroup UnitManipulators Unit Manipulators
476 * @ingroup Units
477 * @brief Defines a series of classes used to manipulate unit types, such as `inverse<>`, `squared<>`, and metric prefixes.
478 * Unit manipulators can be chained together, e.g. `inverse<squared<pico<time::seconds>>>` to
479 * represent picoseconds^-2.
480 */
481
482 /**
483 * @defgroup CompileTimeUnitManipulators Compile-time Unit Manipulators
484 * @ingroup Units
485 * @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.
486 * 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
487 * represent `c = sqrt(a^2 + b^2).
488 */
489
490 /**
491 * @defgroup UnitMath Unit Math
492 * @ingroup Units
493 * @brief Defines a collection of unit-enabled, strongly-typed versions of `<cmath>` functions.
494 * @details Includes most c++11 extensions.
495 */
496
497 /**
498 * @defgroup Conversion Explicit Conversion
499 * @ingroup Units
500 * @brief Functions used to convert values of one logical type to another.
501 */
502
503 /**
504 * @defgroup TypeTraits Type Traits
505 * @ingroup Units
506 * @brief Defines a series of classes to obtain unit type information at compile-time.
507 */
508
509 //------------------------------
510 // FORWARD DECLARATIONS
511 //------------------------------
512
513 /** @cond */ // DOXYGEN IGNORE
514 namespace constants
515 {
516 namespace detail
517 {
518 static constexpr const UNIT_LIB_DEFAULT_TYPE PI_VAL = 3.14159265358979323846264338327950288419716939937510;
519 }
520 }
521 /** @endcond */ // END DOXYGEN IGNORE
522
523 //------------------------------
524 // RATIO TRAITS
525 //------------------------------
526
527 /**
528 * @ingroup TypeTraits
529 * @{
530 */
531
532 /** @cond */ // DOXYGEN IGNORE
533 namespace detail
534 {
535 /// has_num implementation.
536 template<class T>
537 struct has_num_impl
538 {
539 template<class U>
540 static constexpr auto test(U*)->std::is_integral<decltype(U::num)> {return std::is_integral<decltype(U::num)>{}; }
541 template<typename>
542 static constexpr std::false_type test(...) { return std::false_type{}; }
543
544 using type = decltype(test<T>(0));
545 };
546 }
547
548 /**
549 * @brief Trait which checks for the existence of a static numerator.
550 * @details Inherits from `std::true_type` or `std::false_type`. Use `has_num<T>::value` to test
551 * whether `class T` has a numerator static member.
552 */
553 template<class T>
554 struct has_num : units::detail::has_num_impl<T>::type {};
555
556 namespace detail
557 {
558 /// has_den implementation.
559 template<class T>
560 struct has_den_impl
561 {
562 template<class U>
563 static constexpr auto test(U*)->std::is_integral<decltype(U::den)> { return std::is_integral<decltype(U::den)>{}; }
564 template<typename>
565 static constexpr std::false_type test(...) { return std::false_type{}; }
566
567 using type = decltype(test<T>(0));
568 };
569 }
570
571 /**
572 * @brief Trait which checks for the existence of a static denominator.
573 * @details Inherits from `std::true_type` or `std::false_type`. Use `has_den<T>::value` to test
574 * whether `class T` has a denominator static member.
575 */
576 template<class T>
577 struct has_den : units::detail::has_den_impl<T>::type {};
578
579 /** @endcond */ // END DOXYGEN IGNORE
580
581 namespace traits
582 {
583 /**
584 * @brief Trait that tests whether a type represents a std::ratio.
585 * @details Inherits from `std::true_type` or `std::false_type`. Use `is_ratio<T>::value` to test
586 * whether `class T` implements a std::ratio.
587 */
588 template<class T>
589 struct is_ratio : std::integral_constant<bool,
590 has_num<T>::value &&
591 has_den<T>::value>
592 {};
593 template<class T>
594 inline constexpr bool is_ratio_v = is_ratio<T>::value;
595 }
596
597 //------------------------------
598 // UNIT TRAITS
599 //------------------------------
600
601 /** @cond */ // DOXYGEN IGNORE
602 /**
603 * @brief void type.
604 * @details Helper class for creating type traits.
605 */
606 template<class ...>
607 struct void_t { typedef void type; };
608
609 /**
610 * @brief parameter pack for boolean arguments.
611 */
612 template<bool...> struct bool_pack {};
613
614 /**
615 * @brief Trait which tests that a set of other traits are all true.
616 */
617 template<bool... Args>
618 struct all_true : std::is_same<units::bool_pack<true, Args...>, units::bool_pack<Args..., true>> {};
619 template<bool... Args>
620 inline constexpr bool all_true_t_v = all_true<Args...>::type::value;
621 /** @endcond */ // DOXYGEN IGNORE
622
623 /**
624 * @brief namespace representing type traits which can access the properties of types provided by the units library.
625 */
626 namespace traits
627 {
628#ifdef FOR_DOXYGEN_PURPOSES_ONLY
629 /**
630 * @ingroup TypeTraits
631 * @brief Traits class defining the properties of units.
632 * @details The units library determines certain properties of the units passed to
633 * them and what they represent by using the members of the corresponding
634 * unit_traits instantiation.
635 */
636 template<class T>
637 struct unit_traits
638 {
639 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.
640 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.
641 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.
642 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.
643 };
644#endif
645 /** @cond */ // DOXYGEN IGNORE
646 /**
647 * @brief unit traits implementation for classes which are not units.
648 */
649 template<class T, typename = void>
650 struct unit_traits
651 {
652 typedef void base_unit_type;
653 typedef void conversion_ratio;
654 typedef void pi_exponent_ratio;
655 typedef void translation_ratio;
656 };
657
658 template<class T>
659 struct unit_traits
660 <T, typename void_t<
661 typename T::base_unit_type,
662 typename T::conversion_ratio,
663 typename T::pi_exponent_ratio,
664 typename T::translation_ratio>::type>
665 {
666 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.
667 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.
668 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.
669 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.
670 };
671 /** @endcond */ // END DOXYGEN IGNORE
672 }
673
674 /** @cond */ // DOXYGEN IGNORE
675 namespace detail
676 {
677 /**
678 * @brief helper type to identify base units.
679 * @details A non-templated base class for `base_unit` which enables RTTI testing.
680 */
681 struct _base_unit_t {};
682 }
683 /** @endcond */ // END DOXYGEN IGNORE
684
685 namespace traits
686 {
687 /**
688 * @ingroup TypeTraits
689 * @brief Trait which tests if a class is a `base_unit` type.
690 * @details Inherits from `std::true_type` or `std::false_type`. Use `is_base_unit<T>::value` to test
691 * whether `class T` implements a `base_unit`.
692 */
693 template<class T>
694 struct is_base_unit : std::is_base_of<units::detail::_base_unit_t, T> {};
695 }
696
697 /** @cond */ // DOXYGEN IGNORE
698 namespace detail
699 {
700 /**
701 * @brief helper type to identify units.
702 * @details A non-templated base class for `unit` which enables RTTI testing.
703 */
704 struct _unit {};
705
706 template<std::intmax_t Num, std::intmax_t Den = 1>
707 using meter_ratio = std::ratio<Num, Den>;
708 }
709 /** @endcond */ // END DOXYGEN IGNORE
710
711 namespace traits
712 {
713 /**
714 * @ingroup TypeTraits
715 * @brief Traits which tests if a class is a `unit`
716 * @details Inherits from `std::true_type` or `std::false_type`. Use `is_unit<T>::value` to test
717 * whether `class T` implements a `unit`.
718 */
719 template<class T>
720 struct is_unit : std::is_base_of<units::detail::_unit, T>::type {};
721 template<class T>
722 inline constexpr bool is_unit_v = is_unit<T>::value;
723 }
724
725 /** @} */ // end of TypeTraits
726
727 //------------------------------
728 // BASE UNIT CLASS
729 //------------------------------
730
731 /**
732 * @ingroup UnitTypes
733 * @brief Class representing SI base unit types.
734 * @details Base units are represented by a combination of `std::ratio` template parameters, each
735 * describing the exponent of the type of unit they represent. Example: meters per second
736 * would be described by a +1 exponent for meters, and a -1 exponent for seconds, thus:
737 * `base_unit<std::ratio<1>, std::ratio<0>, std::ratio<-1>>`
738 * @tparam Meter `std::ratio` representing the exponent value for meters.
739 * @tparam Kilogram `std::ratio` representing the exponent value for kilograms.
740 * @tparam Second `std::ratio` representing the exponent value for seconds.
741 * @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.
742 * @tparam Ampere `std::ratio` representing the exponent value for amperes.
743 * @tparam Kelvin `std::ratio` representing the exponent value for Kelvin.
744 * @tparam Mole `std::ratio` representing the exponent value for moles.
745 * @tparam Candela `std::ratio` representing the exponent value for candelas.
746 * @tparam Byte `std::ratio` representing the exponent value for bytes.
747 * @sa category for type aliases for SI base_unit types.
748 */
749 template<class Meter = detail::meter_ratio<0>,
750 class Kilogram = std::ratio<0>,
751 class Second = std::ratio<0>,
752 class Radian = std::ratio<0>,
753 class Ampere = std::ratio<0>,
754 class Kelvin = std::ratio<0>,
755 class Mole = std::ratio<0>,
756 class Candela = std::ratio<0>,
757 class Byte = std::ratio<0>>
758 struct base_unit : units::detail::_base_unit_t
759 {
760 static_assert(traits::is_ratio<Meter>::value, "Template parameter `Meter` must be a `std::ratio` representing the exponent of meters the unit has");
761 static_assert(traits::is_ratio<Kilogram>::value, "Template parameter `Kilogram` must be a `std::ratio` representing the exponent of kilograms the unit has");
762 static_assert(traits::is_ratio<Second>::value, "Template parameter `Second` must be a `std::ratio` representing the exponent of seconds the unit has");
763 static_assert(traits::is_ratio<Ampere>::value, "Template parameter `Ampere` must be a `std::ratio` representing the exponent of amperes the unit has");
764 static_assert(traits::is_ratio<Kelvin>::value, "Template parameter `Kelvin` must be a `std::ratio` representing the exponent of kelvin the unit has");
765 static_assert(traits::is_ratio<Candela>::value, "Template parameter `Candela` must be a `std::ratio` representing the exponent of candelas the unit has");
766 static_assert(traits::is_ratio<Mole>::value, "Template parameter `Mole` must be a `std::ratio` representing the exponent of moles the unit has");
767 static_assert(traits::is_ratio<Radian>::value, "Template parameter `Radian` must be a `std::ratio` representing the exponent of radians the unit has");
768 static_assert(traits::is_ratio<Byte>::value, "Template parameter `Byte` must be a `std::ratio` representing the exponent of bytes the unit has");
769
770 typedef Meter meter_ratio;
771 typedef Kilogram kilogram_ratio;
772 typedef Second second_ratio;
773 typedef Radian radian_ratio;
774 typedef Ampere ampere_ratio;
775 typedef Kelvin kelvin_ratio;
776 typedef Mole mole_ratio;
777 typedef Candela candela_ratio;
778 typedef Byte byte_ratio;
779 };
780
781 //------------------------------
782 // UNIT CATEGORIES
783 //------------------------------
784
785 /**
786 * @brief namespace representing the implemented base and derived unit types. These will not generally be needed by library users.
787 * @sa base_unit for the definition of the category parameters.
788 */
789 namespace category
790 {
791 // SCALAR (DIMENSIONLESS) TYPES
792 typedef base_unit<> scalar_unit; ///< Represents a quantity with no dimension.
793 typedef base_unit<> dimensionless_unit; ///< Represents a quantity with no dimension.
794
795 // SI BASE UNIT TYPES
796 // METERS KILOGRAMS SECONDS RADIANS AMPERES KELVIN MOLE CANDELA BYTE --- CATEGORY
797 typedef base_unit<detail::meter_ratio<1>> length_unit; ///< Represents an SI base unit of length
798 typedef base_unit<detail::meter_ratio<0>, std::ratio<1>> mass_unit; ///< Represents an SI base unit of mass
799 typedef base_unit<detail::meter_ratio<0>, std::ratio<0>, std::ratio<1>> time_unit; ///< Represents an SI base unit of time
800 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
801 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
802 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
803 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
804 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
805
806 // SI DERIVED UNIT TYPES
807 // METERS KILOGRAMS SECONDS RADIANS AMPERES KELVIN MOLE CANDELA BYTE --- CATEGORY
808 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
809 typedef base_unit<detail::meter_ratio<0>, std::ratio<0>, std::ratio<-1>> frequency_unit; ///< Represents an SI derived unit of frequency
810 typedef base_unit<detail::meter_ratio<1>, std::ratio<0>, std::ratio<-1>> velocity_unit; ///< Represents an SI derived unit of velocity
811 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
812 typedef base_unit<detail::meter_ratio<1>, std::ratio<0>, std::ratio<-2>> acceleration_unit; ///< Represents an SI derived unit of acceleration
813 typedef base_unit<detail::meter_ratio<0>, std::ratio<0>, std::ratio<-2>, std::ratio<1>> angular_acceleration_unit; ///< Represents an SI derived unit of angular acceleration
814 typedef base_unit<detail::meter_ratio<0>, std::ratio<0>, std::ratio<-3>, std::ratio<1>> angular_jerk_unit; ///< Represents an SI derived unit of angular jerk
815 typedef base_unit<detail::meter_ratio<1>, std::ratio<1>, std::ratio<-2>> force_unit; ///< Represents an SI derived unit of force
816 typedef base_unit<detail::meter_ratio<-1>, std::ratio<1>, std::ratio<-2>> pressure_unit; ///< Represents an SI derived unit of pressure
817 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
818 typedef base_unit<detail::meter_ratio<2>, std::ratio<1>, std::ratio<-2>> energy_unit; ///< Represents an SI derived unit of energy
819 typedef base_unit<detail::meter_ratio<2>, std::ratio<1>, std::ratio<-3>> power_unit; ///< Represents an SI derived unit of power
820 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
821 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
822 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
823 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
824 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
825 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
826 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
827 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
828 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
829 typedef base_unit<detail::meter_ratio<0>, std::ratio<0>, std::ratio<-1>> radioactivity_unit; ///< Represents an SI derived unit of radioactivity
830
831 // OTHER UNIT TYPES
832 // METERS KILOGRAMS SECONDS RADIANS AMPERES KELVIN MOLE CANDELA BYTE --- CATEGORY
833 typedef base_unit<detail::meter_ratio<2>, std::ratio<1>, std::ratio<-2>> torque_unit; ///< Represents an SI derived unit of torque
834 typedef base_unit<detail::meter_ratio<2>> area_unit; ///< Represents an SI derived unit of area
835 typedef base_unit<detail::meter_ratio<3>> volume_unit; ///< Represents an SI derived unit of volume
836 typedef base_unit<detail::meter_ratio<-3>, std::ratio<1>> density_unit; ///< Represents an SI derived unit of density
837 typedef base_unit<> concentration_unit; ///< Represents a unit of concentration
838 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
839 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
840 }
841
842 //------------------------------
843 // UNIT CLASSES
844 //------------------------------
845
846 /** @cond */ // DOXYGEN IGNORE
847 /**
848 * @brief unit type template specialization for units derived from base units.
849 */
850 template <class, class, class, class> struct unit;
851 template<class Conversion, class... Exponents, class PiExponent, class Translation>
852 struct unit<Conversion, base_unit<Exponents...>, PiExponent, Translation> : units::detail::_unit
853 {
854 static_assert(traits::is_ratio<Conversion>::value, "Template parameter `Conversion` must be a `std::ratio` representing the conversion factor to `BaseUnit`.");
855 static_assert(traits::is_ratio<PiExponent>::value, "Template parameter `PiExponent` must be a `std::ratio` representing the exponents of Pi the unit has.");
856 static_assert(traits::is_ratio<Translation>::value, "Template parameter `Translation` must be a `std::ratio` representing an additive translation required by the unit conversion.");
857
858 typedef typename units::base_unit<Exponents...> base_unit_type;
859 typedef Conversion conversion_ratio;
860 typedef Translation translation_ratio;
861 typedef PiExponent pi_exponent_ratio;
862 };
863 /** @endcond */ // END DOXYGEN IGNORE
864
865 /**
866 * @brief Type representing an arbitrary unit.
867 * @ingroup UnitTypes
868 * @details `unit` types are used as tags for the `conversion` function. They are *not* containers
869 * (see `unit_t` for a container class). Each unit is defined by:
870 *
871 * - A `std::ratio` defining the conversion factor to the base unit type. (e.g. `std::ratio<1,12>` for inches to feet)
872 * - A base unit that the unit is derived from (or a unit category. Must be of type `unit` or `base_unit`)
873 * - An exponent representing factors of PI required by the conversion. (e.g. `std::ratio<-1>` for a radians to degrees conversion)
874 * - a ratio representing a datum translation required for the conversion (e.g. `std::ratio<32>` for a fahrenheit to celsius conversion)
875 *
876 * Typically, a specific unit, like `meters`, would be implemented as a type alias
877 * of `unit`, i.e. `using meters = unit<std::ratio<1>, units::category::length_unit`, or
878 * `using inches = unit<std::ratio<1,12>, feet>`.
879 * @tparam Conversion std::ratio representing scalar multiplication factor.
880 * @tparam BaseUnit Unit type which this unit is derived from. May be a `base_unit`, or another `unit`.
881 * @tparam PiExponent std::ratio representing the exponent of pi required by the conversion.
882 * @tparam Translation std::ratio representing any datum translation required by the conversion.
883 */
884 template<class Conversion, class BaseUnit, class PiExponent = std::ratio<0>, class Translation = std::ratio<0>>
885 struct unit : units::detail::_unit
886 {
887 static_assert(traits::is_unit<BaseUnit>::value, "Template parameter `BaseUnit` must be a `unit` type.");
888 static_assert(traits::is_ratio<Conversion>::value, "Template parameter `Conversion` must be a `std::ratio` representing the conversion factor to `BaseUnit`.");
889 static_assert(traits::is_ratio<PiExponent>::value, "Template parameter `PiExponent` must be a `std::ratio` representing the exponents of Pi the unit has.");
890
891 typedef typename units::traits::unit_traits<BaseUnit>::base_unit_type base_unit_type;
892 typedef typename std::ratio_multiply<typename BaseUnit::conversion_ratio, Conversion> conversion_ratio;
893 typedef typename std::ratio_add<typename BaseUnit::pi_exponent_ratio, PiExponent> pi_exponent_ratio;
894 typedef typename std::ratio_add<std::ratio_multiply<typename BaseUnit::conversion_ratio, Translation>, typename BaseUnit::translation_ratio> translation_ratio;
895 };
896
897 //------------------------------
898 // BASE UNIT MANIPULATORS
899 //------------------------------
900
901 /** @cond */ // DOXYGEN IGNORE
902 namespace detail
903 {
904 /**
905 * @brief base_unit_of trait implementation
906 * @details recursively seeks base_unit type that a unit is derived from. Since units can be
907 * derived from other units, the `base_unit_type` typedef may not represent this value.
908 */
909 template<class> struct base_unit_of_impl;
910 template<class Conversion, class BaseUnit, class PiExponent, class Translation>
911 struct base_unit_of_impl<unit<Conversion, BaseUnit, PiExponent, Translation>> : base_unit_of_impl<BaseUnit> {};
912 template<class... Exponents>
913 struct base_unit_of_impl<base_unit<Exponents...>>
914 {
915 typedef base_unit<Exponents...> type;
916 };
917 template<>
918 struct base_unit_of_impl<void>
919 {
920 typedef void type;
921 };
922 }
923 /** @endcond */ // END DOXYGEN IGNORE
924
925 namespace traits
926 {
927 /**
928 * @brief Trait which returns the `base_unit` type that a unit is originally derived from.
929 * @details Since units can be derived from other `unit` types in addition to `base_unit` types,
930 * the `base_unit_type` typedef will not always be a `base_unit` (or unit category).
931 * Since compatible
932 */
933 template<class U>
935 }
936
937 /** @cond */ // DOXYGEN IGNORE
938 namespace detail
939 {
940 /**
941 * @brief implementation of base_unit_multiply
942 * @details 'multiples' (adds exponent ratios of) two base unit types. Base units can be found
943 * using `base_unit_of`.
944 */
945 template<class, class> struct base_unit_multiply_impl;
946 template<class... Exponents1, class... Exponents2>
947 struct base_unit_multiply_impl<base_unit<Exponents1...>, base_unit<Exponents2...>> {
949 };
950
951 /**
952 * @brief represents type of two base units multiplied together
953 */
954 template<class U1, class U2>
955 using base_unit_multiply = typename base_unit_multiply_impl<U1, U2>::type;
956
957 /**
958 * @brief implementation of base_unit_divide
959 * @details 'dived' (subtracts exponent ratios of) two base unit types. Base units can be found
960 * using `base_unit_of`.
961 */
962 template<class, class> struct base_unit_divide_impl;
963 template<class... Exponents1, class... Exponents2>
964 struct base_unit_divide_impl<base_unit<Exponents1...>, base_unit<Exponents2...>> {
965 using type = base_unit<std::ratio_subtract<Exponents1, Exponents2>...>;
966 };
967
968 /**
969 * @brief represents the resulting type of `base_unit` U1 divided by U2.
970 */
971 template<class U1, class U2>
972 using base_unit_divide = typename base_unit_divide_impl<U1, U2>::type;
973
974 /**
975 * @brief implementation of inverse_base
976 * @details multiplies all `base_unit` exponent ratios by -1. The resulting type represents
977 * the inverse base unit of the given `base_unit` type.
978 */
979 template<class> struct inverse_base_impl;
980
981 template<class... Exponents>
982 struct inverse_base_impl<base_unit<Exponents...>> {
983 using type = base_unit<std::ratio_multiply<Exponents, std::ratio<-1>>...>;
984 };
985
986 /**
987 * @brief represent the inverse type of `class U`
988 * @details E.g. if `U` is `length_unit`, then `inverse<U>` will represent `length_unit^-1`.
989 */
990 template<class U> using inverse_base = typename inverse_base_impl<U>::type;
991
992 /**
993 * @brief implementation of `squared_base`
994 * @details multiplies all the exponent ratios of the given class by 2. The resulting type is
995 * equivalent to the given type squared.
996 */
997 template<class U> struct squared_base_impl;
998 template<class... Exponents>
999 struct squared_base_impl<base_unit<Exponents...>> {
1000 using type = base_unit<std::ratio_multiply<Exponents, std::ratio<2>>...>;
1001 };
1002
1003 /**
1004 * @brief represents the type of a `base_unit` squared.
1005 * @details E.g. `squared<length_unit>` will represent `length_unit^2`.
1006 */
1007 template<class U> using squared_base = typename squared_base_impl<U>::type;
1008
1009 /**
1010 * @brief implementation of `cubed_base`
1011 * @details multiplies all the exponent ratios of the given class by 3. The resulting type is
1012 * equivalent to the given type cubed.
1013 */
1014 template<class U> struct cubed_base_impl;
1015 template<class... Exponents>
1016 struct cubed_base_impl<base_unit<Exponents...>> {
1017 using type = base_unit<std::ratio_multiply<Exponents, std::ratio<3>>...>;
1018 };
1019
1020 /**
1021 * @brief represents the type of a `base_unit` cubed.
1022 * @details E.g. `cubed<length_unit>` will represent `length_unit^3`.
1023 */
1024 template<class U> using cubed_base = typename cubed_base_impl<U>::type;
1025
1026 /**
1027 * @brief implementation of `sqrt_base`
1028 * @details divides all the exponent ratios of the given class by 2. The resulting type is
1029 * equivalent to the square root of the given type.
1030 */
1031 template<class U> struct sqrt_base_impl;
1032 template<class... Exponents>
1033 struct sqrt_base_impl<base_unit<Exponents...>> {
1034 using type = base_unit<std::ratio_divide<Exponents, std::ratio<2>>...>;
1035 };
1036
1037 /**
1038 * @brief represents the square-root type of a `base_unit`.
1039 * @details E.g. `sqrt<length_unit>` will represent `length_unit^(1/2)`.
1040 */
1041 template<class U> using sqrt_base = typename sqrt_base_impl<U>::type;
1042
1043 /**
1044 * @brief implementation of `cbrt_base`
1045 * @details divides all the exponent ratios of the given class by 3. The resulting type is
1046 * equivalent to the given type's cube-root.
1047 */
1048 template<class U> struct cbrt_base_impl;
1049 template<class... Exponents>
1050 struct cbrt_base_impl<base_unit<Exponents...>> {
1051 using type = base_unit<std::ratio_divide<Exponents, std::ratio<3>>...>;
1052 };
1053
1054 /**
1055 * @brief represents the cube-root type of a `base_unit` .
1056 * @details E.g. `cbrt<length_unit>` will represent `length_unit^(1/3)`.
1057 */
1058 template<class U> using cbrt_base = typename cbrt_base_impl<U>::type;
1059 }
1060 /** @endcond */ // END DOXYGEN IGNORE
1061
1062 //------------------------------
1063 // UNIT MANIPULATORS
1064 //------------------------------
1065
1066 /** @cond */ // DOXYGEN IGNORE
1067 namespace detail
1068 {
1069 /**
1070 * @brief implementation of `unit_multiply`.
1071 * @details multiplies two units. The base unit becomes the base units of each with their exponents
1072 * added together. The conversion factors of each are multiplied by each other. Pi exponent ratios
1073 * are added, and datum translations are removed.
1074 */
1075 template<class Unit1, class Unit2>
1076 struct unit_multiply_impl
1077 {
1078 using type = unit < std::ratio_multiply<typename Unit1::conversion_ratio, typename Unit2::conversion_ratio>,
1079 base_unit_multiply <traits::base_unit_of<typename Unit1::base_unit_type>, traits::base_unit_of<typename Unit2::base_unit_type>>,
1080 std::ratio_add<typename Unit1::pi_exponent_ratio, typename Unit2::pi_exponent_ratio>,
1081 std::ratio < 0 >> ;
1082 };
1083
1084 /**
1085 * @brief represents the type of two units multiplied together.
1086 * @details recalculates conversion and exponent ratios at compile-time.
1087 */
1088 template<class U1, class U2>
1089 using unit_multiply = typename unit_multiply_impl<U1, U2>::type;
1090
1091 /**
1092 * @brief implementation of `unit_divide`.
1093 * @details divides two units. The base unit becomes the base units of each with their exponents
1094 * subtracted from each other. The conversion factors of each are divided by each other. Pi exponent ratios
1095 * are subtracted, and datum translations are removed.
1096 */
1097 template<class Unit1, class Unit2>
1098 struct unit_divide_impl
1099 {
1100 using type = unit < std::ratio_divide<typename Unit1::conversion_ratio, typename Unit2::conversion_ratio>,
1101 base_unit_divide<traits::base_unit_of<typename Unit1::base_unit_type>, traits::base_unit_of<typename Unit2::base_unit_type>>,
1102 std::ratio_subtract<typename Unit1::pi_exponent_ratio, typename Unit2::pi_exponent_ratio>,
1103 std::ratio < 0 >> ;
1104 };
1105
1106 /**
1107 * @brief represents the type of two units divided by each other.
1108 * @details recalculates conversion and exponent ratios at compile-time.
1109 */
1110 template<class U1, class U2>
1111 using unit_divide = typename unit_divide_impl<U1, U2>::type;
1112
1113 /**
1114 * @brief implementation of `inverse`
1115 * @details inverts a unit (equivalent to 1/unit). The `base_unit` and pi exponents are all multiplied by
1116 * -1. The conversion ratio numerator and denominator are swapped. Datum translation
1117 * ratios are removed.
1118 */
1119 template<class Unit>
1120 struct inverse_impl
1121 {
1122 using type = unit < std::ratio<Unit::conversion_ratio::den, Unit::conversion_ratio::num>,
1123 inverse_base<traits::base_unit_of<typename units::traits::unit_traits<Unit>::base_unit_type>>,
1124 std::ratio_multiply<typename units::traits::unit_traits<Unit>::pi_exponent_ratio, std::ratio<-1>>,
1125 std::ratio < 0 >> ; // inverses are rates or change, the translation factor goes away.
1126 };
1127 }
1128 /** @endcond */ // END DOXYGEN IGNORE
1129
1130 /**
1131 * @brief represents the inverse unit type of `class U`.
1132 * @ingroup UnitManipulators
1133 * @tparam U `unit` type to invert.
1134 * @details E.g. `inverse<meters>` will represent meters^-1 (i.e. 1/meters).
1135 */
1136 template<class U> using inverse = typename units::detail::inverse_impl<U>::type;
1137
1138 /** @cond */ // DOXYGEN IGNORE
1139 namespace detail
1140 {
1141 /**
1142 * @brief implementation of `squared`
1143 * @details Squares the conversion ratio, `base_unit` exponents, pi exponents, and removes
1144 * datum translation ratios.
1145 */
1146 template<class Unit>
1147 struct squared_impl
1148 {
1149 static_assert(traits::is_unit<Unit>::value, "Template parameter `Unit` must be a `unit` type.");
1150 using Conversion = typename Unit::conversion_ratio;
1152 squared_base<traits::base_unit_of<typename Unit::base_unit_type>>,
1153 std::ratio_multiply<typename Unit::pi_exponent_ratio, std::ratio<2>>,
1154 typename Unit::translation_ratio
1155 > ;
1156 };
1157 }
1158 /** @endcond */ // END DOXYGEN IGNORE
1159
1160 /**
1161 * @brief represents the unit type of `class U` squared
1162 * @ingroup UnitManipulators
1163 * @tparam U `unit` type to square.
1164 * @details E.g. `square<meters>` will represent meters^2.
1165 */
1166 template<class U>
1168
1169 /** @cond */ // DOXYGEN IGNORE
1170 namespace detail
1171 {
1172 /**
1173 * @brief implementation of `cubed`
1174 * @details Cubes the conversion ratio, `base_unit` exponents, pi exponents, and removes
1175 * datum translation ratios.
1176 */
1177 template<class Unit>
1178 struct cubed_impl
1179 {
1180 static_assert(traits::is_unit<Unit>::value, "Template parameter `Unit` must be a `unit` type.");
1181 using Conversion = typename Unit::conversion_ratio;
1183 cubed_base<traits::base_unit_of<typename Unit::base_unit_type>>,
1184 std::ratio_multiply<typename Unit::pi_exponent_ratio, std::ratio<3>>,
1185 typename Unit::translation_ratio> ;
1186 };
1187 }
1188 /** @endcond */ // END DOXYGEN IGNORE
1189
1190 /**
1191 * @brief represents the type of `class U` cubed.
1192 * @ingroup UnitManipulators
1193 * @tparam U `unit` type to cube.
1194 * @details E.g. `cubed<meters>` will represent meters^3.
1195 */
1196 template<class U>
1198
1199 /** @cond */ // DOXYGEN IGNORE
1200 namespace detail
1201 {
1202 //----------------------------------
1203 // RATIO_SQRT IMPLEMENTATION
1204 //----------------------------------
1205
1206 using Zero = std::ratio<0>;
1207 using One = std::ratio<1>;
1208 template <typename R> using Square = std::ratio_multiply<R, R>;
1209
1210 // Find the largest std::integer N such that Predicate<N>::value is true.
1211 template <template <std::intmax_t N> class Predicate, typename enabled = void>
1212 struct BinarySearch {
1213 template <std::intmax_t N>
1214 struct SafeDouble_ {
1215 static constexpr const std::intmax_t value = 2 * N;
1216 static_assert(value > 0, "Overflows when computing 2 * N");
1217 };
1218
1219 template <intmax_t Lower, intmax_t Upper, typename Condition1 = void, typename Condition2 = void>
1220 struct DoubleSidedSearch_ : DoubleSidedSearch_<Lower, Upper,
1221 std::integral_constant<bool, (Upper - Lower == 1)>,
1222 std::integral_constant<bool, ((Upper - Lower>1 && Predicate<Lower + (Upper - Lower) / 2>::value))>> {};
1223
1224 template <intmax_t Lower, intmax_t Upper>
1225 struct DoubleSidedSearch_<Lower, Upper, std::false_type, std::false_type> : DoubleSidedSearch_<Lower, Lower + (Upper - Lower) / 2> {};
1226
1227 template <intmax_t Lower, intmax_t Upper, typename Condition2>
1228 struct DoubleSidedSearch_<Lower, Upper, std::true_type, Condition2> : std::integral_constant<intmax_t, Lower>{};
1229
1230 template <intmax_t Lower, intmax_t Upper, typename Condition1>
1231 struct DoubleSidedSearch_<Lower, Upper, Condition1, std::true_type> : DoubleSidedSearch_<Lower + (Upper - Lower) / 2, Upper>{};
1232
1233 template <std::intmax_t Lower, class enabled1 = void>
1234 struct SingleSidedSearch_ : SingleSidedSearch_<Lower, std::integral_constant<bool, Predicate<SafeDouble_<Lower>::value>::value>>{};
1235
1236 template <std::intmax_t Lower>
1237 struct SingleSidedSearch_<Lower, std::false_type> : DoubleSidedSearch_<Lower, SafeDouble_<Lower>::value> {};
1238
1239 template <std::intmax_t Lower>
1240 struct SingleSidedSearch_<Lower, std::true_type> : SingleSidedSearch_<SafeDouble_<Lower>::value>{};
1241
1242 static constexpr const std::intmax_t value = SingleSidedSearch_<1>::value;
1243 };
1244
1245 template <template <std::intmax_t N> class Predicate>
1246 struct BinarySearch<Predicate, std::enable_if_t<!Predicate<1>::value>> : std::integral_constant<std::intmax_t, 0>{};
1247
1248 // Find largest std::integer N such that N<=sqrt(R)
1249 template <typename R>
1250 struct Integer {
1251 template <std::intmax_t N> using Predicate_ = std::ratio_less_equal<std::ratio<N>, std::ratio_divide<R, std::ratio<N>>>;
1252 static constexpr const std::intmax_t value = BinarySearch<Predicate_>::value;
1253 };
1254
1255 template <typename R>
1256 struct IsPerfectSquare {
1257 static constexpr const std::intmax_t DenSqrt_ = Integer<std::ratio<R::den>>::value;
1258 static constexpr const std::intmax_t NumSqrt_ = Integer<std::ratio<R::num>>::value;
1259 static constexpr const bool value =( DenSqrt_ * DenSqrt_ == R::den && NumSqrt_ * NumSqrt_ == R::num);
1260 using Sqrt = std::ratio<NumSqrt_, DenSqrt_>;
1261 };
1262
1263 // Represents sqrt(P)-Q.
1264 template <typename Tp, typename Tq>
1265 struct Remainder {
1266 using P = Tp;
1267 using Q = Tq;
1268 };
1269
1270 // Represents 1/R = I + Rem where R is a Remainder.
1271 template <typename R>
1272 struct Reciprocal {
1273 using P_ = typename R::P;
1274 using Q_ = typename R::Q;
1275 using Den_ = std::ratio_subtract<P_, Square<Q_>>;
1276 using A_ = std::ratio_divide<Q_, Den_>;
1277 using B_ = std::ratio_divide<P_, Square<Den_>>;
1278 static constexpr const std::intmax_t I_ = (A_::num + Integer<std::ratio_multiply<B_, Square<std::ratio<A_::den>>>>::value) / A_::den;
1279 using I = std::ratio<I_>;
1280 using Rem = Remainder<B_, std::ratio_subtract<I, A_>>;
1281 };
1282
1283 // Expands sqrt(R) to continued fraction:
1284 // f(x)=C1+1/(C2+1/(C3+1/(...+1/(Cn+x)))) = (U*x+V)/(W*x+1) and sqrt(R)=f(Rem).
1285 // The error |f(Rem)-V| = |(U-W*V)x/(W*x+1)| <= |U-W*V|*Rem <= |U-W*V|/I' where
1286 // I' is the std::integer part of reciprocal of Rem.
1287 template <typename Tr, std::intmax_t N>
1288 struct ContinuedFraction {
1289 template <typename T>
1290 using Abs_ = std::conditional_t<std::ratio_less<T, Zero>::value, std::ratio_subtract<Zero, T>, T>;
1291
1292 using R = Tr;
1293 using Last_ = ContinuedFraction<R, N - 1>;
1294 using Reciprocal_ = Reciprocal<typename Last_::Rem>;
1295 using Rem = typename Reciprocal_::Rem;
1296 using I_ = typename Reciprocal_::I;
1297 using Den_ = std::ratio_add<typename Last_::W, I_>;
1298 using U = std::ratio_divide<typename Last_::V, Den_>;
1299 using V = std::ratio_divide<std::ratio_add<typename Last_::U, std::ratio_multiply<typename Last_::V, I_>>, Den_>;
1300 using W = std::ratio_divide<One, Den_>;
1301 using Error = Abs_<std::ratio_divide<std::ratio_subtract<U, std::ratio_multiply<V, W>>, typename Reciprocal<Rem>::I>>;
1302 };
1303
1304 template <typename Tr>
1305 struct ContinuedFraction<Tr, 1> {
1306 using R = Tr;
1307 using U = One;
1308 using V = std::ratio<Integer<R>::value>;
1309 using W = Zero;
1310 using Rem = Remainder<R, V>;
1311 using Error = std::ratio_divide<One, typename Reciprocal<Rem>::I>;
1312 };
1313
1314 template <typename R, typename Eps, std::intmax_t N = 1, typename enabled = void>
1315 struct Sqrt_ : Sqrt_<R, Eps, N + 1> {};
1316
1317 template <typename R, typename Eps, std::intmax_t N>
1318 struct Sqrt_<R, Eps, N, std::enable_if_t<std::ratio_less_equal<typename ContinuedFraction<R, N>::Error, Eps>::value>> {
1319 using type = typename ContinuedFraction<R, N>::V;
1320 };
1321
1322 template <typename R, typename Eps, typename enabled = void>
1323 struct Sqrt {
1324 static_assert(std::ratio_greater_equal<R, Zero>::value, "R can't be negative");
1325 };
1326
1327 template <typename R, typename Eps>
1328 struct Sqrt<R, Eps, std::enable_if_t<std::ratio_greater_equal<R, Zero>::value && IsPerfectSquare<R>::value>> {
1329 using type = typename IsPerfectSquare<R>::Sqrt;
1330 };
1331
1332 template <typename R, typename Eps>
1333 struct Sqrt<R, Eps, std::enable_if_t<(std::ratio_greater_equal<R, Zero>::value && !IsPerfectSquare<R>::value)>> : Sqrt_<R, Eps>{};
1334 }
1335 /** @endcond */ // END DOXYGEN IGNORE
1336
1337 /**
1338 * @ingroup TypeTraits
1339 * @brief Calculate square root of a ratio at compile-time
1340 * @details Calculates a rational approximation of the square root of the ratio. The error
1341 * in the calculation is bounded by 1/epsilon (Eps). E.g. for the default value
1342 * of 10000000000, the maximum error will be a/10000000000, or 1e-8, or said another way,
1343 * the error will be on the order of 10^-9. Since these calculations are done at
1344 * compile time, it is advisable to set epsilon to the highest value that does not
1345 * cause an integer overflow in the calculation. If you can't compile `ratio_sqrt`
1346 * due to overflow errors, reducing the value of epsilon sufficiently will correct
1347 * the problem.\n\n
1348 * `ratio_sqrt` is guaranteed to converge for all values of `Ratio` which do not
1349 * overflow.
1350 * @note This function provides a rational approximation, _NOT_ an exact value.
1351 * @tparam Ratio ratio to take the square root of. This can represent any rational value,
1352 * _not_ just integers or values with integer roots.
1353 * @tparam Eps Value of epsilon, which represents the inverse of the maximum allowable
1354 * error. This value should be chosen to be as high as possible before
1355 * integer overflow errors occur in the compiler.
1356 */
1357 template<typename Ratio, std::intmax_t Eps = 10000000000>
1358 using ratio_sqrt = typename units::detail::Sqrt<Ratio, std::ratio<1, Eps>>::type;
1359
1360 /** @cond */ // DOXYGEN IGNORE
1361 namespace detail
1362 {
1363 /**
1364 * @brief implementation of `sqrt`
1365 * @details square roots the conversion ratio, `base_unit` exponents, pi exponents, and removes
1366 * datum translation ratios.
1367 */
1368 template<class Unit, std::intmax_t Eps>
1369 struct sqrt_impl
1370 {
1371 static_assert(traits::is_unit<Unit>::value, "Template parameter `Unit` must be a `unit` type.");
1372 using Conversion = typename Unit::conversion_ratio;
1374 sqrt_base<traits::base_unit_of<typename Unit::base_unit_type>>,
1375 std::ratio_divide<typename Unit::pi_exponent_ratio, std::ratio<2>>,
1376 typename Unit::translation_ratio>;
1377 };
1378 }
1379 /** @endcond */ // END DOXYGEN IGNORE
1380
1381 /**
1382 * @ingroup UnitManipulators
1383 * @brief represents the square root of type `class U`.
1384 * @details Calculates a rational approximation of the square root of the unit. The error
1385 * in the calculation is bounded by 1/epsilon (Eps). E.g. for the default value
1386 * of 10000000000, the maximum error will be a/10000000000, or 1e-8, or said another way,
1387 * the error will be on the order of 10^-9. Since these calculations are done at
1388 * compile time, it is advisable to set epsilon to the highest value that does not
1389 * cause an integer overflow in the calculation. If you can't compile `ratio_sqrt`
1390 * due to overflow errors, reducing the value of epsilon sufficiently will correct
1391 * the problem.\n\n
1392 * `ratio_sqrt` is guaranteed to converge for all values of `Ratio` which do not
1393 * overflow.
1394 * @tparam U `unit` type to take the square root of.
1395 * @tparam Eps Value of epsilon, which represents the inverse of the maximum allowable
1396 * error. This value should be chosen to be as high as possible before
1397 * integer overflow errors occur in the compiler.
1398 * @note USE WITH CAUTION. The is an approximate value. In general, squared<sqrt<meter>> != meter,
1399 * i.e. the operation is not reversible, and it will result in propagated approximations.
1400 * Use only when absolutely necessary.
1401 */
1402 template<class U, std::intmax_t Eps = 10000000000>
1404
1405 //------------------------------
1406 // COMPOUND UNITS
1407 //------------------------------
1408
1409 /** @cond */ // DOXYGEN IGNORE
1410 namespace detail
1411 {
1412 /**
1413 * @brief implementation of compound_unit
1414 * @details multiplies a variadic list of units together, and is inherited from the resulting
1415 * type.
1416 */
1417 template<class U, class... Us> struct compound_impl;
1418 template<class U> struct compound_impl<U> { using type = U; };
1419 template<class U1, class U2, class...Us>
1420 struct compound_impl<U1, U2, Us...>
1421 : compound_impl<unit_multiply<U1, U2>, Us...> {};
1422 }
1423 /** @endcond */ // END DOXYGEN IGNORE
1424
1425 /**
1426 * @brief Represents a unit type made up from other units.
1427 * @details Compound units are formed by multiplying the units of all the types provided in
1428 * the template argument. Types provided must inherit from `unit`. A compound unit can
1429 * be formed from any number of other units, and unit manipulators like `inverse` and
1430 * `squared` are supported. E.g. to specify acceleration, on could create
1431 * `using acceleration = compound_unit<length::meters, inverse<squared<seconds>>;`
1432 * @tparam U... units which, when multiplied together, form the desired compound unit.
1433 * @ingroup UnitTypes
1434 */
1435 template<class U, class... Us>
1436 using compound_unit = typename units::detail::compound_impl<U, Us...>::type;
1437
1438 //------------------------------
1439 // PREFIXES
1440 //------------------------------
1441
1442 /** @cond */ // DOXYGEN IGNORE
1443 namespace detail
1444 {
1445 /**
1446 * @brief prefix applicator.
1447 * @details creates a unit type from a prefix and a unit
1448 */
1449 template<class Ratio, class Unit>
1450 struct prefix
1451 {
1452 static_assert(traits::is_ratio<Ratio>::value, "Template parameter `Ratio` must be a `std::ratio`.");
1453 static_assert(traits::is_unit<Unit>::value, "Template parameter `Unit` must be a `unit` type.");
1454 typedef typename units::unit<Ratio, Unit> type;
1455 };
1456
1457 /// recursive exponential implementation
1458 template <int N, class U>
1459 struct power_of_ratio
1460 {
1461 typedef std::ratio_multiply<U, typename power_of_ratio<N - 1, U>::type> type;
1462 };
1463
1464 /// End recursion
1465 template <class U>
1466 struct power_of_ratio<1, U>
1467 {
1468 typedef U type;
1469 };
1470 }
1471 /** @endcond */ // END DOXYGEN IGNORE
1472
1473 /**
1474 * @ingroup UnitManipulators
1475 * @{
1476 * @ingroup Decimal Prefixes
1477 * @{
1478 */
1479 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.
1480 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.
1481 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.
1482 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.
1483 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.
1484 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.
1485 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.
1486 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.
1487 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.
1488 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.
1489 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.
1490 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.
1491 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.
1492 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.
1493 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.
1494 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.
1495 /** @} @} */
1496
1497 /**
1498 * @ingroup UnitManipulators
1499 * @{
1500 * @ingroup Binary Prefixes
1501 * @{
1502 */
1503 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.
1504 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.
1505 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.
1506 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.
1507 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.
1508 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.
1509 /** @} @} */
1510
1511 //------------------------------
1512 // CONVERSION TRAITS
1513 //------------------------------
1514
1515 namespace traits
1516 {
1517 /**
1518 * @ingroup TypeTraits
1519 * @brief Trait which checks whether two units can be converted to each other
1520 * @details Inherits from `std::true_type` or `std::false_type`. Use `is_convertible_unit<U1, U2>::value` to test
1521 * whether `class U1` is convertible to `class U2`. Note: convertible has both the semantic meaning,
1522 * (i.e. meters can be converted to feet), and the c++ meaning of conversion (type meters can be
1523 * converted to type feet). Conversion is always symmetric, so if U1 is convertible to U2, then
1524 * U2 will be convertible to U1.
1525 * @tparam U1 Unit to convert from.
1526 * @tparam U2 Unit to convert to.
1527 * @sa is_convertible_unit_t
1528 */
1529 template<class U1, class U2>
1530 struct is_convertible_unit : std::is_same <traits::base_unit_of<typename units::traits::unit_traits<U1>::base_unit_type>,
1531 base_unit_of<typename units::traits::unit_traits<U2>::base_unit_type >> {};
1532 template<class U1, class U2>
1534 }
1535
1536 //------------------------------
1537 // CONVERSION FUNCTION
1538 //------------------------------
1539
1540 /** @cond */ // DOXYGEN IGNORE
1541 namespace detail
1542 {
1543 constexpr inline UNIT_LIB_DEFAULT_TYPE pow(UNIT_LIB_DEFAULT_TYPE x, unsigned long long y)
1544 {
1545 return y == 0 ? 1.0 : x * pow(x, y - 1);
1546 }
1547
1549 {
1550 return x < 0 ? -x : x;
1551 }
1552
1553 /// convert dispatch for units which are both the same
1554 template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
1555 static inline constexpr T convert(const T& value, std::true_type, std::false_type, std::false_type) noexcept
1556 {
1557 return value;
1558 }
1559
1560 /// convert dispatch for units which are both the same
1561 template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
1562 static inline constexpr T convert(const T& value, std::true_type, std::false_type, std::true_type) noexcept
1563 {
1564 return value;
1565 }
1566
1567 /// convert dispatch for units which are both the same
1568 template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
1569 static inline constexpr T convert(const T& value, std::true_type, std::true_type, std::false_type) noexcept
1570 {
1571 return value;
1572 }
1573
1574 /// convert dispatch for units which are both the same
1575 template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
1576 static inline constexpr T convert(const T& value, std::true_type, std::true_type, std::true_type) noexcept
1577 {
1578 return value;
1579 }
1580
1581 /// convert dispatch for units of different types w/ no translation and no PI
1582 template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
1583 static inline constexpr T convert(const T& value, std::false_type, std::false_type, std::false_type) noexcept
1584 {
1585 return ((value * Ratio::num) / Ratio::den);
1586 }
1587
1588 /// convert dispatch for units of different types w/ no translation, but has PI in numerator
1589 // constepxr with PI in numerator
1590 template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
1591 static inline constexpr
1592 std::enable_if_t<(PiRatio::num / PiRatio::den >= 1 && PiRatio::num % PiRatio::den == 0), T>
1593 convert(const T& value, std::false_type, std::true_type, std::false_type) noexcept
1594 {
1595 return ((value * pow(constants::detail::PI_VAL, PiRatio::num / PiRatio::den) * Ratio::num) / Ratio::den);
1596 }
1597
1598 /// convert dispatch for units of different types w/ no translation, but has PI in denominator
1599 // constexpr with PI in denominator
1600 template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
1601 static inline constexpr
1602 std::enable_if_t<(PiRatio::num / PiRatio::den <= -1 && PiRatio::num % PiRatio::den == 0), T>
1603 convert(const T& value, std::false_type, std::true_type, std::false_type) noexcept
1604 {
1605 return (value * Ratio::num) / (Ratio::den * pow(constants::detail::PI_VAL, -PiRatio::num / PiRatio::den));
1606 }
1607
1608 /// convert dispatch for units of different types w/ no translation, but has PI in numerator
1609 // Not constexpr - uses std::pow
1610 template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
1611 static inline // sorry, this can't be constexpr!
1612 std::enable_if_t<(PiRatio::num / PiRatio::den < 1 && PiRatio::num / PiRatio::den > -1), T>
1613 convert(const T& value, std::false_type, std::true_type, std::false_type) noexcept
1614 {
1615 return ((value * std::pow(constants::detail::PI_VAL, PiRatio::num / PiRatio::den) * Ratio::num) / Ratio::den);
1616 }
1617
1618 /// convert dispatch for units of different types with a translation, but no PI
1619 template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
1620 static inline constexpr T convert(const T& value, std::false_type, std::false_type, std::true_type) noexcept
1621 {
1622 return ((value * Ratio::num) / Ratio::den) + (static_cast<UNIT_LIB_DEFAULT_TYPE>(Translation::num) / Translation::den);
1623 }
1624
1625 /// convert dispatch for units of different types with a translation AND PI
1626 template<class UnitFrom, class UnitTo, class Ratio, class PiRatio, class Translation, typename T>
1627 static inline constexpr T convert(const T& value, const std::false_type, const std::true_type, const std::true_type) noexcept
1628 {
1629 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);
1630 }
1631 }
1632 /** @endcond */ // END DOXYGEN IGNORE
1633
1634 /**
1635 * @ingroup Conversion
1636 * @brief converts a <i>value</i> from one type to another.
1637 * @details Converts a <i>value</i> of a built-in arithmetic type to another unit. This does not change
1638 * 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
1639 * @sa unit_t for implicit conversion of unit containers.
1640 * @tparam UnitFrom unit tag to convert <i>value</i> from. Must be a `unit` type (i.e. is_unit<UnitFrom>::value == true),
1641 * and must be convertible to `UnitTo` (i.e. is_convertible_unit<UnitFrom, UnitTo>::value == true).
1642 * @tparam UnitTo unit tag to convert <i>value</i> to. Must be a `unit` type (i.e. is_unit<UnitTo>::value == true),
1643 * and must be convertible from `UnitFrom` (i.e. is_convertible_unit<UnitFrom, UnitTo>::value == true).
1644 * @tparam T type of <i>value</i>. It is inferred from <i>value</i>, and is expected to be a built-in arithmetic type.
1645 * @param[in] value Arithmetic value to convert from `UnitFrom` to `UnitTo`. The value should represent
1646 * a quantity in units of `UnitFrom`.
1647 * @returns value, converted from units of `UnitFrom` to `UnitTo`.
1648 */
1649 template<class UnitFrom, class UnitTo, typename T = UNIT_LIB_DEFAULT_TYPE>
1650 static inline constexpr T convert(const T& value) noexcept
1651 {
1652 static_assert(traits::is_unit<UnitFrom>::value, "Template parameter `UnitFrom` must be a `unit` type.");
1653 static_assert(traits::is_unit<UnitTo>::value, "Template parameter `UnitTo` must be a `unit` type.");
1654 static_assert(traits::is_convertible_unit<UnitFrom, UnitTo>::value, "Units are not compatible.");
1655
1656 using Ratio = std::ratio_divide<typename UnitFrom::conversion_ratio, typename UnitTo::conversion_ratio>;
1657 using PiRatio = std::ratio_subtract<typename UnitFrom::pi_exponent_ratio, typename UnitTo::pi_exponent_ratio>;
1658 using Translation = std::ratio_divide<std::ratio_subtract<typename UnitFrom::translation_ratio, typename UnitTo::translation_ratio>, typename UnitTo::conversion_ratio>;
1659
1660 using isSame = typename std::is_same<std::decay_t<UnitFrom>, std::decay_t<UnitTo>>::type;
1661 using piRequired = std::integral_constant<bool, !(std::is_same<std::ratio<0>, PiRatio>::value)>;
1662 using translationRequired = std::integral_constant<bool, !(std::is_same<std::ratio<0>, Translation>::value)>;
1663
1664 return units::detail::convert<UnitFrom, UnitTo, Ratio, PiRatio, Translation, T>
1665 (value, isSame{}, piRequired{}, translationRequired{});
1666 }
1667
1668 //----------------------------------
1669 // NON-LINEAR SCALE TRAITS
1670 //----------------------------------
1671
1672 /** @cond */ // DOXYGEN IGNORE
1673 namespace traits
1674 {
1675 namespace detail
1676 {
1677 /**
1678 * @brief implementation of has_operator_parenthesis
1679 * @details checks that operator() returns the same type as `Ret`
1680 */
1681 template<class T, class Ret>
1682 struct has_operator_parenthesis_impl
1683 {
1684 template<class U>
1685 static constexpr auto test(U*) -> decltype(std::declval<U>()()) { return decltype(std::declval<U>()()){}; }
1686 template<typename>
1687 static constexpr std::false_type test(...) { return std::false_type{}; }
1688
1689 using type = typename std::is_same<Ret, decltype(test<T>(0))>::type;
1690 };
1691 }
1692
1693 /**
1694 * @brief checks that `class T` has an `operator()` member which returns `Ret`
1695 * @details used as part of the linear_scale concept.
1696 */
1697 template<class T, class Ret>
1698 struct has_operator_parenthesis : traits::detail::has_operator_parenthesis_impl<T, Ret>::type {};
1699 }
1700
1701 namespace traits
1702 {
1703 namespace detail
1704 {
1705 /**
1706 * @brief implementation of has_value_member
1707 * @details checks for a member named `m_member` with type `Ret`
1708 */
1709 template<class T, class Ret>
1710 struct has_value_member_impl
1711 {
1712 template<class U>
1713 static constexpr auto test(U* p) -> decltype(p->m_value) { return p->m_value; }
1714 template<typename>
1715 static constexpr auto test(...)->std::false_type { return std::false_type{}; }
1716
1717 using type = typename std::is_same<std::decay_t<Ret>, std::decay_t<decltype(test<T>(0))>>::type;
1718 };
1719 }
1720
1721 /**
1722 * @brief checks for a member named `m_member` with type `Ret`
1723 * @details used as part of the linear_scale concept checker.
1724 */
1725 template<class T, class Ret>
1726 struct has_value_member : traits::detail::has_value_member_impl<T, Ret>::type {};
1727 template<class T, class Ret>
1728 inline constexpr bool has_value_member_v = has_value_member<T, Ret>::value;
1729 }
1730 /** @endcond */ // END DOXYGEN IGNORE
1731
1732 namespace traits
1733 {
1734 /**
1735 * @ingroup TypeTraits
1736 * @brief Trait which tests that `class T` meets the requirements for a non-linear scale
1737 * @details A non-linear scale must:
1738 * - be default constructible
1739 * - have an `operator()` member which returns the non-linear value stored in the scale
1740 * - have an accessible `m_value` member type which stores the linearized value in the scale.
1741 *
1742 * Linear/nonlinear scales are used by `units::unit` to store values and scale them
1743 * if they represent things like dB.
1744 */
1745 template<class T, class Ret>
1746 struct is_nonlinear_scale : std::integral_constant<bool,
1747 std::is_default_constructible<T>::value &&
1748 has_operator_parenthesis<T, Ret>::value &&
1749 has_value_member<T, Ret>::value &&
1750 std::is_trivial<T>::value>
1751 {};
1752 }
1753
1754 //------------------------------
1755 // UNIT_T TYPE TRAITS
1756 //------------------------------
1757
1758 namespace traits
1759 {
1760#ifdef FOR_DOXYGEN_PURPOSOES_ONLY
1761 /**
1762 * @ingroup TypeTraits
1763 * @brief Trait for accessing the publicly defined types of `units::unit_t`
1764 * @details The units library determines certain properties of the unit_t types passed to them
1765 * and what they represent by using the members of the corresponding unit_t_traits instantiation.
1766 */
1767 template<typename T>
1768 struct unit_t_traits
1769 {
1770 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.
1771 typedef typename T::underlying_type underlying_type; ///< Underlying storage type of the `unit_t`, e.g. `double`.
1772 typedef typename T::value_type value_type; ///< Synonym for underlying type. May be removed in future versions. Prefer underlying_type.
1773 typedef typename T::unit_type unit_type; ///< Type of unit the `unit_t` represents, e.g. `meters`
1774 };
1775#endif
1776
1777 /** @cond */ // DOXYGEN IGNORE
1778 /**
1779 * @brief unit_t_traits specialization for things which are not unit_t
1780 * @details
1781 */
1782 template<typename T, typename = void>
1783 struct unit_t_traits
1784 {
1785 typedef void non_linear_scale_type;
1786 typedef void underlying_type;
1787 typedef void value_type;
1788 typedef void unit_type;
1789 };
1790
1791 /**
1792 * @ingroup TypeTraits
1793 * @brief Trait for accessing the publicly defined types of `units::unit_t`
1794 * @details
1795 */
1796 template<typename T>
1797 struct unit_t_traits <T, typename void_t<
1798 typename T::non_linear_scale_type,
1799 typename T::underlying_type,
1800 typename T::value_type,
1801 typename T::unit_type>::type>
1802 {
1803 typedef typename T::non_linear_scale_type non_linear_scale_type;
1804 typedef typename T::underlying_type underlying_type;
1805 typedef typename T::value_type value_type;
1806 typedef typename T::unit_type unit_type;
1807 };
1808 /** @endcond */ // END DOXYGEN IGNORE
1809 }
1810
1811 namespace traits
1812 {
1813 /**
1814 * @ingroup TypeTraits
1815 * @brief Trait which tests whether two container types derived from `unit_t` are convertible to each other
1816 * @details Inherits from `std::true_type` or `std::false_type`. Use `is_convertible_unit_t<U1, U2>::value` to test
1817 * whether `class U1` is convertible to `class U2`. Note: convertible has both the semantic meaning,
1818 * (i.e. meters can be converted to feet), and the c++ meaning of conversion (type meters can be
1819 * converted to type feet). Conversion is always symmetric, so if U1 is convertible to U2, then
1820 * U2 will be convertible to U1.
1821 * @tparam U1 Unit to convert from.
1822 * @tparam U2 Unit to convert to.
1823 * @sa is_convertible_unit
1824 */
1825 template<class U1, class U2>
1826 struct is_convertible_unit_t : std::integral_constant<bool,
1827 is_convertible_unit<typename units::traits::unit_t_traits<U1>::unit_type, typename units::traits::unit_t_traits<U2>::unit_type>::value>
1828 {};
1829 }
1830
1831 //----------------------------------
1832 // UNIT TYPE
1833 //----------------------------------
1834
1835 /** @cond */ // DOXYGEN IGNORE
1836 // forward declaration
1837 template<typename T> struct linear_scale;
1838 template<typename T> struct decibel_scale;
1839
1840 namespace detail
1841 {
1842 /**
1843 * @brief helper type to identify units.
1844 * @details A non-templated base class for `unit` which enables RTTI testing.
1845 */
1846 struct _unit_t {};
1847 }
1848 /** @endcond */ // END DOXYGEN IGNORE
1849
1850 namespace traits
1851 {
1852 // forward declaration
1853 #if !defined(_MSC_VER) || _MSC_VER > 1800 // bug in VS2013 prevents this from working
1854 template<typename... T> struct is_dimensionless_unit;
1855 #else
1856 template<typename T1, typename T2 = T1, typename T3 = T1> struct is_dimensionless_unit;
1857 #endif
1858
1859 /**
1860 * @ingroup TypeTraits
1861 * @brief Traits which tests if a class is a `unit`
1862 * @details Inherits from `std::true_type` or `std::false_type`. Use `is_unit<T>::value` to test
1863 * whether `class T` implements a `unit`.
1864 */
1865 template<class T>
1866 struct is_unit_t : std::is_base_of<units::detail::_unit_t, T>::type {};
1867 template<class T>
1868 inline constexpr bool is_unit_t_v = is_unit_t<T>::value;
1869 }
1870
1871 /**
1872 * @ingroup UnitContainers
1873 * @brief Container for values which represent quantities of a given unit.
1874 * @details Stores a value which represents a quantity in the given units. Unit containers
1875 * (except scalar values) are *not* convertible to built-in c++ types, in order to
1876 * provide type safety in dimensional analysis. Unit containers *are* implicitly
1877 * convertible to other compatible unit container types. Unit containers support
1878 * various types of arithmetic operations, depending on their scale type.
1879 *
1880 * The value of a `unit_t` can only be changed on construction, or by assignment
1881 * from another `unit_t` type. If necessary, the underlying value can be accessed
1882 * using `operator()`: @code
1883 * meter_t m(5.0);
1884 * double val = m(); // val == 5.0 @endcode.
1885 * @tparam Units unit tag for which type of units the `unit_t` represents (e.g. meters)
1886 * @tparam T underlying type of the storage. Defaults to double.
1887 * @tparam NonLinearScale optional scale class for the units. Defaults to linear (i.e. does
1888 * not scale the unit value). Examples of non-linear scales could be logarithmic,
1889 * decibel, or richter scales. Non-linear scales must adhere to the non-linear-scale
1890 * concept, i.e. `is_nonlinear_scale<...>::value` must be `true`.
1891 * @sa
1892 * - \ref lengthContainers "length unit containers"
1893 * - \ref massContainers "mass unit containers"
1894 * - \ref timeContainers "time unit containers"
1895 * - \ref angleContainers "angle unit containers"
1896 * - \ref currentContainers "current unit containers"
1897 * - \ref temperatureContainers "temperature unit containers"
1898 * - \ref substanceContainers "substance unit containers"
1899 * - \ref luminousIntensityContainers "luminous intensity unit containers"
1900 * - \ref solidAngleContainers "solid angle unit containers"
1901 * - \ref frequencyContainers "frequency unit containers"
1902 * - \ref velocityContainers "velocity unit containers"
1903 * - \ref angularVelocityContainers "angular velocity unit containers"
1904 * - \ref accelerationContainers "acceleration unit containers"
1905 * - \ref forceContainers "force unit containers"
1906 * - \ref pressureContainers "pressure unit containers"
1907 * - \ref chargeContainers "charge unit containers"
1908 * - \ref energyContainers "energy unit containers"
1909 * - \ref powerContainers "power unit containers"
1910 * - \ref voltageContainers "voltage unit containers"
1911 * - \ref capacitanceContainers "capacitance unit containers"
1912 * - \ref impedanceContainers "impedance unit containers"
1913 * - \ref magneticFluxContainers "magnetic flux unit containers"
1914 * - \ref magneticFieldStrengthContainers "magnetic field strength unit containers"
1915 * - \ref inductanceContainers "inductance unit containers"
1916 * - \ref luminousFluxContainers "luminous flux unit containers"
1917 * - \ref illuminanceContainers "illuminance unit containers"
1918 * - \ref radiationContainers "radiation unit containers"
1919 * - \ref torqueContainers "torque unit containers"
1920 * - \ref areaContainers "area unit containers"
1921 * - \ref volumeContainers "volume unit containers"
1922 * - \ref densityContainers "density unit containers"
1923 * - \ref concentrationContainers "concentration unit containers"
1924 * - \ref constantContainers "constant unit containers"
1925 */
1926 template<class Units, typename T = UNIT_LIB_DEFAULT_TYPE, template<typename> class NonLinearScale = linear_scale>
1927 class unit_t : public NonLinearScale<T>, units::detail::_unit_t
1928 {
1929 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).");
1930 static_assert(traits::is_nonlinear_scale<NonLinearScale<T>, T>::value, "Template parameter `NonLinearScale` does not conform to the `is_nonlinear_scale` concept.");
1931
1932 protected:
1933
1934 using nls = NonLinearScale<T>;
1935 using nls::m_value;
1936
1937 public:
1938
1939 typedef NonLinearScale<T> non_linear_scale_type; ///< Type of the non-linear scale of the unit_t (e.g. linear_scale)
1940 typedef T underlying_type; ///< Type of the underlying storage of the unit_t (e.g. double)
1941 typedef T value_type; ///< Synonym for underlying type. May be removed in future versions. Prefer underlying_type.
1942 typedef Units unit_type; ///< Type of `unit` the `unit_t` represents (e.g. meters)
1943
1944 /**
1945 * @ingroup Constructors
1946 * @brief default constructor.
1947 */
1948 constexpr unit_t() = default;
1949
1950 /**
1951 * @brief constructor
1952 * @details constructs a new unit_t using the non-linear scale's constructor.
1953 * @param[in] value unit value magnitude.
1954 * @param[in] args additional constructor arguments are forwarded to the non-linear scale constructor. Which
1955 * args are required depends on which scale is used. For the default (linear) scale,
1956 * no additional args are necessary.
1957 */
1958 template<class... Args>
1959 inline explicit constexpr unit_t(const T value, const Args&... args) noexcept : nls(value, args...)
1960 {
1961
1962 }
1963
1964 /**
1965 * @brief constructor
1966 * @details enable implicit conversions from T types ONLY for linear scalar units
1967 * @param[in] value value of the unit_t
1968 */
1969 template<class Ty, class = typename std::enable_if<traits::is_dimensionless_unit<Units>::value && std::is_arithmetic<Ty>::value>::type>
1970 inline constexpr unit_t(const Ty value) noexcept : nls(value)
1971 {
1972
1973 }
1974
1975 /**
1976 * @brief chrono constructor
1977 * @details enable implicit conversions from std::chrono::duration types ONLY for time units
1978 * @param[in] value value of the unit_t
1979 */
1980 template<class Rep, class Period, class = std::enable_if_t<std::is_arithmetic<Rep>::value && traits::is_ratio<Period>::value>>
1981 inline constexpr unit_t(const std::chrono::duration<Rep, Period>& value) noexcept :
1982 nls(units::convert<unit<std::ratio<1,1000000000>, category::time_unit>, Units>(static_cast<T>(std::chrono::duration_cast<std::chrono::nanoseconds>(value).count())))
1983 {
1984
1985 }
1986
1987 /**
1988 * @brief copy constructor (converting)
1989 * @details performs implicit unit conversions if required.
1990 * @param[in] rhs unit to copy.
1991 */
1992 template<class UnitsRhs, typename Ty, template<typename> class NlsRhs>
1993 inline constexpr unit_t(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) noexcept :
1994 nls(units::convert<UnitsRhs, Units, T>(rhs.m_value), std::true_type() /*store linear value*/)
1995 {
1996
1997 }
1998
1999 /**
2000 * @brief assignment
2001 * @details performs implicit unit conversions if required
2002 * @param[in] rhs unit to copy.
2003 */
2004 template<class UnitsRhs, typename Ty, template<typename> class NlsRhs>
2005 inline unit_t& operator=(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) noexcept
2006 {
2007 nls::m_value = units::convert<UnitsRhs, Units, T>(rhs.m_value);
2008 return *this;
2009 }
2010
2011 /**
2012 * @brief assignment
2013 * @details performs implicit conversions from built-in types ONLY for scalar units
2014 * @param[in] rhs value to copy.
2015 */
2016 template<class Ty, class = std::enable_if_t<traits::is_dimensionless_unit<Units>::value && std::is_arithmetic<Ty>::value>>
2017 inline unit_t& operator=(const Ty& rhs) noexcept
2018 {
2019 nls::m_value = rhs;
2020 return *this;
2021 }
2022
2023 /**
2024 * @brief less-than
2025 * @details compares the linearized value of two units. Performs unit conversions if necessary.
2026 * @param[in] rhs right-hand side unit for the comparison
2027 * @returns true IFF the value of `this` is less than the value of `rhs`
2028 */
2029 template<class UnitsRhs, typename Ty, template<typename> class NlsRhs>
2030 inline constexpr bool operator<(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept
2031 {
2032 return (nls::m_value < units::convert<UnitsRhs, Units>(rhs.m_value));
2033 }
2034
2035 /**
2036 * @brief less-than or equal
2037 * @details compares the linearized value of two units. Performs unit conversions if necessary.
2038 * @param[in] rhs right-hand side unit for the comparison
2039 * @returns true IFF the value of `this` is less than or equal to the value of `rhs`
2040 */
2041 template<class UnitsRhs, typename Ty, template<typename> class NlsRhs>
2042 inline constexpr bool operator<=(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept
2043 {
2044 return (nls::m_value <= units::convert<UnitsRhs, Units>(rhs.m_value));
2045 }
2046
2047 /**
2048 * @brief greater-than
2049 * @details compares the linearized value of two units. Performs unit conversions if necessary.
2050 * @param[in] rhs right-hand side unit for the comparison
2051 * @returns true IFF the value of `this` is greater than the value of `rhs`
2052 */
2053 template<class UnitsRhs, typename Ty, template<typename> class NlsRhs>
2054 inline constexpr bool operator>(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept
2055 {
2056 return (nls::m_value > units::convert<UnitsRhs, Units>(rhs.m_value));
2057 }
2058
2059 /**
2060 * @brief greater-than or equal
2061 * @details compares the linearized value of two units. Performs unit conversions if necessary.
2062 * @param[in] rhs right-hand side unit for the comparison
2063 * @returns true IFF the value of `this` is greater than or equal to the value of `rhs`
2064 */
2065 template<class UnitsRhs, typename Ty, template<typename> class NlsRhs>
2066 inline constexpr bool operator>=(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept
2067 {
2068 return (nls::m_value >= units::convert<UnitsRhs, Units>(rhs.m_value));
2069 }
2070
2071 /**
2072 * @brief equality
2073 * @details compares the linearized value of two units. Performs unit conversions if necessary.
2074 * @param[in] rhs right-hand side unit for the comparison
2075 * @returns true IFF the value of `this` exactly equal to the value of rhs.
2076 * @note This may not be suitable for all applications when the underlying_type of unit_t is a double.
2077 */
2078 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>
2079 inline constexpr bool operator==(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept
2080 {
2081 return detail::abs(nls::m_value - units::convert<UnitsRhs, Units>(rhs.m_value)) < std::numeric_limits<T>::epsilon() *
2082 detail::abs(nls::m_value + units::convert<UnitsRhs, Units>(rhs.m_value)) ||
2083 detail::abs(nls::m_value - units::convert<UnitsRhs, Units>(rhs.m_value)) < (std::numeric_limits<T>::min)();
2084 }
2085
2086 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>
2087 inline constexpr bool operator==(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept
2088 {
2089 return nls::m_value == units::convert<UnitsRhs, Units>(rhs.m_value);
2090 }
2091
2092 /**
2093 * @brief inequality
2094 * @details compares the linearized value of two units. Performs unit conversions if necessary.
2095 * @param[in] rhs right-hand side unit for the comparison
2096 * @returns true IFF the value of `this` is not equal to the value of rhs.
2097 * @note This may not be suitable for all applications when the underlying_type of unit_t is a double.
2098 */
2099 template<class UnitsRhs, typename Ty, template<typename> class NlsRhs>
2100 inline constexpr bool operator!=(const unit_t<UnitsRhs, Ty, NlsRhs>& rhs) const noexcept
2101 {
2102 return !(*this == rhs);
2103 }
2104
2105 /**
2106 * @brief unit value
2107 * @returns value of the unit in it's underlying, non-safe type.
2108 */
2109 inline constexpr underlying_type value() const noexcept
2110 {
2111 return static_cast<underlying_type>(*this);
2112 }
2113
2114 /**
2115 * @brief unit value
2116 * @returns value of the unit converted to an arithmetic, non-safe type.
2117 */
2118 template<typename Ty, class = std::enable_if_t<std::is_arithmetic<Ty>::value>>
2119 inline constexpr Ty to() const noexcept
2120 {
2121 return static_cast<Ty>(*this);
2122 }
2123
2124 /**
2125 * @brief linearized unit value
2126 * @returns linearized value of unit which has a non-linear scale. For `unit_t` types with
2127 * linear scales, this is equivalent to `value`.
2128 */
2129 template<typename Ty, class = std::enable_if_t<std::is_arithmetic<Ty>::value>>
2130 inline constexpr Ty toLinearized() const noexcept
2131 {
2132 return static_cast<Ty>(m_value);
2133 }
2134
2135 /**
2136 * @brief conversion
2137 * @details Converts to a different unit container. Units can be converted to other containers
2138 * implicitly, but this can be used in cases where explicit notation of a conversion
2139 * is beneficial, or where an r-value container is needed.
2140 * @tparam U unit (not unit_t) to convert to
2141 * @returns a unit container with the specified units containing the equivalent value to
2142 * *this.
2143 */
2144 template<class U>
2145 inline constexpr unit_t<U> convert() const noexcept
2146 {
2147 static_assert(traits::is_unit<U>::value, "Template parameter `U` must be a unit type.");
2148 return unit_t<U>(*this);
2149 }
2150
2151 /**
2152 * @brief implicit type conversion.
2153 * @details only enabled for scalar unit types.
2154 */
2155 template<class Ty, std::enable_if_t<traits::is_dimensionless_unit<Units>::value && std::is_arithmetic<Ty>::value, int> = 0>
2156 inline constexpr operator Ty() const noexcept
2157 {
2158 // this conversion also resolves any PI exponents, by converting from a non-zero PI ratio to a zero-pi ratio.
2159 return static_cast<Ty>(units::convert<Units, unit<std::ratio<1>, units::category::scalar_unit>>((*this)()));
2160 }
2161
2162 /**
2163 * @brief explicit type conversion.
2164 * @details only enabled for non-dimensionless unit types.
2165 */
2166 template<class Ty, std::enable_if_t<!traits::is_dimensionless_unit<Units>::value && std::is_arithmetic<Ty>::value, int> = 0>
2167 inline constexpr explicit operator Ty() const noexcept
2168 {
2169 return static_cast<Ty>((*this)());
2170 }
2171
2172 /**
2173 * @brief chrono implicit type conversion.
2174 * @details only enabled for time unit types.
2175 */
2176 template<typename U = Units, std::enable_if_t<units::traits::is_convertible_unit<U, unit<std::ratio<1>, category::time_unit>>::value, int> = 0>
2177 inline constexpr operator std::chrono::nanoseconds() const noexcept
2178 {
2179 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)())));
2180 }
2181
2182 /**
2183 * @brief returns the unit name
2184 */
2185 inline constexpr const char* name() const noexcept
2186 {
2187 return units::name(*this);
2188 }
2189
2190 /**
2191 * @brief returns the unit abbreviation
2192 */
2193 inline constexpr const char* abbreviation() const noexcept
2194 {
2195 return units::abbreviation(*this);
2196 }
2197
2198 public:
2199
2200 template<class U, typename Ty, template<typename> class Nlt>
2201 friend class unit_t;
2202 };
2203
2204 //------------------------------
2205 // UNIT_T NON-MEMBER FUNCTIONS
2206 //------------------------------
2207
2208 /**
2209 * @ingroup UnitContainers
2210 * @brief Constructs a unit container from an arithmetic type.
2211 * @details make_unit can be used to construct a unit container from an arithmetic type, as an alternative to
2212 * using the explicit constructor. Unlike the explicit constructor it forces the user to explicitly
2213 * specify the units.
2214 * @tparam UnitType Type to construct.
2215 * @tparam Ty Arithmetic type.
2216 * @param[in] value Arithmetic value that represents a quantity in units of `UnitType`.
2217 */
2218 template<class UnitType, typename T, class = std::enable_if_t<std::is_arithmetic<T>::value>>
2219 inline constexpr UnitType make_unit(const T value) noexcept
2220 {
2221 static_assert(traits::is_unit_t<UnitType>::value, "Template parameter `UnitType` must be a unit type (_t).");
2222
2223 return UnitType(value);
2224 }
2225
2226#if defined(UNIT_LIB_ENABLE_IOSTREAM)
2227 template<class Units, typename T, template<typename> class NonLinearScale>
2228 inline std::ostream& operator<<(std::ostream& os, const unit_t<Units, T, NonLinearScale>& obj) noexcept
2229 {
2230 using BaseUnits = unit<std::ratio<1>, typename traits::unit_traits<Units>::base_unit_type>;
2231 os << convert<Units, BaseUnits>(obj());
2232
2233 if (traits::unit_traits<Units>::base_unit_type::meter_ratio::num != 0) { os << " m"; }
2234 if (traits::unit_traits<Units>::base_unit_type::meter_ratio::num != 0 &&
2235 traits::unit_traits<Units>::base_unit_type::meter_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::meter_ratio::num; }
2236 if (traits::unit_traits<Units>::base_unit_type::meter_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::meter_ratio::den; }
2237
2238 if (traits::unit_traits<Units>::base_unit_type::kilogram_ratio::num != 0) { os << " kg"; }
2239 if (traits::unit_traits<Units>::base_unit_type::kilogram_ratio::num != 0 &&
2240 traits::unit_traits<Units>::base_unit_type::kilogram_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::kilogram_ratio::num; }
2241 if (traits::unit_traits<Units>::base_unit_type::kilogram_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::kilogram_ratio::den; }
2242
2243 if (traits::unit_traits<Units>::base_unit_type::second_ratio::num != 0) { os << " s"; }
2244 if (traits::unit_traits<Units>::base_unit_type::second_ratio::num != 0 &&
2245 traits::unit_traits<Units>::base_unit_type::second_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::second_ratio::num; }
2246 if (traits::unit_traits<Units>::base_unit_type::second_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::second_ratio::den; }
2247
2248 if (traits::unit_traits<Units>::base_unit_type::ampere_ratio::num != 0) { os << " A"; }
2249 if (traits::unit_traits<Units>::base_unit_type::ampere_ratio::num != 0 &&
2250 traits::unit_traits<Units>::base_unit_type::ampere_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::ampere_ratio::num; }
2251 if (traits::unit_traits<Units>::base_unit_type::ampere_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::ampere_ratio::den; }
2252
2253 if (traits::unit_traits<Units>::base_unit_type::kelvin_ratio::num != 0) { os << " K"; }
2254 if (traits::unit_traits<Units>::base_unit_type::kelvin_ratio::num != 0 &&
2255 traits::unit_traits<Units>::base_unit_type::kelvin_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::kelvin_ratio::num; }
2256 if (traits::unit_traits<Units>::base_unit_type::kelvin_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::kelvin_ratio::den; }
2257
2258 if (traits::unit_traits<Units>::base_unit_type::mole_ratio::num != 0) { os << " mol"; }
2259 if (traits::unit_traits<Units>::base_unit_type::mole_ratio::num != 0 &&
2260 traits::unit_traits<Units>::base_unit_type::mole_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::mole_ratio::num; }
2261 if (traits::unit_traits<Units>::base_unit_type::mole_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::mole_ratio::den; }
2262
2263 if (traits::unit_traits<Units>::base_unit_type::candela_ratio::num != 0) { os << " cd"; }
2264 if (traits::unit_traits<Units>::base_unit_type::candela_ratio::num != 0 &&
2265 traits::unit_traits<Units>::base_unit_type::candela_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::candela_ratio::num; }
2266 if (traits::unit_traits<Units>::base_unit_type::candela_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::candela_ratio::den; }
2267
2268 if (traits::unit_traits<Units>::base_unit_type::radian_ratio::num != 0) { os << " rad"; }
2269 if (traits::unit_traits<Units>::base_unit_type::radian_ratio::num != 0 &&
2270 traits::unit_traits<Units>::base_unit_type::radian_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::radian_ratio::num; }
2271 if (traits::unit_traits<Units>::base_unit_type::radian_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::radian_ratio::den; }
2272
2273 if (traits::unit_traits<Units>::base_unit_type::byte_ratio::num != 0) { os << " b"; }
2274 if (traits::unit_traits<Units>::base_unit_type::byte_ratio::num != 0 &&
2275 traits::unit_traits<Units>::base_unit_type::byte_ratio::num != 1) { os << "^" << traits::unit_traits<Units>::base_unit_type::byte_ratio::num; }
2276 if (traits::unit_traits<Units>::base_unit_type::byte_ratio::den != 1) { os << "/" << traits::unit_traits<Units>::base_unit_type::byte_ratio::den; }
2277
2278 return os;
2279 }
2280#endif
2281
2282 template<class Units, typename T, template<typename> class NonLinearScale, typename RhsType>
2284 {
2286 (traits::is_dimensionless_unit<decltype(lhs)>::value && std::is_arithmetic<RhsType>::value),
2287 "parameters are not compatible units.");
2288
2289 lhs = lhs + rhs;
2290 return lhs;
2291 }
2292
2293 template<class Units, typename T, template<typename> class NonLinearScale, typename RhsType>
2295 {
2297 (traits::is_dimensionless_unit<decltype(lhs)>::value && std::is_arithmetic<RhsType>::value),
2298 "parameters are not compatible units.");
2299
2300 lhs = lhs - rhs;
2301 return lhs;
2302 }
2303
2304 template<class Units, typename T, template<typename> class NonLinearScale, typename RhsType>
2306 {
2307 static_assert((traits::is_dimensionless_unit<RhsType>::value || std::is_arithmetic<RhsType>::value),
2308 "right-hand side parameter must be dimensionless.");
2309
2310 lhs = lhs * rhs;
2311 return lhs;
2312 }
2313
2314 template<class Units, typename T, template<typename> class NonLinearScale, typename RhsType>
2316 {
2317 static_assert((traits::is_dimensionless_unit<RhsType>::value || std::is_arithmetic<RhsType>::value),
2318 "right-hand side parameter must be dimensionless.");
2319
2320 lhs = lhs / rhs;
2321 return lhs;
2322 }
2323
2324 //------------------------------
2325 // UNIT_T UNARY OPERATORS
2326 //------------------------------
2327
2328 // unary addition: +T
2329 template<class Units, typename T, template<typename> class NonLinearScale>
2331 {
2332 return u;
2333 }
2334
2335 // prefix increment: ++T
2336 template<class Units, typename T, template<typename> class NonLinearScale>
2338 {
2340 return u;
2341 }
2342
2343 // postfix increment: T++
2344 template<class Units, typename T, template<typename> class NonLinearScale>
2346 {
2347 auto ret = u;
2349 return ret;
2350 }
2351
2352 // unary addition: -T
2353 template<class Units, typename T, template<typename> class NonLinearScale>
2355 {
2357 }
2358
2359 // prefix increment: --T
2360 template<class Units, typename T, template<typename> class NonLinearScale>
2362 {
2364 return u;
2365 }
2366
2367 // postfix increment: T--
2368 template<class Units, typename T, template<typename> class NonLinearScale>
2370 {
2371 auto ret = u;
2373 return ret;
2374 }
2375
2376 //------------------------------
2377 // UNIT_CAST
2378 //------------------------------
2379
2380 /**
2381 * @ingroup Conversion
2382 * @brief Casts a unit container to an arithmetic type.
2383 * @details unit_cast can be used to remove the strong typing from a unit class, and convert it
2384 * to a built-in arithmetic type. This may be useful for compatibility with libraries
2385 * and legacy code that don't support `unit_t` types. E.g
2386 * @code meter_t unitVal(5);
2387 * double value = units::unit_cast<double>(unitVal); // value = 5.0
2388 * @endcode
2389 * @tparam T Type to cast the unit type to. Must be a built-in arithmetic type.
2390 * @param value Unit value to cast.
2391 * @sa unit_t::to
2392 */
2393 template<typename T, typename Units, class = std::enable_if_t<std::is_arithmetic<T>::value && traits::is_unit_t<Units>::value>>
2394 inline constexpr T unit_cast(const Units& value) noexcept
2395 {
2396 return static_cast<T>(value);
2397 }
2398
2399 //------------------------------
2400 // NON-LINEAR SCALE TRAITS
2401 //------------------------------
2402
2403 // forward declaration
2404 template<typename T> struct decibel_scale;
2405
2406 namespace traits
2407 {
2408 /**
2409 * @ingroup TypeTraits
2410 * @brief Trait which tests whether a type is inherited from a linear scale.
2411 * @details Inherits from `std::true_type` or `std::false_type`. Use `has_linear_scale<U1 [, U2, ...]>::value` to test
2412 * one or more types to see if they represent unit_t's whose scale is linear.
2413 * @tparam T one or more types to test.
2414 */
2415#if !defined(_MSC_VER) || _MSC_VER > 1800 // bug in VS2013 prevents this from working
2416 template<typename... T>
2417 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 > {};
2418 template<typename... T>
2419 inline constexpr bool has_linear_scale_v = has_linear_scale<T...>::value;
2420#else
2421 template<typename T1, typename T2 = T1, typename T3 = T1>
2422 struct has_linear_scale : std::integral_constant<bool,
2423 std::is_base_of<units::linear_scale<typename units::traits::unit_t_traits<T1>::underlying_type>, T1>::value &&
2424 std::is_base_of<units::linear_scale<typename units::traits::unit_t_traits<T2>::underlying_type>, T2>::value &&
2425 std::is_base_of<units::linear_scale<typename units::traits::unit_t_traits<T3>::underlying_type>, T3>::value> {};
2426 template<typename T1, typename T2 = T1, typename T3 = T1>
2427 inline constexpr bool has_linear_scale_v = has_linear_scale<T1, T2, T3>::value;
2428#endif
2429
2430 /**
2431 * @ingroup TypeTraits
2432 * @brief Trait which tests whether a type is inherited from a decibel scale.
2433 * @details Inherits from `std::true_type` or `std::false_type`. Use `has_decibel_scale<U1 [, U2, ...]>::value` to test
2434 * one or more types to see if they represent unit_t's whose scale is in decibels.
2435 * @tparam T one or more types to test.
2436 */
2437#if !defined(_MSC_VER) || _MSC_VER > 1800 // bug in VS2013 prevents this from working
2438 template<typename... T>
2439 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> {};
2440 template<typename... T>
2441 inline constexpr bool has_decibel_scale_v = has_decibel_scale<T...>::value;
2442#else
2443 template<typename T1, typename T2 = T1, typename T3 = T1>
2444 struct has_decibel_scale : std::integral_constant<bool,
2445 std::is_base_of<units::decibel_scale<typename units::traits::unit_t_traits<T1>::underlying_type>, T1>::value &&
2446 std::is_base_of<units::decibel_scale<typename units::traits::unit_t_traits<T2>::underlying_type>, T2>::value &&
2447 std::is_base_of<units::decibel_scale<typename units::traits::unit_t_traits<T2>::underlying_type>, T3>::value> {};
2448 template<typename T1, typename T2 = T1, typename T3 = T1>
2449 inline constexpr bool has_decibel_scale_v = has_decibel_scale<T1, T2, T3>::value;
2450#endif
2451
2452 /**
2453 * @ingroup TypeTraits
2454 * @brief Trait which tests whether two types has the same non-linear scale.
2455 * @details Inherits from `std::true_type` or `std::false_type`. Use `is_same_scale<U1 , U2>::value` to test
2456 * whether two types have the same non-linear scale.
2457 * @tparam T1 left hand type.
2458 * @tparam T2 right hand type
2459 */
2460 template<typename T1, typename T2>
2461 struct is_same_scale : std::integral_constant<bool,
2462 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>
2463 {};
2464 template<typename T1, typename T2>
2466 }
2467
2468 //----------------------------------
2469 // NON-LINEAR SCALES
2470 //----------------------------------
2471
2472 // Non-linear transforms are used to pre and post scale units which are defined in terms of non-
2473 // linear functions of their current value. A good example of a non-linear scale would be a
2474 // logarithmic or decibel scale
2475
2476 //------------------------------
2477 // LINEAR SCALE
2478 //------------------------------
2479
2480 /**
2481 * @brief unit_t scale which is linear
2482 * @details Represents units on a linear scale. This is the appropriate unit_t scale for almost
2483 * all units almost all of the time.
2484 * @tparam T underlying storage type
2485 * @sa unit_t
2486 */
2487 template<typename T>
2489 {
2490 inline constexpr linear_scale() = default; ///< default constructor.
2491 inline constexpr linear_scale(const linear_scale&) = default;
2492 inline ~linear_scale() = default;
2493 inline linear_scale& operator=(const linear_scale&) = default;
2494#if defined(_MSC_VER) && (_MSC_VER > 1800)
2495 inline constexpr linear_scale(linear_scale&&) = default;
2496 inline linear_scale& operator=(linear_scale&&) = default;
2497#endif
2498 template<class... Args>
2499 inline constexpr linear_scale(const T& value, Args&&...) noexcept : m_value(value) {} ///< constructor.
2500 inline constexpr T operator()() const noexcept { return m_value; } ///< returns value.
2501
2502 T m_value; ///< linearized value.
2503 };
2504
2505 //----------------------------------
2506 // SCALAR (LINEAR) UNITS
2507 //----------------------------------
2508
2509 // Scalar units are the *ONLY* units implicitly convertible to/from built-in types.
2511 {
2514
2517 }
2518
2519// ignore the redeclaration of the default template parameters
2520#if defined(_MSC_VER)
2521# pragma warning(push)
2522# pragma warning(disable : 4348)
2523#endif
2526#if defined(_MSC_VER)
2527# pragma warning(pop)
2528#endif
2529
2530 //------------------------------
2531 // LINEAR ARITHMETIC
2532 //------------------------------
2533
2534 template<class UnitTypeLhs, class UnitTypeRhs, std::enable_if_t<!traits::is_same_scale<UnitTypeLhs, UnitTypeRhs>::value, int> = 0>
2535 constexpr inline int operator+(const UnitTypeLhs& /* lhs */, const UnitTypeRhs& /* rhs */) noexcept
2536 {
2537 static_assert(traits::is_same_scale<UnitTypeLhs, UnitTypeRhs>::value, "Cannot add units with different linear/non-linear scales.");
2538 return 0;
2539 }
2540
2541 /// Addition operator for unit_t types with a linear_scale.
2542 template<class UnitTypeLhs, class UnitTypeRhs, std::enable_if_t<traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value, int> = 0>
2543 inline constexpr UnitTypeLhs operator+(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept
2544 {
2545 using UnitsLhs = typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type;
2546 using UnitsRhs = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type;
2547 return UnitTypeLhs(lhs() + convert<UnitsRhs, UnitsLhs>(rhs()));
2548 }
2549
2550 /// Addition operator for scalar unit_t types with a linear_scale. Scalar types can be implicitly converted to built-in types.
2551 template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, int> = 0>
2552 inline constexpr dimensionless::scalar_t operator+(const dimensionless::scalar_t& lhs, T rhs) noexcept
2553 {
2554 return dimensionless::scalar_t(lhs() + rhs);
2555 }
2556
2557 /// Addition operator for scalar unit_t types with a linear_scale. Scalar types can be implicitly converted to built-in types.
2558 template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, int> = 0>
2559 inline constexpr dimensionless::scalar_t operator+(T lhs, const dimensionless::scalar_t& rhs) noexcept
2560 {
2561 return dimensionless::scalar_t(lhs + rhs());
2562 }
2563
2564 /// Subtraction operator for unit_t types with a linear_scale.
2565 template<class UnitTypeLhs, class UnitTypeRhs, std::enable_if_t<traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value, int> = 0>
2566 inline constexpr UnitTypeLhs operator-(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept
2567 {
2568 using UnitsLhs = typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type;
2569 using UnitsRhs = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type;
2570 return UnitTypeLhs(lhs() - convert<UnitsRhs, UnitsLhs>(rhs()));
2571 }
2572
2573 /// Subtraction operator for scalar unit_t types with a linear_scale. Scalar types can be implicitly converted to built-in types.
2574 template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, int> = 0>
2575 inline constexpr dimensionless::scalar_t operator-(const dimensionless::scalar_t& lhs, T rhs) noexcept
2576 {
2577 return dimensionless::scalar_t(lhs() - rhs);
2578 }
2579
2580 /// Subtraction operator for scalar unit_t types with a linear_scale. Scalar types can be implicitly converted to built-in types.
2581 template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, int> = 0>
2582 inline constexpr dimensionless::scalar_t operator-(T lhs, const dimensionless::scalar_t& rhs) noexcept
2583 {
2584 return dimensionless::scalar_t(lhs - rhs());
2585 }
2586
2587 /// Multiplication type for convertible unit_t types with a linear scale. @returns the multiplied value, with the same type as left-hand side unit.
2588 template<class UnitTypeLhs, class UnitTypeRhs,
2589 std::enable_if_t<traits::is_convertible_unit_t<UnitTypeLhs, UnitTypeRhs>::value && traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value, int> = 0>
2590 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>>>
2591 {
2592 using UnitsLhs = typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type;
2593 using UnitsRhs = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type;
2595 (lhs() * convert<UnitsRhs, UnitsLhs>(rhs()));
2596 }
2597
2598 /// 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.
2599 template<class UnitTypeLhs, class UnitTypeRhs,
2600 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>
2601 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>>
2602 {
2603 using UnitsLhs = typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type;
2604 using UnitsRhs = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type;
2605 return unit_t<compound_unit<UnitsLhs, UnitsRhs>>
2606 (lhs() * rhs());
2607 }
2608
2609 /// Multiplication by a dimensionless unit for unit_t types with a linear scale.
2610 template<class UnitTypeLhs, typename UnitTypeRhs,
2611 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>
2612 inline constexpr UnitTypeLhs operator*(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept
2613 {
2614 // the cast makes sure factors of PI are handled as expected
2615 return UnitTypeLhs(lhs() * static_cast<UNIT_LIB_DEFAULT_TYPE>(rhs));
2616 }
2617
2618 /// Multiplication by a dimensionless unit for unit_t types with a linear scale.
2619 template<class UnitTypeLhs, typename UnitTypeRhs,
2620 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>
2621 inline constexpr UnitTypeRhs operator*(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept
2622 {
2623 // the cast makes sure factors of PI are handled as expected
2624 return UnitTypeRhs(static_cast<UNIT_LIB_DEFAULT_TYPE>(lhs) * rhs());
2625 }
2626
2627 /// Multiplication by a scalar for unit_t types with a linear scale.
2628 template<class UnitTypeLhs, typename T,
2629 std::enable_if_t<std::is_arithmetic<T>::value && traits::has_linear_scale<UnitTypeLhs>::value, int> = 0>
2630 inline constexpr UnitTypeLhs operator*(const UnitTypeLhs& lhs, T rhs) noexcept
2631 {
2632 return UnitTypeLhs(lhs() * rhs);
2633 }
2634
2635 /// Multiplication by a scalar for unit_t types with a linear scale.
2636 template<class UnitTypeRhs, typename T,
2637 std::enable_if_t<std::is_arithmetic<T>::value && traits::has_linear_scale<UnitTypeRhs>::value, int> = 0>
2638 inline constexpr UnitTypeRhs operator*(T lhs, const UnitTypeRhs& rhs) noexcept
2639 {
2640 return UnitTypeRhs(lhs * rhs());
2641 }
2642
2643 /// Division for convertible unit_t types with a linear scale. @returns the lhs divided by rhs value, whose type is a scalar
2644 template<class UnitTypeLhs, class UnitTypeRhs,
2645 std::enable_if_t<traits::is_convertible_unit_t<UnitTypeLhs, UnitTypeRhs>::value && traits::has_linear_scale<UnitTypeLhs, UnitTypeRhs>::value, int> = 0>
2646 inline constexpr dimensionless::scalar_t operator/(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept
2647 {
2648 using UnitsLhs = typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type;
2649 using UnitsRhs = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type;
2650 return dimensionless::scalar_t(lhs() / convert<UnitsRhs, UnitsLhs>(rhs()));
2651 }
2652
2653 /// 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
2654 template<class UnitTypeLhs, class UnitTypeRhs,
2655 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>
2657 {
2658 using UnitsLhs = typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type;
2659 using UnitsRhs = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type;
2661 (lhs() / rhs());
2662 }
2663
2664 /// Division by a dimensionless unit for unit_t types with a linear scale
2665 template<class UnitTypeLhs, class UnitTypeRhs,
2666 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>
2667 inline constexpr UnitTypeLhs operator/(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept
2668 {
2669 return UnitTypeLhs(lhs() / static_cast<UNIT_LIB_DEFAULT_TYPE>(rhs));
2670 }
2671
2672 /// Division of a dimensionless unit by a unit_t type with a linear scale
2673 template<class UnitTypeLhs, class UnitTypeRhs,
2674 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>
2675 inline constexpr auto operator/(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs) noexcept -> unit_t<inverse<typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type>>
2676 {
2678 (static_cast<UNIT_LIB_DEFAULT_TYPE>(lhs) / rhs());
2679 }
2680
2681 /// Division by a scalar for unit_t types with a linear scale
2682 template<class UnitTypeLhs, typename T,
2683 std::enable_if_t<std::is_arithmetic<T>::value && traits::has_linear_scale<UnitTypeLhs>::value, int> = 0>
2684 inline constexpr UnitTypeLhs operator/(const UnitTypeLhs& lhs, T rhs) noexcept
2685 {
2686 return UnitTypeLhs(lhs() / rhs);
2687 }
2688
2689 /// Division of a scalar by a unit_t type with a linear scale
2690 template<class UnitTypeRhs, typename T,
2691 std::enable_if_t<std::is_arithmetic<T>::value && traits::has_linear_scale<UnitTypeRhs>::value, int> = 0>
2692 inline constexpr auto operator/(T lhs, const UnitTypeRhs& rhs) noexcept -> unit_t<inverse<typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type>>
2693 {
2694 using UnitsRhs = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type;
2696 (lhs / rhs());
2697 }
2698
2699 //----------------------------------
2700 // SCALAR COMPARISONS
2701 //----------------------------------
2702
2703 template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>>
2704 constexpr bool operator==(const UNIT_LIB_DEFAULT_TYPE lhs, const Units& rhs) noexcept
2705 {
2706 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)) ||
2708 }
2709
2710 template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>>
2711 constexpr bool operator==(const Units& lhs, const UNIT_LIB_DEFAULT_TYPE rhs) noexcept
2712 {
2713 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) ||
2715 }
2716
2717 template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>>
2718 constexpr bool operator!=(const UNIT_LIB_DEFAULT_TYPE lhs, const Units& rhs) noexcept
2719 {
2720 return!(lhs == static_cast<UNIT_LIB_DEFAULT_TYPE>(rhs));
2721 }
2722
2723 template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>>
2724 constexpr bool operator!=(const Units& lhs, const UNIT_LIB_DEFAULT_TYPE rhs) noexcept
2725 {
2726 return !(static_cast<UNIT_LIB_DEFAULT_TYPE>(lhs) == rhs);
2727 }
2728
2729 template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>>
2730 constexpr bool operator>=(const UNIT_LIB_DEFAULT_TYPE lhs, const Units& rhs) noexcept
2731 {
2732 return std::isgreaterequal(lhs, static_cast<UNIT_LIB_DEFAULT_TYPE>(rhs));
2733 }
2734
2735 template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>>
2736 constexpr bool operator>=(const Units& lhs, const UNIT_LIB_DEFAULT_TYPE rhs) noexcept
2737 {
2738 return std::isgreaterequal(static_cast<UNIT_LIB_DEFAULT_TYPE>(lhs), rhs);
2739 }
2740
2741 template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>>
2742 constexpr bool operator>(const UNIT_LIB_DEFAULT_TYPE lhs, const Units& rhs) noexcept
2743 {
2744 return lhs > static_cast<UNIT_LIB_DEFAULT_TYPE>(rhs);
2745 }
2746
2747 template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>>
2748 constexpr bool operator>(const Units& lhs, const UNIT_LIB_DEFAULT_TYPE rhs) noexcept
2749 {
2750 return static_cast<UNIT_LIB_DEFAULT_TYPE>(lhs) > rhs;
2751 }
2752
2753 template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>>
2754 constexpr bool operator<=(const UNIT_LIB_DEFAULT_TYPE lhs, const Units& rhs) noexcept
2755 {
2756 return std::islessequal(lhs, static_cast<UNIT_LIB_DEFAULT_TYPE>(rhs));
2757 }
2758
2759 template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>>
2760 constexpr bool operator<=(const Units& lhs, const UNIT_LIB_DEFAULT_TYPE rhs) noexcept
2761 {
2762 return std::islessequal(static_cast<UNIT_LIB_DEFAULT_TYPE>(lhs), rhs);
2763 }
2764
2765 template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>>
2766 constexpr bool operator<(const UNIT_LIB_DEFAULT_TYPE lhs, const Units& rhs) noexcept
2767 {
2768 return lhs < static_cast<UNIT_LIB_DEFAULT_TYPE>(rhs);
2769 }
2770
2771 template<typename Units, class = std::enable_if_t<units::traits::is_dimensionless_unit<Units>::value>>
2772 constexpr bool operator<(const Units& lhs, const UNIT_LIB_DEFAULT_TYPE rhs) noexcept
2773 {
2774 return static_cast<UNIT_LIB_DEFAULT_TYPE>(lhs) < rhs;
2775 }
2776
2777 //----------------------------------
2778 // POW
2779 //----------------------------------
2780
2781 /** @cond */ // DOXYGEN IGNORE
2782 namespace detail
2783 {
2784 /// recursive exponential implementation
2785 template <int N, class U> struct power_of_unit
2786 {
2787 typedef typename units::detail::unit_multiply<U, typename power_of_unit<N - 1, U>::type> type;
2788 };
2789
2790 /// End recursion
2791 template <class U> struct power_of_unit<1, U>
2792 {
2793 typedef U type;
2794 };
2795 }
2796 /** @endcond */ // END DOXYGEN IGNORE
2797
2798 namespace math
2799 {
2800 /**
2801 * @brief computes the value of <i>value</i> raised to the <i>power</i>
2802 * @details Only implemented for linear_scale units. <i>Power</i> must be known at compile time, so the resulting unit type can be deduced.
2803 * @tparam power exponential power to raise <i>value</i> by.
2804 * @param[in] value `unit_t` derived type to raise to the given <i>power</i>
2805 * @returns new unit_t, raised to the given exponent
2806 */
2807 template<int power, class UnitType, class = typename std::enable_if<traits::has_linear_scale<UnitType>::value, int>>
2808 inline constexpr auto pow(const UnitType& value) noexcept -> unit_t<typename units::detail::power_of_unit<power, typename units::traits::unit_t_traits<UnitType>::unit_type>::type, typename units::traits::unit_t_traits<UnitType>::underlying_type, linear_scale>
2809 {
2811 (gcem::pow(value(), power));
2812 }
2813
2814 /**
2815 * @brief computes the value of <i>value</i> raised to the <i>power</i> as a constexpr
2816 * @details Only implemented for linear_scale units. <i>Power</i> must be known at compile time, so the resulting unit type can be deduced.
2817 * Additionally, the power must be <i>a positive, integral, value</i>.
2818 * @tparam power exponential power to raise <i>value</i> by.
2819 * @param[in] value `unit_t` derived type to raise to the given <i>power</i>
2820 * @returns new unit_t, raised to the given exponent
2821 */
2822 template<int power, class UnitType, class = typename std::enable_if<traits::has_linear_scale<UnitType>::value, int>>
2823 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>
2824 {
2825 static_assert(power >= 0, "cpow cannot accept negative numbers. Try units::math::pow instead.");
2827 (detail::pow(value(), power));
2828 }
2829 }
2830
2831 //------------------------------
2832 // DECIBEL SCALE
2833 //------------------------------
2834
2835 /**
2836 * @brief unit_t scale for representing decibel values.
2837 * @details internally stores linearized values. `operator()` returns the value in dB.
2838 * @tparam T underlying storage type
2839 * @sa unit_t
2840 */
2841 template<typename T>
2843 {
2844 inline constexpr decibel_scale() = default;
2845 inline constexpr decibel_scale(const decibel_scale&) = default;
2846 inline ~decibel_scale() = default;
2847 inline decibel_scale& operator=(const decibel_scale&) = default;
2848#if defined(_MSC_VER) && (_MSC_VER > 1800)
2849 inline constexpr decibel_scale(decibel_scale&&) = default;
2850 inline decibel_scale& operator=(decibel_scale&&) = default;
2851#endif
2852 inline constexpr decibel_scale(const T value) noexcept : m_value(std::pow(10, value / 10)) {}
2853 template<class... Args>
2854 inline constexpr decibel_scale(const T value, std::true_type, Args&&...) noexcept : m_value(value) {}
2855 inline constexpr T operator()() const noexcept { return 10 * std::log10(m_value); }
2856
2857 T m_value; ///< linearized value
2858 };
2859
2860 //------------------------------
2861 // SCALAR (DECIBEL) UNITS
2862 //------------------------------
2863
2864 /**
2865 * @brief namespace for unit types and containers for units that have no dimension (scalar units)
2866 * @sa See unit_t for more information on unit type containers.
2867 */
2868 namespace dimensionless
2869 {
2871 typedef dB_t dBi_t;
2872 }
2873#if defined(UNIT_LIB_ENABLE_IOSTREAM)
2874 namespace dimensionless
2875 {
2876 inline std::ostream& operator<<(std::ostream& os, const dB_t& obj) { os << obj() << " dB"; return os; }
2877 }
2878#endif
2879}
2880#if __has_include(<fmt/format.h>) && !defined(UNIT_LIB_DISABLE_FMT)
2881template <>
2882struct fmt::formatter<units::dimensionless::dB_t> : fmt::formatter<double>
2883{
2884 template <typename FormatContext>
2885 auto format(const units::dimensionless::dB_t& obj,
2886 FormatContext& ctx) -> decltype(ctx.out())
2887 {
2888 auto out = ctx.out();
2889 out = fmt::formatter<double>::format(obj(), ctx);
2890 return fmt::format_to(out, " dB");
2891 }
2892};
2893#endif
2894
2895namespace units {
2896 //------------------------------
2897 // DECIBEL ARITHMETIC
2898 //------------------------------
2899
2900 /// Addition for convertible unit_t types with a decibel_scale
2901 template<class UnitTypeLhs, class UnitTypeRhs,
2902 std::enable_if_t<traits::has_decibel_scale<UnitTypeLhs, UnitTypeRhs>::value, int> = 0>
2903 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>
2904 {
2905 using LhsUnits = typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type;
2906 using RhsUnits = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type;
2907 using underlying_type = typename units::traits::unit_t_traits<UnitTypeLhs>::underlying_type;
2908
2909 return unit_t<compound_unit<squared<LhsUnits>>, underlying_type, decibel_scale>
2910 (lhs.template toLinearized<underlying_type>() * convert<RhsUnits, LhsUnits>(rhs.template toLinearized<underlying_type>()), std::true_type());
2911 }
2912
2913 /// Addition between unit_t types with a decibel_scale and dimensionless dB units
2914 template<class UnitTypeLhs, std::enable_if_t<traits::has_decibel_scale<UnitTypeLhs>::value && !traits::is_dimensionless_unit<UnitTypeLhs>::value, int> = 0>
2915 constexpr inline UnitTypeLhs operator+(const UnitTypeLhs& lhs, const dimensionless::dB_t& rhs) noexcept
2916 {
2917 using underlying_type = typename units::traits::unit_t_traits<UnitTypeLhs>::underlying_type;
2918 return UnitTypeLhs(lhs.template toLinearized<underlying_type>() * rhs.template toLinearized<underlying_type>(), std::true_type());
2919 }
2920
2921 /// Addition between unit_t types with a decibel_scale and dimensionless dB units
2922 template<class UnitTypeRhs, std::enable_if_t<traits::has_decibel_scale<UnitTypeRhs>::value && !traits::is_dimensionless_unit<UnitTypeRhs>::value, int> = 0>
2923 constexpr inline UnitTypeRhs operator+(const dimensionless::dB_t& lhs, const UnitTypeRhs& rhs) noexcept
2924 {
2925 using underlying_type = typename units::traits::unit_t_traits<UnitTypeRhs>::underlying_type;
2926 return UnitTypeRhs(lhs.template toLinearized<underlying_type>() * rhs.template toLinearized<underlying_type>(), std::true_type());
2927 }
2928
2929 /// Subtraction for convertible unit_t types with a decibel_scale
2930 template<class UnitTypeLhs, class UnitTypeRhs, std::enable_if_t<traits::has_decibel_scale<UnitTypeLhs, UnitTypeRhs>::value, int> = 0>
2931 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>
2932 {
2933 using LhsUnits = typename units::traits::unit_t_traits<UnitTypeLhs>::unit_type;
2934 using RhsUnits = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type;
2935 using underlying_type = typename units::traits::unit_t_traits<UnitTypeLhs>::underlying_type;
2936
2938 (lhs.template toLinearized<underlying_type>() / convert<RhsUnits, LhsUnits>(rhs.template toLinearized<underlying_type>()), std::true_type());
2939 }
2940
2941 /// Subtraction between unit_t types with a decibel_scale and dimensionless dB units
2942 template<class UnitTypeLhs, std::enable_if_t<traits::has_decibel_scale<UnitTypeLhs>::value && !traits::is_dimensionless_unit<UnitTypeLhs>::value, int> = 0>
2943 constexpr inline UnitTypeLhs operator-(const UnitTypeLhs& lhs, const dimensionless::dB_t& rhs) noexcept
2944 {
2945 using underlying_type = typename units::traits::unit_t_traits<UnitTypeLhs>::underlying_type;
2946 return UnitTypeLhs(lhs.template toLinearized<underlying_type>() / rhs.template toLinearized<underlying_type>(), std::true_type());
2947 }
2948
2949 /// Subtraction between unit_t types with a decibel_scale and dimensionless dB units
2950 template<class UnitTypeRhs, std::enable_if_t<traits::has_decibel_scale<UnitTypeRhs>::value && !traits::is_dimensionless_unit<UnitTypeRhs>::value, int> = 0>
2951 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>
2952 {
2953 using RhsUnits = typename units::traits::unit_t_traits<UnitTypeRhs>::unit_type;
2954 using underlying_type = typename units::traits::unit_t_traits<RhsUnits>::underlying_type;
2955
2956 return unit_t<inverse<RhsUnits>, underlying_type, decibel_scale>
2957 (lhs.template toLinearized<underlying_type>() / rhs.template toLinearized<underlying_type>(), std::true_type());
2958 }
2959
2960 //----------------------------------
2961 // UNIT RATIO CLASS
2962 //----------------------------------
2963
2964 /** @cond */ // DOXYGEN IGNORE
2965 namespace detail
2966 {
2967 template<class Units>
2968 struct _unit_value_t {};
2969 }
2970 /** @endcond */ // END DOXYGEN IGNORE
2971
2972 namespace traits
2973 {
2974#ifdef FOR_DOXYGEN_PURPOSES_ONLY
2975 /**
2976 * @ingroup TypeTraits
2977 * @brief Trait for accessing the publicly defined types of `units::unit_value_t_traits`
2978 * @details The units library determines certain properties of the `unit_value_t` types passed to
2979 * them and what they represent by using the members of the corresponding `unit_value_t_traits`
2980 * instantiation.
2981 */
2982 template<typename T>
2983 struct unit_value_t_traits
2984 {
2985 typedef typename T::unit_type unit_type; ///< Dimension represented by the `unit_value_t`.
2986 typedef typename T::ratio ratio; ///< Quantity represented by the `unit_value_t`, expressed as arational number.
2987 };
2988#endif
2989
2990 /** @cond */ // DOXYGEN IGNORE
2991 /**
2992 * @brief unit_value_t_traits specialization for things which are not unit_t
2993 * @details
2994 */
2995 template<typename T, typename = void>
2996 struct unit_value_t_traits
2997 {
2998 typedef void unit_type;
2999 typedef void ratio;
3000 };
3001
3002 /**
3003 * @ingroup TypeTraits
3004 * @brief Trait for accessing the publicly defined types of `units::unit_value_t_traits`
3005 * @details
3006 */
3007 template<typename T>
3008 struct unit_value_t_traits <T, typename void_t<
3009 typename T::unit_type,
3010 typename T::ratio>::type>
3011 {
3012 typedef typename T::unit_type unit_type;
3013 typedef typename T::ratio ratio;
3014 };
3015 /** @endcond */ // END DOXYGEN IGNORE
3016 }
3017
3018 //------------------------------------------------------------------------------
3019 // COMPILE-TIME UNIT VALUES AND ARITHMETIC
3020 //------------------------------------------------------------------------------
3021
3022 /**
3023 * @ingroup UnitContainers
3024 * @brief Stores a rational unit value as a compile-time constant
3025 * @details unit_value_t is useful for performing compile-time arithmetic on known
3026 * unit quantities.
3027 * @tparam Units units represented by the `unit_value_t`
3028 * @tparam Num numerator of the represented value.
3029 * @tparam Denom denominator of the represented value.
3030 * @sa unit_value_t_traits to access information about the properties of the class,
3031 * such as it's unit type and rational value.
3032 * @note This is intentionally identical in concept to a `std::ratio`.
3033 *
3034 */
3035 template<typename Units, std::uintmax_t Num, std::uintmax_t Denom = 1>
3036 struct unit_value_t : units::detail::_unit_value_t<Units>
3037 {
3038 typedef Units unit_type;
3039 typedef std::ratio<Num, Denom> ratio;
3040
3041 static_assert(traits::is_unit<Units>::value, "Template parameter `Units` must be a unit type.");
3042 static constexpr const unit_t<Units> value() { return unit_t<Units>((UNIT_LIB_DEFAULT_TYPE)ratio::num / ratio::den); }
3043 };
3044
3045 namespace traits
3046 {
3047 /**
3048 * @ingroup TypeTraits
3049 * @brief Trait which tests whether a type is a unit_value_t representing the given unit type.
3050 * @details e.g. `is_unit_value_t<meters, myType>::value` would test that `myType` is a
3051 * `unit_value_t<meters>`.
3052 * @tparam Units units that the `unit_value_t` is supposed to have.
3053 * @tparam T type to test.
3054 */
3055 template<typename T, typename Units = typename traits::unit_value_t_traits<T>::unit_type>
3056 struct is_unit_value_t : std::integral_constant<bool,
3057 std::is_base_of<units::detail::_unit_value_t<Units>, T>::value>
3058 {};
3059 template<typename T, typename Units = typename traits::unit_value_t_traits<T>::unit_type>
3061
3062 /**
3063 * @ingroup TypeTraits
3064 * @brief Trait which tests whether type T is a unit_value_t with a unit type in the given category.
3065 * @details e.g. `is_unit_value_t_category<units::category::length, unit_value_t<feet>>::value` would be true
3066 */
3067 template<typename Category, typename T>
3068 struct is_unit_value_t_category : std::integral_constant<bool,
3069 std::is_same<units::traits::base_unit_of<typename traits::unit_value_t_traits<T>::unit_type>, Category>::value>
3070 {
3071 static_assert(is_base_unit<Category>::value, "Template parameter `Category` must be a `base_unit` type.");
3072 };
3073 template<typename Category, typename T>
3075 }
3076
3077 /** @cond */ // DOXYGEN IGNORE
3078 namespace detail
3079 {
3080 // base class for common arithmetic
3081 template<class U1, class U2>
3082 struct unit_value_arithmetic
3083 {
3084 static_assert(traits::is_unit_value_t<U1>::value, "Template parameter `U1` must be a `unit_value_t` type.");
3085 static_assert(traits::is_unit_value_t<U2>::value, "Template parameter `U2` must be a `unit_value_t` type.");
3086
3087 using _UNIT1 = typename traits::unit_value_t_traits<U1>::unit_type;
3088 using _UNIT2 = typename traits::unit_value_t_traits<U2>::unit_type;
3089 using _CONV1 = typename units::traits::unit_traits<_UNIT1>::conversion_ratio;
3090 using _CONV2 = typename units::traits::unit_traits<_UNIT2>::conversion_ratio;
3091 using _RATIO1 = typename traits::unit_value_t_traits<U1>::ratio;
3092 using _RATIO2 = typename traits::unit_value_t_traits<U2>::ratio;
3093 using _RATIO2CONV = typename std::ratio_divide<std::ratio_multiply<_RATIO2, _CONV2>, _CONV1>;
3094 using _PI_EXP = std::ratio_subtract<typename units::traits::unit_traits<_UNIT2>::pi_exponent_ratio, typename units::traits::unit_traits<_UNIT1>::pi_exponent_ratio>;
3095 };
3096 }
3097 /** @endcond */ // END DOXYGEN IGNORE
3098
3099 /**
3100 * @ingroup CompileTimeUnitManipulators
3101 * @brief adds two unit_value_t types at compile-time
3102 * @details The resulting unit will the the `unit_type` of `U1`
3103 * @tparam U1 left-hand `unit_value_t`
3104 * @tparam U2 right-hand `unit_value_t`
3105 * @sa unit_value_t_traits to access information about the properties of the class,
3106 * such as it's unit type and rational value.
3107 * @note very similar in concept to `std::ratio_add`
3108 */
3109 template<class U1, class U2>
3110 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>
3111 {
3112 /** @cond */ // DOXYGEN IGNORE
3113 using Base = units::detail::unit_value_arithmetic<U1, U2>;
3114 typedef typename Base::_UNIT1 unit_type;
3115 using ratio = std::ratio_add<typename Base::_RATIO1, typename Base::_RATIO2CONV>;
3116
3117 static_assert(traits::is_convertible_unit<typename Base::_UNIT1, typename Base::_UNIT2>::value, "Unit types are not compatible.");
3118 /** @endcond */ // END DOXYGEN IGNORE
3119
3120 /**
3121 * @brief Value of sum
3122 * @details Returns the calculated value of the sum of `U1` and `U2`, in the same
3123 * units as `U1`.
3124 * @returns Value of the sum in the appropriate units.
3125 */
3126 static constexpr const unit_t<unit_type> value() noexcept
3127 {
3128 using UsePi = std::integral_constant<bool, Base::_PI_EXP::num != 0>;
3129 return value(UsePi());
3130 }
3131
3132 /** @cond */ // DOXYGEN IGNORE
3133 // value if PI isn't involved
3134 static constexpr const unit_t<unit_type> value(std::false_type) noexcept
3135 {
3136 return unit_t<unit_type>((UNIT_LIB_DEFAULT_TYPE)ratio::num / ratio::den);
3137 }
3138
3139 // value if PI *is* involved
3140 static constexpr const unit_t<unit_type> value(std::true_type) noexcept
3141 {
3142 return unit_t<unit_type>(((UNIT_LIB_DEFAULT_TYPE)Base::_RATIO1::num / Base::_RATIO1::den) +
3143 ((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)));
3144 }
3145 /** @endcond */ // END DOXYGEN IGNORE
3146 };
3147
3148 /**
3149 * @ingroup CompileTimeUnitManipulators
3150 * @brief subtracts two unit_value_t types at compile-time
3151 * @details The resulting unit will the the `unit_type` of `U1`
3152 * @tparam U1 left-hand `unit_value_t`
3153 * @tparam U2 right-hand `unit_value_t`
3154 * @sa unit_value_t_traits to access information about the properties of the class,
3155 * such as it's unit type and rational value.
3156 * @note very similar in concept to `std::ratio_subtract`
3157 */
3158 template<class U1, class U2>
3159 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>
3160 {
3161 /** @cond */ // DOXYGEN IGNORE
3162 using Base = units::detail::unit_value_arithmetic<U1, U2>;
3163
3164 typedef typename Base::_UNIT1 unit_type;
3165 using ratio = std::ratio_subtract<typename Base::_RATIO1, typename Base::_RATIO2CONV>;
3166
3167 static_assert(traits::is_convertible_unit<typename Base::_UNIT1, typename Base::_UNIT2>::value, "Unit types are not compatible.");
3168 /** @endcond */ // END DOXYGEN IGNORE
3169
3170 /**
3171 * @brief Value of difference
3172 * @details Returns the calculated value of the difference of `U1` and `U2`, in the same
3173 * units as `U1`.
3174 * @returns Value of the difference in the appropriate units.
3175 */
3176 static constexpr const unit_t<unit_type> value() noexcept
3177 {
3178 using UsePi = std::integral_constant<bool, Base::_PI_EXP::num != 0>;
3179 return value(UsePi());
3180 }
3181
3182 /** @cond */ // DOXYGEN IGNORE
3183 // value if PI isn't involved
3184 static constexpr const unit_t<unit_type> value(std::false_type) noexcept
3185 {
3186 return unit_t<unit_type>((UNIT_LIB_DEFAULT_TYPE)ratio::num / ratio::den);
3187 }
3188
3189 // value if PI *is* involved
3190 static constexpr const unit_t<unit_type> value(std::true_type) noexcept
3191 {
3192 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)
3193 * std::pow(units::constants::detail::PI_VAL, ((UNIT_LIB_DEFAULT_TYPE)Base::_PI_EXP::num / Base::_PI_EXP::den)));
3194 }
3195 /** @endcond */ // END DOXYGEN IGNORE };
3196 };
3197
3198 /**
3199 * @ingroup CompileTimeUnitManipulators
3200 * @brief multiplies two unit_value_t types at compile-time
3201 * @details The resulting unit will the the `unit_type` of `U1 * U2`
3202 * @tparam U1 left-hand `unit_value_t`
3203 * @tparam U2 right-hand `unit_value_t`
3204 * @sa unit_value_t_traits to access information about the properties of the class,
3205 * such as it's unit type and rational value.
3206 * @note very similar in concept to `std::ratio_multiply`
3207 */
3208 template<class U1, class U2>
3209 struct unit_value_multiply : units::detail::unit_value_arithmetic<U1, U2>,
3210 units::detail::_unit_value_t<typename std::conditional<traits::is_convertible_unit<typename traits::unit_value_t_traits<U1>::unit_type,
3211 typename traits::unit_value_t_traits<U2>::unit_type>::value, compound_unit<squared<typename traits::unit_value_t_traits<U1>::unit_type>>,
3212 compound_unit<typename traits::unit_value_t_traits<U1>::unit_type, typename traits::unit_value_t_traits<U2>::unit_type>>::type>
3213 {
3214 /** @cond */ // DOXYGEN IGNORE
3215 using Base = units::detail::unit_value_arithmetic<U1, U2>;
3216
3217 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>>;
3218 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>>;
3219 /** @endcond */ // END DOXYGEN IGNORE
3220
3221 /**
3222 * @brief Value of product
3223 * @details Returns the calculated value of the product of `U1` and `U2`, in units
3224 * of `U1 x U2`.
3225 * @returns Value of the product in the appropriate units.
3226 */
3227 static constexpr const unit_t<unit_type> value() noexcept
3228 {
3229 using UsePi = std::integral_constant<bool, Base::_PI_EXP::num != 0>;
3230 return value(UsePi());
3231 }
3232
3233 /** @cond */ // DOXYGEN IGNORE
3234 // value if PI isn't involved
3235 static constexpr const unit_t<unit_type> value(std::false_type) noexcept
3236 {
3237 return unit_t<unit_type>((UNIT_LIB_DEFAULT_TYPE)ratio::num / ratio::den);
3238 }
3239
3240 // value if PI *is* involved
3241 static constexpr const unit_t<unit_type> value(std::true_type) noexcept
3242 {
3243 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)));
3244 }
3245 /** @endcond */ // END DOXYGEN IGNORE
3246 };
3247
3248 /**
3249 * @ingroup CompileTimeUnitManipulators
3250 * @brief divides two unit_value_t types at compile-time
3251 * @details The resulting unit will the the `unit_type` of `U1`
3252 * @tparam U1 left-hand `unit_value_t`
3253 * @tparam U2 right-hand `unit_value_t`
3254 * @sa unit_value_t_traits to access information about the properties of the class,
3255 * such as it's unit type and rational value.
3256 * @note very similar in concept to `std::ratio_divide`
3257 */
3258 template<class U1, class U2>
3259 struct unit_value_divide : units::detail::unit_value_arithmetic<U1, U2>,
3260 units::detail::_unit_value_t<typename std::conditional<traits::is_convertible_unit<typename traits::unit_value_t_traits<U1>::unit_type,
3261 typename traits::unit_value_t_traits<U2>::unit_type>::value, dimensionless::scalar, compound_unit<typename traits::unit_value_t_traits<U1>::unit_type,
3262 inverse<typename traits::unit_value_t_traits<U2>::unit_type>>>::type>
3263 {
3264 /** @cond */ // DOXYGEN IGNORE
3265 using Base = units::detail::unit_value_arithmetic<U1, U2>;
3266
3267 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>>>;
3268 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>>;
3269 /** @endcond */ // END DOXYGEN IGNORE
3270
3271 /**
3272 * @brief Value of quotient
3273 * @details Returns the calculated value of the quotient of `U1` and `U2`, in units
3274 * of `U1 x U2`.
3275 * @returns Value of the quotient in the appropriate units.
3276 */
3277 static constexpr const unit_t<unit_type> value() noexcept
3278 {
3279 using UsePi = std::integral_constant<bool, Base::_PI_EXP::num != 0>;
3280 return value(UsePi());
3281 }
3282
3283 /** @cond */ // DOXYGEN IGNORE
3284 // value if PI isn't involved
3285 static constexpr const unit_t<unit_type> value(std::false_type) noexcept
3286 {
3287 return unit_t<unit_type>((UNIT_LIB_DEFAULT_TYPE)ratio::num / ratio::den);
3288 }
3289
3290 // value if PI *is* involved
3291 static constexpr const unit_t<unit_type> value(std::true_type) noexcept
3292 {
3293 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)));
3294 }
3295 /** @endcond */ // END DOXYGEN IGNORE
3296 };
3297
3298 /**
3299 * @ingroup CompileTimeUnitManipulators
3300 * @brief raises unit_value_to a power at compile-time
3301 * @details The resulting unit will the `unit_type` of `U1` squared
3302 * @tparam U1 `unit_value_t` to take the exponentiation of.
3303 * @sa unit_value_t_traits to access information about the properties of the class,
3304 * such as it's unit type and rational value.
3305 * @note very similar in concept to `units::math::pow`
3306 */
3307 template<class U1, int power>
3308 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>
3309 {
3310 /** @cond */ // DOXYGEN IGNORE
3311 using Base = units::detail::unit_value_arithmetic<U1, U1>;
3312
3315 using pi_exponent = std::ratio_multiply<std::ratio<power>, typename Base::_UNIT1::pi_exponent_ratio>;
3316 /** @endcond */ // END DOXYGEN IGNORE
3317
3318 /**
3319 * @brief Value of exponentiation
3320 * @details Returns the calculated value of the exponentiation of `U1`, in units
3321 * of `U1^power`.
3322 * @returns Value of the exponentiation in the appropriate units.
3323 */
3324 static constexpr const unit_t<unit_type> value() noexcept
3325 {
3326 using UsePi = std::integral_constant<bool, Base::_PI_EXP::num != 0>;
3327 return value(UsePi());
3328 }
3329
3330 /** @cond */ // DOXYGEN IGNORE
3331 // value if PI isn't involved
3332 static constexpr const unit_t<unit_type> value(std::false_type) noexcept
3333 {
3334 return unit_t<unit_type>((UNIT_LIB_DEFAULT_TYPE)ratio::num / ratio::den);
3335 }
3336
3337 // value if PI *is* involved
3338 static constexpr const unit_t<unit_type> value(std::true_type) noexcept
3339 {
3340 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)));
3341 }
3342 /** @endcond */ // END DOXYGEN IGNORE };
3343 };
3344
3345 /**
3346 * @ingroup CompileTimeUnitManipulators
3347 * @brief calculates square root of unit_value_t at compile-time
3348 * @details The resulting unit will the square root `unit_type` of `U1`
3349 * @tparam U1 `unit_value_t` to take the square root of.
3350 * @sa unit_value_t_traits to access information about the properties of the class,
3351 * such as it's unit type and rational value.
3352 * @note very similar in concept to `units::ratio_sqrt`
3353 */
3354 template<class U1, std::intmax_t Eps = 10000000000>
3355 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>>
3356 {
3357 /** @cond */ // DOXYGEN IGNORE
3358 using Base = units::detail::unit_value_arithmetic<U1, U1>;
3359
3363 /** @endcond */ // END DOXYGEN IGNORE
3364
3365 /**
3366 * @brief Value of square root
3367 * @details Returns the calculated value of the square root of `U1`, in units
3368 * of `U1^1/2`.
3369 * @returns Value of the square root in the appropriate units.
3370 */
3371 static constexpr const unit_t<unit_type> value() noexcept
3372 {
3373 using UsePi = std::integral_constant<bool, Base::_PI_EXP::num != 0>;
3374 return value(UsePi());
3375 }
3376
3377 /** @cond */ // DOXYGEN IGNORE
3378 // value if PI isn't involved
3379 static constexpr const unit_t<unit_type> value(std::false_type) noexcept
3380 {
3381 return unit_t<unit_type>((UNIT_LIB_DEFAULT_TYPE)ratio::num / ratio::den);
3382 }
3383
3384 // value if PI *is* involved
3385 static constexpr const unit_t<unit_type> value(std::true_type) noexcept
3386 {
3387 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)));
3388 }
3389 /** @endcond */ // END DOXYGEN IGNORE
3390 };
3391
3392 //----------------------------------
3393 // UNIT-ENABLED CMATH FUNCTIONS
3394 //----------------------------------
3395
3396 /**
3397 * @brief namespace for unit-enabled versions of the `<cmath>` library
3398 * @details Includes trigonometric functions, exponential/log functions, rounding functions, etc.
3399 * @sa See `unit_t` for more information on unit type containers.
3400 */
3401 namespace math
3402 {
3403
3404 //----------------------------------
3405 // MIN/MAX FUNCTIONS
3406 //----------------------------------
3407 // XXX: min/max are defined here instead of math.h to avoid a conflict with
3408 // the "_min" user-defined literal in time.h.
3409
3410 template<class UnitTypeLhs, class UnitTypeRhs>
3411 UnitTypeLhs (min)(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs)
3412 {
3413 static_assert(traits::is_convertible_unit_t<UnitTypeLhs, UnitTypeRhs>::value, "Unit types are not compatible.");
3414 UnitTypeLhs r(rhs);
3415 return (lhs < r ? lhs : r);
3416 }
3417
3418 template<class UnitTypeLhs, class UnitTypeRhs>
3419 UnitTypeLhs (max)(const UnitTypeLhs& lhs, const UnitTypeRhs& rhs)
3420 {
3421 static_assert(traits::is_convertible_unit_t<UnitTypeLhs, UnitTypeRhs>::value, "Unit types are not compatible.");
3422 UnitTypeLhs r(rhs);
3423 return (lhs > r ? lhs : r);
3424 }
3425 }
3426}
3427
3428#ifdef _MSC_VER
3429# if _MSC_VER <= 1800
3430# pragma warning(pop)
3431# undef constexpr
3432# pragma pop_macro("constexpr")
3433# undef noexcept
3434# pragma pop_macro("noexcept")
3435# undef _ALLOW_KEYWORD_MACROS
3436# endif // _MSC_VER < 1800
3437# pragma pop_macro("pascal")
3438#endif // _MSC_VER
3439
3440#if defined(UNIT_HAS_LITERAL_SUPPORT)
3442using namespace units::literals;
3443#endif // UNIT_HAS_LITERAL_SUPPORT
3444
3445#if __has_include(<fmt/format.h>) && !defined(UNIT_LIB_DISABLE_FMT)
3446#include "units/formatter.h"
3447#endif
#define UNIT_LIB_DEFAULT_TYPE
Definition: base.h:59
#define UNIT_ADD_CATEGORY_TRAIT(unitCategory)
Macro to create the is_category_unit type trait.
Definition: base.h:371
Container for values which represent quantities of a given unit.
Definition: base.h:1928
constexpr bool operator<(const unit_t< UnitsRhs, Ty, NlsRhs > &rhs) const noexcept
less-than
Definition: base.h:2030
constexpr bool operator<=(const unit_t< UnitsRhs, Ty, NlsRhs > &rhs) const noexcept
less-than or equal
Definition: base.h:2042
constexpr unit_t< U > convert() const noexcept
conversion
Definition: base.h:2145
unit_t & operator=(const Ty &rhs) noexcept
assignment
Definition: base.h:2017
constexpr unit_t(const std::chrono::duration< Rep, Period > &value) noexcept
chrono constructor
Definition: base.h:1981
constexpr underlying_type value() const noexcept
unit value
Definition: base.h:2109
constexpr unit_t(const Ty value) noexcept
constructor
Definition: base.h:1970
constexpr unit_t(const unit_t< UnitsRhs, Ty, NlsRhs > &rhs) noexcept
copy constructor (converting)
Definition: base.h:1993
constexpr const char * name() const noexcept
returns the unit name
Definition: base.h:2185
constexpr Ty toLinearized() const noexcept
linearized unit value
Definition: base.h:2130
constexpr Ty to() const noexcept
unit value
Definition: base.h:2119
constexpr bool operator!=(const unit_t< UnitsRhs, Ty, NlsRhs > &rhs) const noexcept
inequality
Definition: base.h:2100
Units unit_type
Type of unit the unit_t represents (e.g. meters)
Definition: base.h:1942
constexpr bool operator>(const unit_t< UnitsRhs, Ty, NlsRhs > &rhs) const noexcept
greater-than
Definition: base.h:2054
T value_type
Synonym for underlying type. May be removed in future versions. Prefer underlying_type.
Definition: base.h:1941
constexpr bool operator==(const unit_t< UnitsRhs, Ty, NlsRhs > &rhs) const noexcept
equality
Definition: base.h:2079
constexpr unit_t(const T value, const Args &... args) noexcept
constructor
Definition: base.h:1959
constexpr const char * abbreviation() const noexcept
returns the unit abbreviation
Definition: base.h:2193
NonLinearScale< T > non_linear_scale_type
Type of the non-linear scale of the unit_t (e.g. linear_scale)
Definition: base.h:1939
NonLinearScale< T > nls
Definition: base.h:1934
constexpr bool operator>=(const unit_t< UnitsRhs, Ty, NlsRhs > &rhs) const noexcept
greater-than or equal
Definition: base.h:2066
constexpr unit_t()=default
default constructor.
unit_t & operator=(const unit_t< UnitsRhs, Ty, NlsRhs > &rhs) noexcept
assignment
Definition: base.h:2005
T underlying_type
Type of the underlying storage of the unit_t (e.g. double)
Definition: base.h:1940
typename std::enable_if< B, T >::type enable_if_t
Definition: core.h:271
FMT_INLINE auto format_to(OutputIt out, const Locale &loc, format_string< T... > fmt, T &&... args) -> OutputIt
Definition: format.h:4495
auto format(const Locale &loc, format_string< T... > fmt, T &&... args) -> std::string
Definition: format.h:4476
constexpr T unit_cast(const Units &value) noexcept
Casts a unit container to an arithmetic type.
Definition: base.h:2394
static constexpr T convert(const T &value) noexcept
converts a value from one type to another.
Definition: base.h:1650
typename units::detail::Sqrt< Ratio, std::ratio< 1, Eps > >::type ratio_sqrt
Calculate square root of a ratio at compile-time.
Definition: base.h:1358
constexpr UnitType make_unit(const T value) noexcept
Constructs a unit container from an arithmetic type.
Definition: base.h:2219
typename units::detail::prefix< std::peta, U >::type peta
Represents the type of class U with the metric 'peta' prefix appended.
Definition: base.h:1493
typename units::detail::prefix< std::ratio< 1099511627776 >, U >::type tebi
Represents the type of class U with the binary 'tebi' prefix appended.
Definition: base.h:1506
typename units::detail::prefix< std::milli, U >::type milli
Represents the type of class U with the metric 'milli' prefix appended.
Definition: base.h:1484
typename units::detail::inverse_impl< U >::type inverse
represents the inverse unit type of class U.
Definition: base.h:1136
typename units::detail::prefix< std::micro, U >::type micro
Represents the type of class U with the metric 'micro' prefix appended.
Definition: base.h:1483
typename units::detail::prefix< std::ratio< 1048576 >, U >::type mebi
Represents the type of class U with the binary 'mibi' prefix appended.
Definition: base.h:1504
typename units::detail::prefix< std::ratio< 1152921504606846976 >, U >::type exbi
Represents the type of class U with the binary 'exbi' prefix appended.
Definition: base.h:1508
typename units::detail::prefix< std::giga, U >::type giga
Represents the type of class U with the metric 'giga' prefix appended.
Definition: base.h:1491
typename units::detail::squared_impl< U >::type squared
represents the unit type of class U squared
Definition: base.h:1167
typename units::detail::prefix< std::deca, U >::type deca
Represents the type of class U with the metric 'deca' prefix appended.
Definition: base.h:1487
typename units::detail::prefix< std::deci, U >::type deci
Represents the type of class U with the metric 'deci' prefix appended.
Definition: base.h:1486
typename units::detail::cubed_impl< U >::type cubed
represents the type of class U cubed.
Definition: base.h:1197
typename units::detail::prefix< std::femto, U >::type femto
Represents the type of class U with the metric 'femto' prefix appended.
Definition: base.h:1480
typename units::detail::prefix< std::pico, U >::type pico
Represents the type of class U with the metric 'pico' prefix appended.
Definition: base.h:1481
typename units::detail::prefix< std::tera, U >::type tera
Represents the type of class U with the metric 'tera' prefix appended.
Definition: base.h:1492
typename units::detail::prefix< std::hecto, U >::type hecto
Represents the type of class U with the metric 'hecto' prefix appended.
Definition: base.h:1488
typename units::detail::prefix< std::atto, U >::type atto
Represents the type of class U with the metric 'atto' prefix appended.
Definition: base.h:1479
typename units::detail::prefix< std::ratio< 1073741824 >, U >::type gibi
Represents the type of class U with the binary 'gibi' prefix appended.
Definition: base.h:1505
typename units::detail::prefix< std::exa, U >::type exa
Represents the type of class U with the metric 'exa' prefix appended.
Definition: base.h:1494
typename units::detail::sqrt_impl< U, Eps >::type square_root
represents the square root of type class U.
Definition: base.h:1403
typename units::detail::prefix< std::ratio< 1125899906842624 >, U >::type pebi
Represents the type of class U with the binary 'pebi' prefix appended.
Definition: base.h:1507
typename units::detail::prefix< std::ratio< 1024 >, U >::type kibi
Represents the type of class U with the binary 'kibi' prefix appended.
Definition: base.h:1503
typename units::detail::prefix< std::centi, U >::type centi
Represents the type of class U with the metric 'centi' prefix appended.
Definition: base.h:1485
typename units::detail::prefix< std::nano, U >::type nano
Represents the type of class U with the metric 'nano' prefix appended.
Definition: base.h:1482
typename units::detail::prefix< std::mega, U >::type mega
Represents the type of class U with the metric 'mega' prefix appended.
Definition: base.h:1490
typename units::detail::prefix< std::kilo, U >::type kilo
Represents the type of class U with the metric 'kilo' prefix appended.
Definition: base.h:1489
constexpr UnitType abs(const UnitType x) noexcept
Compute absolute value.
Definition: math.h:726
constexpr dimensionless::scalar_t log10(const ScalarUnit x) noexcept
Compute common logarithm.
Definition: math.h:367
typename units::detail::compound_impl< U, Us... >::type compound_unit
Represents a unit type made up from other units.
Definition: base.h:1436
detail namespace with internal helper functions
Definition: ostream.h:24
void void_t
Definition: core.h:1534
@ value
the parser finished reading a JSON value
constexpr auto count() -> size_t
Definition: core.h:1222
type
Definition: core.h:573
constexpr common_t< T1, T2 > pow(const T1 base, const T2 exp_term) noexcept
Compile-time power function.
Definition: pow.hpp:82
Implement std::hash so that hash_code can be used in STL containers.
Definition: array.h:89
base_unit< detail::meter_ratio< 0 >, std::ratio< 0 >, std::ratio< 1 > > time_unit
Represents an SI base unit of time.
Definition: base.h:799
base_unit< detail::meter_ratio< 0 >, std::ratio< 1 > > mass_unit
Represents an SI base unit of mass.
Definition: base.h:798
base_unit< detail::meter_ratio<-3 >, std::ratio< 1 > > density_unit
Represents an SI derived unit of density.
Definition: base.h:836
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.
Definition: base.h:824
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.
Definition: base.h:811
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.
Definition: base.h:822
base_unit< detail::meter_ratio< 1 > > length_unit
Represents an SI base unit of length.
Definition: base.h:797
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.
Definition: base.h:804
base_unit concentration_unit
Represents a unit of concentration.
Definition: base.h:837
base_unit< detail::meter_ratio< 2 >, std::ratio< 1 >, std::ratio<-2 > > energy_unit
Represents an SI derived unit of energy.
Definition: base.h:818
base_unit< detail::meter_ratio< 3 > > volume_unit
Represents an SI derived unit of volume.
Definition: base.h:835
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.
Definition: base.h:828
base_unit dimensionless_unit
Represents a quantity with no dimension.
Definition: base.h:793
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.
Definition: base.h:838
base_unit< detail::meter_ratio<-1 >, std::ratio< 1 >, std::ratio<-2 > > pressure_unit
Represents an SI derived unit of pressure.
Definition: base.h:816
base_unit< detail::meter_ratio< 1 >, std::ratio< 0 >, std::ratio<-2 > > acceleration_unit
Represents an SI derived unit of acceleration.
Definition: base.h:812
base_unit scalar_unit
Represents a quantity with no dimension.
Definition: base.h:792
base_unit< detail::meter_ratio< 2 >, std::ratio< 1 >, std::ratio<-3 > > power_unit
Represents an SI derived unit of power.
Definition: base.h:819
base_unit< detail::meter_ratio< 0 >, std::ratio< 0 >, std::ratio<-1 > > frequency_unit
Represents an SI derived unit of frequency.
Definition: base.h:809
base_unit< detail::meter_ratio< 0 >, std::ratio< 0 >, std::ratio< 0 >, std::ratio< 1 > > angle_unit
Represents an SI base unit of angle.
Definition: base.h:800
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.
Definition: base.h:801
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.
Definition: base.h:817
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.
Definition: base.h:808
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.
Definition: base.h:803
base_unit< detail::meter_ratio< 0 >, std::ratio< 0 >, std::ratio<-3 >, std::ratio< 1 > > angular_jerk_unit
Represents an SI derived unit of angular jerk.
Definition: base.h:814
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.
Definition: base.h:820
base_unit< detail::meter_ratio< 0 >, std::ratio< 0 >, std::ratio<-1 > > radioactivity_unit
Represents an SI derived unit of radioactivity.
Definition: base.h:829
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.
Definition: base.h:827
base_unit< detail::meter_ratio< 2 >, std::ratio< 1 >, std::ratio<-2 > > torque_unit
Represents an SI derived unit of torque.
Definition: base.h:833
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.
Definition: base.h:826
base_unit< detail::meter_ratio< 1 >, std::ratio< 0 >, std::ratio<-1 > > velocity_unit
Represents an SI derived unit of velocity.
Definition: base.h:810
base_unit< detail::meter_ratio< 1 >, std::ratio< 1 >, std::ratio<-2 > > force_unit
Represents an SI derived unit of force.
Definition: base.h:815
base_unit< detail::meter_ratio< 0 >, std::ratio< 0 >, std::ratio<-2 >, std::ratio< 1 > > angular_acceleration_unit
Represents an SI derived unit of angular acceleration.
Definition: base.h:813
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.
Definition: base.h:839
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.
Definition: base.h:821
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.
Definition: base.h:823
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.
Definition: base.h:825
base_unit< detail::meter_ratio< 2 > > area_unit
Represents an SI derived unit of area.
Definition: base.h:834
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.
Definition: base.h:802
static constexpr const unit_t< compound_unit< energy::joules, inverse< temperature::kelvin >, inverse< substance::moles > > > R(8.3144598)
Gas constant.
std::string to_string(const T &t)
Definition: base.h:94
unit_t< scalar, UNIT_LIB_DEFAULT_TYPE, decibel_scale > dB_t
Definition: base.h:2870
unit< std::ratio< 1 >, units::category::dimensionless_unit > dimensionless
Definition: base.h:2513
dB_t dBi_t
Definition: base.h:2871
scalar_t dimensionless_t
Definition: base.h:2516
unit_t< scalar > scalar_t
Definition: base.h:2515
unit< std::ratio< 1 >, units::category::scalar_unit > scalar
Definition: base.h:2512
Definition: base.h:3441
UnitTypeLhs() max(const UnitTypeLhs &lhs, const UnitTypeRhs &rhs)
Definition: base.h:3419
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 >
computes the value of value raised to the power as a constexpr
Definition: base.h:2823
constexpr auto pow(const UnitType &value) noexcept -> unit_t< typename units::detail::power_of_unit< power, typename units::traits::unit_t_traits< UnitType >::unit_type >::type, typename units::traits::unit_t_traits< UnitType >::underlying_type, linear_scale >
computes the value of value raised to the power
Definition: base.h:2808
UnitTypeLhs() min(const UnitTypeLhs &lhs, const UnitTypeRhs &rhs)
Definition: base.h:3411
constexpr bool has_decibel_scale_v
Definition: base.h:2441
constexpr bool is_convertible_unit_v
Definition: base.h:1533
constexpr bool has_linear_scale_v
Definition: base.h:2419
constexpr bool is_unit_value_t_category_v
Definition: base.h:3074
constexpr bool is_same_scale_v
Definition: base.h:2465
constexpr bool is_unit_v
Definition: base.h:722
constexpr bool is_unit_t_v
Definition: base.h:1868
typename units::detail::base_unit_of_impl< U >::type base_unit_of
Trait which returns the base_unit type that a unit is originally derived from.
Definition: base.h:934
constexpr bool is_ratio_v
Definition: base.h:594
constexpr bool is_unit_value_t_v
Definition: base.h:3060
Unit Conversion Library namespace.
Definition: volume.h:32
unit_t< Units, T, NonLinearScale > & operator*=(unit_t< Units, T, NonLinearScale > &lhs, const RhsType &rhs) noexcept
Definition: base.h:2305
unit_t< Units, T, NonLinearScale > & operator/=(unit_t< Units, T, NonLinearScale > &lhs, const RhsType &rhs) noexcept
Definition: base.h:2315
constexpr bool operator!=(const UNIT_LIB_DEFAULT_TYPE lhs, const Units &rhs) noexcept
Definition: base.h:2718
unit_t< Units, T, NonLinearScale > & operator+=(unit_t< Units, T, NonLinearScale > &lhs, const RhsType &rhs) noexcept
Definition: base.h:2283
constexpr const char * abbreviation(const T &)
constexpr bool operator==(const UNIT_LIB_DEFAULT_TYPE lhs, const Units &rhs) noexcept
Definition: base.h:2704
constexpr dimensionless::scalar_t operator/(const UnitTypeLhs &lhs, const UnitTypeRhs &rhs) noexcept
Division for convertible unit_t types with a linear scale.
Definition: base.h:2646
constexpr const char * name(const T &)
constexpr bool operator<(const UNIT_LIB_DEFAULT_TYPE lhs, const Units &rhs) noexcept
Definition: base.h:2766
unit_t< Units, T, NonLinearScale > & operator++(unit_t< Units, T, NonLinearScale > &u) noexcept
Definition: base.h:2337
unit_t< Units, T, NonLinearScale > & operator-=(unit_t< Units, T, NonLinearScale > &lhs, const RhsType &rhs) noexcept
Definition: base.h:2294
constexpr bool operator<=(const UNIT_LIB_DEFAULT_TYPE lhs, const Units &rhs) noexcept
Definition: base.h:2754
unit_t< Units, T, NonLinearScale > & operator--(unit_t< Units, T, NonLinearScale > &u) noexcept
Definition: base.h:2361
constexpr bool operator>=(const UNIT_LIB_DEFAULT_TYPE lhs, const Units &rhs) noexcept
Definition: base.h:2730
constexpr bool operator>(const UNIT_LIB_DEFAULT_TYPE lhs, const Units &rhs) noexcept
Definition: base.h:2742
constexpr unit_t< Units, T, NonLinearScale > operator-(const unit_t< Units, T, NonLinearScale > &u) noexcept
Definition: base.h:2354
constexpr unit_t< Units, T, NonLinearScale > operator+(const unit_t< Units, T, NonLinearScale > &u) noexcept
Definition: base.h:2330
constexpr auto operator*(const UnitTypeLhs &lhs, const UnitTypeRhs &rhs) noexcept -> unit_t< compound_unit< squared< typename units::traits::unit_t_traits< UnitTypeLhs >::unit_type > > >
Multiplication type for convertible unit_t types with a linear scale.
Definition: base.h:2590
raw_ostream & operator<<(raw_ostream &OS, sys::TimePoint<> TP)
Class representing SI base unit types.
Definition: base.h:759
Kilogram kilogram_ratio
Definition: base.h:771
Radian radian_ratio
Definition: base.h:773
Kelvin kelvin_ratio
Definition: base.h:775
Ampere ampere_ratio
Definition: base.h:774
Byte byte_ratio
Definition: base.h:778
Candela candela_ratio
Definition: base.h:777
Second second_ratio
Definition: base.h:772
Meter meter_ratio
Definition: base.h:770
Mole mole_ratio
Definition: base.h:776
unit_t scale for representing decibel values.
Definition: base.h:2843
decibel_scale & operator=(const decibel_scale &)=default
constexpr decibel_scale(const T value) noexcept
Definition: base.h:2852
constexpr decibel_scale(const T value, std::true_type, Args &&...) noexcept
Definition: base.h:2854
constexpr decibel_scale()=default
T m_value
linearized value
Definition: base.h:2857
constexpr T operator()() const noexcept
Definition: base.h:2855
constexpr decibel_scale(const decibel_scale &)=default
~decibel_scale()=default
unit_t scale which is linear
Definition: base.h:2489
constexpr T operator()() const noexcept
returns value.
Definition: base.h:2500
UNIT_LIB_DEFAULT_TYPE m_value
linearized value.
Definition: base.h:2502
constexpr linear_scale(const linear_scale &)=default
linear_scale & operator=(const linear_scale &)=default
constexpr linear_scale()=default
default constructor.
~linear_scale()=default
constexpr linear_scale(const T &value, Args &&...) noexcept
constructor.
Definition: base.h:2499
Trait which tests whether a type is inherited from a decibel scale.
Definition: base.h:2439
Trait which tests whether a type is inherited from a linear scale.
Definition: base.h:2417
Trait which tests if a class is a base_unit type.
Definition: base.h:694
Trait which tests whether two container types derived from unit_t are convertible to each other.
Definition: base.h:1828
Trait which checks whether two units can be converted to each other.
Definition: base.h:1531
Trait which tests that class T meets the requirements for a non-linear scale.
Definition: base.h:1751
Trait that tests whether a type represents a std::ratio.
Definition: base.h:592
Trait which tests whether two types has the same non-linear scale.
Definition: base.h:2463
Traits which tests if a class is a unit
Definition: base.h:1866
Trait which tests whether type T is a unit_value_t with a unit type in the given category.
Definition: base.h:3070
Trait which tests whether a type is a unit_value_t representing the given unit type.
Definition: base.h:3058
Traits which tests if a class is a unit
Definition: base.h:720
adds two unit_value_t types at compile-time
Definition: base.h:3111
static constexpr const unit_t< unit_type > value() noexcept
Value of sum.
Definition: base.h:3126
divides two unit_value_t types at compile-time
Definition: base.h:3263
static constexpr const unit_t< unit_type > value() noexcept
Value of quotient.
Definition: base.h:3277
multiplies two unit_value_t types at compile-time
Definition: base.h:3213
static constexpr const unit_t< unit_type > value() noexcept
Value of product.
Definition: base.h:3227
raises unit_value_to a power at compile-time
Definition: base.h:3309
static constexpr const unit_t< unit_type > value() noexcept
Value of exponentiation.
Definition: base.h:3324
calculates square root of unit_value_t at compile-time
Definition: base.h:3356
static constexpr const unit_t< unit_type > value() noexcept
Value of square root.
Definition: base.h:3371
subtracts two unit_value_t types at compile-time
Definition: base.h:3160
static constexpr const unit_t< unit_type > value() noexcept
Value of difference.
Definition: base.h:3176
Stores a rational unit value as a compile-time constant.
Definition: base.h:3037
Units unit_type
Definition: base.h:3038
std::ratio< Num, Denom > ratio
Definition: base.h:3039
static constexpr const unit_t< Units > value()
Definition: base.h:3042
Type representing an arbitrary unit.
Definition: base.h:886
std::ratio_add< std::ratio_multiply< typename BaseUnit::conversion_ratio, Translation >, typename BaseUnit::translation_ratio > translation_ratio
Definition: base.h:894
std::ratio_multiply< typename BaseUnit::conversion_ratio, Conversion > conversion_ratio
Definition: base.h:892
units::traits::unit_traits< BaseUnit >::base_unit_type base_unit_type
Definition: base.h:891
std::ratio_add< typename BaseUnit::pi_exponent_ratio, PiExponent > pi_exponent_ratio
Definition: base.h:893