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