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