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